From b769ac0a58bee673c881214f1a753468bfc1b142 Mon Sep 17 00:00:00 2001 From: Ruslan Isaev Date: Mon, 23 Jun 2025 23:36:14 +0300 Subject: [PATCH] tasking: continue fixing task_kill --- include/paging.h | 1 + src/mm/page_alloc.c | 31 ++++++++++------- src/mm/paging.c | 61 ++++++++++++++++++++++------------ src/tasking/exec_from_file.c | 20 +++++------ src/tasking/syscalls.c | 21 ++++++------ src/tasking/task.c | 64 +++++++++++++++++++++++++----------- 6 files changed, 125 insertions(+), 73 deletions(-) diff --git a/include/paging.h b/include/paging.h index 01baa0a..2d0c359 100644 --- a/include/paging.h +++ b/include/paging.h @@ -46,6 +46,7 @@ static inline uint32_t virt_to_phys(void* virt) { } //page_alloc.c +int is_page_in_use(uint32_t page_index); void set_bit(uint32_t page_index); void clear_bit(uint32_t page_index); void init_allocator(); diff --git a/src/mm/page_alloc.c b/src/mm/page_alloc.c index 6d3a217..b3bd459 100644 --- a/src/mm/page_alloc.c +++ b/src/mm/page_alloc.c @@ -7,6 +7,15 @@ // Каждый бит представляет одну страницу: 0 = свободна, 1 = занята uint8_t page_bitmap[BITMAP_SIZE]; +int is_page_in_use(uint32_t page_index) { + if (page_index >= PAGE_COUNT) { + return 0; // Out of range is considered "not in use by our allocator" + } + uint32_t byte_index = page_index / 8; + uint8_t bit_offset = page_index % 8; + return (page_bitmap[byte_index] & (1 << bit_offset)); +} + // Установить бит (пометить страницу как занятую) void set_bit(uint32_t page_index) { uint32_t byte_index = page_index / 8; // Номер байта в битовой карте @@ -21,16 +30,14 @@ void clear_bit(uint32_t page_index) { return; } - uint32_t byte_index = page_index / 8; - uint8_t bit_offset = page_index % 8; - - //check if this is needed at all except for debug purposes - if(!(page_bitmap[byte_index] & (1 << bit_offset))) - { - printf("clear_bit: page #0x%X already free\n", page_index); + if (!is_page_in_use(page_index)) { + printf("clear_bit: warning, page #0x%X was already free.\n", page_index); return; } + uint32_t byte_index = page_index / 8; + uint8_t bit_offset = page_index % 8; + page_bitmap[byte_index] &= ~(1 << bit_offset); // Сбрасываем бит } @@ -49,14 +56,14 @@ void* alloc_page() { //printf("!!!free page at 0x%X!!!\n", i); for (j = 0; j < 8; j++) { if (!(page_bitmap[i] & (1 << j))) { // Если этот бит = 0 (свободен) - page_bitmap[i] |= (1 << j); // Помечаем как занятый - - // Вычисляем физический адрес страницы uint32_t page_num = i * 8 + j; - void* addr = (void*)(page_num * PAGE_SIZE); - //printf("allocated page at 0x%X (page #0x%X)\n", addr, page_num); + if(page_num == 0) + continue; + + printf("allocating page %X\n", page_num * PAGE_SIZE); + page_bitmap[i] |= (1 << j); // Помечаем как занятый return (void*)(page_num * PAGE_SIZE); } } diff --git a/src/mm/paging.c b/src/mm/paging.c index d458f92..72528e8 100644 --- a/src/mm/paging.c +++ b/src/mm/paging.c @@ -41,8 +41,8 @@ uint32_t setup_tmp_pgdir(uint32_t magic, uint32_t info) if(!(n % 1024)) { pd = n / 1024; uint32_t pt_phys = (uint32_t)page_table - PAGE_OFFSET + (PAGE_SIZE * pd); - kpage_dir[pd] = pt_phys | PAGE_PRESENT | PAGE_RW | PAGE_USER;//TODO: fix, I don't think pd should have DPL3 - kpage_dir[GET_PGDIR(PAGE_OFFSET) + pd] = pt_phys | PAGE_PRESENT | PAGE_RW | PAGE_USER;//TODO: fix, I don't think pd should have DPL3 + kpage_dir[pd] = pt_phys | PAGE_PRESENT | PAGE_RW;//TODO: fix, I don't think pd should have DPL3 + kpage_dir[GET_PGDIR(PAGE_OFFSET) + pd] = pt_phys | PAGE_PRESENT | PAGE_RW;//TODO: fix, I don't think pd should have DPL3 } } @@ -134,7 +134,9 @@ uint32_t* create_page_dir() for(int i = 768; i < 1023; i++) { - new_pd[i] = current_pd[i]; + if(current_pd[i] & PAGE_PRESENT) { + new_pd[i] = current_pd[i]; + } } int vga_pde_index = 0; // Virtual address 0x000B8000 is covered by PDE[0] @@ -147,27 +149,44 @@ uint32_t* create_page_dir() return new_pd; } -//TODO: this function is somehow messes up addresses so free_page passes page_nums like 0xF000F into clear_bit -void destroy_page_dir(uint32_t* page_dir) { - // Temporarily switch to target PD for freeing - uint32_t orig_cr3; - asm volatile("mov %%cr3, %0" : "=r"(orig_cr3)); - asm volatile("mov %0, %%cr3" : : "r"(virt_to_phys(page_dir))); - - // Free only user-space pages (entries 0-767) +void destroy_page_dir(uint32_t* page_dir_virt) { + if (page_dir_virt == NULL) { + return; + } + + // Iterate through user-space page directory entries (PDEs 0-767). + // Kernel space (768+) is shared and should not be freed. for (int i = 0; i < 768; i++) { - if (page_dir[i] & PAGE_PRESENT) { - uint32_t* pt = (uint32_t*)phys_to_virt(page_dir[i] & ~0xFFF); - for (int j = 0; j < 1024; j++) { - if (pt[j] & PAGE_PRESENT) { - free_page((void*)(pt[j] & ~0xFFF)); + uint32_t pde = page_dir_virt[i]; + + // Check if the page directory entry is present + if (pde & PAGE_PRESENT) { + // Get the physical address of the page table + uint32_t pt_phys = pde & ~0xFFF; + + if(is_page_in_use(pt_phys / PAGE_SIZE)){ + // Convert it to a virtual address the kernel can access + uint32_t* page_table_virt = (uint32_t*)phys_to_virt(pt_phys); + + // Iterate through all 1024 entries in this page table + for (int j = 0; j < 1024; j++) { + uint32_t pte = page_table_virt[j]; + + // If the page table entry is present, free the physical page (frame) it points to + if (pte & PAGE_PRESENT) { + printf("freeing page %X\n", pte); + free_page((void*)(pte & ~0xFFF)); + } } + + // After freeing all pages within the table, free the page table itself + free_page((void*)pt_phys); } - free_page((void*)(page_dir[i] & ~0xFFF)); } } - - // Restore original page directory - asm volatile("mov %0, %%cr3" : : "r"(orig_cr3)); - free_page((void*)virt_to_phys(page_dir)); + + // Finally, free the page directory itself. + // We need its physical address to pass to the physical memory manager. + printf("freeing PD page %X\n", virt_to_phys(page_dir_virt)); + free_page((void*)virt_to_phys(page_dir_virt)); } \ No newline at end of file diff --git a/src/tasking/exec_from_file.c b/src/tasking/exec_from_file.c index 5052963..0725410 100644 --- a/src/tasking/exec_from_file.c +++ b/src/tasking/exec_from_file.c @@ -69,16 +69,16 @@ void exec_from_file(const char* filename) uint8_t* file; int result = read_file(filename, &file); - debug_log("result: %X\n", result); - debug_log("buffer: %s\n", file); + //debug_log("result: %X\n", result); + //debug_log("buffer: %s\n", file); Elf32_Ehdr *elf_ehdr = (Elf32_Ehdr*)file; int program_header_table_entry_count = elf_ehdr->e_phnum; int program_header_table_entry_size = elf_ehdr->e_phentsize; - debug_log("magic: %X, type: %X, entry: 0x%X\n", elf_ehdr->e_ident, elf_ehdr->e_type, elf_ehdr->e_entry); - debug_log("PHNUM: %X\n", program_header_table_entry_count); - debug_log("PHENTSIZE: %X\n\n", program_header_table_entry_size); + //debug_log("magic: %X, type: %X, entry: 0x%X\n", elf_ehdr->e_ident, elf_ehdr->e_type, elf_ehdr->e_entry); + //debug_log("PHNUM: %X\n", program_header_table_entry_count); + //debug_log("PHENTSIZE: %X\n\n", program_header_table_entry_size); uint32_t* proc_pd = create_page_dir(); uint32_t proc_pd_phys = (uint32_t)get_physaddr((void*)proc_pd); @@ -93,15 +93,15 @@ void exec_from_file(const char* filename) Elf32_Phdr *elf_phdr = (Elf32_Phdr *)((uint32_t)file + elf_ehdr->e_phoff + i * elf_ehdr->e_phentsize); - debug_log("HEADER %X, type: 0x%X, vaddr: 0x%X, paddr: 0x%X, memsz: 0x%X\n", i, elf_phdr->p_type, elf_phdr->p_vaddr, elf_phdr->p_paddr, elf_phdr->p_memsz); + //debug_log("HEADER %X, type: 0x%X, vaddr: 0x%X, paddr: 0x%X, memsz: 0x%X\n", i, elf_phdr->p_type, elf_phdr->p_vaddr, elf_phdr->p_paddr, elf_phdr->p_memsz); if(elf_phdr->p_type != PT_LOAD) { - debug_log("not PT_LOAD, skipping...\n"); + //debug_log("not PT_LOAD, skipping...\n"); continue; } int pages_needed = DivRoundUp(elf_phdr->p_memsz, 0x1000);//(elf_phdr->p_memsz / 0x1000) + 1; - debug_log("pages needed: %X\n", pages_needed); + //debug_log("pages needed: %X\n", pages_needed); for(int j = 0; j < pages_needed; j++) { @@ -120,8 +120,8 @@ void exec_from_file(const char* filename) memset((void*)bss_start, 0, bss_end - bss_start); } - debug_log("p_filesz: 0x%X (%X)\n", elf_phdr->p_filesz, elf_phdr->p_filesz); - debug_log("================================\n\n\n\n"); + //debug_log("p_filesz: 0x%X (%X)\n", elf_phdr->p_filesz, elf_phdr->p_filesz); + //debug_log("================================\n\n\n\n"); } debug_log("setting up the user stack...\n"); diff --git a/src/tasking/syscalls.c b/src/tasking/syscalls.c index e01996a..654720b 100644 --- a/src/tasking/syscalls.c +++ b/src/tasking/syscalls.c @@ -79,9 +79,9 @@ int sys_write(TrapFrame *tf) //stdin, stdout or stderr if(tf->ebx == STDOUT_FILENO) { - debug_log("\n=================SYS_WRITE output to stdout=====================\n"); + //debug_log("\n=================SYS_WRITE output to stdout=====================\n"); print((char*)tf->ecx, tf->edx); - debug_log("\n=================END OF THAT SHIT=====================\n"); + //debug_log("\n=================END OF THAT SHIT=====================\n"); return tf->edx; } } @@ -103,16 +103,16 @@ int sys_open(TrapFrame *tf) 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); + //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); + //debug_log("\n====i: %X\n", i); if(current->file_descriptors[i] == NULL) { current->file_descriptors[i] = malloc(sizeof(file_t)); // Kernel malloc - debug_log("\n====FILE_DESCRIPTOR: %X\n", i); + //debug_log("\n====FILE_DESCRIPTOR: %X\n", i); int result = fat_fopen(current->file_descriptors[i], filename, mode_str); if (result < 0) { free(current->file_descriptors[i]); // Free on failure @@ -130,12 +130,12 @@ int sys_open(TrapFrame *tf) int sys_close(TrapFrame *tf) { int fd = tf->ebx; - debug_log("SYS_CLOSE: fd = 0x%X", fd); + //debug_log("SYS_CLOSE: fd = 0x%X", fd); if(current->file_descriptors[fd] != NULL) { - debug_log("SYS_CLOSE: current->file_descriptors[fd] != NULL"); + //debug_log("SYS_CLOSE: current->file_descriptors[fd] != NULL"); int result = fat_fclose(current->file_descriptors[fd]); - debug_log("SYS_CLOSE: fat_fclose result: 0x%X", result); + //debug_log("SYS_CLOSE: fat_fclose result: 0x%X", result); free(current->file_descriptors[fd]); current->file_descriptors[fd] = NULL; return result; @@ -145,11 +145,12 @@ int sys_close(TrapFrame *tf) 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); + */ if(tf->eax == 1)//exit { diff --git a/src/tasking/task.c b/src/tasking/task.c index 4d16317..760e9a7 100644 --- a/src/tasking/task.c +++ b/src/tasking/task.c @@ -98,37 +98,61 @@ void scheduler_unlock() //TODO: there's an issue with this. If there's only one task in the queue (or is it there really?), //the scheduler doesn't switch the context to it, but just does nothing void schedule() { - if (!current) return; + scheduler_lock(); - // Clean any terminated processes in queue Process* prev = NULL; - Process* curr = queue; - while (curr) { - if (curr->state == Terminated) { - Process* next = curr->next; - if (prev) prev->next = next; - else queue = next; - - destroy_page_dir(curr->pagedir); - free_page((void*)virt_to_phys(curr->kstack)); - free_page((void*)virt_to_phys(curr)); - - curr = next; + Process* p = queue; + while (p) { + if (p->state == Terminated) { + Process* next_proc = p->next; + // Unlink from the queue + if (prev) { + prev->next = next_proc; + } else { + queue = next_proc; + } + + // If the terminated process is the current one, we must not switch to it. + if (p == current) { + current = NULL; + } + + 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 = curr; - curr = curr->next; + prev = p; + p = p->next; } } - Process* next = current->next; + // If 'current' was terminated or this is the first run, find a new process. + if (!current || current->state != Ready) { + current = queue; // Start search from the beginning + } + + // Find the next ready process to run + Process* next = current ? current->next : NULL; if (!next) next = queue; + + // Iterate through the list to find a process that is ready to run + Process* start_node = next; while (next && next->state != Ready) { next = next->next; - if (!next) next = queue; + if (!next) next = queue; // Wrap around + if (next == start_node) { // Full circle, no ready process + scheduler_unlock(); + return; + } } - if (!next || next == current) return; - switchProcess(next); + if (next && next != current) { + switchProcess(next); + } + + scheduler_unlock(); } void idle()