tasking: prevent many page faults
This commit is contained in:
@@ -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
@@ -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
@@ -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
@@ -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++)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user