diff --git a/src/mm/kheap.c b/src/mm/kheap.c index 4e25f6f..2d67f3c 100644 --- a/src/mm/kheap.c +++ b/src/mm/kheap.c @@ -53,6 +53,31 @@ static void kheap_bitmap_clear(uint32_t index) { // Initialize kernel heap void kheap_init() { memset(kheap_bitmap, 0, sizeof(kheap_bitmap)); + + void* temp_phys = alloc_page(); + if (!temp_phys) { + printf("CRITICAL: Failed to init heap - No physical memory\n"); + while(1); + } + + uint32_t heap_limit = 4 * 1024 * 1024; + + for (uint32_t vaddr = KHEAP_START; vaddr < KHEAP_START + heap_limit; vaddr += 0x400000) { + + // This call checks if the Page Table exists. + // If not, it allocates a new Page Table and inserts it into the Current PD. + map_page(temp_phys, (void*)vaddr, PAGE_PRESENT | PAGE_RW); + + // We don't actually want the page mapped, we just wanted the Side Effect + // of creating the Page Table. So we unmap the page immediately. + // unmap_page clears the Entry, but DOES NOT free the Page Table itself. + unmap_page((void*)vaddr); + } + + // Free the dummy page + free_page(temp_phys); + + printf("Kernel Heap Initialized (Pre-allocated tables for 0x%X MB)\n", heap_limit / 1024 / 1024); } // Allocate contiguous virtual pages @@ -88,7 +113,8 @@ void* kvalloc(size_t npages) { for (uint32_t i = 0; i < npages; i++) { void* phys = alloc_page(); if (!phys) { - // Out of physical memory! Unmap what we just did and fail. + debug_log("NO MEMORY FOR KVALLOC!!\n"); + while(1){asm volatile("cli; hlt");} kvfree((void*)vaddr, i); return NULL; } @@ -117,14 +143,16 @@ void kvfree(void* addr, size_t npages) { for (uint32_t i = 0; i < npages; i++) { uint32_t current_vaddr = vaddr + i * PAGE_SIZE; + void* phys = get_physaddr((void*)current_vaddr); if (phys) { free_page(phys); - unmap_page((void*)current_vaddr); } else { - printf("kvfree: no physical mapping for 0x%x\n", current_vaddr); + debug_log("kvfree: no phys mapping for %x\n", current_vaddr); } + + unmap_page((void*)current_vaddr); kheap_bitmap_clear(start + i); } diff --git a/src/mm/page_alloc.c b/src/mm/page_alloc.c index baa5c24..0395f64 100644 --- a/src/mm/page_alloc.c +++ b/src/mm/page_alloc.c @@ -49,6 +49,7 @@ void init_allocator() { } void* alloc_page() { + asm volatile("cli"); int i, j; // Проходим по всему битмапу for (i = 0; i < BITMAP_SIZE; i++) { @@ -64,6 +65,7 @@ void* alloc_page() { //debug_log("allocating page %X\n", page_num * PAGE_SIZE); page_bitmap[i] |= (1 << j); // Помечаем как занятый + asm volatile("sti"); return (void*)(page_num * PAGE_SIZE); } } @@ -71,6 +73,7 @@ void* alloc_page() { } printf("no bitches? no free pages?\n"); + asm volatile("sti"); return (void*)0; // Нет свободных страниц } @@ -86,5 +89,7 @@ void free_page(void* physaddr) { // Вычисляем номер страницы uint32_t page_num = addr / PAGE_SIZE; + asm volatile("cli"); clear_bit(page_num); + asm volatile("sti"); } diff --git a/src/tasking/syscalls.c b/src/tasking/syscalls.c index c102b8c..503f973 100644 --- a/src/tasking/syscalls.c +++ b/src/tasking/syscalls.c @@ -348,8 +348,9 @@ int sys_execve(TrapFrame *tf) { if (!kernel_argv) return -1; for(int i = 0; i < argc; i++) { - kernel_argv[i] = malloc(EXECVE_MAX_ARGUMENT_SIZE); + kernel_argv[i] = malloc(EXECVE_MAX_ARGUMENT_SIZE+1); strcpy(kernel_argv[i], argv[i]); + kernel_argv[i][EXECVE_MAX_ARGUMENT_SIZE] = '\0'; } kernel_argv[argc] = NULL; @@ -357,8 +358,9 @@ int sys_execve(TrapFrame *tf) { if (!kernel_envp) return -1; // TODO: cleanup kernel_argv for(int i = 0; i < envc; i++) { - kernel_envp[i] = malloc(EXECVE_MAX_ARGUMENT_SIZE); + kernel_envp[i] = malloc(EXECVE_MAX_ARGUMENT_SIZE+1); strcpy(kernel_envp[i], envp[i]); + kernel_envp[i][EXECVE_MAX_ARGUMENT_SIZE] = '\0'; } kernel_envp[envc] = NULL; @@ -367,12 +369,22 @@ int sys_execve(TrapFrame *tf) { if (err != 0) { // TODO: Free kernel_argv/envp debug_log("execve: failed to read file\n"); + for(int i=0; ie_ident, "\x7F" "ELF", 4) != 0) { // TODO: Free resources + for(int i=0; i= 0; i--) { size_t len = strlen(kernel_envp[i]) + 1; user_esp -= len; @@ -432,7 +445,8 @@ int sys_execve(TrapFrame *tf) { } envp_pointers[envc] = 0; - uint32_t argv_pointers[argc + 1]; + //uint32_t argv_pointers[argc + 1]; + uint32_t* argv_pointers = malloc((argc + 1) * sizeof(uint32_t)); for (int i = argc - 1; i >= 0; i--) { size_t len = strlen(kernel_argv[i]) + 1; user_esp -= len; @@ -446,11 +460,16 @@ int sys_execve(TrapFrame *tf) { user_esp -= (argc + 1) * sizeof(uint32_t); memcpy((void*)user_esp, argv_pointers, (argc + 1) * sizeof(uint32_t)); + + free(argv_pointers); + free(envp_pointers); user_esp -= sizeof(uint32_t); *((uint32_t*)user_esp) = argc; current->brk = (void*)(DivRoundUp(highest_vaddr, PAGE_SIZE) * PAGE_SIZE); + + uint32_t entry_point = elf_header->e_entry; free(file_buffer); for(int i=0; igs = 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->eip = entry_point; tf->cs = SEG_UCODE | DPL_USER; tf->eflags = FL_IF; tf->usermode_esp = user_esp; tf->usermode_ss = SEG_UDATA | DPL_USER; + destroy_page_dir(old_page_dir_to_free); + execve_return(tf); return 0; } diff --git a/src/tasking/task.c b/src/tasking/task.c index 44f3715..e0c3ba9 100644 --- a/src/tasking/task.c +++ b/src/tasking/task.c @@ -119,78 +119,58 @@ void schedule() { Process* prev = NULL; p = queue; while (p) { - if (p->state == Terminated) { - Process* next_proc = p->next; + if (p->state == Terminated && p != current) { + Process* to_free = p; + + // Unlink from queue if (prev) { - prev->next = next_proc; + prev->next = p->next; + p = p->next; // Move to next } else { - queue = next_proc; + queue = p->next; + p = queue; // Move to head } - // If we are terminating the currently running process, we must find a new one. - if (p == current) { - current = NULL; - } - - // Free the terminated process's resources. - destroy_page_dir(p->pagedir); - free_page((void*)virt_to_phys(p->kstack)); - free_page((void*)virt_to_phys(p)); - - p = next_proc; - } else { - prev = p; - p = p->next; + // Safe to free resources now because we are NOT running on this stack + destroy_page_dir(to_free->pagedir); + free_page((void*)virt_to_phys(to_free->kstack)); + free_page((void*)virt_to_phys(to_free)); + + // Continue loop without advancing prev (since we removed p) + continue; } + + prev = p; + p = p->next; } - // If there are no processes left, we have a problem. - if (!queue) { - scheduler_unlock(); - // Ideally, you would panic the kernel here. - // For now, we just return and hope an interrupt happens. - return; - } + Process* start_search = (current && current->next) ? current->next : queue; + if (!start_search) start_search = queue; - // Step 3: Find the next process to run using a round-robin algorithm. - Process* start_search = NULL; - if (current && current->state == Ready) { - // If the current process is still ready, start searching from the next one. - start_search = current->next; - } else { - // If the current process is not ready (e.g., it's Waiting or was Terminated), - // start the search from the beginning of the queue. - start_search = queue; - } - - // Ensure start_search is not NULL (handles wrapping around). - if (!start_search) { - start_search = queue; - } - - // Find the first available 'Ready' process. Process* next = start_search; - do { - if (next->state == Ready) { - // We found a process to run. - // If it's not the same one we're already running, switch to it. - if (next != current) { - tss.esp0 = next->kstack_top; - switchProcess(next); // This will update 'current' and switch contexts. + if (next) { // Check if queue is empty + do { + if (next->state == Ready) { + if (next != current) { + tss.esp0 = next->kstack_top; + switchProcess(next); + } + scheduler_unlock(); + return; } - // If next == current, we don't need to switch. Just continue execution. - scheduler_unlock(); - return; - } - next = next->next; - if (!next) { - next = queue; // Wrap around to the beginning of the list. - } - } while (next != start_search); + next = next->next; + if (!next) next = queue; + } while (next != start_search); + } + + // If current is Terminated and we found no one else, we MUST run idle + // otherwise we return to a dead stack. + if (current->state == Terminated) { + // Find idle task or panic. + // Assuming first task (pid 1) is idle/init and never dies. + // For now, just unlock (unsafe if current is dead) or loop. + } - // If we get here, it means no process is in the 'Ready' state. - // This can happen if all tasks are waiting for I/O or sleeping. - // We just unlock and wait for the next interrupt to change a process's state. scheduler_unlock(); } @@ -220,34 +200,14 @@ void scheduler_init() } void task_kill(Process* proc) { - //TODO: that proc != current is sus - if (!proc || proc != current) return; + if (!proc) return; scheduler_lock(); proc->state = Terminated; - // Remove from process queue - if (queue == proc) { - queue = proc->next; - } else { - Process* prev = queue; - while (prev && prev->next != proc) prev = prev->next; - if (prev) prev->next = proc->next; + if(proc == current) + { + schedule(); } - - // Schedule next process - Process* next = queue; - while (next && next->state != Ready) next = next->next; - if (!next) next = queue; // Fallback to idle if needed - - current = next; - set_page_dir(virt_to_phys(next->pagedir)); - - // Free resources safely from new context - destroy_page_dir(proc->pagedir); - free_page((void*)virt_to_phys(proc->kstack)); - free_page((void*)virt_to_phys(proc)); - scheduler_unlock(); - switchProcess(next); } \ No newline at end of file