#include "../include/syscalls.h" #include #include "../include/stdio.h" #include "../include/liballoc.h" #include "../include/paging.h" #include "../include/string.h" #define STDIN_FILENO 0 #define STDOUT_FILENO 1 #define STDERR_FILENO 2 #define EBADF 9 const char* flags_to_mode_str(int flags) { static char mode[4] = {0}; int accmode = flags & 3; if (accmode == 0) { // O_RDONLY mode[0] = 'r'; mode[1] = '\0'; } else if (accmode == 1) { // O_WRONLY if (flags & 0x400) { // O_APPEND mode[0] = 'a'; mode[1] = '\0'; } else { mode[0] = 'w'; mode[1] = '\0'; } } else if (accmode == 2) { // O_RDWR if (flags & 0x400) { // O_APPEND mode[0] = 'a'; mode[1] = '+'; mode[2] = '\0'; } else if (flags & 0x200) { // O_TRUNC mode[0] = 'w'; mode[1] = '+'; mode[2] = '\0'; } else { mode[0] = 'r'; mode[1] = '+'; mode[2] = '\0'; } } else { mode[0] = 'r'; mode[1] = '\0'; } return mode; } int sys_exit(TrapFrame *tf) { int error_code = tf->ebx; debug_log("killing task\n"); task_kill(current); asm("sti"); while(1){} return error_code; } extern void trapret(void); int sys_fork(TrapFrame *tf) { debug_log("FORKFORKFORKFORK\n"); scheduler_lock(); uint32_t* new_pd = copy_page_dir(current->pagedir); if (!new_pd) { debug_log("Failed to copy page directory\n"); return -1; } debug_log("new_pd: %X\n", new_pd); void *p_physical = alloc_page(); if (!p_physical) { destroy_page_dir(new_pd); return -1; } Process* child = (Process*)((uint32_t)p_physical + 0xC0000000); map_page(p_physical, (void*)child, PAGE_PRESENT | PAGE_RW); memset(child, 0, sizeof(Process)); child->pid = ++pid_counter; child->state = Ready; child->ring = current->ring; child->pagedir = new_pd; void *kstack_physical = alloc_page(); if (!kstack_physical) { destroy_page_dir(new_pd); free_page(p_physical); debug_log("Failed to allocate kernel stack\n"); return -1; } child->kstack = (char*)((uint32_t)kstack_physical + 0xC0000000); map_page(kstack_physical, child->kstack, PAGE_PRESENT | PAGE_RW); debug_log("child->kstack: %X\n", child->kstack); uint8_t* sp = (uint8_t*)(child->kstack + KSTACKSIZE); // 1. Place the TrapFrame on the child's stack. sp -= sizeof(TrapFrame); child->tf = (TrapFrame*)sp; memcpy(&child->tf->gs, &tf->gs, 12 * sizeof(uint32_t)); uint32_t* parent_cpu_state_ptr = (uint32_t*)&tf->interrupt; child->tf->eip = parent_cpu_state_ptr[0]; child->tf->cs = parent_cpu_state_ptr[1]; child->tf->eflags = parent_cpu_state_ptr[2]; child->tf->usermode_esp = parent_cpu_state_ptr[3]; child->tf->usermode_ss = parent_cpu_state_ptr[4]; child->tf->eax = 0; // Child returns 0 debug_log("Parent returns PID: %X, Child returns 0\n", child->pid); sp -= sizeof(Context); child->context = (Context*)sp; memset(child->context, 0, sizeof(Context)); // 5. Set the child's starting instruction pointer to trapret. // When the child is scheduled, it will execute trapret, which will // restore the registers from the TrapFrame and iret to user mode. child->context->eip = (uint32_t)trapret; // 6. IMPORTANT: Set the child's kernel stack pointer for the scheduler. child->kesp = (uint32_t)sp; for (int i = 0; i < MAX_OPEN_FILES; i++) { child->file_descriptors[i] = current->file_descriptors[i]; } debug_log("File descriptors copied\n"); Process* curr = queue; while (curr->next) { curr = curr->next; } curr->next = child; debug_log("Child added to queue\n"); scheduler_unlock(); // Release the lock return child->pid; } int sys_read(TrapFrame *tf) { if(tf->ebx < 3) { //TODO: implement stdin handling here } else { if(current->file_descriptors[tf->ebx] == NULL) { return -EBADF; } return fat_fread(current->file_descriptors[tf->ebx], (void*)tf->ecx, tf->edx); } } int sys_write(TrapFrame *tf) { if(tf->ebx < 3) { //stdin, stdout or stderr if(tf->ebx == STDOUT_FILENO) { //debug_log("\n=================SYS_WRITE output to stdout=====================\n"); print((char*)tf->ecx, tf->edx); //debug_log("\n=================END OF THAT SHIT=====================\n"); return tf->edx; } } else { if(current->file_descriptors[tf->ebx] == NULL) { return -EBADF; } return fat_fwrite(current->file_descriptors[tf->ebx], (void*)tf->ecx, tf->edx); } } int sys_open(TrapFrame *tf) { const char* filename = (const char*)tf->ebx; int flags = tf->ecx; int fd = -1; const char* mode_str = flags_to_mode_str(flags); //debug_log("\n====filename: %s\n", filename); //debug_log("\n====mode_str: %s\n", mode_str); for(int i = 3; i < MAX_OPEN_FILES; i++) { //debug_log("\n====i: %X\n", i); if(current->file_descriptors[i] == NULL) { current->file_descriptors[i] = malloc(sizeof(file_t)); // Kernel malloc //debug_log("\n====FILE_DESCRIPTOR: %X\n", i); int result = fat_fopen(current->file_descriptors[i], filename, mode_str); if (result < 0) { free(current->file_descriptors[i]); // Free on failure current->file_descriptors[i] = NULL; return result; } fd = i; break; } } return fd; } int sys_close(TrapFrame *tf) { int fd = tf->ebx; //debug_log("SYS_CLOSE: fd = 0x%X", fd); if(current->file_descriptors[fd] != NULL) { //debug_log("SYS_CLOSE: current->file_descriptors[fd] != NULL"); int result = fat_fclose(current->file_descriptors[fd]); //debug_log("SYS_CLOSE: fat_fclose result: 0x%X", result); free(current->file_descriptors[fd]); current->file_descriptors[fd] = NULL; return result; } return -1; } int sys_chdir(TrapFrame *tf) { strcat(current->cwd->fat->path, "/"); strcat(current->cwd->fat->path, (char*)tf->ebx); return fat_opendir(current->cwd, (const char*)tf->ebx); } int sys_getcwd(TrapFrame *tf) { strcpy((char*)tf->ebx, current->cwd->fat->path); return tf->ebx; } int sys_getpid(TrapFrame *tf) { return current->pid; } void handle_syscall(TrapFrame *tf) { /* debug_log("EAX: %X ", tf->eax); debug_log("EBX: %X ", tf->ebx); debug_log("ECX: %s ", tf->ecx); debug_log("EDX: %X\n", tf->edx); */ switch(tf->eax) { case 1://exit tf->eax = sys_exit(tf); break; case 2://fork tf->eax = sys_fork(tf); break; case 3://read tf->eax = sys_read(tf); break; case 4://write tf->eax = sys_write(tf); break; case 5://open tf->eax = sys_open(tf); break; case 6://close tf->eax = sys_close(tf); break; case 12://chdir tf->eax = sys_chdir(tf); break; case 20://getpid tf->eax = sys_getpid(tf); break; case 183://getcwd tf->eax = sys_getcwd(tf); break; default: debug_log("unknown syscall: %X\n", tf->eax); tf->eax = -1; break; } }