SimpleOS

LXR

Navigation



Site hébergé par : enix

The LXR Cross Referencer for SOS

source navigation ]
diff markup ]
identifier search ]
general search ]
 
 
Article:1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 6.5 ] [ 7 ] [ 7.5 ] [ 8 ] [ 9 ] [ 9.5 ]

001 /* Copyright (C) 2005  David Decotigny
002 
003    This program is free software; you can redistribute it and/or
004    modify it under the terms of the GNU General Public License
005    as published by the Free Software Foundation; either version 2
006    of the License, or (at your option) any later version.
007    
008    This program is distributed in the hope that it will be useful,
009    but WITHOUT ANY WARRANTY; without even the implied warranty of
010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
011    GNU General Public License for more details.
012    
013    You should have received a copy of the GNU General Public License
014    along with this program; if not, write to the Free Software
015    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
016    USA. 
017 */
018 #include <sos/thread.h>
019 #include <sos/kmalloc.h>
020 #include <sos/klibc.h>
021 #include <drivers/bochs.h>
022 #include <hwcore/paging.h>
023 #include <sos/physmem.h>
024 #include <sos/umem_vmm.h>
025 #include <drivers/zero.h>
026 #include <drivers/mem.h>
027 #include <sos/binfmt_elf32.h>
028 
029 #include <hwcore/cpu_context.h>
030 #include <sos/uaccess.h>
031 #include "syscall.h"
032 
033 
034 /**
035  * THE syscall entry point
036  */
037 sos_ret_t sos_do_syscall(int syscall_id,
038                          const struct sos_cpu_state *user_ctxt)
039 {
040   sos_ret_t retval;
041 
042   switch(syscall_id)
043     {
044     case SOS_SYSCALL_ID_EXIT:
045       {
046         unsigned int status;
047         retval = sos_syscall_get1arg(user_ctxt, & status);
048         if (SOS_OK != retval)
049           break;
050         sos_thread_exit();
051         retval = -SOS_EFATAL; /* Not reached */
052       }
053       break;
054 
055     case SOS_SYSCALL_ID_FORK:
056       {
057         struct sos_thread *cur_thr, *new_thr;
058         struct sos_process *new_proc;
059 
060         cur_thr = sos_thread_get_current();
061 
062         /* Duplicate the current process (and its address space) */
063         new_proc = sos_process_create(NULL, TRUE);
064         if (! new_proc)
065           {
066             retval = -SOS_ENOMEM;
067             break;
068           }
069         
070         /* Create *the* thread in this new processs, copy of the
071            current user thread (same registers, EXCEPT eax which is
072            set to 0) */
073         new_thr =
074           sos_duplicate_user_thread(NULL, new_proc,
075                                     cur_thr,
076                                     user_ctxt,
077                                     0);
078         if (! new_thr)
079           {
080             sos_process_unref(new_proc);
081             retval = -SOS_ENOMEM;
082             break;
083           }
084 
085         sos_process_unref(new_proc);
086 
087         /* Return to the "parent" thread with a value different from
088            0. Unix says it should be the "PID" of the child. We don't
089            have such a "PID" notion for now */
090         retval = (sos_ui32_t)new_proc;
091       }
092       break;
093 
094     case SOS_SYSCALL_ID_EXEC:
095       {
096         struct sos_thread *cur_thr, *new_thr;
097         struct sos_umem_vmm_as *new_as;
098         sos_uaddr_t user_str, ustack, start_uaddr;
099         sos_size_t len;
100         char * str;
101 
102         cur_thr = sos_thread_get_current();
103 
104         /* Make sure the process has exactly 1 thread in it */
105         if (sos_process_get_nb_threads(cur_thr->process) != 1)
106           {
107             retval = -SOS_EBUSY;
108             break;
109           }
110 
111         /* Get the user arguments */
112         retval = sos_syscall_get2args(user_ctxt, & user_str, & len);
113         if (SOS_OK != retval)
114           break;
115 
116         /* Copy the program name into kernel sppace */
117         str = (char*)sos_kmalloc(len + 1, 0);
118         if (! str)
119           {
120             retval = -SOS_ENOMEM;
121             break;
122           }
123         retval = sos_strzcpy_from_user(str, user_str, len + 1);
124         if (retval < SOS_OK)
125           {
126             sos_kfree((sos_vaddr_t)str);
127             break;
128           }
129 
130         /* Create a new empty address space to map the program */
131         new_as = sos_umem_vmm_create_empty_as(cur_thr->process);
132         if (! new_as)
133           {
134             sos_kfree((sos_vaddr_t)str);
135             retval = -SOS_ENOMEM;
136             break;
137           }
138 
139         /* Map the program in it */
140         start_uaddr = sos_binfmt_elf32_map(new_as, str);
141         if (start_uaddr == (sos_uaddr_t)NULL)
142           {
143             sos_umem_vmm_delete_as(new_as);
144             sos_kfree((sos_vaddr_t)str);
145             retval = -SOS_ENOENT;
146             break;
147           }
148 
149         /* Allocate space for the user stack (8MB) */
150 #define SOS_DEFAULT_USER_STACK_SIZE (8 << 20)
151         ustack = (SOS_PAGING_TOP_USER_ADDRESS - SOS_DEFAULT_USER_STACK_SIZE)
152                     + 1;
153         retval = sos_dev_zero_map(new_as, &ustack, SOS_DEFAULT_USER_STACK_SIZE,
154                                   SOS_VM_MAP_PROT_READ | SOS_VM_MAP_PROT_WRITE,
155                                   /* PRIVATE */ 0);
156         if (SOS_OK != retval)
157           {
158             sos_umem_vmm_delete_as(new_as);
159             sos_kfree((sos_vaddr_t)str);
160             break;
161           }
162 
163         /* Now create the user thread */
164         new_thr = sos_create_user_thread(NULL,
165                                          cur_thr->process,
166                                          start_uaddr,
167                                          0, 0,
168                                          ustack + SOS_DEFAULT_USER_STACK_SIZE
169                                            - 4,
170                                          SOS_SCHED_PRIO_TS_LOWEST);
171         if (! new_thr)
172           {
173             sos_umem_vmm_delete_as(new_as);
174             sos_kfree((sos_vaddr_t)str);
175             retval = -SOS_ENOMEM;
176             break;          
177           }
178 
179         sos_process_set_name(cur_thr->process, str);
180 
181         /* Switch to this address space */
182         retval = sos_process_set_address_space(cur_thr->process,
183                                                new_as);
184         if (SOS_OK != retval)
185           {
186             sos_umem_vmm_delete_as(new_as);
187             sos_kfree((sos_vaddr_t)str);
188             break;          
189           }
190 
191         /* The current thread must exit now */
192         sos_kfree((sos_vaddr_t)str);
193         sos_thread_exit();
194         retval = -SOS_EFATAL;
195       }
196       break;
197 
198     case SOS_SYSCALL_ID_MMAP:
199       {
200         sos_uaddr_t ptr_hint_uaddr;
201         sos_uaddr_t hint_uaddr;
202         sos_size_t  length;
203         sos_ui32_t  prot;
204         sos_ui32_t  flags;
205         sos_uaddr_t name_user;
206         sos_ui32_t  offs64_hi;
207         sos_ui32_t  offs64_lo;
208         sos_luoffset_t offset_in_resource;
209         char        name[256];
210         struct sos_umem_vmm_as * my_as;
211         
212         retval = sos_syscall_get7args(user_ctxt,
213                                       (unsigned int*)& ptr_hint_uaddr,
214                                       (unsigned int*)& length,
215                                       (unsigned int*)& prot,
216                                       (unsigned int*)& flags,
217                                       (unsigned int*)& name_user,
218                                       (unsigned int*)& offs64_hi,
219                                       (unsigned int*)& offs64_lo);
220         if (SOS_OK != retval)
221           break;
222 
223         /* Compute 64 bits offset value */
224         offset_in_resource   = offs64_hi;
225         offset_in_resource <<= 32;
226         offset_in_resource  |= offs64_lo;
227 
228         retval = sos_memcpy_from_user((sos_vaddr_t)& hint_uaddr,
229                                       ptr_hint_uaddr,
230                                       sizeof(hint_uaddr));
231         if (sizeof(hint_uaddr) != retval)
232           {
233             retval = -SOS_EFAULT;
234             break;
235           }
236 
237         retval = sos_strzcpy_from_user(name, name_user, sizeof(name));
238         if (SOS_OK != retval)
239           break;
240 
241         my_as
242           = sos_process_get_address_space(sos_thread_get_current()->process);
243         if ( (0 == strncmp(name, "/dev/zero", sizeof(name)))
244              || (0 == strncmp(name, "/dev/null", sizeof(name))) )
245           retval = sos_dev_zero_map(my_as, & hint_uaddr, length, prot, flags);
246         else if (0 == strncmp(name, "/dev/mem", sizeof(name)))
247           retval = sos_dev_physmem_map(my_as, & hint_uaddr, length,
248                                        offset_in_resource, prot, flags);
249         else if (0 == strncmp(name, "/dev/kmem", sizeof(name)))
250           retval = sos_dev_kmem_map(my_as, & hint_uaddr, length,
251                                     offset_in_resource, prot, flags);
252         else
253           retval = -SOS_ENOENT;
254 
255         if (SOS_OK == retval)
256           {
257             if (sizeof(hint_uaddr)
258                 != sos_memcpy_to_user(ptr_hint_uaddr,
259                                       (sos_vaddr_t)& hint_uaddr,
260                                       sizeof(hint_uaddr)))
261               {
262                 sos_umem_vmm_unmap(my_as, hint_uaddr, length);
263                 retval = -SOS_EFAULT;
264               }
265           }
266 
267       }
268       break;
269 
270     case SOS_SYSCALL_ID_MUNMAP:
271       {
272         sos_uaddr_t start_uaddr;
273         sos_size_t  size;
274         struct sos_umem_vmm_as * my_as;
275 
276         my_as
277           = sos_process_get_address_space(sos_thread_get_current()->process);
278 
279         retval = sos_syscall_get2args(user_ctxt,
280                                       (unsigned int*)& start_uaddr,
281                                       (unsigned int*)& size);
282         if (SOS_OK != retval)
283           break;
284 
285         retval = sos_umem_vmm_unmap(my_as, start_uaddr, size);
286       }
287       break;
288 
289     case SOS_SYSCALL_ID_MPROTECT:
290       {
291         sos_uaddr_t start_uaddr;
292         sos_size_t  size;
293         sos_ui32_t  new_access_rights;
294         struct sos_umem_vmm_as * my_as;
295 
296         my_as
297           = sos_process_get_address_space(sos_thread_get_current()->process);
298 
299         retval = sos_syscall_get3args(user_ctxt,
300                                       (unsigned int*)& start_uaddr,
301                                       (unsigned int*)& size,
302                                       (unsigned int*)& new_access_rights);
303         if (SOS_OK != retval)
304           break;
305 
306         retval = sos_thread_prepare_user_space_access(NULL, (sos_vaddr_t)NULL);
307         if (SOS_OK != retval)
308           break;
309 
310         retval = sos_umem_vmm_chprot(my_as, start_uaddr, size,
311                                      new_access_rights);
312 
313         sos_thread_end_user_space_access();
314       }
315       break;
316 
317     case SOS_SYSCALL_ID_MRESIZE:
318       {
319         sos_uaddr_t old_uaddr;
320         sos_size_t  old_size;
321         sos_uaddr_t *uptr_new_uaddr;
322         sos_uaddr_t new_uaddr;
323         sos_size_t  new_size;
324         sos_ui32_t  flags;
325         struct sos_umem_vmm_as * my_as;
326 
327         my_as
328           = sos_process_get_address_space(sos_thread_get_current()->process);
329 
330         retval = sos_syscall_get5args(user_ctxt,
331                                       (unsigned int*)& old_uaddr,
332                                       (unsigned int*)& old_size,
333                                       (unsigned int*)& uptr_new_uaddr,
334                                       (unsigned int*)& new_size,
335                                       (unsigned int*)& flags);
336         if (SOS_OK != retval)
337           break;
338 
339         if (sizeof(new_uaddr) != sos_memcpy_from_user((sos_vaddr_t)& new_uaddr,
340                                                       (sos_uaddr_t)
341                                                         uptr_new_uaddr,
342                                                       sizeof(new_uaddr)))
343           {
344             retval = -SOS_EFAULT;
345             break;
346           }
347 
348         retval = sos_thread_prepare_user_space_access(NULL, (sos_vaddr_t)NULL);
349         if (SOS_OK != retval)
350           break;
351 
352         retval = sos_umem_vmm_resize(my_as, old_uaddr, old_size,
353                                      & new_uaddr, new_size, flags);
354         sos_thread_end_user_space_access();
355         if (SOS_OK != retval)
356           break;
357 
358         if (sizeof(new_uaddr)
359             == sos_memcpy_to_user((sos_uaddr_t)uptr_new_uaddr,
360                                   (sos_vaddr_t)&new_uaddr,
361                                   sizeof(new_uaddr)))
362           {
363             retval = -SOS_EFAULT;
364             break;
365           }
366       }
367       break;
368 
369     case SOS_SYSCALL_ID_NEW_THREAD:
370       {
371         sos_uaddr_t start_func;
372         sos_ui32_t  start_arg1, start_arg2;
373         sos_size_t  stack_size;
374         sos_uaddr_t stack_uaddr;
375 
376         struct sos_thread * new_thr;
377         struct sos_umem_vmm_as * my_as;
378 
379         my_as
380           = sos_process_get_address_space(sos_thread_get_current()->process);
381 
382         retval = sos_syscall_get4args(user_ctxt,
383                                       (unsigned int*)& start_func,
384                                       (unsigned int*)& start_arg1,
385                                       (unsigned int*)& start_arg2,
386                                       (unsigned int*)& stack_size);
387         if (SOS_OK != retval)
388           break;
389 
390         if (stack_size <= 0)
391           {
392             retval = -SOS_EINVAL;
393             break;
394           }
395 
396         /* Allocate the stack */
397         stack_uaddr = 0;
398         stack_size = SOS_PAGE_ALIGN_SUP(stack_size);
399         retval = sos_dev_zero_map(my_as, & stack_uaddr, stack_size,
400                                   SOS_VM_MAP_PROT_READ | SOS_VM_MAP_PROT_WRITE,
401                                   /* PRIVATE */ 0);
402         if (SOS_OK != retval)
403           break;
404 
405         /* Now create the user thread */
406         new_thr = sos_create_user_thread(NULL,
407                                          sos_thread_get_current()->process,
408                                          start_func,
409                                          start_arg1,
410                                          start_arg2,
411                                          stack_uaddr + stack_size - 4,
412                                          SOS_SCHED_PRIO_TS_LOWEST);
413 
414         if (! new_thr)
415           {
416             sos_umem_vmm_unmap(my_as, stack_uaddr, stack_size);
417             retval = -SOS_ENOMEM;
418             break;          
419           }
420       }
421       break;
422 
423     case SOS_SYSCALL_ID_NANOSLEEP:
424       {
425         struct sos_time delay;
426 
427         retval = sos_syscall_get2args(user_ctxt,
428                                       (unsigned int*)& delay.sec,
429                                       (unsigned int*)& delay.nanosec);
430         if (SOS_OK != retval)
431           break;
432 
433         retval = sos_thread_sleep(& delay);
434       }
435       break;
436 
437     case SOS_SYSCALL_ID_BRK:
438       {
439         sos_uaddr_t new_top_heap;
440         struct sos_umem_vmm_as * my_as;
441 
442         my_as
443           = sos_process_get_address_space(sos_thread_get_current()->process);
444 
445         retval = sos_syscall_get1arg(user_ctxt,
446                                      (unsigned int*)& new_top_heap);
447         if (SOS_OK != retval)
448           break;
449 
450         retval = sos_thread_prepare_user_space_access(NULL, (sos_vaddr_t)NULL);
451         if (SOS_OK != retval)
452           break;
453 
454         retval = sos_umem_vmm_brk(my_as, new_top_heap);
455         sos_thread_end_user_space_access();
456       }
457       break;
458 
459     case SOS_SYSCALL_ID_BOCHS_WRITE:
460       {
461         sos_uaddr_t user_str;
462         sos_size_t len;
463         char * str;
464         retval = sos_syscall_get2args(user_ctxt, & user_str, & len);
465         if (SOS_OK != retval)
466           break;
467 
468         str = (char*)sos_kmalloc(len + 1, 0);
469         if (str)
470           {
471             retval = sos_strzcpy_from_user(str, user_str, len+1);
472             str[len] = '\0';
473             if (SOS_OK == retval)
474               {
475                 sos_bochs_printf("THR 0x%x: ",
476                                  (unsigned)sos_thread_get_current());
477                 retval = sos_bochs_putstring(str);
478                 retval = len;
479               }
480             sos_kfree((sos_vaddr_t)str);
481           }
482         else
483           retval = -SOS_ENOMEM;
484       }
485       break;
486 
487 
488       /* ***********************************************
489        * Debug syscalls (will be removed in the future)
490        */
491 
492 
493       /**
494        * Syscall 4012: hexdump of a user-space memory region
495        * args: addr_start size, retval=ignored
496        */
497     case 4012:
498       {
499         sos_uaddr_t user_str;
500         unsigned int len;
501         unsigned char * str;
502 
503         retval = sos_syscall_get2args(user_ctxt, & user_str, & len);
504         if (SOS_OK != retval)
505           break;
506 
507         str = (char*)sos_kmalloc(len + 1, 0);
508         if (str)
509           {
510             int i;
511             sos_bochs_printf("Hexdump(0x%x, %d):\n", user_str, len);
512             retval = sos_memcpy_from_user((sos_vaddr_t) str, user_str, len);
513             sos_bochs_printf("  (Successfully copied %d out of %d)\n",
514                              retval, len);
515 
516             for (i = 0 ; i < retval ; i++)
517               {
518                 if ((i % 32) == 0)
519                   sos_bochs_printf("%x:", i);
520                 sos_bochs_printf(" %x", str[i]);
521                 if (((i+1) % 32) == 0)
522                   sos_bochs_printf("\n");
523               }
524             if (i % 32)
525               sos_bochs_printf("\n");
526 
527             sos_kfree((sos_vaddr_t)str);
528           }
529         else
530           retval = -SOS_ENOMEM;
531       }
532       break;
533 
534       
535       /**
536        * Syscall 4004: lists the VR of the current thread's address space
537        * args: debug_string, retval=ignored
538        */
539     case 4004:
540       {
541         sos_uaddr_t ustr;
542         char * kstr;
543         struct sos_umem_vmm_as * my_as;
544 
545         retval = sos_syscall_get1arg(user_ctxt, & ustr);
546         if (SOS_OK != retval)
547           break;
548 
549         retval = sos_strndup_from_user(& kstr, ustr, 256, 0);
550         if (SOS_OK != retval)
551           break;
552 
553         extern void sos_dump_as(const struct sos_umem_vmm_as *, const char *);
554         my_as
555           = sos_process_get_address_space(sos_thread_get_current()->process);
556         sos_dump_as(my_as, kstr);
557         sos_kfree((sos_vaddr_t)kstr);
558       }
559       break;
560 
561 
562       /**
563        * Syscall 4008: dump the list of processes in the system
564        * args: none, retval=ignored
565        */
566     case 4008:
567       {
568         extern void sos_process_dumplist(void);
569         sos_process_dumplist();
570         retval = SOS_OK;
571       }
572       break;
573 
574     default:
575       sos_bochs_printf("Syscall: UNKNOWN[%d]\n", syscall_id);
576       retval = -SOS_ENOSUP;
577     }
578   
579   return retval;
580 }

source navigation ] diff markup ] identifier search ] general search ]