From 64d5cd1d2f12074adfc09df837b55890aa97943b Mon Sep 17 00:00:00 2001 From: Ruslan Isaev Date: Thu, 16 Apr 2026 15:16:57 +0300 Subject: [PATCH] tasking: prevent many page faults --- src/fs/vfs.c | 3 ++ src/kernel/isr.asm | 14 ++++++-- src/kernel/isr.c | 4 +-- src/mm/paging.c | 8 +++-- src/tasking/exec_from_file.c | 21 +++++++++++ src/tasking/sys_exit.asm | 9 +++-- src/tasking/syscalls.c | 67 +++++++++++++++++++++++++++++------- src/tasking/task.c | 20 ++++++++++- 8 files changed, 123 insertions(+), 23 deletions(-) diff --git a/src/fs/vfs.c b/src/fs/vfs.c index 6c42b58..1ebe04a 100644 --- a/src/fs/vfs.c +++ b/src/fs/vfs.c @@ -201,6 +201,9 @@ int vfs_read_file_by_path(const char* path, uint8_t** buffer) err = follow_path(path, file, dir); if(err != L9660_OK) { + free(file); + free(dir); + *buffer = NULL; return err; } diff --git a/src/kernel/isr.asm b/src/kernel/isr.asm index 8822ba4..b577527 100644 --- a/src/kernel/isr.asm +++ b/src/kernel/isr.asm @@ -20,11 +20,21 @@ page_fault_handler: ; Get the faulting address from CR2 mov eax, cr2 + ; Stack layout AFTER pushad + 4 pushes (user-mode fault, ring change): + ; [esp+0..15] gs, fs, es, ds (our pushes, gs is lowest) + ; [esp+16..47] pushad registers (edi..eax, edi is lowest) + ; [esp+48] Error Code (pushed by CPU last = lowest CPU-pushed addr) + ; [esp+52] EIP + ; [esp+56] CS + ; [esp+60] EFLAGS + ; [esp+64] ESP (user, only on privilege change) + ; [esp+68] SS (user, only on privilege change) + mov ebx, [esp + 48] ; Error code is at this offset + ; Push parameters for the C function: ; - Faulting address (from CR2) - ; - Error code (at [esp + 48], after pushed registers and segment selectors) + ; - Error code (from correct offset) push eax ; Push CR2 (faulting address) - mov ebx, [esp + 48] ; Get error code (adjust offset based on stack layout) push ebx ; Push error code ; Call the C handler diff --git a/src/kernel/isr.c b/src/kernel/isr.c index de7c110..887fdf5 100644 --- a/src/kernel/isr.c +++ b/src/kernel/isr.c @@ -123,9 +123,9 @@ __attribute__((interrupt)) void isr_timer(struct interrupt_frame *frame) pic_end_int(0x0); } - //scheduler_lock(); + scheduler_lock(); schedule(); - //scheduler_unlock(); + scheduler_unlock(); } __attribute__((interrupt)) void isr_custom(struct interrupt_frame *frame) diff --git a/src/mm/paging.c b/src/mm/paging.c index b0bc6dd..2e7de6f 100644 --- a/src/mm/paging.c +++ b/src/mm/paging.c @@ -136,10 +136,14 @@ void* phys_to_virt2(void* phys) uint32_t* create_page_dir() { void* ppp = alloc_page(); - memset(ppp, 0, 0x1000); + if (!ppp) { + debug_log("create_page_dir: alloc_page returned NULL\n"); + return NULL; + } + uint32_t* new_pd = (uint32_t*)phys_to_virt((uint32_t)ppp); + memset(new_pd, 0, 0x1000); uint32_t* current_pd = (uint32_t*)0xFFFFF000; // Current PD (self-mapped) - uint32_t* new_pd = (uint32_t*)phys_to_virt((uint32_t)ppp); for(int i = 768; i < 1024; i++) { diff --git a/src/tasking/exec_from_file.c b/src/tasking/exec_from_file.c index 50bf41c..24559d6 100644 --- a/src/tasking/exec_from_file.c +++ b/src/tasking/exec_from_file.c @@ -49,6 +49,12 @@ void exec_from_file(l9660_file* fs_file, l9660_dir* dir) //debug_log("PHENTSIZE: %X\n\n", program_header_table_entry_size); uint32_t* proc_pd = create_page_dir(); + if (!proc_pd) { + printf("exec_from_file: create_page_dir failed\n"); + free(file); + asm volatile("sti"); + return; + } uint32_t proc_pd_phys = (uint32_t)get_physaddr((void*)proc_pd); debug_log("proc_pd_phys: 0x%X\n", proc_pd_phys); @@ -83,6 +89,14 @@ void exec_from_file(l9660_file* fs_file, l9660_dir* dir) { uint32_t vaddr = start_page + j * 0x1000; void* phys_addr = alloc_page(); + if (!phys_addr) { + printf("exec_from_file: alloc_page failed for segment\n"); + set_page_dir(curr_pd_phys); + //TODO: free previously allocated pages + free(file); + asm volatile("sti"); + return; + } debug_log("mapping 0x%X -> 0x%X\n", phys_addr, vaddr); map_page(phys_addr, (void*)vaddr, PAGE_PRESENT | PAGE_RW | PAGE_USER); @@ -136,6 +150,13 @@ void exec_from_file(l9660_file* fs_file, l9660_dir* dir) set_page_dir(curr_pd_phys); Process* p_task1 = task_create(elf_ehdr->e_entry, USER_STACK_TOP, 3, proc_pd); + if (!p_task1) { + printf("exec_from_file: task_create failed\n"); + set_page_dir(curr_pd_phys); + free(file); + asm volatile("sti"); + return; + } p_task1->cwd = dir; uint32_t brk_address = DivRoundUp(bss_end+1, 0x1000)*0x1000; diff --git a/src/tasking/sys_exit.asm b/src/tasking/sys_exit.asm index 010ac4a..e740181 100644 --- a/src/tasking/sys_exit.asm +++ b/src/tasking/sys_exit.asm @@ -34,7 +34,12 @@ sys_exit_handler: global execve_return execve_return: - mov esp, [esp+4] + ; tf is passed as first argument in cdecl at [esp+4] + ; We need to move ESP to point to the TrapFrame that tf points to. + ; Save tf pointer in eax first (before changing esp) + mov eax, [esp+4] ; eax = tf pointer + ; Now load ESP with the trapframe + mov esp, eax ; esp = tf, now stack is: gs, fs, es, ds, edi, esi... pop gs pop fs @@ -42,8 +47,6 @@ execve_return: pop ds popa - ;add esp, 8 - iret section .data diff --git a/src/tasking/syscalls.c b/src/tasking/syscalls.c index 13a629e..db11f01 100644 --- a/src/tasking/syscalls.c +++ b/src/tasking/syscalls.c @@ -77,6 +77,7 @@ int sys_fork(TrapFrame *tf) uint32_t* new_pd = copy_page_dir(current->pagedir); if (!new_pd) { debug_log("Failed to copy page directory\n"); + scheduler_unlock(); return -1; } debug_log("new_pd: %X\n", new_pd); @@ -84,6 +85,7 @@ int sys_fork(TrapFrame *tf) void *p_physical = alloc_page(); if (!p_physical) { destroy_page_dir(new_pd); + scheduler_unlock(); return -1; } @@ -103,6 +105,13 @@ int sys_fork(TrapFrame *tf) child->ring = current->ring; child->pagedir = new_pd; child->cwd = malloc(sizeof(l9660_dir)); + if (!child->cwd) { + debug_log("sys_fork: malloc for cwd failed\n"); + destroy_page_dir(new_pd); + free_page(p_physical); + scheduler_unlock(); + return -1; + } memcpy(child->cwd, current->cwd, sizeof(l9660_dir)); void *kstack_physical = alloc_page(); @@ -110,6 +119,7 @@ int sys_fork(TrapFrame *tf) destroy_page_dir(new_pd); free_page(p_physical); debug_log("Failed to allocate kernel stack\n"); + scheduler_unlock(); return -1; } @@ -341,6 +351,8 @@ int sys_execve(TrapFrame *tf) { char **argv = (char**)tf->ecx; char **envp = (char**)tf->edx; + scheduler_lock(); + int argc = 0; while(argv[argc] != NULL) argc++; @@ -348,7 +360,10 @@ int sys_execve(TrapFrame *tf) { while(envp[envc] != NULL) envc++; char** kernel_argv = malloc((argc + 1) * sizeof(char*)); - if (!kernel_argv) return -1; + if (!kernel_argv) { + scheduler_unlock(); + return -1; + } for(int i = 0; i < argc; i++) { kernel_argv[i] = malloc(EXECVE_MAX_ARGUMENT_SIZE+1); @@ -358,7 +373,10 @@ int sys_execve(TrapFrame *tf) { kernel_argv[argc] = NULL; char** kernel_envp = malloc((envc + 1) * sizeof(char*)); - if (!kernel_envp) return -1; // TODO: cleanup kernel_argv + if (!kernel_envp) { + scheduler_unlock(); // TODO: cleanup kernel_argv + return -1; + } for(int i = 0; i < envc; i++) { kernel_envp[i] = malloc(EXECVE_MAX_ARGUMENT_SIZE+1); @@ -367,7 +385,7 @@ int sys_execve(TrapFrame *tf) { } kernel_envp[envc] = NULL; - uint8_t* file_buffer; + uint8_t* file_buffer = NULL; int err = vfs_read_file_by_path(filename, &file_buffer); if (err != 0) { // TODO: Free kernel_argv/envp @@ -377,6 +395,7 @@ int sys_execve(TrapFrame *tf) { for(int i=0; ikstack); - map_page_in_directory(new_page_dir, kstack_phys, current->kstack, PAGE_PRESENT | PAGE_RW); - - void* argv_phys = get_physaddr(kernel_argv); - map_page_in_directory(new_page_dir, argv_phys, kernel_argv, PAGE_PRESENT | PAGE_RW); + if (!new_page_dir_phys) { + debug_log("execve: get_physaddr(new_page_dir) failed\n"); + destroy_page_dir(new_page_dir); + scheduler_unlock(); + return -1; + } uint32_t* old_page_dir_to_free = current->pagedir; set_page_dir(new_page_dir_phys); @@ -420,6 +440,15 @@ int sys_execve(TrapFrame *tf) { for (uint32_t vaddr = start_page; vaddr <= end_page; vaddr += PAGE_SIZE) { void* phys_addr = alloc_page(); + if (!phys_addr) { + debug_log("execve: alloc_page failed for segment\n"); + //TODO: cleanup allocated pages and restore old page dir + set_page_dir(virt_to_phys(old_page_dir_to_free)); + current->pagedir = old_page_dir_to_free; + destroy_page_dir(new_page_dir); + scheduler_unlock(); + return -1; + } map_page(phys_addr, (void*)vaddr, PAGE_PRESENT | PAGE_RW | PAGE_USER); } @@ -433,7 +462,16 @@ int sys_execve(TrapFrame *tf) { for (uint32_t vaddr = USER_STACK_BOTTOM; vaddr <= USER_STACK_TOP; vaddr += PAGE_SIZE) { void* phys_addr = alloc_page(); + if (!phys_addr) { + debug_log("execve: alloc_page failed for user stack\n"); + set_page_dir((uint32_t)old_page_dir_to_free); + current->pagedir = old_page_dir_to_free; + destroy_page_dir(new_page_dir); + scheduler_unlock(); + return -1; + } map_page(phys_addr, (void*)(vaddr & ~0xFFF), PAGE_PRESENT | PAGE_RW | PAGE_USER); + memset((void*)(vaddr & ~0xFFF), 0, PAGE_SIZE); } uint32_t user_esp = USER_STACK_TOP; @@ -491,9 +529,12 @@ int sys_execve(TrapFrame *tf) { tf->eflags = FL_IF; tf->usermode_esp = user_esp; tf->usermode_ss = SEG_UDATA | DPL_USER; + tf->esp = (uint32_t)tf + offsetof(TrapFrame, eip); destroy_page_dir(old_page_dir_to_free); + scheduler_unlock(); + execve_return(tf); return 0; } diff --git a/src/tasking/task.c b/src/tasking/task.c index acba655..51b48d7 100644 --- a/src/tasking/task.c +++ b/src/tasking/task.c @@ -21,6 +21,10 @@ extern void switchProcess(Process* next); Process* task_create(uint32_t func, uint32_t user_esp, uint32_t ring, uint32_t* pagedir) { void *p_physical = alloc_page(); + if (!p_physical) { + debug_log("task_create: alloc_page failed for process\n"); + return NULL; + } Process* p = (Process*)((uint32_t)p_physical+0xC0000000); map_page(p_physical, (void*)p, PAGE_PRESENT | PAGE_RW); memset(p, 0, sizeof(Process)); @@ -30,6 +34,11 @@ Process* task_create(uint32_t func, uint32_t user_esp, uint32_t ring, uint32_t* // Выделяем стек ядра void *kstack_physical = alloc_page(); + if (!kstack_physical) { + debug_log("task_create: alloc_page failed for kernel stack\n"); + //TODO: free p_physical and its page table entry + return NULL; + } p->kstack = (char*)((uint32_t)kstack_physical+0xC0000000); map_page(kstack_physical, p->kstack, PAGE_PRESENT | PAGE_RW); debug_log("kstack: %X!!!!!!!!!!!!\n", p->kstack); @@ -52,6 +61,7 @@ Process* task_create(uint32_t func, uint32_t user_esp, uint32_t ring, uint32_t* p->tf->eflags = FL_IF; p->tf->eip = (uint32_t)func; + p->tf->esp = (uint32_t)p->tf + offsetof(TrapFrame, eip); p->pagedir = pagedir; @@ -196,8 +206,16 @@ void task2() void scheduler_init() { uint32_t* kernel_tasks_pagedir = (uint32_t*)create_page_dir(); + if (!kernel_tasks_pagedir) { + printf("scheduler_init: create_page_dir failed\n"); + while(1) {} + } - task_create((uint32_t)idle, 0, 0, kernel_tasks_pagedir); + Process* idle_proc = task_create((uint32_t)idle, 0, 0, kernel_tasks_pagedir); + if (!idle_proc) { + printf("scheduler_init: task_create failed\n"); + while(1) {} + } } void task_kill(Process* proc) {