#include "../include/syscalls.h" #include #include "../include/stdio.h" #include "../include/liballoc.h" #include "../include/paging.h" #include "../include/string.h" #include "../include/screen.h" #include "../include/fat.h" #include "../include/vfs.h" #include "../include/isr.h" #include "../include/task.h" extern void switchProcess(Process* next); #define STDIN_FILENO 0 #define STDOUT_FILENO 1 #define STDERR_FILENO 2 #define EBADF 9 #define EXECVE_MAX_ARGUMENT_SIZE 255 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; } #include "../../include/keyboard.h" int sys_read(TrapFrame *tf) { int fd = tf->ebx; char *user_buf = (char *)tf->ecx; size_t count = tf->edx; if (fd == STDIN_FILENO) { scheduler_lock(); while (!stdin_has_line) {//while enter has not been pressed current->state = Waiting; current->waiting_reason = STDIN; schedule(); } scheduler_unlock(); //find the pos of the first \n int line_len = 0; while (line_len < stdin_pos && stdin_buffer[line_len] != '\n') line_len++; if (line_len < stdin_pos) line_len++; //copy the input to the user buffer int to_copy = (line_len < count) ? line_len : count; memcpy(user_buf, stdin_buffer, to_copy); memmove(stdin_buffer, stdin_buffer + to_copy, stdin_pos - to_copy); stdin_pos -= to_copy; stdin_has_line = false; for (int i = 0; i < stdin_pos; i++) { if (stdin_buffer[i] == '\n') { stdin_has_line = true; break; } } return to_copy; } else if(fd < 3) { return -EBADF; } else { if(current->file_descriptors[fd] == NULL) { return -EBADF; } return vfs_read_file_length(current->file_descriptors[fd], (uint8_t*)user_buf, count); //return 0;//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; } if(tf->ebx == STDERR_FILENO) { uint8_t prev_color = terminal_getcolor(); terminal_setcolor(VGA_COLOR_RED); print((char*)tf->ecx, tf->edx); terminal_setcolor(prev_color); return tf->edx; } } else { if(current->file_descriptors[tf->ebx] == NULL) { return -EBADF; } return 0;//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] = (l9660_file*)malloc(sizeof(l9660_file)); // Kernel malloc l9660_openat(current->file_descriptors[i], root_dir, filename); //debug_log("\n====FILE_DESCRIPTOR: %X\n", i); int result = 0;//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 = 0;//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; } #include "../include/exec_from_file.h" extern void execve_return(TrapFrame *tf); /** * this might be a not really good implementation as it only supports * up to EXECVE_MAX_ARGUMENT_SIZE characters in each argument or environment * string and for some reason I was unable to use malloc for kernel_argv and * kernel_envp */ int sys_execve(TrapFrame *tf) { const char* filename = (const char*)tf->ebx; char **argv = (char**)tf->ecx; char **envp = (char**)tf->edx; int argc = 0; int envc = 0; while(argv[argc] != NULL) { argc++; } while(envp[envc] != NULL) { envc++; } //TODO: check why was there a triple fault when I tried using malloc char kernel_argv[argc][EXECVE_MAX_ARGUMENT_SIZE]; char kernel_envp[envc][EXECVE_MAX_ARGUMENT_SIZE]; for(int i = 0; i < argc; i++) { strcpy(kernel_argv[i], argv[i]); } for(int i = 0; i < envc; i++) { strcpy(kernel_envp[i], envp[i]); } uint8_t* file_buffer; int err = vfs_read_file_by_path(filename, &file_buffer); if (err != 0) { debug_log("execve: failed to read file '%s'\n", filename); return -1; } Elf32_Ehdr *elf_header = (Elf32_Ehdr*)file_buffer; if (memcmp(elf_header->e_ident, "\x7F" "ELF", 4) != 0) { debug_log("execve: '%s' is not a valid ELF file\n", filename); free(file_buffer); return -1; } uint32_t* new_page_dir = create_page_dir(); if (!new_page_dir) { free(file_buffer); return -1; } uint32_t new_page_dir_phys = (uint32_t)get_physaddr((void*)new_page_dir); uint32_t* old_page_dir_to_free = current->pagedir; set_page_dir(new_page_dir_phys); current->pagedir = new_page_dir; void* kstack_phys = get_physaddr(current->kstack); map_page(kstack_phys, current->kstack, PAGE_PRESENT | PAGE_RW); uint32_t highest_vaddr = 0; for (int i = 0; i < elf_header->e_phnum; i++) { Elf32_Phdr *p_header = (Elf32_Phdr *)(file_buffer + elf_header->e_phoff + i * elf_header->e_phentsize); if (p_header->p_type == PT_LOAD) { uint32_t start_addr = p_header->p_vaddr; uint32_t end_addr = start_addr + p_header->p_memsz; uint32_t start_page = start_addr & ~0xFFF; uint32_t end_page = (end_addr - 1) & ~0xFFF; for (uint32_t vaddr = start_page; vaddr <= end_page; vaddr += PAGE_SIZE) { void* phys_addr = alloc_page(); map_page(phys_addr, (void*)vaddr, PAGE_PRESENT | PAGE_RW | PAGE_USER); } memcpy((void*)p_header->p_vaddr, file_buffer + p_header->p_offset, p_header->p_filesz); if (p_header->p_memsz > p_header->p_filesz) { memset((void*)(p_header->p_vaddr + p_header->p_filesz), 0, p_header->p_memsz - p_header->p_filesz); } if (p_header->p_vaddr + p_header->p_memsz > highest_vaddr) { highest_vaddr = p_header->p_vaddr + p_header->p_memsz; } } } for (uint32_t vaddr = USER_STACK_BOTTOM; vaddr <= USER_STACK_TOP; vaddr += PAGE_SIZE) { void* phys_addr = alloc_page(); map_page(phys_addr, (void*)(vaddr & ~0xFFF), PAGE_PRESENT | PAGE_RW | PAGE_USER); } uint32_t user_esp = USER_STACK_TOP; //push environment strings uint32_t envp_pointers[envc + 1]; for (int i = envc - 1; i >= 0; i--) { size_t len = strlen(kernel_envp[i]) + 1; user_esp -= len; memcpy((void*)user_esp, kernel_envp[i], len); envp_pointers[i] = user_esp; } envp_pointers[envc] = 0;//null terminator //push argument strings uint32_t argv_pointers[argc + 1]; for (int i = argc - 1; i >= 0; i--) { size_t len = strlen(kernel_argv[i]) + 1; user_esp -= len; memcpy((void*)user_esp, kernel_argv[i], len); argv_pointers[i] = user_esp; } argv_pointers[argc] = 0;//null terminator //push envp pointers user_esp -= (envc + 1) * sizeof(uint32_t); memcpy((void*)user_esp, envp_pointers, (envc + 1) * sizeof(uint32_t)); //push argv pointers user_esp -= (argc + 1) * sizeof(uint32_t); memcpy((void*)user_esp, argv_pointers, (argc + 1) * sizeof(uint32_t)); //push argc user_esp -= sizeof(uint32_t); *((uint32_t*)user_esp) = argc; current->brk = (void*)(DivRoundUp(highest_vaddr, PAGE_SIZE) * PAGE_SIZE); free(file_buffer); destroy_page_dir(old_page_dir_to_free); tf->gs = SEG_UDATA | DPL_USER; tf->fs = SEG_UDATA | DPL_USER; tf->es = SEG_UDATA | DPL_USER; tf->ds = SEG_UDATA | DPL_USER; tf->eax = 0; tf->ecx = 0; tf->edx = 0; tf->ebx = 0; tf->ebp = 0; tf->esi = 0; tf->edi = 0; tf->eip = elf_header->e_entry; tf->cs = SEG_UCODE | DPL_USER; tf->eflags = FL_IF; tf->usermode_esp = user_esp; tf->usermode_ss = SEG_UDATA | DPL_USER; execve_return(tf); return 0; } int sys_chdir(TrapFrame *tf) { l9660_dir new_cwd; l9660_file placeholder_file; int status = follow_path((char*)tf->ebx, &placeholder_file, &new_cwd); if(status == L9660_OK) { *(current->cwd) = new_cwd; } switch(status) { case L9660_EIO: return -5;//-EIO break; case L9660_EBADFS: return -5;//EIO as well break; case L9660_ENOENT: return -2; break; case L9660_ENOTDIR: return -20;//ENOTDIR break; default: return -5;//EIO break; } //strcat(current->cwd->fat->path, "/"); //strcat(current->cwd->fat->path, (char*)tf->ebx); int result = 0;//fat_opendir(current->cwd, (const char*)tf->ebx); if(result == 0) return 0; return -1; } #include "../include/vfs.h" /** * I'm very sorry before myself for this but these directory traversing things are so hard, follow_path in vfs was pretty okay, * this is when shit got real though */ uint32_t sys_getcwd(TrapFrame *tf) { l9660_dir current_dir = *(current->cwd); char path_reversed[256] = {0}; char component_name[64]; while (!is_root_dir(¤t_dir)) { uint32_t child_sector = current_dir.file.first_sector; // Open the parent directory l9660_dir parent_dir; l9660_opendirat(&parent_dir, ¤t_dir, ".."); // Find our previous directory's name within the parent find_name_for_sector(component_name, sizeof(component_name), &parent_dir, child_sector); // Prepend the name to our reversed path string (e.g., "dash/" + "katau/" -> "katau/dash/") strcat(path_reversed, component_name); strcat(path_reversed, "/"); // Move up one level current_dir = parent_dir; } // Now, reverse the string "dash/katau/" to create the final path "/katau/dash" char final_path[256] = "/"; char* token = strtok(path_reversed, "/"); while (token != NULL) { // A bit of a trick to prepend tokens char temp[256]; strcpy(temp, "/"); strcat(temp, token); strcat(temp, final_path); strcpy(final_path, temp); token = strtok(NULL, "/"); } // Handle the root case where the loop doesn't run if (strlen(final_path) > 1) { final_path[strlen(final_path) - 1] = '\0'; // Remove trailing slash } strcpy((char*)tf->ebx, final_path); //strcpy((char*)tf->ebx, current->cwd->fat->path); return strlen(final_path);//tf->ebx; } int sys_getpid(TrapFrame *tf) { return current->pid; } #define DivRoundUp(number, divisor) ((number + divisor - 1) / divisor) uint32_t sys_brk(TrapFrame *tf) { if(!tf->ebx) { //debug_log("current brk is %X\n", (uint32_t)current->brk); return (uint32_t)current->brk; } if(tf->ebx < (uint32_t)current->brk) { debug_log("PIZDETS!!!! new brk less than current brk\n"); while(1){} } uint32_t old_brk_page = DivRoundUp((uint32_t)current->brk, 0x1000); uint32_t new_brk_page = DivRoundUp(tf->ebx, 0x1000); uint32_t pages_needed = new_brk_page - old_brk_page; for(uint32_t i = 0; i < pages_needed; i++) { void* phys_addr = alloc_page(); void* virt_addr = (void*)(old_brk_page * 0x1000 + i * 0x1000); map_page(phys_addr, virt_addr, 0x7); //debug_log("mapping page %X to %X\n", phys_addr, virt_addr); memset(virt_addr, 0, 0x1000); current->brk = (void*)tf->ebx; //debug_log("new brk is %X\n", (uint32_t)current->brk); } return (uint32_t)current->brk; } typedef struct timespec { int32_t tv_sec; // seconds int32_t tv_nsec; // nanoseconds } timespec; uint32_t sys_nanosleep(TrapFrame *tf) { timespec* duration = (timespec*)tf->ebx; size_t ms = duration->tv_sec * 1000 + duration->tv_nsec / 1000000; //debug_log("waiting for 0x%X ms\n", ms); scheduler_lock(); current->wake_up_time = timer_ticks + ms; current->state = Waiting; current->waiting_reason = TIMER; schedule(); scheduler_unlock(); return 0; } 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); */ //debug_log("calling 0x%X\n", tf->eax); 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 11://execve tf->eax = sys_execve(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; case 0x2d://brk tf->eax = sys_brk(tf); break; case 0x36://ioctl debug_log("IOCTL WAS CALLED, FUCKFUCK!!!!\n"); tf->eax = -38;//-ENOSYS break; case 0xa2://nanosleep tf->eax = sys_nanosleep(tf); break; default: debug_log("unknown syscall: %X\n", tf->eax); tf->eax = -38;//-ENOSYS break; } }