001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
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
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;
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
063 new_proc = sos_process_create(NULL, TRUE);
064 if (! new_proc)
065 {
066 retval = -SOS_ENOMEM;
067 break;
068 }
069
070
071
072
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
088
089
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
105 if (sos_process_get_nb_threads(cur_thr->process) != 1)
106 {
107 retval = -SOS_EBUSY;
108 break;
109 }
110
111
112 retval = sos_syscall_get2args(user_ctxt, & user_str, & len);
113 if (SOS_OK != retval)
114 break;
115
116
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
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
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
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 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
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
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
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
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
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 0);
402 if (SOS_OK != retval)
403 break;
404
405
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
490
491
492
493
494
495
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
537
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
564
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 }