#include "syscalls.h" #include "fs.h" #include "process.h" #include "screen.h" #include "alloc.h" #include "pipe.h" #include "debugprint.h" #include "timer.h" #include "sleep.h" #include "ttydriver.h" #include "spinlock.h" #include "message.h" #include "commonuser.h" #include "syscalltable.h" #include "isr.h" #include "sharedmemory.h" /************** * All of syscall entered with interrupts disabled! * A syscall can enable interrupts if it is needed. * **************/ static void handleSyscall(Registers* regs); static void* gSyscallTable[SYSCALL_COUNT]; int syscall_open(const char *pathname, int flags); int syscall_close(int fd); int syscall_read(int fd, void *buf, int nbytes); int syscall_write(int fd, void *buf, int nbytes); int syscall_lseek(int fd, int offset, int whence); int syscall_stat(const char *path, struct stat *buf); int syscall_fstat(int fd, struct stat *buf); int syscall_ioctl(int fd, int32 request, void *arg); int syscall_exit(int status); void* syscall_sbrk(uint32 increment); int syscall_fork(); int syscall_getpid(); int syscall_execute(const char *path, char *const argv[], char *const envp[]); int syscall_execve(const char *path, char *const argv[], char *const envp[]); int syscall_wait(int *wstatus); int syscall_kill(int pid, int sig); int syscall_mount(const char *source, const char *target, const char *fsType, unsigned long flags, void *data); int syscall_unmount(const char *target); int syscall_mkdir(const char *path, uint32 mode); int syscall_rmdir(const char *path); int syscall_getdents(int fd, char *buf, int nbytes); int syscall_getWorkingDirectory(char *buf, int size); int syscall_setWorkingDirectory(const char *path); int syscall_managePipe(const char *pipeName, int operation, int data); int syscall_readDir(int fd, void *dirent, int index); int syscall_getUptimeMilliseconds(); int syscall_sleepMilliseconds(int ms); int syscall_executeOnTTY(const char *path, char *const argv[], char *const envp[], const char *ttyPath); int syscall_manageMessage(int command, void* message); void* syscall_mmap(void *addr, int length, int flags, int fd, int offset); int syscall_munmap(void *addr, int length); int syscall_shm_open(const char *name, int oflag, int mode); int syscall_shm_unlink(const char *name); int syscall_ftruncate(int fd, int size); int syscall_posix_openpt(int flags); int syscall_ptsname_r(int fd, char *buf, int buflen); void initialiseSyscalls() { memset((uint8*)gSyscallTable, 0, sizeof(void*) * SYSCALL_COUNT); gSyscallTable[SYS_open] = syscall_open; gSyscallTable[SYS_close] = syscall_close; gSyscallTable[SYS_read] = syscall_read; gSyscallTable[SYS_write] = syscall_write; gSyscallTable[SYS_lseek] = syscall_lseek; gSyscallTable[SYS_stat] = syscall_stat; gSyscallTable[SYS_fstat] = syscall_fstat; gSyscallTable[SYS_ioctl] = syscall_ioctl; gSyscallTable[SYS_exit] = syscall_exit; gSyscallTable[SYS_sbrk] = syscall_sbrk; gSyscallTable[SYS_fork] = syscall_fork; gSyscallTable[SYS_getpid] = syscall_getpid; gSyscallTable[SYS_execute] = syscall_execute; gSyscallTable[SYS_execve] = syscall_execve; gSyscallTable[SYS_wait] = syscall_wait; gSyscallTable[SYS_kill] = syscall_kill; gSyscallTable[SYS_mount] = syscall_mount; gSyscallTable[SYS_unmount] = syscall_unmount; gSyscallTable[SYS_mkdir] = syscall_mkdir; gSyscallTable[SYS_rmdir] = syscall_rmdir; gSyscallTable[SYS_getdents] = syscall_getdents; gSyscallTable[SYS_getWorkingDirectory] = syscall_getWorkingDirectory; gSyscallTable[SYS_setWorkingDirectory] = syscall_setWorkingDirectory; gSyscallTable[SYS_managePipe] = syscall_managePipe; gSyscallTable[SYS_readDir] = syscall_readDir; gSyscallTable[SYS_getUptimeMilliseconds] = syscall_getUptimeMilliseconds; gSyscallTable[SYS_sleepMilliseconds] = syscall_sleepMilliseconds; gSyscallTable[SYS_executeOnTTY] = syscall_executeOnTTY; gSyscallTable[SYS_manageMessage] = syscall_manageMessage; gSyscallTable[SYS_UNUSED] = NULL; gSyscallTable[SYS_mmap] = syscall_mmap; gSyscallTable[SYS_munmap] = syscall_munmap; gSyscallTable[SYS_shm_open] = syscall_shm_open; gSyscallTable[SYS_shm_unlink] = syscall_shm_unlink; gSyscallTable[SYS_ftruncate] = syscall_ftruncate; gSyscallTable[SYS_posix_openpt] = syscall_posix_openpt; gSyscallTable[SYS_ptsname_r] = syscall_ptsname_r; // Register our syscall handler. registerInterruptHandler (0x80, &handleSyscall); } static void handleSyscall(Registers* regs) { if (regs->eax >= SYSCALL_COUNT) { return; } void *location = gSyscallTable[regs->eax]; if (NULL == location) { regs->eax = -1; return; } //printkf("We are in syscall_handler\n"); //Screen_PrintInterruptsEnabled(); //I think it is better to enable interrupts in syscall implementations if it is needed. int ret; asm volatile (" \ pushl %1; \ pushl %2; \ pushl %3; \ pushl %4; \ pushl %5; \ call *%6; \ popl %%ebx; \ popl %%ebx; \ popl %%ebx; \ popl %%ebx; \ popl %%ebx; \ " : "=a" (ret) : "r" (regs->edi), "r" (regs->esi), "r" (regs->edx), "r" (regs->ecx), "r" (regs->ebx), "r" (location)); regs->eax = ret; } int syscall_open(const char *pathname, int flags) { Process* process = getCurrentThread()->owner; if (process) { //printkf("open():[%s]\n", pathname); FileSystemNode* node = getFileSystemNodeAbsoluteOrRelative(pathname, process); if (node) { //printkf("open():node:[%s]\n", node->name); File* file = open_fs(node, flags); if (file) { return file->fd; } } } return -1; } int syscall_close(int fd) { Process* process = getCurrentThread()->owner; if (process) { if (fd < MAX_OPENED_FILES) { File* file = process->fd[fd]; if (file) { close_fs(file); return 0; } else { //TODO: error invalid fd } } else { //TODO: error invalid fd } } else { PANIC("Process is NULL!\n"); } return -1; } int syscall_read(int fd, void *buf, int nbytes) { //printkf("syscall_read: begin - nbytes:%d\n", nbytes); Process* process = getCurrentThread()->owner; if (process) { if (fd < MAX_OPENED_FILES) { File* file = process->fd[fd]; if (file) { //Debug_PrintF("syscall_read(%d): %s\n", process->pid, buf); //enableInterrupts(); //Each handler is free to enable interrupts. //We don't enable them here. return read_fs(file, nbytes, buf); } else { //TODO: error invalid fd } } else { //TODO: error invalid fd } } else { PANIC("Process is NULL!\n"); } return -1; } int syscall_write(int fd, void *buf, int nbytes) { Process* process = getCurrentThread()->owner; if (process) { //printkf("syscall_write() called from process: %d. fd:%d\n", process->pid, fd); if (fd < MAX_OPENED_FILES) { File* file = process->fd[fd]; if (file) { /* for (int i = 0; i < nbytes; ++i) { Debug_PrintF("pid:%d syscall_write:buf[%d]=%c\n", process->pid, i, ((char*)buf)[i]); } */ uint32 writeResult = write_fs(file, nbytes, buf); return writeResult; } else { //TODO: error invalid fd } } else { //TODO: error invalid fd } } else { PANIC("Process is NULL!\n"); } return -1; } int syscall_lseek(int fd, int offset, int whence) { Process* process = getCurrentThread()->owner; if (process) { //printkf("syscall_lseek() called from process: %d. fd:%d\n", process->pid, fd); if (fd < MAX_OPENED_FILES) { File* file = process->fd[fd]; if (file) { return lseek_fs(file, offset, whence); } else { //TODO: error invalid fd } } else { //TODO: error invalid fd } } else { PANIC("Process is NULL!\n"); } return -1; } int syscall_stat(const char *path, struct stat *buf) { Process* process = getCurrentThread()->owner; if (process) { //printkf("syscall_stat() called from process: %d. path:%s\n", process->pid, path); FileSystemNode* node = getFileSystemNodeAbsoluteOrRelative(path, process); if (node) { return stat_fs(node, buf); } } else { PANIC("Process is NULL!\n"); } return -1; } int syscall_fstat(int fd, struct stat *buf) { Process* process = getCurrentThread()->owner; if (process) { if (fd < MAX_OPENED_FILES) { File* file = process->fd[fd]; if (file) { return stat_fs(file->node, buf); } else { //TODO: error invalid fd } } else { //TODO: error invalid fd } } else { PANIC("Process is NULL!\n"); } return -1; } int syscall_ioctl(int fd, int32 request, void *arg) { Process* process = getCurrentThread()->owner; if (process) { if (fd < MAX_OPENED_FILES) { File* file = process->fd[fd]; if (file) { return ioctl_fs(file, request, arg); } else { //TODO: error invalid fd } } else { //TODO: error invalid fd } } else { PANIC("Process is NULL!\n"); } return -1; } int syscall_exit(int status) { Process* process = getCurrentThread()->owner; if (process) { printkf("syscall_exit(%d)\n", status); printkf("process pid: %d\n", process->pid); if (process->parent) { printkf("process parent pid: %d\n", process->parent->pid); printkf("writing %d to %p\n", 1, &process->parent->childExitStatusPresent); process->parent->childExitStatusPresent = 1; printkf("writing %d to %x\n", status, &process->parent->childExitStatus); process->parent->childExitStatus = status; } destroyProcess(process); waitForSchedule(); } else { PANIC("Process is NULL!\n"); } return -1; } void* syscall_sbrk(uint32 increment) { //printkf("syscall_sbrk() !!! inc:%d\n", increment); Process* process = getCurrentThread()->owner; if (process) { return sbrk(process, increment); } else { PANIC("Process is NULL!\n"); } return (void*)-1; } int syscall_fork() { //Not implemented return -1; } int syscall_getpid() { Process* process = getCurrentThread()->owner; if (process) { return process->pid; } else { PANIC("Process is NULL!\n"); } return -1; } //NON-posix int syscall_execute(const char *path, char *const argv[], char *const envp[]) { int result = -1; printkf("syscall_execute: %s\n", path); Process* process = getCurrentThread()->owner; if (process) { printkf("found current process\n"); FileSystemNode* node = getFileSystemNodeAbsoluteOrRelative(path, process); if (node) { File* f = open_fs(node, 0); if (f) { printkf("file found\n"); void* image = kmalloc(node->length); //printkf("executing %s and its %d bytes\n", filename, node->length); int32 bytesRead = read_fs(f, node->length, image); //printkf("syscall_execute: read_fs returned %d bytes\n", bytesRead); if (bytesRead > 0) { printkf("creating user process from ELF data\n"); Process* newProcess = createUserProcessFromElfData("userProcess", image, argv, envp, process, NULL); if (newProcess) { result = newProcess->pid; } } close_fs(f); kfree(image); } } } else { PANIC("Process is NULL!\n"); } return result; } int syscall_executeOnTTY(const char *path, char *const argv[], char *const envp[], const char *ttyPath) { int result = -1; Process* process = getCurrentThread()->owner; if (process) { FileSystemNode* node = getFileSystemNodeAbsoluteOrRelative(path, process); FileSystemNode* ttyNode = getFileSystemNodeAbsoluteOrRelative(ttyPath, process); if (node && ttyNode) { File* f = open_fs(node, 0); if (f) { void* image = kmalloc(node->length); //printkf("executing %s and its %d bytes\n", filename, node->length); int32 bytesRead = read_fs(f, node->length, image); //printkf("syscall_execute: read_fs returned %d bytes\n", bytesRead); if (bytesRead > 0) { Process* newProcess = createUserProcessFromElfData("userProcess", image, argv, envp, process, ttyNode); if (newProcess) { result = newProcess->pid; } } close_fs(f); kfree(image); } } } else { PANIC("Process is NULL!\n"); } return result; } int syscall_execve(const char *path, char *const argv[], char *const envp[]) { Process* callingProcess = getCurrentThread()->owner; FileSystemNode* node = getFileSystemNode(path); if (node) { File* f = open_fs(node, 0); if (f) { void* image = kmalloc(node->length); if (read_fs(f, node->length, image) > 0) { disableInterrupts(); //just in case if a file operation left interrupts enabled. Process* newProcess = createUserProcessEx("fromExecve", callingProcess->pid, 0, NULL, image, argv, envp, NULL, callingProcess->tty); close_fs(f); kfree(image); if (newProcess) { destroyProcess(callingProcess); waitForSchedule(); //unreachable } } close_fs(f); kfree(image); } } //if it all goes well, this line is unreachable return 0; } int syscall_wait(int *wstatus) { //TODO: return pid of exited child. implement with sendsignal Thread* currentThread = getCurrentThread(); Process* process = currentThread->owner; if (process) { printkf("wait: I am %d at %x\n", process->pid, process); Thread* thread = getMainKernelThread(); while (thread) { printkf("wait: checking %d at %x\n", thread->owner->pid, thread->owner); printkf("wait: parent is %d at %x\n", thread->owner->parent->pid, thread->owner->parent); if (process == thread->owner->parent) { //We have a child process printkf("wait: d\n"); currentThread->state = TS_WAITCHILD; enableInterrupts(); while (currentThread->state == TS_WAITCHILD); if (process->childExitStatusPresent) { printkf("wait: reading from %x: %d\n", &process->childExitStatus, process->childExitStatus); return process->childExitStatus; } break; } thread = thread->next; } } else { PANIC("Process is NULL!\n"); } return -1; } int syscall_kill(int pid, int sig) { Process* selfProcess = getCurrentThread()->owner; Thread* thread = getMainKernelThread(); while (thread) { if (pid == thread->owner->pid) { //We have found the process //TODO if (sig==KILL) { destroyProcess(thread->owner); if (thread->owner == selfProcess) { waitForSchedule(); } else { return 0; } } break; } thread = thread->next; } return -1; } int syscall_mount(const char *source, const char *target, const char *fsType, unsigned long flags, void *data) { // non-posix BOOL result = mountFileSystem(source, target, fsType, flags, data); if (TRUE == result) { return 0;//on success } return -1;//on error } int syscall_unmount(const char *target) { // non-posix FileSystemNode* targetNode = getFileSystemNode(target); if (targetNode) { if (targetNode->nodeType == FT_MountPoint) { targetNode->nodeType = FT_Directory; targetNode->mountPoint = NULL; //TODO: check conditions, maybe busy. make clean up. return 0;//on success } } return -1;//on error } int syscall_mkdir(const char *path, uint32 mode) { char parentPath[128]; const char* name = NULL; int length = strlen(path); for (int i = length - 1; i >= 0; --i) { if (path[i] == '/') { name = path + i + 1; strncpy(parentPath, path, i); parentPath[i] = '\0'; break; } } if (strlen(parentPath) == 0) { parentPath[0] = '/'; parentPath[1] = '\0'; } if (strlen(name) == 0) { return -1; } //printkf("mkdir: parent:[%s] name:[%s]\n", parentPath, name); FileSystemNode* targetNode = getFileSystemNode(parentPath); if (targetNode) { BOOL success = mkdir_fs(targetNode, name, mode); if (success) { return 0;//on success } } return -1;//on error } int syscall_rmdir(const char *path) { //TODO: //return 0;//on success return -1;//on error } int syscall_getdents(int fd, char *buf, int nbytes) { Process* process = getCurrentThread()->owner; if (process) { if (fd < MAX_OPENED_FILES) { File* file = process->fd[fd]; if (file) { //printkf("syscall_getdents(%d): %s\n", process->pid, buf); int byteCounter = 0; int index = 0; FileSystemDirent* dirent = readdir_fs(file->node, index); while (NULL != dirent && (byteCounter + sizeof(FileSystemDirent) <= nbytes)) { memcpy((uint8*)buf + byteCounter, (uint8*)dirent, sizeof(FileSystemDirent)); byteCounter += sizeof(FileSystemDirent); index += 1; dirent = readdir_fs(file->node, index); } return byteCounter; } else { //TODO: error invalid fd } } else { //TODO: error invalid fd } } else { PANIC("Process is NULL!\n"); } return -1;//on error } int syscall_readDir(int fd, void *dirent, int index) { Process* process = getCurrentThread()->owner; if (process) { if (fd < MAX_OPENED_FILES) { File* file = process->fd[fd]; if (file) { FileSystemDirent* direntFs = readdir_fs(file->node, index); if (direntFs) { memcpy((uint8*)dirent, (uint8*)direntFs, sizeof(FileSystemDirent)); return 1; } } else { //TODO: error invalid fd } } else { //TODO: error invalid fd } } else { PANIC("Process is NULL!\n"); } return -1;//on error } int syscall_getWorkingDirectory(char *buf, int size) { Process* process = getCurrentThread()->owner; if (process) { if (process->workingDirectory) { return getFileSystemNodePath(process->workingDirectory, buf, size); } } else { PANIC("Process is NULL!\n"); } return -1;//on error } int syscall_setWorkingDirectory(const char *path) { Process* process = getCurrentThread()->owner; if (process) { FileSystemNode* node = getFileSystemNodeAbsoluteOrRelative(path, process); if (node) { process->workingDirectory = node; return 0; //success } } else { PANIC("Process is NULL!\n"); } return -1;//on error } int syscall_managePipe(const char *pipeName, int operation, int data) { int result = -1; switch (operation) { case 0: result = existsPipe(pipeName); break; case 1: result = createPipe(pipeName, data); break; case 2: result = destroyPipe(pipeName); break; } return result; } int syscall_getUptimeMilliseconds() { return getUptimeMilliseconds(); } int syscall_sleepMilliseconds(int ms) { Thread* thread = getCurrentThread(); sleepMilliseconds(thread, (uint32)ms); return 0; } int syscall_manageMessage(int command, void* message) { Thread* thread = getCurrentThread(); int result = -1; switch (command) { case 0: result = getMessageQueueCount(thread); break; case 1: sendMesage(thread, (SosoMessage*)message); result = 0; break; case 2: //make blocking result = getNextMessage(thread, (SosoMessage*)message); break; default: break; } return result; } void* syscall_mmap(void *addr, int length, int flags, int fd, int offset) { if (addr) { //Mapping to a specified address is not implemented return (void*)-1; } Process* process = getCurrentThread()->owner; if (process) { if (fd < MAX_OPENED_FILES) { File* file = process->fd[fd]; if (file) { void* ret = mmap_fs(file, length, offset, flags); if (ret) { return ret; } } else { //TODO: error invalid fd } } else { //TODO: error invalid fd } } else { PANIC("Process is NULL!\n"); } return (void*)-1; } int syscall_munmap(void *addr, int length) { //TODO: fd /* Process* process = getCurrentThread()->owner; if (process) { if (fd < MAX_OPENED_FILES) { File* file = process->fd[fd]; if (file) { if (munmap_fs(file, addr, length)) { return 0;//on success } } else { //TODO: error invalid fd } } else { //TODO: error invalid fd } } else { PANIC("Process is NULL!\n"); } */ return -1; } #define O_CREAT 0x200 int syscall_shm_open(const char *name, int oflag, int mode) { FileSystemNode* node = NULL; if ((oflag & O_CREAT) == O_CREAT) { node = createSharedMemory(name); } else { node = getSharedMemoryNode(name); } if (node) { File* file = open_fs(node, oflag); if (file) { return file->fd; } } return -1; } int syscall_shm_unlink(const char *name) { return -1; } int syscall_ftruncate(int fd, int size) { Process* process = getCurrentThread()->owner; if (process) { if (fd < MAX_OPENED_FILES) { File* file = process->fd[fd]; if (file) { return ftruncate_fs(file, size); } else { //TODO: error invalid fd } } else { //TODO: error invalid fd } } else { PANIC("Process is NULL!\n"); } return -1; } int syscall_posix_openpt(int flags) { Process* process = getCurrentThread()->owner; if (process) { FileSystemNode* node = createPseudoTerminal(); if (node) { File* file = open_fs(node, flags); if (file) { return file->fd; } } } else { PANIC("Process is NULL!\n"); } return -1; } int syscall_ptsname_r(int fd, char *buf, int buflen) { Process* process = getCurrentThread()->owner; if (process) { if (fd < MAX_OPENED_FILES) { File* file = process->fd[fd]; if (file) { /* int result = getSlavePath(file->node, buf, buflen); if (result > 0) { return 0; //return 0 on success } */ } else { //TODO: error invalid fd } } else { //TODO: error invalid fd } } else { PANIC("Process is NULL!\n"); } return -1;//on error }