diff options
Diffstat (limited to 'tools/iso/kernel.soso/syscalls.c')
-rw-r--r-- | tools/iso/kernel.soso/syscalls.c | 983 |
1 files changed, 983 insertions, 0 deletions
diff --git a/tools/iso/kernel.soso/syscalls.c b/tools/iso/kernel.soso/syscalls.c new file mode 100644 index 00000000..8b72941f --- /dev/null +++ b/tools/iso/kernel.soso/syscalls.c @@ -0,0 +1,983 @@ +#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 +} |