- Implemented execp*.
[planlOS.git] / system / kernel / sys / syscall.c
bloba4e0d53de34bc4cf15ba7e8f4a58b66fa2b37163
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;
361 for (i = 0; i < envcount; i++)
363 ((uintptr_t*)argdata)[argcount + 1 + i] += dataaddr;
365 mmMapKernelMemory(0, argdata, 0);
366 for (i = 0; i < (stringsize + 0xFFF) / 0x1000; i++)
368 mmMapMemory(&process->memory, datapage + i * 0x1000,
369 dataaddr + i * 0x1000, MM_MAP_READ | MM_MAP_WRITE);
370 mmMapKernelMemory(0, datavirt + i * 0x1000, 0);
372 keUnlockSpinlock(mmGetMemoryLock());
373 free(program);
374 keDestroyThread(thread);
375 keCreateThread(process, entry, 4, envcount,
376 targetaddr + (argcount + 1) * sizeof(char*), argcount, targetaddr);
377 keSetExecutionLevel(KE_LEVEL_NORMAL);
378 // Schedule into other thread
379 asm volatile("int $0x32");
381 void sysPipe(KeThread *thread, uintptr_t *param1, uintptr_t *param2,
382 uintptr_t *param3, uintptr_t *param4, uintptr_t *param5)
384 KeProcess *process = thread->process;
385 // Create pipe
386 FsFileHandle *in = malloc(sizeof(FsFileHandle));
387 memset(in, 0, sizeof(FsFileHandle));
388 FsFileHandle *out = malloc(sizeof(FsFileHandle));
389 memset(out, 0, sizeof(FsFileHandle));
390 if (sysOpenPipe(in, out))
392 free(in);
393 free(out);
394 *param1 = -1;
396 // Save file descriptors
397 keLockSpinlock(&process->lock);
398 *param1 = sysCreateFileDescriptor(process, in);
399 *param2 = sysCreateFileDescriptor(process, out);
400 keUnlockSpinlock(&process->lock);
402 void sysSocket(KeThread *thread, uintptr_t *param1, uintptr_t *param2,
403 uintptr_t *param3, uintptr_t *param4, uintptr_t *param5)
405 KeProcess *process = thread->process;
406 // Create socket
407 FsFileHandle *fh = malloc(sizeof(FsFileHandle));
408 memset(fh, 0, sizeof(FsFileHandle));
409 keSetExecutionLevel(KE_LEVEL_NORMAL);
410 int status = netOpenSocket(fh, NET_SOCKET_STREAM);
411 keSetExecutionLevel(KE_LEVEL_HIGH);
412 if (status)
414 *param1 = -1;
415 return;
417 // Save file descriptors
418 keLockSpinlock(&process->lock);
419 *param1 = sysCreateFileDescriptor(process, fh);
420 keUnlockSpinlock(&process->lock);
422 void sysIoctl(KeThread *thread, uintptr_t *param1, uintptr_t *param2,
423 uintptr_t *param3, uintptr_t *param4, uintptr_t *param5)
425 KeProcess *process = thread->process;
426 // Check maximum fd
427 if ((*param1 >= process->fdcount) || !process->fd[*param1])
429 kePrint("ioctl: invalid fd.\n");
430 *param1 = -1;
431 return;
433 // Get ioctl size
434 keSetExecutionLevel(KE_LEVEL_NORMAL);
435 int datasize = fsGetIOCTLSize(process->fd[*param1], *param2);
436 keSetExecutionLevel(KE_LEVEL_HIGH);
437 if (datasize == -1)
439 *param1 = -1;
440 return;
442 // Map memory to kernel space
443 uintptr_t data;
444 if (datasize)
446 keLockSpinlock(mmGetMemoryLock());
447 void *buffer = sysMapUserMemory(thread, *param3, datasize, 0);
448 keUnlockSpinlock(mmGetMemoryLock());
449 if (!buffer)
451 kePrint("ioctl: sysMapUserMemory failed (%x: %d).\n", (uint32_t)*param3, datasize);
452 *param1 = -1;
453 return;
455 data = (uintptr_t)buffer;
457 else
459 data = *param3;
461 // Send ioctl
462 keSetExecutionLevel(KE_LEVEL_NORMAL);
463 *param1 = fsIOCTL(process->fd[*param1], *param2, data);
464 keSetExecutionLevel(KE_LEVEL_HIGH);
465 // Unmap memory
466 if (datasize)
468 keLockSpinlock(mmGetMemoryLock());
469 sysUnmapUserMemory((void*)data, datasize);
470 keUnlockSpinlock(mmGetMemoryLock());
473 void sysFcntl(KeThread *thread, uintptr_t *param1, uintptr_t *param2,
474 uintptr_t *param3, uintptr_t *param4, uintptr_t *param5)
476 KeProcess *process = thread->process;
477 // Check file descriptor
478 if ((*param1 >= process->fdcount) || !process->fd[*param1])
480 kePrint("fcntl: invalid fd.\n");
481 *param1 = -1;
482 return;
484 // Execute action
485 int fcntl = *param2;
486 switch (fcntl)
488 case SYS_FCNTL_DUP:
490 int newfd = *param3;
491 if (!newfd)
493 // dup()
494 process->fd[*param1]->file->refcount++;
495 FsFileHandle *newfh = malloc(sizeof(FsFileHandle));
496 memcpy(newfh, process->fd[*param1], sizeof(FsFileHandle));
497 *param1 = sysCreateFileDescriptor(process, newfh);
499 else
501 // dup2()
502 if (newfd > 4096)
504 *param1 = -1;
505 return;
507 process->fd[*param1]->file->refcount++;
508 FsFileHandle *newfh = malloc(sizeof(FsFileHandle));
509 memcpy(newfh, process->fd[*param1], sizeof(FsFileHandle));
511 while ((newfd < (int)process->fdcount) && process->fd[newfd])
513 newfd++;
515 if ((int)process->fdcount <= newfd)
517 process->fd = realloc(process->fd, (newfd + 1) * sizeof(FsFileHandle*));
518 memset(process->fd + process->fdcount, 0, (newfd + 1 - process->fdcount) * sizeof(FsFileHandle*));
519 process->fdcount = newfd + 1;
521 process->fd[newfd] = newfh;
522 *param1 = newfd;
524 break;
526 default:
527 *param1 = -1;
528 break;
531 void sysSignal(KeThread *thread, uintptr_t *param1, uintptr_t *param2,
532 uintptr_t *param3, uintptr_t *param4, uintptr_t *param5)
534 int signal = *param1;
535 uintptr_t handler = *param2;
536 if (signal >= NSIG)
538 *param1 = -1;
540 thread->process->signal_handlers[signal] = handler;
541 *param1 = 0;
543 void sysRaise(KeThread *thread, uintptr_t *param1, uintptr_t *param2,
544 uintptr_t *param3, uintptr_t *param4, uintptr_t *param5)
546 int signal = *param1;
547 if (signal >= NSIG)
549 *param1 = -1;
550 return;
552 *param1 = 0;
553 keSendSignal(thread->process, 0, signal);
555 void sysKill(KeThread *thread, uintptr_t *param1, uintptr_t *param2,
556 uintptr_t *param3, uintptr_t *param4, uintptr_t *param5)
558 int pid = *param1;
559 int signal = *param2;
560 if (signal >= NSIG)
562 *param1 = -1;
563 return;
565 KeProcess *target = keGetProcess(pid);
566 if (!target)
568 *param1 = -1;
569 return;
571 *param1 = 0;
572 keSendSignal(target, 0, signal);
575 void sysSyscall(KeThread *thread, uintptr_t index, uintptr_t *param1,
576 uintptr_t *param2, uintptr_t *param3, uintptr_t *param4, uintptr_t *param5)
578 if (!thread->process)
580 // TODO: Panic
581 return;
584 switch (index)
586 case SYS_EXIT:
587 keTerminateProcess(thread->process);
588 asm volatile("int $0x32");
589 break;
590 case SYS_OPEN:
591 sysOpen(thread, param1, param2, param3, param4, param5);
592 break;
593 case SYS_CLOSE:
595 KeProcess *process = thread->process;
596 // Check maximum fd
597 if ((*param1 >= process->fdcount) || !process->fd[*param1])
599 *param1 = -1;
600 return;
602 kePrint("Closing %d.\n", *param1);
603 FsFileHandle *file = process->fd[*param1];
604 process->fd[*param1] = 0;
605 // Close file
606 keSetExecutionLevel(KE_LEVEL_NORMAL);
607 fsClose(file);
608 keSetExecutionLevel(KE_LEVEL_HIGH);
609 *param1 = 0;
611 break;
612 case SYS_READ:
614 KeProcess *process = thread->process;
615 // Check maximum fd
616 if ((*param1 >= process->fdcount) || !process->fd[*param1])
618 kePrint("read: invalid fd.\n");
619 *param1 = -1;
620 return;
623 // Map buffer
624 keLockSpinlock(mmGetMemoryLock());
625 void *buffer = sysMapUserMemory(thread, *param2, *param3, 1);
626 keUnlockSpinlock(mmGetMemoryLock());
627 if (!buffer)
629 kePrint("read: sysMapUserMemory failed (%x: %d).\n", (uint32_t)*param2, (int)*param3);
630 // TODO: Stop program here
631 *param1 = -1;
632 return;
634 // Read data
635 keSetExecutionLevel(KE_LEVEL_NORMAL);
636 FsFileHandle *file = process->fd[*param1];
637 //kePrint("Reading %d bytes from %d.\n", (int)*param3, (int)*param1);
638 int read = fsRead(file, buffer, *param3, 1);
639 keSetExecutionLevel(KE_LEVEL_HIGH);
641 // Unmap buffer
642 keLockSpinlock(mmGetMemoryLock());
643 sysUnmapUserMemory(buffer, *param3);
644 keUnlockSpinlock(mmGetMemoryLock());
646 *param1 = read;
648 break;
649 case SYS_WRITE:
651 KeProcess *process = thread->process;
652 // Check maximum fd
653 if ((*param1 >= process->fdcount) || !process->fd[*param1])
655 kePrint("write: invalid fd.\n");
656 *param1 = -1;
657 return;
660 // Map buffer
661 keLockSpinlock(mmGetMemoryLock());
662 void *buffer = sysMapUserMemory(thread, *param2, *param3, 0);
663 keUnlockSpinlock(mmGetMemoryLock());
664 if (!buffer)
666 kePrint("write: sysMapUserMemory failed (%x: %d).\n", (uint32_t)*param2, (int)*param3);
667 // TODO: Stop program here
668 *param1 = -1;
669 return;
671 // Read data
672 keSetExecutionLevel(KE_LEVEL_NORMAL);
673 FsFileHandle *file = process->fd[*param1];
674 int written = fsWrite(file, buffer, *param3);
675 keSetExecutionLevel(KE_LEVEL_HIGH);
677 // Unmap buffer
678 keLockSpinlock(mmGetMemoryLock());
679 sysUnmapUserMemory(buffer, *param3);
680 keUnlockSpinlock(mmGetMemoryLock());
682 *param1 = written;
684 break;
685 case SYS_SEEK:
687 KeProcess *process = thread->process;
688 // Check maximum fd
689 if ((*param1 >= process->fdcount) || !process->fd[*param1])
691 kePrint("seek: invalid fd.\n");
692 *param1 = -1;
693 return;
695 // Seek in file
696 keSetExecutionLevel(KE_LEVEL_NORMAL);
697 FsFileHandle *file = process->fd[*param1];
698 *param1 = fsSeek(file, *param2, *param3);
699 keSetExecutionLevel(KE_LEVEL_HIGH);
701 break;
702 case SYS_MKNOD:
704 // TODO: Can be crashed easily
705 char *filename = strdup((char*)*param1);
706 uint32_t mode = 0;
707 uint32_t type = *param2 & 0xF00;
708 if (type == 0x400)
709 mode = FS_MKNOD_FILE;
710 else if (type == 0x500)
711 mode = FS_MKNOD_DIR;
712 keSetExecutionLevel(KE_LEVEL_NORMAL);
713 *param1 = fsMknod(filename, mode);
714 keSetExecutionLevel(KE_LEVEL_HIGH);
716 break;
717 case SYS_ALLOC:
719 KeProcess *process = thread->process;
720 uint32_t size = *param1;
721 uint32_t pagecount = (size + 0xFFF) / 0x1000;
722 keLockSpinlock(mmGetMemoryLock());
723 // Look for free memory
724 uintptr_t vaddr = mmFindFreePages(&process->memory, MM_MAX_USER_PAGE,
725 MM_MIN_USER_PAGE, 0, pagecount * 0x1000);
726 // Map memory
727 if (vaddr)
729 uint32_t i;
730 for (i = 0; i < pagecount; i++)
732 uintptr_t paddr = mmAllocPhysicalMemory(0, 0, 0x1000);
733 // TODO: Error handling
734 mmMapMemory(&process->memory, paddr, vaddr + i * 0x1000,
735 MM_MAP_READ | MM_MAP_WRITE);
738 keUnlockSpinlock(mmGetMemoryLock());
739 *param1 = vaddr;
741 break;
742 case SYS_FREE:
744 KeProcess *process = thread->process;
745 uint32_t addr = *param1;
746 uint32_t size = *param2;
747 uint32_t pagecount = (size + 0xFFF) / 0x1000;
748 uint32_t i;
749 for (i = 0; i < pagecount; i++)
751 uintptr_t vaddr = (addr & ~0xFFF) + i * 0x1000;
752 // Free memory
753 uintptr_t paddr = mmGetPhysAddress(&process->memory, vaddr);
754 if (paddr) mmFreePhysicalMemory(paddr, 0x1000);
755 // Unmap page
756 mmMapMemory(&process->memory, 0, vaddr, 0);
759 break;
760 case SYS_FORK:
761 sysFork(thread, param1, param2, param3, param4, param5);
762 break;
763 case SYS_EXEC:
764 sysExec(thread, param1, param2, param3, param4, param5);
765 break;
766 case SYS_WAIT:
768 // Get process
769 int pid = *param1;
770 uint32_t options = *param3;
771 keSetExecutionLevel(KE_LEVEL_NORMAL);
772 KeProcess *process = keGetProcess(pid);
773 keSetExecutionLevel(KE_LEVEL_HIGH);
774 if (!process)
776 *param1 = -1;
777 break;
779 // If the process was terminated, return at once
780 if (process->zombie)
782 keSetExecutionLevel(KE_LEVEL_NORMAL);
783 keDestroyProcess(process);
784 keSetExecutionLevel(KE_LEVEL_HIGH);
785 *param1 = 0;
786 break;
788 if (options & 1)
790 // Don't block
791 *param1 = -1;
792 break;
794 else
796 if (process->waitthread)
798 *param1 = -1;
799 break;
801 process->waitthread = thread;
802 thread->status = KE_THREAD_WAIT;
803 asm volatile("int $0x32");
806 break;
807 case SYS_SLEEP:
808 thread->status = KE_THREAD_SLEEP;
809 thread->timeout = keGetTime() + *param1;
810 asm volatile("int $0x32");
811 break;
812 case SYS_GETWD:
814 KeProcess *process = thread->process;
815 int length = strlen(process->cwd) + 1;
816 if (length > (int)*param2)
818 length = *param2;
820 // Map buffer
821 keLockSpinlock(mmGetMemoryLock());
822 char *buffer = sysMapUserMemory(thread, *param1, length + 1, 0);
823 keUnlockSpinlock(mmGetMemoryLock());
824 if (!buffer)
826 *param1 = -1;
827 return;
829 // Read data
830 strncpy(buffer, process->cwd, length);
832 // Unmap buffer
833 keLockSpinlock(mmGetMemoryLock());
834 sysUnmapUserMemory(buffer, length + 1);
835 keUnlockSpinlock(mmGetMemoryLock());
837 *param1 = 0;
839 break;
840 case SYS_CHDIR:
842 // FIXME: Can be crashed by users
843 char *filename = strdup((char*)*param1);
844 KeProcess *process = thread->process;
845 // Validate path
846 keSetExecutionLevel(KE_LEVEL_NORMAL);
847 if (strlen(filename) == 0)
849 *param1 = -1;
850 keSetExecutionLevel(KE_LEVEL_HIGH);
851 break;
853 if (filename[0] != '/')
855 // Relative path
856 char *tmp = malloc(strlen(filename) + strlen(process->cwd) + 2);
857 strcpy(tmp, process->cwd);
858 strcpy(tmp + strlen(process->cwd), filename);
859 free(filename);
860 filename = tmp;
861 if (filename[strlen(filename) - 1] != '/')
863 filename[strlen(filename) + 1] = 0;
864 filename[strlen(filename)] = '/';
867 FsFileHandle *file = fsOpen(filename, FS_OPEN_READ);
868 if (!file)
870 *param1 = -1;
871 keSetExecutionLevel(KE_LEVEL_HIGH);
872 break;
874 fsClose(file);
875 keSetExecutionLevel(KE_LEVEL_HIGH);
876 // Set working directory
877 free(process->cwd);
878 process->cwd = filename;
879 *param1 = 0;
881 break;
882 case SYS_PIPE:
883 sysPipe(thread, param1, param2, param3, param4, param5);
884 break;
885 case SYS_SOCKET:
886 sysSocket(thread, param1, param2, param3, param4, param5);
887 break;
888 case SYS_IOCTL:
889 sysIoctl(thread, param1, param2, param3, param4, param5);
890 break;
891 case SYS_FCNTL:
892 sysFcntl(thread, param1, param2, param3, param4, param5);
893 break;
894 case SYS_SIGNAL:
895 sysSignal(thread, param1, param2, param3, param4, param5);
896 break;
897 case SYS_RAISE:
898 sysRaise(thread, param1, param2, param3, param4, param5);
899 break;
900 case SYS_KILL:
901 sysKill(thread, param1, param2, param3, param4, param5);
902 break;
903 case SYS_GETPID:
904 *param1 = thread->process->pid;
905 break;
906 case SYS_TIME:
908 uint64_t time = keGetTime();
909 uint32_t seconds = keGetCurrentCPU()->starttime + time / 1000000;
910 *param1 = seconds;
911 *param2 = time % 1000000;
913 break;
914 default:
915 *param1 = -1;
916 break;