First part of program argument and environment variable support.
[planlOS.git] / system / kernel / sys / syscall.c
blob952a01e7c3d1c964e08aaedd96831ad06e6d0398
1 /*
2 Copyright (C) 2008 Mathias Gottschlag
4 Permission is hereby granted, free of charge, to any person obtaining a copy of
5 this software and associated documentation files (the "Software"), to deal in the
6 Software without restriction, including without limitation the rights to use,
7 copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
8 Software, and to permit persons to whom the Software is furnished to do so,
9 subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16 PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 #include "sys/syscall.h"
23 #include "sys/pipe.h"
24 #include "ke/debug.h"
25 #include "ke/level.h"
26 #include "ke/elf.h"
27 #include "ke/timer.h"
28 #include "ke/cpu.h"
29 #include "net/socket.h"
30 #include <string.h>
31 #include <stdlib.h>
33 void *sysMapUserMemory(KeThread *thread, uintptr_t addr, uint32_t size, uint32_t writeable)
35 KeProcess *process = thread->process;
36 uint32_t pageoffset = addr & 0xFFF;
37 uint32_t pagecount = (size + pageoffset + 0xFFF) / 0x1000;
38 uint32_t i;
39 // Validate pages
40 for (i = 0; i < pagecount; i++)
42 // TODO: Check flags
43 if (!mmGetPhysAddress(&process->memory, (addr & ~0xFFF) + i * 0x1000))
45 kePrint("No memory at %x\n", (addr & ~0xFFF) + i * 0x1000);
46 return 0;
49 // Map pages
50 uintptr_t vaddr = mmFindFreeKernelPages(MM_MAX_KERNEL_PAGE, MM_MIN_KERNEL_PAGE,
51 1, pagecount * 0x1000);
52 if (!vaddr)
54 kePrint("Could not allocate %d bytes.\n", pagecount * 0x1000);
55 return 0;
57 for (i = 0; i < pagecount; i++)
59 uintptr_t paddr = mmGetPhysAddress(&process->memory, (addr & ~0xFFF) + i * 0x1000);
60 mmMapKernelMemory(paddr, vaddr + i * 0x1000,
61 MM_MAP_READ | MM_MAP_WRITE);
63 return (void*)(vaddr + pageoffset);
66 void sysUnmapUserMemory(void *data, uint32_t size)
68 uintptr_t addr = (uintptr_t)data;
69 uint32_t pageoffset = addr & 0xFFF;
70 uint32_t pagecount = (size + pageoffset + 0xFFF) / 0x1000;
71 uint32_t i;
72 for (i = 0; i < pagecount; i++)
74 mmMapKernelMemory(0, addr + i * 0x1000, 0);
78 int sysCreateFileDescriptor(KeProcess *process, FsFileHandle *fh)
80 // Search for empty fds
81 uint32_t i;
82 int fd = -1;
83 for (i = 3; i < process->fdcount; i++)
85 if (process->fd[i] == 0)
87 fd = i;
90 if (fd == -1)
92 // Increase fd array
93 process->fd = realloc(process->fd, (process->fdcount + 1) * sizeof(FsFileHandle*));
94 fd = process->fdcount;
95 process->fdcount++;
97 process->fd[fd] = fh;
98 return fd;
101 void sysOpen(KeThread *thread, uintptr_t *param1, uintptr_t *param2,
102 uintptr_t *param3, uintptr_t *param4, uintptr_t *param5)
104 KeProcess *process = thread->process;
105 keSetExecutionLevel(KE_LEVEL_NORMAL);
106 // TODO: Can be crashed easily
107 char *filename = strdup((char*)*param1);
108 if (strlen(filename) == 0)
110 *param1 = -1;
111 keSetExecutionLevel(KE_LEVEL_HIGH);
112 return;
114 if (filename[0] != '/')
116 // Relative path
117 char *tmp = malloc(strlen(filename) + 1 + strlen(process->cwd));
118 strcpy(tmp, process->cwd);
119 strcpy(tmp + strlen(process->cwd), filename);
120 free(filename);
121 filename = tmp;
123 kePrint("Opening %s\n", filename);
124 uint32_t mode = 0;
125 if (*param2 & 1) mode |= FS_OPEN_CREATE;
126 if (*param2 & 0x200) mode |= FS_OPEN_READ;
127 if (*param2 & 0x400) mode |= FS_OPEN_RW;
128 if (*param2 & 0x800) mode |= FS_OPEN_WRITE;
129 FsFileHandle *file = fsOpen(filename, mode);
130 if (!file)
132 *param1 = -1;
133 keSetExecutionLevel(KE_LEVEL_HIGH);
135 else
137 keSetExecutionLevel(KE_LEVEL_HIGH);
138 keLockSpinlock(&process->lock);
139 uint32_t i;
140 int fd = -1;
141 for (i = 3; i < process->fdcount; i++)
143 if (process->fd[i] == 0)
145 fd = i;
148 if (fd == -1)
150 process->fd = realloc(process->fd, (process->fdcount + 1) * sizeof(FsFileHandle*));
151 fd = process->fdcount;
152 process->fdcount++;
154 process->fd[fd] = file;
155 *param1 = fd;
156 keUnlockSpinlock(&process->lock);
157 kePrint("Opened %s as %d\n", filename, fd);
159 free(filename);
162 void sysFork(KeThread *thread, uintptr_t *param1, uintptr_t *param2,
163 uintptr_t *param3, uintptr_t *param4, uintptr_t *param5)
165 uintptr_t current_stack = thread->kernelstack;
166 KeProcess *process = thread->process;
167 keSetExecutionLevel(KE_LEVEL_NORMAL);
168 // Create new process
169 KeProcess *newprocess = keCreateProcess();
170 keSetExecutionLevel(KE_LEVEL_HIGH);
171 keLockSpinlock(mmGetMemoryLock());
172 if (mmCloneAddressSpace(&newprocess->memory, &process->memory))
174 keUnlockSpinlock(mmGetMemoryLock());
175 keSetExecutionLevel(KE_LEVEL_NORMAL);
176 keDestroyProcess(newprocess);
177 keSetExecutionLevel(KE_LEVEL_HIGH);
178 *param1 = -1;
180 else
182 keUnlockSpinlock(mmGetMemoryLock());
183 // Clone file handles
184 keLockSpinlock(&newprocess->lock);
185 newprocess->fd = realloc(newprocess->fd, process->fdcount * sizeof(FsFileHandle*));
186 newprocess->fdcount = process->fdcount;
187 memcpy(newprocess->fd, process->fd, process->fdcount * sizeof(FsFileHandle*));
188 uint32_t i;
189 for (i = 0; i < process->fdcount; i++)
191 if (process->fd[i])
193 process->fd[i]->file->refcount++;
194 newprocess->fd[i] = malloc(sizeof(FsFileHandle));
195 memcpy(newprocess->fd[i], process->fd[i], sizeof(FsFileHandle));
199 free(newprocess->cwd);
200 newprocess->cwd = strdup(process->cwd);
201 keUnlockSpinlock(&newprocess->lock);
202 // Create thread
203 KeThread *newthread = keCloneThread(newprocess, thread, current_stack);
204 keThreadSetParam(newthread, 1, 0);
206 *param1 = newprocess->pid;
209 void sysExec(KeThread *thread, uintptr_t *param1, uintptr_t *param2,
210 uintptr_t *param3, uintptr_t *param4, uintptr_t *param5)
212 KeProcess *process = thread->process;
213 keSetExecutionLevel(KE_LEVEL_NORMAL);
214 // Load executable file
215 // FIXME: Can be crashed by users
216 char *filename = strdup((char*)*param1);
217 FsFileHandle *file = fsOpen(filename, FS_OPEN_READ);
218 if (!file)
220 kePrint("exec: Could not open \"%s\".\n", filename);
221 free(filename);
222 keSetExecutionLevel(KE_LEVEL_HIGH);
223 *param1 = -1;
224 return;
226 // Read program
227 int size = fsSeek(file, 0, 2);
228 fsSeek(file, 0, 0);
229 keSetExecutionLevel(KE_LEVEL_HIGH);
230 char *program = malloc(size);
231 keSetExecutionLevel(KE_LEVEL_NORMAL);
232 if (!program)
234 kePrint("exec: Out of memory.\n");
235 free(filename);
236 fsClose(file);
237 keSetExecutionLevel(KE_LEVEL_HIGH);
238 *param1 = -1;
239 return;
241 if (fsRead(file, program, size + 10, 1) != size)
243 kePrint("exec: Could not read \"%s\".\n", filename);
244 free(filename);
245 fsClose(file);
246 keSetExecutionLevel(KE_LEVEL_HIGH);
247 *param1 = -1;
248 return;
250 uintptr_t entry = ((ElfHeader*)program)->e_entry;
251 free(filename);
252 fsClose(file);
253 if ((program[0] != 0x7F) || (program[1] != 'E')
254 || (program[2] != 'L') || (program[3] != 'F'))
256 kePrint("Not a valid ELF file: %x%x\n", *((uint32_t*)program + 1), *((uint32_t*)program));
257 keSetExecutionLevel(KE_LEVEL_HIGH);
258 free(program);
259 *param1 = -1;
260 return;
262 // Map arguments/environment variables
263 keSetExecutionLevel(KE_LEVEL_HIGH);
264 keLockSpinlock(mmGetMemoryLock());
265 uint32_t argcount = *param2;
266 uintptr_t *args = 0;
267 if (argcount != 0)
269 args = sysMapUserMemory(thread, *param3, argcount * sizeof(char*), 0);
270 if (!args)
272 keUnlockSpinlock(mmGetMemoryLock());
273 free(program);
274 *param1 = -1;
275 return;
278 uint32_t envcount = *param4;
279 uintptr_t *env = 0;
280 if (envcount != 0)
282 env = sysMapUserMemory(thread, *param5, envcount * sizeof(char*), 0);
283 if (!env)
285 if (args)
286 sysUnmapUserMemory(args, argcount * sizeof(char*));
287 keUnlockSpinlock(mmGetMemoryLock());
288 free(program);
289 *param1 = -1;
290 return;
293 // Copy data to kernel space
294 uint32_t pagecount = ((argcount + envcount + 2) * sizeof(char*) + 4095) / 0x1000;
295 if (pagecount > 1)
297 keSetExecutionLevel(KE_LEVEL_HIGH);
298 free(program);
299 *param1 = -1;
300 return;
302 uintptr_t page = mmAllocPhysicalMemory(0, 0, 0x1000);
303 uintptr_t argdata = mmFindFreeKernelPages(MM_MAX_KERNEL_PAGE,
304 MM_MIN_KERNEL_PAGE, 1, 0x1000);
305 mmMapKernelMemory(page, argdata, MM_MAP_READ | MM_MAP_WRITE);
306 uint32_t stringsize = 0;
307 uint32_t i;
308 for (i = 0; i < argcount; i++)
310 stringsize += strlen((char*)args[i]) + 1;
312 for (i = 0; i < envcount; i++)
314 stringsize += strlen((char*)env[i]) + 1;
316 memset((void*)argdata, 0xab, 0x1000);
317 ((uintptr_t*)argdata)[argcount] = 0;
318 ((uintptr_t*)argdata)[argcount + 1 + envcount] = 0;
319 uintptr_t datapage = mmAllocPhysicalMemory(0, 0, (stringsize + 0xFFF) & ~0xFFF);
320 uintptr_t datavirt = mmFindFreeKernelPages(MM_MAX_KERNEL_PAGE,
321 MM_MIN_KERNEL_PAGE, 1, (stringsize + 0xFFF) & ~0xFFF);
322 for (i = 0; i < (stringsize + 0xFFF) / 0x1000; i++)
324 mmMapKernelMemory(datapage + i * 0x1000, datavirt + i * 0x1000,
325 MM_MAP_READ | MM_MAP_WRITE);
327 char *s = (char*)datavirt;
328 for (i = 0; i < argcount; i++)
330 ((uintptr_t*)argdata)[i] = (uintptr_t)s - datavirt;
331 strcpy(s, (char*)args[i]);
332 s += strlen((char*)args[i]) + 1;
334 for (i = 0; i < envcount; i++)
336 ((uintptr_t*)argdata)[argcount + 1 + i] = (uintptr_t)s - datavirt;
337 strcpy(s, (char*)env[i]);
338 s += strlen((char*)env[i]) + 1;
340 // Unmap arguments again
341 if (args)
342 sysUnmapUserMemory(args, argcount * sizeof(char*));
343 if (env)
344 sysUnmapUserMemory(args, argcount * sizeof(char*));
345 keUnlockSpinlock(mmGetMemoryLock());
346 keSetExecutionLevel(KE_LEVEL_NORMAL);
347 // Clear process
348 keClearProcess(process, thread);
349 keSetExecutionLevel(KE_LEVEL_HIGH);
350 keLockSpinlock(mmGetMemoryLock());
351 keElfMapProgram(&process->memory, program, size);
352 uintptr_t targetaddr = mmFindFreePages(&process->memory, MM_MAX_USER_PAGE,
353 MM_MIN_USER_PAGE, 0, 0x1000);
354 mmMapMemory(&process->memory, page, targetaddr, MM_MAP_READ | MM_MAP_WRITE);
355 uintptr_t dataaddr = mmFindFreePages(&process->memory, MM_MAX_USER_PAGE,
356 MM_MIN_USER_PAGE, 0, (stringsize + 0xFFF) & ~0xFFF);
357 for (i = 0; i < argcount; i++)
359 ((uintptr_t*)argdata)[i] += dataaddr;
360 kePrint("Arg: %x\n", ((uintptr_t*)argdata)[i]);
362 for (i = 0; i < envcount; i++)
364 ((uintptr_t*)argdata)[argcount + 1 + i] += dataaddr;
366 mmMapKernelMemory(0, argdata, 0);
367 for (i = 0; i < (stringsize + 0xFFF) / 0x1000; i++)
369 mmMapMemory(&process->memory, datapage + i * 0x1000,
370 dataaddr + i * 0x1000, MM_MAP_READ | MM_MAP_WRITE);
371 mmMapKernelMemory(0, datavirt + i * 0x1000, 0);
373 keUnlockSpinlock(mmGetMemoryLock());
374 free(program);
375 keDestroyThread(thread);
376 keCreateThread(process, entry, 4, envcount,
377 targetaddr + (argcount + 1) * sizeof(char*), argcount, targetaddr);
378 keSetExecutionLevel(KE_LEVEL_NORMAL);
379 // Schedule into other thread
380 asm volatile("int $0x32");
382 void sysPipe(KeThread *thread, uintptr_t *param1, uintptr_t *param2,
383 uintptr_t *param3, uintptr_t *param4, uintptr_t *param5)
385 KeProcess *process = thread->process;
386 // Create pipe
387 FsFileHandle *in = malloc(sizeof(FsFileHandle));
388 memset(in, 0, sizeof(FsFileHandle));
389 FsFileHandle *out = malloc(sizeof(FsFileHandle));
390 memset(out, 0, sizeof(FsFileHandle));
391 if (sysOpenPipe(in, out))
393 free(in);
394 free(out);
395 *param1 = -1;
397 // Save file descriptors
398 keLockSpinlock(&process->lock);
399 *param1 = sysCreateFileDescriptor(process, in);
400 *param2 = sysCreateFileDescriptor(process, out);
401 keUnlockSpinlock(&process->lock);
403 void sysSocket(KeThread *thread, uintptr_t *param1, uintptr_t *param2,
404 uintptr_t *param3, uintptr_t *param4, uintptr_t *param5)
406 KeProcess *process = thread->process;
407 // Create socket
408 FsFileHandle *fh = malloc(sizeof(FsFileHandle));
409 memset(fh, 0, sizeof(FsFileHandle));
410 keSetExecutionLevel(KE_LEVEL_NORMAL);
411 int status = netOpenSocket(fh, NET_SOCKET_STREAM);
412 keSetExecutionLevel(KE_LEVEL_HIGH);
413 if (status)
415 *param1 = -1;
416 return;
418 // Save file descriptors
419 keLockSpinlock(&process->lock);
420 *param1 = sysCreateFileDescriptor(process, fh);
421 keUnlockSpinlock(&process->lock);
423 void sysIoctl(KeThread *thread, uintptr_t *param1, uintptr_t *param2,
424 uintptr_t *param3, uintptr_t *param4, uintptr_t *param5)
426 KeProcess *process = thread->process;
427 // Check maximum fd
428 if ((*param1 >= process->fdcount) || !process->fd[*param1])
430 kePrint("ioctl: invalid fd.\n");
431 *param1 = -1;
432 return;
434 // Get ioctl size
435 keSetExecutionLevel(KE_LEVEL_NORMAL);
436 int datasize = fsGetIOCTLSize(process->fd[*param1], *param2);
437 keSetExecutionLevel(KE_LEVEL_HIGH);
438 if (datasize == -1)
440 *param1 = -1;
441 return;
443 // Map memory to kernel space
444 uintptr_t data;
445 if (datasize)
447 keLockSpinlock(mmGetMemoryLock());
448 void *buffer = sysMapUserMemory(thread, *param3, datasize, 0);
449 keUnlockSpinlock(mmGetMemoryLock());
450 if (!buffer)
452 kePrint("ioctl: sysMapUserMemory failed (%x: %d).\n", (uint32_t)*param3, datasize);
453 *param1 = -1;
454 return;
456 data = (uintptr_t)buffer;
458 else
460 data = *param3;
462 // Send ioctl
463 keSetExecutionLevel(KE_LEVEL_NORMAL);
464 *param1 = fsIOCTL(process->fd[*param1], *param2, data);
465 keSetExecutionLevel(KE_LEVEL_HIGH);
466 // Unmap memory
467 if (datasize)
469 keLockSpinlock(mmGetMemoryLock());
470 sysUnmapUserMemory((void*)data, datasize);
471 keUnlockSpinlock(mmGetMemoryLock());
474 void sysFcntl(KeThread *thread, uintptr_t *param1, uintptr_t *param2,
475 uintptr_t *param3, uintptr_t *param4, uintptr_t *param5)
477 KeProcess *process = thread->process;
478 // Check file descriptor
479 if ((*param1 >= process->fdcount) || !process->fd[*param1])
481 kePrint("fcntl: invalid fd.\n");
482 *param1 = -1;
483 return;
485 // Execute action
486 int fcntl = *param2;
487 switch (fcntl)
489 case SYS_FCNTL_DUP:
491 int newfd = *param3;
492 if (!newfd)
494 // dup()
495 process->fd[*param1]->file->refcount++;
496 FsFileHandle *newfh = malloc(sizeof(FsFileHandle));
497 memcpy(newfh, process->fd[*param1], sizeof(FsFileHandle));
498 *param1 = sysCreateFileDescriptor(process, newfh);
500 else
502 // dup2()
503 if (newfd > 4096)
505 *param1 = -1;
506 return;
508 process->fd[*param1]->file->refcount++;
509 FsFileHandle *newfh = malloc(sizeof(FsFileHandle));
510 memcpy(newfh, process->fd[*param1], sizeof(FsFileHandle));
512 while ((newfd < (int)process->fdcount) && process->fd[newfd])
514 newfd++;
516 if ((int)process->fdcount <= newfd)
518 process->fd = realloc(process->fd, (newfd + 1) * sizeof(FsFileHandle*));
519 memset(process->fd + process->fdcount, 0, (newfd + 1 - process->fdcount) * sizeof(FsFileHandle*));
520 process->fdcount = newfd + 1;
522 process->fd[newfd] = newfh;
523 *param1 = newfd;
525 break;
527 default:
528 *param1 = -1;
529 break;
532 void sysSignal(KeThread *thread, uintptr_t *param1, uintptr_t *param2,
533 uintptr_t *param3, uintptr_t *param4, uintptr_t *param5)
535 int signal = *param1;
536 uintptr_t handler = *param2;
537 if (signal >= NSIG)
539 *param1 = -1;
541 thread->process->signal_handlers[signal] = handler;
542 *param1 = 0;
544 void sysRaise(KeThread *thread, uintptr_t *param1, uintptr_t *param2,
545 uintptr_t *param3, uintptr_t *param4, uintptr_t *param5)
547 int signal = *param1;
548 if (signal >= NSIG)
550 *param1 = -1;
552 *param1 = 0;
553 keSendSignal(thread->process, 0, signal);
556 void sysSyscall(KeThread *thread, uintptr_t index, uintptr_t *param1,
557 uintptr_t *param2, uintptr_t *param3, uintptr_t *param4, uintptr_t *param5)
559 if (!thread->process)
561 // TODO: Panic
562 return;
565 switch (index)
567 case SYS_EXIT:
568 keTerminateProcess(thread->process);
569 asm volatile("int $0x32");
570 break;
571 case SYS_OPEN:
572 sysOpen(thread, param1, param2, param3, param4, param5);
573 break;
574 case SYS_CLOSE:
576 KeProcess *process = thread->process;
577 // Check maximum fd
578 if ((*param1 >= process->fdcount) || !process->fd[*param1])
580 *param1 = -1;
581 return;
583 kePrint("Closing %d.\n", *param1);
584 FsFileHandle *file = process->fd[*param1];
585 process->fd[*param1] = 0;
586 // Close file
587 keSetExecutionLevel(KE_LEVEL_NORMAL);
588 fsClose(file);
589 keSetExecutionLevel(KE_LEVEL_HIGH);
590 *param1 = 0;
592 break;
593 case SYS_READ:
595 KeProcess *process = thread->process;
596 // Check maximum fd
597 if ((*param1 >= process->fdcount) || !process->fd[*param1])
599 kePrint("read: invalid fd.\n");
600 *param1 = -1;
601 return;
604 // Map buffer
605 keLockSpinlock(mmGetMemoryLock());
606 void *buffer = sysMapUserMemory(thread, *param2, *param3, 1);
607 keUnlockSpinlock(mmGetMemoryLock());
608 if (!buffer)
610 kePrint("read: sysMapUserMemory failed (%x: %d).\n", (uint32_t)*param2, (int)*param3);
611 // TODO: Stop program here
612 *param1 = -1;
613 return;
615 // Read data
616 keSetExecutionLevel(KE_LEVEL_NORMAL);
617 FsFileHandle *file = process->fd[*param1];
618 //kePrint("Reading %d bytes from %d.\n", (int)*param3, (int)*param1);
619 int read = fsRead(file, buffer, *param3, 1);
620 keSetExecutionLevel(KE_LEVEL_HIGH);
622 // Unmap buffer
623 keLockSpinlock(mmGetMemoryLock());
624 sysUnmapUserMemory(buffer, *param3);
625 keUnlockSpinlock(mmGetMemoryLock());
627 *param1 = read;
629 break;
630 case SYS_WRITE:
632 KeProcess *process = thread->process;
633 // Check maximum fd
634 if ((*param1 >= process->fdcount) || !process->fd[*param1])
636 kePrint("write: invalid fd.\n");
637 *param1 = -1;
638 return;
641 // Map buffer
642 keLockSpinlock(mmGetMemoryLock());
643 void *buffer = sysMapUserMemory(thread, *param2, *param3, 0);
644 keUnlockSpinlock(mmGetMemoryLock());
645 if (!buffer)
647 kePrint("write: sysMapUserMemory failed (%x: %d).\n", (uint32_t)*param2, (int)*param3);
648 // TODO: Stop program here
649 *param1 = -1;
650 return;
652 // Read data
653 keSetExecutionLevel(KE_LEVEL_NORMAL);
654 FsFileHandle *file = process->fd[*param1];
655 int written = fsWrite(file, buffer, *param3);
656 keSetExecutionLevel(KE_LEVEL_HIGH);
658 // Unmap buffer
659 keLockSpinlock(mmGetMemoryLock());
660 sysUnmapUserMemory(buffer, *param3);
661 keUnlockSpinlock(mmGetMemoryLock());
663 *param1 = written;
665 break;
666 case SYS_SEEK:
668 KeProcess *process = thread->process;
669 // Check maximum fd
670 if ((*param1 >= process->fdcount) || !process->fd[*param1])
672 kePrint("seek: invalid fd.\n");
673 *param1 = -1;
674 return;
676 // Seek in file
677 keSetExecutionLevel(KE_LEVEL_NORMAL);
678 FsFileHandle *file = process->fd[*param1];
679 *param1 = fsSeek(file, *param2, *param3);
680 keSetExecutionLevel(KE_LEVEL_HIGH);
682 break;
683 case SYS_MKNOD:
685 // TODO: Can be crashed easily
686 char *filename = strdup((char*)*param1);
687 uint32_t mode = 0;
688 uint32_t type = *param2 & 0xF00;
689 if (type == 0x400)
690 mode = FS_MKNOD_FILE;
691 else if (type == 0x500)
692 mode = FS_MKNOD_DIR;
693 keSetExecutionLevel(KE_LEVEL_NORMAL);
694 *param1 = fsMknod(filename, mode);
695 keSetExecutionLevel(KE_LEVEL_HIGH);
697 break;
698 case SYS_ALLOC:
700 KeProcess *process = thread->process;
701 uint32_t size = *param1;
702 uint32_t pagecount = (size + 0xFFF) / 0x1000;
703 keLockSpinlock(mmGetMemoryLock());
704 // Look for free memory
705 uintptr_t vaddr = mmFindFreePages(&process->memory, MM_MAX_USER_PAGE,
706 MM_MIN_USER_PAGE, 0, pagecount * 0x1000);
707 // Map memory
708 if (vaddr)
710 uint32_t i;
711 for (i = 0; i < pagecount; i++)
713 uintptr_t paddr = mmAllocPhysicalMemory(0, 0, 0x1000);
714 // TODO: Error handling
715 mmMapMemory(&process->memory, paddr, vaddr + i * 0x1000,
716 MM_MAP_READ | MM_MAP_WRITE);
719 keUnlockSpinlock(mmGetMemoryLock());
720 *param1 = vaddr;
722 break;
723 case SYS_FREE:
725 KeProcess *process = thread->process;
726 uint32_t addr = *param1;
727 uint32_t size = *param2;
728 uint32_t pagecount = (size + 0xFFF) / 0x1000;
729 uint32_t i;
730 for (i = 0; i < pagecount; i++)
732 uintptr_t vaddr = (addr & ~0xFFF) + i * 0x1000;
733 // Free memory
734 uintptr_t paddr = mmGetPhysAddress(&process->memory, vaddr);
735 if (paddr) mmFreePhysicalMemory(paddr, 0x1000);
736 // Unmap page
737 mmMapMemory(&process->memory, 0, vaddr, 0);
740 break;
741 case SYS_FORK:
742 sysFork(thread, param1, param2, param3, param4, param5);
743 break;
744 case SYS_EXEC:
745 sysExec(thread, param1, param2, param3, param4, param5);
746 break;
747 case SYS_WAIT:
749 // Get process
750 int pid = *param1;
751 uint32_t options = *param3;
752 keSetExecutionLevel(KE_LEVEL_NORMAL);
753 KeProcess *process = keGetProcess(pid);
754 keSetExecutionLevel(KE_LEVEL_HIGH);
755 if (!process)
757 *param1 = -1;
758 break;
760 // If the process was terminated, return at once
761 if (process->zombie)
763 keSetExecutionLevel(KE_LEVEL_NORMAL);
764 keDestroyProcess(process);
765 keSetExecutionLevel(KE_LEVEL_HIGH);
766 *param1 = 0;
767 break;
769 if (options & 1)
771 // Don't block
772 *param1 = -1;
773 break;
775 else
777 if (process->waitthread)
779 *param1 = -1;
780 break;
782 process->waitthread = thread;
783 thread->status = KE_THREAD_WAIT;
784 asm volatile("int $0x32");
787 break;
788 case SYS_SLEEP:
789 thread->status = KE_THREAD_SLEEP;
790 thread->timeout = keGetTime() + *param1;
791 asm volatile("int $0x32");
792 break;
793 case SYS_GETWD:
795 KeProcess *process = thread->process;
796 int length = strlen(process->cwd) + 1;
797 if (length > (int)*param2)
799 length = *param2;
801 // Map buffer
802 keLockSpinlock(mmGetMemoryLock());
803 char *buffer = sysMapUserMemory(thread, *param1, length + 1, 0);
804 keUnlockSpinlock(mmGetMemoryLock());
805 if (!buffer)
807 *param1 = -1;
808 return;
810 // Read data
811 strncpy(buffer, process->cwd, length);
813 // Unmap buffer
814 keLockSpinlock(mmGetMemoryLock());
815 sysUnmapUserMemory(buffer, length + 1);
816 keUnlockSpinlock(mmGetMemoryLock());
818 *param1 = 0;
820 break;
821 case SYS_CHDIR:
823 // FIXME: Can be crashed by users
824 char *filename = strdup((char*)*param1);
825 KeProcess *process = thread->process;
826 // Validate path
827 keSetExecutionLevel(KE_LEVEL_NORMAL);
828 if (strlen(filename) == 0)
830 *param1 = -1;
831 keSetExecutionLevel(KE_LEVEL_HIGH);
832 break;
834 if (filename[0] != '/')
836 // Relative path
837 char *tmp = malloc(strlen(filename) + strlen(process->cwd) + 2);
838 strcpy(tmp, process->cwd);
839 strcpy(tmp + strlen(process->cwd), filename);
840 free(filename);
841 filename = tmp;
842 if (filename[strlen(filename) - 1] != '/')
844 filename[strlen(filename) + 1] = 0;
845 filename[strlen(filename)] = '/';
848 FsFileHandle *file = fsOpen(filename, FS_OPEN_READ);
849 if (!file)
851 *param1 = -1;
852 keSetExecutionLevel(KE_LEVEL_HIGH);
853 break;
855 fsClose(file);
856 keSetExecutionLevel(KE_LEVEL_HIGH);
857 // Set working directory
858 free(process->cwd);
859 process->cwd = filename;
860 *param1 = 0;
862 break;
863 case SYS_PIPE:
864 sysPipe(thread, param1, param2, param3, param4, param5);
865 break;
866 case SYS_SOCKET:
867 sysSocket(thread, param1, param2, param3, param4, param5);
868 break;
869 case SYS_IOCTL:
870 sysIoctl(thread, param1, param2, param3, param4, param5);
871 break;
872 case SYS_FCNTL:
873 sysFcntl(thread, param1, param2, param3, param4, param5);
874 break;
875 case SYS_SIGNAL:
876 sysSignal(thread, param1, param2, param3, param4, param5);
877 break;
878 case SYS_RAISE:
879 sysRaise(thread, param1, param2, param3, param4, param5);
880 break;
881 case SYS_GETPID:
882 *param1 = thread->process->pid;
883 break;
884 case SYS_TIME:
886 uint64_t time = keGetTime();
887 uint32_t seconds = keGetCurrentCPU()->starttime + time / 1000000;
888 *param1 = seconds;
889 *param2 = time % 1000000;
891 break;
892 default:
893 *param1 = -1;
894 break;