nckernel  0.1
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pthread_fork.c
Go to the documentation of this file.
1 #include <sys/syscall.h>
2 #include <sys/types.h>
3 #include <stdio.h>
4 #include <stdarg.h>
5 #include <stddef.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <stdint.h>
9 #include <unistd.h>
10 #include <assert.h>
11 #include <pthread.h>
12 #include <errno.h>
13 #include <limits.h>
14 #include <fcntl.h>
15 
16 #include <object.h>
17 #include <crt0.h>
18 #include <isr.h>
19 #include <list.h>
20 #include <thread.h>
21 #include <vfs.h>
22 #include <interrupt.h>
23 #include <x86_util.h>
24 #include <semaphore0.h>
25 
26 #include <zone.h>
27 #include <page_frame.h>
28 #include <onetime_map.h>
29 
30 #include <elf.h>
31 
32 #include <segment.h> /* DESC_KERNEL_DS, DESC_KERNEL_CS */
33 #include <arch.h>
34 
35 #include <debug.h>
36 #include <common.h>
37 
38 #include <paging.h> /* struct cr3, referenced by x86.h */
39 #include <x86.h> /* struct x86_arch_data */
40 
41 /* A whole new world */
42 
43 static int __attribute__((noreturn)) cleanup(struct thread *tcb, void *arg)
44 {
50  if (!tcb) {
51  panic("Failed to get TCB");
52  }
53 
54  dbg_printf("\nTHREAD DESTROYING %p (arg: %p)\n", tcb, arg);
56  while (1) {
57  }
58 }
59 
66 static inline void push_user_stackframe(struct thread *tcb)
67 {
68  struct pt_regs *isr_frame;
69  struct pt_regs_user *user_frame;
70 
71  user_frame = (struct pt_regs_user *)tcb->esp;
72  user_frame--;
73 
79  user_frame->esp = atoi(getenv("kvma"));
80  user_frame->ss = (DESC_USER_SS << 3) | TI(GDT) | USER;
81 
82  isr_frame = (struct pt_regs *)user_frame;
83  isr_frame--;
84  memset(&isr_frame->pushad, 0, sizeof(isr_frame->pushad));
85  isr_frame->pushad.esp = 0;
86  isr_frame->pushad.ebp = 0;
87  isr_frame->reserved0 = 0;
88  isr_frame->reserved1 = 0;
89  isr_frame->reserved2 = 0;
90  isr_frame->reserved3 = 0;
91  isr_frame->ds = (DESC_USER_DS << 3) | TI(GDT) | USER;
92  isr_frame->es = isr_frame->ds;
93  isr_frame->fs = isr_frame->ds;
94  isr_frame->gs = isr_frame->ds;
95  isr_frame->irq = IRQ_NR_TIMER;
96  isr_frame->cs = (DESC_USER_CS << 3) | TI(GDT) | USER;
97  isr_frame->eflags = 0x0202;
105  isr_frame->eip = 0;
106 
111  isr_frame->ebp = 0;
112 
113  tcb->esp = (uint32_t *)isr_frame;
114  return;
115 }
116 
117 static inline void push_kernel_stackframe(struct thread *tcb,
118  unsigned long eip, unsigned long arg)
119 {
120  struct pt_regs *isr_frame;
121  struct pt_regs_kernel *thread_frame;
122  unsigned long *exit_stack;
123 
124  exit_stack = (unsigned long *)tcb->esp;
125 
130  exit_stack--;
131  *exit_stack = arg;
132 
133  exit_stack--;
134  *exit_stack = (unsigned long)tcb;
135 
136  thread_frame = (struct pt_regs_kernel *)exit_stack;
137  thread_frame--;
145  thread_frame->ret_addr = (unsigned long)cleanup;
146  thread_frame->arg = (unsigned long)arg;
147 
155  isr_frame = (struct pt_regs *)thread_frame;
156  isr_frame--;
157  memset(&isr_frame->pushad, 0, sizeof(isr_frame->pushad));
158  isr_frame->pushad.esp = 0;
159  isr_frame->pushad.ebp = 0;
160  isr_frame->reserved0 = 0;
161  isr_frame->reserved1 = 0;
162  isr_frame->reserved2 = 0;
163  isr_frame->reserved3 = 0;
164  isr_frame->ds = (DESC_KERNEL_DS << 3) | TI(GDT) | KERNEL;
165  isr_frame->es = isr_frame->ds;
166  isr_frame->fs = isr_frame->ds;
167  isr_frame->gs = isr_frame->ds;
168  isr_frame->irq = IRQ_NR_TIMER;
169  isr_frame->cs = (DESC_KERNEL_CS << 3) | TI(GDT) | KERNEL;
170  isr_frame->eflags = 0x0202;
171  isr_frame->eip = eip;
172  isr_frame->ebp = (unsigned long)&thread_frame->arg;
173 
174  tcb->esp = (uint32_t *)isr_frame;
175 
176  return;
177 }
178 
179 int pthread_init(const pthread_attr_t *_attr)
180 {
181  struct thread *tcb;
182  struct thread_attr *attr;
183  struct x86_arch_data *arch_data;
184  int ret;
185 
186  if (!_attr) {
187  dbg_printf("Invalid argument\n");
188  return -EINVAL;
189  }
190 
191  arch_data = malloc(sizeof(*arch_data));
192  if (!arch_data) {
193  dbg_printf("Failed to allocate heap for arch_data\n");
194  return -ENOMEM;
195  }
196 
197  arch_data->pma_pgd = read_cr3();
198  arch_data->rpgd = vm_rpgd();
199 
200  attr = (struct thread_attr *)*_attr;
201  attr->is_first = 1;
202 
203  tcb = malloc(sizeof(*tcb));
204  if (!tcb) {
205  free(arch_data);
206  return -ENOMEM;
207  }
208 
209  ret = thread_create(tcb, attr);
210  if (ret < 0) {
211  dbg_printf("Failed to create a new thread\n");
212  free(arch_data);
213  free(tcb);
214  return ret;
215  }
216 
217  tcb->arch_data = arch_data;
218  tcb->user_data = NULL;
219  return 0;
220 }
221 
222 pid_t fork(void)
223 {
235  return -ENOSYS;
236 }
237 
238 static inline int update_thread_user_data(struct thread *tcb)
239 {
240  struct x86_user_data *new_user_data;
241 
242  new_user_data = calloc(1, sizeof(*new_user_data));
243  if (!new_user_data) {
244  return -ENOMEM;
245  }
246 
247  tcb->user_data = new_user_data;
248  return 0;
249 }
250 
251 static inline int update_thread_for_user(struct thread *tcb)
252 {
253  struct x86_arch_data *arch_data;
254  struct pgde *pgd;
255  struct pgde *src_pgd;
256  void *rpgd;
257  void *pma_pgd;
258  unsigned long flags;
259  int ret;
260 
261  assert(!tcb->user_data && "user data already initialized");
262  assert(tcb->arch_data && "arch data is not valid");
263 
264  arch_data = tcb->arch_data;
265 
270  pma_pgd = page_frame_alloc(ZONE_NORMAL, 1);
271  if (!pma_pgd) {
272  return -ENOMEM;
273  }
274 
275  pgd = onetime_map(pma_pgd);
276  if (!pgd) {
277  page_frame_free(pma_pgd);
278  return -ENOMEM;
279  }
280 
281  src_pgd = onetime_map(arch_data->pma_pgd);
282  if (!src_pgd) {
283  onetime_unmap(pgd);
284  page_frame_free(pma_pgd);
285  return -ENOMEM;
286  }
287 
288  memcpy(pgd, src_pgd, sysconf(_SC_PAGESIZE));
289 
290  onetime_unmap(pgd);
291  onetime_unmap(src_pgd);
292 
296  rpgd = malloc(sysconf(_SC_PAGESIZE));
297  if (!rpgd) {
298  page_frame_free(pma_pgd);
299  return -ENOMEM;
300  }
301 
302  memcpy(rpgd, arch_data->rpgd, sysconf(_SC_PAGESIZE));
303 
308  irq_local_save(&flags);
312  ret = update_thread_user_data(tcb);
313  if (ret < 0) {
314  irq_local_restore(flags);
315  free(rpgd);
316  page_frame_free(pma_pgd);
317  return ret;
318  }
319 
320  arch_data->pma_pgd = pma_pgd;
321  arch_data->rpgd = rpgd;
322  irq_local_restore(flags);
323  return 0;
324 }
325 
326 int execl(const char *path, const char *arg, ...)
327 {
328  va_list ap;
329  struct thread *tcb;
330  int ret;
331 
332  tcb = (struct thread *)pthread_self();
333  /* \note 커널 쓰레드는 사용자 쓰레드로 변경 될 수 없다. */
334  assert(!tcb->attr.is_first && "Main thread is not able to be user level thread");
335 
336  ret = update_thread_for_user(tcb);
337  if (ret < 0) {
338  return ret;
339  }
340 
341  va_start(ap, arg);
349  va_end(ap);
350 
351  return -ENOSYS;
352 }
353 
354 int execle(const char *path, const char *arg, ...)
355 {
356  va_list ap;
357  struct thread *tcb;
358  int ret;
359 
360  tcb = (struct thread *)pthread_self();
361  /* \note 커널 쓰레드는 사용자 쓰레드로 변경 될 수 없다. */
362  assert(!tcb->attr.is_first && "Main thread is not able to be user level thread");
363 
364  ret = update_thread_for_user(tcb);
365  if (ret < 0) {
366  return ret;
367  }
368 
369  va_start(ap, arg);
377  va_end(ap);
378 
379  return -ENOSYS;
380 }
381 
382 int execlp(const char *file, const char *arg, ...)
383 {
384  va_list ap;
385  struct thread *tcb;
386  int ret;
387 
388  tcb = (struct thread *)pthread_self();
389  /* \note 커널 쓰레드는 사용자 쓰레드로 변경 될 수 없다. */
390  assert(!tcb->attr.is_first && "Main thread is not able to be user level thread");
391 
392  ret = update_thread_for_user(tcb);
393  if (ret < 0) {
394  return ret;
395  }
396 
397  va_start(ap, arg);
405  va_end(ap);
406 
407  return -ENOSYS;
408 }
409 
410 int execv(const char *path, char *const argv[])
411 {
412  struct thread *tcb;
413  int ret;
414 
415  tcb = (struct thread *)pthread_self();
420  assert(!tcb->attr.is_first
421  && "Main thread is not able to be a user level thread");
422 
423  ret = update_thread_for_user(tcb);
424  if (ret < 0) {
425  return ret;
426  }
427 
428  load_elf(tcb, argv[0]);
437  return -ENOSYS;
438 }
439 
440 int execvpe(const char *file, const char *const argv[], char *const envp[])
441 {
442  struct thread *tcb;
443  int ret;
444 
445  tcb = (struct thread *)pthread_self();
446  /* \note 커널 쓰레드는 사용자 쓰레드로 변경 될 수 없다. */
447  assert(!tcb->attr.is_first && "Main thread is not able to be user level thread");
448 
449  ret = update_thread_for_user(tcb);
450  if (ret < 0) {
451  return ret;
452  }
453 
461  return -ENOSYS;
462 }
463 
464 int execvp(const char *file, char *const argv[])
465 {
466  struct thread *tcb;
467  int ret;
468 
469  tcb = (struct thread *)pthread_self();
470 
471  /* \note 커널 쓰레드는 사용자 쓰레드로 변경 될 수 없다. */
472  assert(!tcb->attr.is_first && "Main thread is not able to be user level thread");
473 
474  ret = update_thread_for_user(tcb);
475  if (ret < 0) {
476  return ret;
477  }
478 
486  return -ENOSYS;
487 }
488 
489 int pthread_create(pthread_t *handle, const pthread_attr_t *_attr,
490  void *(*func)(void *), void *arg)
491 {
492  struct x86_arch_data *arch_data;
493  struct thread_attr *attr;
494  struct thread *tcb;
495  int ret;
496 
497  arch_data = malloc(sizeof(*arch_data));
498  if (!arch_data) {
499  return -ENOMEM;
500  }
501 
502  attr = (struct thread_attr *)(_attr ? *_attr : NULL);
503 
504  tcb = malloc(sizeof(*tcb));
505  if (!tcb) {
506  free(arch_data);
507  return -ENOMEM;
508  }
509 
510  ret = thread_create(tcb, attr);
511  if (ret < 0) {
512  free(arch_data);
513  free(tcb);
514  return ret;
515  }
516 
520  memcpy(arch_data, tcb->root->arch_data, sizeof(*arch_data));
521  tcb->arch_data = arch_data;
522  tcb->user_data = NULL;
523 
524  push_kernel_stackframe(tcb, (uint32_t)func, (uint32_t)arg);
525 
526  thread_set_status(tcb, READY);
527  *handle = (pthread_t)tcb;
528  return 0;
529 }
530 
532 {
533  struct thread_attr *attr;
534  uint32_t tcb_sz;
535  struct thread_attr init_attr = {
536  .stack = {
537  .addr = NULL,
538  .size = PTHREAD_STACK_MIN,
539  .is_allocated = 0,
540  },
541 
542  .is_first = 0,
543  };
544 
545  tcb_sz = common_get_tcb_sz();
546  if (!tcb_sz) {
547  return -EFAULT;
548  }
549 
550  attr = malloc(sizeof(*attr));
551  if (!attr) {
552  return -ENOMEM;
553  }
554 
555  memcpy(attr, &init_attr, sizeof(init_attr));
556 
557  /* Reserve more memory for Local TCB */
558  attr->stack.size += tcb_sz;
559 
560  *_attr = (pthread_attr_t)attr;
561  return 0;
562 }
563 
565 {
566  struct thread_attr *attr;
567 
568  attr = (struct thread_attr *)*_attr;
569  free(attr);
570 
571  *_attr = (pthread_attr_t)NULL;
572  return 0;
573 }
574 
575 void __attribute__((noreturn)) pthread_exit(void *retval)
576 {
577  thread_set_status(pthread_self(), DELETED);
578  while (1) {
579  }
580 }
581 
582 int pthread_join(pthread_t handle, void **retval)
583 {
584  struct thread *tcb;
585  tcb = (struct thread *)handle;
586 
587  printf("Join: %p\n", tcb);
588 
589  return -1;
590 }
591 
593 {
594  struct thread *tcb;
595  tcb = (struct thread *)handle;
596 
597  printf("Detach: %p\n", tcb);
598 
599  return -1;
600 }
601 
603 {
604  struct thread *th1;
605  struct thread *th2;
606 
607  th1 = (struct thread *)t1;
608  th2 = (struct thread *)t2;
609 
610  return th1 == th2;
611 }
612 
614 {
615  struct thread *tcb;
616  struct x86_arch_data *arch_data;
617  int ret;
618  int ring;
619  unsigned long flags;
620 
629  irq_local_save(&flags);
630 
631  if (pthread_equal(pthread_self(), thid)) {
632  irq_local_restore(flags);
633  return -EINVAL;
634  }
635 
636  tcb = (struct thread *)thid;
637  ring = x86_util_get_ring(tcb);
638 
639  dbg_printf("Let's canceling the thread %p (ring: %d)\n", tcb, ring);
640 
641  ret = object_destroy(&tcb->object);
642 
643  if (ret < 0) {
644  irq_local_restore(flags);
645  dbg_printf("Failed to destroy an object\n");
646  return ret;
647  }
648 
654  arch_data = tcb->arch_data;
655  if (ring == USER) {
668  if (tcb->user_data) {
669  /* Release this */
670  }
671  } else {
672  arch_data->pma_pgd = NULL;
673  arch_data->rpgd = NULL;
674  }
675  free(arch_data);
676  sem_clear(tcb);
677  free(tcb);
678 
679  irq_local_restore(flags);
680  return 0;
681 }
682 
683 int pthread_attr_setstack(pthread_attr_t *_attr, void *addr, size_t size)
684 {
685  struct thread_attr *attr;
686  uint32_t tcb_sz;
687 
688  tcb_sz = common_get_tcb_sz();
689  if (!tcb_sz) {
690  return -EFAULT;
691  }
692 
693  attr = (struct thread_attr *)*_attr;
694  attr->stack.addr = addr;
695  attr->stack.size = size;
696 
697  return 0;
698 }
699 
700 int pthread_attr_getstack(pthread_attr_t *_attr, void **addr, size_t *size)
701 {
702  struct thread_attr *attr;
703 
704  attr = (struct thread_attr *)*_attr;
705  *addr = (void *)attr->stack.addr;
706  *size = attr->stack.size;
707  return 0;
708 }
709 
720 {
721  register unsigned long esp asm("esp");
722  struct local_tcb *local;
723  struct thread *tcb;
724  uint32_t unit;
725 
726  unit = sysconf(_SC_PAGESIZE);
727  unit = esp & ~(unit - 1);
728  local = (struct local_tcb *)unit;
729 
730  while (strncmp(local->tag, THREAD_TAG, sizeof(local->tag))) {
731  local++;
732 
733  /* Couldn't find the correct instance */
734  if ((unsigned long)local < unit) {
735  return NULL;
736  }
737  }
738 
739  tcb = local->tcb_ptr;
740  return (pthread_t)tcb;
741 }
742 
743 int pthread_attr_setstacksize(pthread_attr_t *_attr, size_t stacksize)
744 {
745  struct thread_attr *attr;
746 
747  attr = (struct thread_attr *)*_attr;
748  attr->stack.size = stacksize;
749  return 0;
750 }
751 
752 int pthread_attr_getstacksize(pthread_attr_t *_attr, size_t *stacksize)
753 {
754  struct thread_attr *attr;
755 
756  attr = (struct thread_attr *)*_attr;
757  *stacksize = attr->stack.size;
758  return 0;
759 }
760 
761 int pthread_attr_setstackaddr(pthread_attr_t *_attr, void *stackaddr)
762 {
763  struct thread_attr *attr;
764 
765  attr = (struct thread_attr *)*_attr;
766  attr->stack.addr = stackaddr;
767  return 0;
768 }
769 
770 int pthread_attr_getstackaddr(pthread_attr_t *_attr, void **stackaddr)
771 {
772  struct thread_attr *attr;
773 
774  attr = (struct thread_attr *)*_attr;
775  *stackaddr = attr->stack.addr;
776  return 0;
777 }
778 
779 int pthread_yield(void)
780 {
781  return syscall(SYS_NR_YIELD);
782 }
783 
784 /* End of a file */