tasking: prevent many page faults

This commit is contained in:
2026-04-16 15:19:12 +03:00
parent 560003b6e3
commit 64d5cd1d2f
8 changed files with 123 additions and 23 deletions
+3
View File
@@ -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;
}
+12 -2
View File
@@ -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
+2 -2
View File
@@ -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)
+6 -2
View File
@@ -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++)
{
+21
View File
@@ -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;
+6 -3
View File
@@ -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
+54 -13
View File
@@ -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; i<envc; i++) free(kernel_envp[i]);
free(kernel_envp);
free(file_buffer);
scheduler_unlock();
return -1;
}
@@ -388,22 +407,23 @@ int sys_execve(TrapFrame *tf) {
for(int i=0; i<envc; i++) free(kernel_envp[i]);
free(kernel_envp);
free(file_buffer);
scheduler_unlock();
return -1;
}
uint32_t* new_page_dir = create_page_dir();
if (!new_page_dir) return -1;
if (!new_page_dir) {
scheduler_unlock();
return -1;
}
uint32_t new_page_dir_phys = (uint32_t)get_physaddr((void*)new_page_dir);
void* process_phys = get_physaddr(current);
map_page_in_directory(new_page_dir, process_phys, current, PAGE_PRESENT | PAGE_RW);
void* kstack_phys = get_physaddr(current->kstack);
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;
}
+19 -1
View File
@@ -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) {