From 229b06c63b5b7ca69fcfbec9fbfbd49ec80eefdd Mon Sep 17 00:00:00 2001 From: apio Date: Thu, 13 Oct 2022 19:19:51 +0200 Subject: [PATCH 01/17] Add basic address space infrastructure --- kernel/include/memory/AddressSpace.h | 17 +++++++ kernel/include/memory/VMM.h | 3 ++ kernel/src/main.cpp | 5 ++ kernel/src/memory/AddressSpace.cpp | 72 ++++++++++++++++++++++++++++ kernel/src/memory/VMM.cpp | 45 ++++++++++++----- 5 files changed, 130 insertions(+), 12 deletions(-) create mode 100644 kernel/include/memory/AddressSpace.h create mode 100644 kernel/src/memory/AddressSpace.cpp diff --git a/kernel/include/memory/AddressSpace.h b/kernel/include/memory/AddressSpace.h new file mode 100644 index 00000000..082ec607 --- /dev/null +++ b/kernel/include/memory/AddressSpace.h @@ -0,0 +1,17 @@ +#pragma once +#include "memory/Paging.h" + +struct AddressSpace +{ + static AddressSpace create(); + + void destroy(); + + PageTable* get_pml4() + { + return m_pml4; + } + + private: + PageTable* m_pml4; +}; \ No newline at end of file diff --git a/kernel/include/memory/VMM.h b/kernel/include/memory/VMM.h index 66aef241..e4dbce24 100644 --- a/kernel/include/memory/VMM.h +++ b/kernel/include/memory/VMM.h @@ -1,4 +1,5 @@ #pragma once +#include "memory/AddressSpace.h" #include "memory/Paging.h" enum Flags @@ -27,4 +28,6 @@ namespace VMM void decompose_vaddr(uint64_t vaddr, uint64_t& page_index, uint64_t& pt_index, uint64_t& pd_index, uint64_t& pdp_index); + + void install_kernel_page_directory_into_address_space(AddressSpace& space); }; \ No newline at end of file diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index 967a35e3..0858ab61 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -16,6 +16,7 @@ #include "io/PIC.h" #include "io/Serial.h" #include "log/Log.h" +#include "memory/AddressSpace.h" #include "memory/Memory.h" #include "memory/MemoryManager.h" #include "memory/MemoryMap.h" @@ -87,6 +88,10 @@ extern "C" void _start() Init::finish_kernel_boot(); + AddressSpace vaspace = AddressSpace::create(); + + vaspace.destroy(); + Interrupts::enable(); // Task switching commences here kinfoln("Interrupts enabled"); diff --git a/kernel/src/memory/AddressSpace.cpp b/kernel/src/memory/AddressSpace.cpp new file mode 100644 index 00000000..875ea606 --- /dev/null +++ b/kernel/src/memory/AddressSpace.cpp @@ -0,0 +1,72 @@ +#define MODULE "vmm" + +#include "memory/AddressSpace.h" +#include "log/Log.h" +#include "memory/PMM.h" +#include "memory/VMM.h" + +AddressSpace AddressSpace::create() +{ + AddressSpace result; + result.m_pml4 = (PageTable*)PMM::request_page(); + VMM::install_kernel_page_directory_into_address_space(result); + return result; +} + +void AddressSpace::destroy() +{ + uint64_t pages_freed = 0; + for (int i = 0; i < 512; i++) + { + PageDirectoryEntry& pdp_pde = m_pml4->entries[i]; + if (!pdp_pde.present) continue; + if (pdp_pde.larger_pages) + { + pages_freed++; + PMM::free_page((void*)pdp_pde.get_address()); + continue; + } + PageTable* pdp = (PageTable*)pdp_pde.get_address(); + for (int j = 0; j < 511; j++) // skip the last page directory, it's the kernel one + { + PageDirectoryEntry& pd_pde = pdp->entries[j]; + if (!pd_pde.present) continue; + if (pd_pde.larger_pages) + { + pages_freed++; + PMM::free_page((void*)pd_pde.get_address()); + continue; + } + PageTable* pd = (PageTable*)pd_pde.get_address(); + for (int k = 0; k < 512; k++) + { + PageDirectoryEntry& pt_pde = pd->entries[k]; + if (!pt_pde.present) continue; + if (pt_pde.larger_pages) + { + pages_freed++; + PMM::free_page((void*)pt_pde.get_address()); + continue; + } + PageTable* pt = (PageTable*)pt_pde.get_address(); + for (int l = 0; l < 512; l++) + { + PageDirectoryEntry& pde = pt->entries[l]; + if (pde.present) continue; + pages_freed++; + PMM::free_page((void*)pde.get_address()); + } + pages_freed++; + PMM::free_page(pt); + } + pages_freed++; + PMM::free_page(pd); + } + pages_freed++; + PMM::free_page(pdp); + } + pages_freed++; + PMM::free_page(m_pml4); + + kdbgln("Reclaimed %ld pages from address space!", pages_freed); +} \ No newline at end of file diff --git a/kernel/src/memory/VMM.cpp b/kernel/src/memory/VMM.cpp index 097de638..e0b81910 100644 --- a/kernel/src/memory/VMM.cpp +++ b/kernel/src/memory/VMM.cpp @@ -7,20 +7,20 @@ #include "misc/utils.h" #include "std/string.h" -// FIXME: There is a lot of duplicate code in this file. This should probably be refactored. - -static PageTable* PML4; +static PageTable* kernel_pml4; +static PageTable* current_pml4; void VMM::init() { - asm volatile("mov %%cr3, %0" : "=r"(PML4)); + asm volatile("mov %%cr3, %0" : "=r"(current_pml4)); + kernel_pml4 = current_pml4; } void VMM::unmap(uint64_t vaddr) { vaddr = Utilities::round_down_to_nearest_page(vaddr); - PageDirectoryEntry* pde = find_pde(PML4, vaddr); + PageDirectoryEntry* pde = find_pde(current_pml4, vaddr); if (!pde) return; // Already unmapped memset(pde, 0, sizeof(PageDirectoryEntry)); @@ -29,7 +29,7 @@ void VMM::unmap(uint64_t vaddr) uint64_t VMM::get_physical(uint64_t vaddr) { - PageDirectoryEntry* pde = find_pde(PML4, Utilities::round_down_to_nearest_page(vaddr)); + PageDirectoryEntry* pde = find_pde(current_pml4, Utilities::round_down_to_nearest_page(vaddr)); if (!pde) return UINT64_MAX; // Not mapped return pde->get_address() | (vaddr % PAGE_SIZE); @@ -37,7 +37,7 @@ uint64_t VMM::get_physical(uint64_t vaddr) uint64_t VMM::get_flags(uint64_t vaddr) { - PageDirectoryEntry* pde = find_pde(PML4, Utilities::round_down_to_nearest_page(vaddr)); + PageDirectoryEntry* pde = find_pde(current_pml4, Utilities::round_down_to_nearest_page(vaddr)); if (!pde) return 0; // Not mapped uint64_t flags = 0; @@ -49,23 +49,23 @@ uint64_t VMM::get_flags(uint64_t vaddr) void VMM::map(uint64_t vaddr, uint64_t paddr, int flags) { vaddr = Utilities::round_down_to_nearest_page(vaddr); - PageDirectoryEntry* pde = find_pde(PML4, vaddr); + PageDirectoryEntry* pde = find_pde(current_pml4, vaddr); bool will_flush_tlb = true; if (!pde) { - pde = create_pde_if_not_exists(PML4, vaddr); + pde = create_pde_if_not_exists(current_pml4, vaddr); will_flush_tlb = false; } else if (pde->larger_pages) { unmap(vaddr); - pde = create_pde_if_not_exists(PML4, vaddr); + pde = create_pde_if_not_exists(current_pml4, vaddr); will_flush_tlb = false; } pde->set_address(Utilities::round_down_to_nearest_page(paddr)); - if (flags & User) propagate_user(PML4, vaddr); - if (flags & ReadWrite) propagate_read_write(PML4, vaddr); + if (flags & User) propagate_user(current_pml4, vaddr); + if (flags & ReadWrite) propagate_read_write(current_pml4, vaddr); if (will_flush_tlb) flush_tlb(vaddr); } @@ -198,4 +198,25 @@ void VMM::decompose_vaddr(uint64_t vaddr, uint64_t& page_index, uint64_t& pt_ind pd_index = vaddr & 0x1ff; vaddr >>= 9; pdp_index = vaddr & 0x1ff; +} + +void VMM::install_kernel_page_directory_into_address_space(AddressSpace& space) +{ + PageTable* space_pml4 = space.get_pml4(); + PageTable* kernel_last_pdp = (PageTable*)kernel_pml4->entries[511].get_address(); + PageTable* kernel_last_pd = (PageTable*)kernel_last_pdp->entries[511].get_address(); + + PageTable* space_last_pdp = (PageTable*)PMM::request_page(); + + PageDirectoryEntry& space_last_pdp_pde = space_pml4->entries[511]; + + space_last_pdp_pde.present = true; + space_last_pdp_pde.read_write = true; + space_last_pdp_pde.set_address((uint64_t)space_last_pdp); + + PageDirectoryEntry& space_last_pd_pde = space_last_pdp->entries[511]; + + space_last_pd_pde.present = true; + space_last_pd_pde.read_write = true; + space_last_pd_pde.set_address((uint64_t)kernel_last_pd); } \ No newline at end of file From ee712432bd70981320ce367b63b31a6d5dea5b0c Mon Sep 17 00:00:00 2001 From: apio Date: Thu, 13 Oct 2022 21:14:39 +0200 Subject: [PATCH 02/17] Some more multiple address space stuff This page-faults. This is because the memory where the ELF should be is all zeroes, which the CPU tries to interpret. --- kernel/include/memory/MemoryManager.h | 2 + kernel/include/memory/VMM.h | 8 +++ kernel/include/thread/Task.h | 3 ++ kernel/src/interrupts/Entry.cpp | 2 + kernel/src/main.cpp | 20 +++----- kernel/src/memory/AddressSpace.cpp | 2 +- kernel/src/memory/MemoryManager.cpp | 5 ++ kernel/src/memory/VMM.cpp | 74 ++++++++++++++++++++++----- kernel/src/sys/elf/ELFLoader.cpp | 9 +++- kernel/src/thread/Scheduler.cpp | 26 +++++++++- 10 files changed, 120 insertions(+), 31 deletions(-) diff --git a/kernel/include/memory/MemoryManager.h b/kernel/include/memory/MemoryManager.h index 8ca074b6..240c9a21 100644 --- a/kernel/include/memory/MemoryManager.h +++ b/kernel/include/memory/MemoryManager.h @@ -29,4 +29,6 @@ namespace MemoryManager void release_page(void* page); void release_pages(void* pages, uint64_t count); + + void protect(void* page, uint64_t count, int flags); } \ No newline at end of file diff --git a/kernel/include/memory/VMM.h b/kernel/include/memory/VMM.h index e4dbce24..15736615 100644 --- a/kernel/include/memory/VMM.h +++ b/kernel/include/memory/VMM.h @@ -12,6 +12,13 @@ namespace VMM { void init(); // Fetch page table from cr3 + void switch_to_user_address_space(AddressSpace& space); + void switch_back_to_kernel_address_space(); + + void apply_address_space(); + + bool is_using_kernel_address_space(); + void map(uint64_t vaddr, uint64_t paddr, int flags); void remap(uint64_t vaddr, int flags); void unmap(uint64_t vaddr); @@ -28,6 +35,7 @@ namespace VMM void decompose_vaddr(uint64_t vaddr, uint64_t& page_index, uint64_t& pt_index, uint64_t& pd_index, uint64_t& pdp_index); + uint64_t recompose_vaddr(uint64_t page_index, uint64_t pt_index, uint64_t pd_index, uint64_t pdp_index); void install_kernel_page_directory_into_address_space(AddressSpace& space); }; \ No newline at end of file diff --git a/kernel/include/thread/Task.h b/kernel/include/thread/Task.h index 77551e5a..20a9579f 100644 --- a/kernel/include/thread/Task.h +++ b/kernel/include/thread/Task.h @@ -1,6 +1,7 @@ #pragma once #include "fs/FileDescriptor.h" #include "interrupts/Context.h" +#include "memory/AddressSpace.h" #include "sys/elf/Image.h" #define TASK_MAX_FDS 8 @@ -43,6 +44,8 @@ struct Task ELFImage* image = nullptr; Descriptor files[TASK_MAX_FDS]; + + AddressSpace address_space; }; void set_context_from_task(Task& task, Context* ctx); diff --git a/kernel/src/interrupts/Entry.cpp b/kernel/src/interrupts/Entry.cpp index d0d9883e..72ef07f3 100644 --- a/kernel/src/interrupts/Entry.cpp +++ b/kernel/src/interrupts/Entry.cpp @@ -51,6 +51,8 @@ extern "C" void common_handler(Context* context) StackTracer tracer(context->rbp); tracer.trace_with_ip(context->rip); + hang(); // FIXME: Remove this when multiple address spaces are working. + Scheduler::task_misbehave(context, -3); } } diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index 0858ab61..459eced6 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -57,16 +57,6 @@ extern "C" void _start() kinfoln("Loaded IDT"); - PIC::remap(); - PIC::enable_master(0b11111100); // enable keyboard and PIT - PIC::enable_slave(0b11111111); - - kinfoln("Prepared PIC"); - - PIT::initialize(1000); // 1000 times per second - - kinfoln("Prepared PIT"); - Scheduler::init(); kinfoln("Prepared scheduler"); @@ -88,9 +78,15 @@ extern "C" void _start() Init::finish_kernel_boot(); - AddressSpace vaspace = AddressSpace::create(); + PIT::initialize(1000); // 1000 times per second - vaspace.destroy(); + kinfoln("Prepared PIT"); + + PIC::remap(); + PIC::enable_master(0b11111100); // enable keyboard and PIT + PIC::enable_slave(0b11111111); + + kinfoln("Prepared PIC"); Interrupts::enable(); // Task switching commences here diff --git a/kernel/src/memory/AddressSpace.cpp b/kernel/src/memory/AddressSpace.cpp index 875ea606..541a73b4 100644 --- a/kernel/src/memory/AddressSpace.cpp +++ b/kernel/src/memory/AddressSpace.cpp @@ -52,7 +52,7 @@ void AddressSpace::destroy() for (int l = 0; l < 512; l++) { PageDirectoryEntry& pde = pt->entries[l]; - if (pde.present) continue; + if (!pde.present) continue; pages_freed++; PMM::free_page((void*)pde.get_address()); } diff --git a/kernel/src/memory/MemoryManager.cpp b/kernel/src/memory/MemoryManager.cpp index 2043f300..b6b4743b 100644 --- a/kernel/src/memory/MemoryManager.cpp +++ b/kernel/src/memory/MemoryManager.cpp @@ -189,4 +189,9 @@ void MemoryManager::release_pages(void* pages, uint64_t count) PMM::free_page((void*)physicalAddress); } KernelHeap::free_virtual_pages((uint64_t)pages, count); +} + +void MemoryManager::protect(void* page, uint64_t count, int flags) +{ + for (uint64_t i = 0; i < count; i++) { VMM::remap((uint64_t)page + (i * PAGE_SIZE), flags); } } \ No newline at end of file diff --git a/kernel/src/memory/VMM.cpp b/kernel/src/memory/VMM.cpp index e0b81910..8f706812 100644 --- a/kernel/src/memory/VMM.cpp +++ b/kernel/src/memory/VMM.cpp @@ -9,6 +9,28 @@ static PageTable* kernel_pml4; static PageTable* current_pml4; +static AddressSpace* user_address_space; + +void VMM::switch_back_to_kernel_address_space() +{ + if (current_pml4 != kernel_pml4) { current_pml4 = kernel_pml4; } +} + +void VMM::switch_to_user_address_space(AddressSpace& space) +{ + user_address_space = &space; + current_pml4 = user_address_space->get_pml4(); +} + +void VMM::apply_address_space() +{ + asm volatile("mov %0, %%cr3" : : "r"(current_pml4)); +} + +bool VMM::is_using_kernel_address_space() +{ + return current_pml4 == kernel_pml4; +} void VMM::init() { @@ -27,6 +49,22 @@ void VMM::unmap(uint64_t vaddr) flush_tlb(vaddr); } +void VMM::remap(uint64_t vaddr, int flags) +{ + vaddr = Utilities::round_down_to_nearest_page(vaddr); + + PageDirectoryEntry* pde = find_pde(current_pml4, vaddr); + if (!pde) return; // Not mapped + + if (flags & User) propagate_user(current_pml4, vaddr); + else + pde->user = false; + if (flags & ReadWrite) propagate_read_write(current_pml4, vaddr); + else + pde->read_write = false; + flush_tlb(vaddr); +} + uint64_t VMM::get_physical(uint64_t vaddr) { PageDirectoryEntry* pde = find_pde(current_pml4, Utilities::round_down_to_nearest_page(vaddr)); @@ -60,24 +98,27 @@ void VMM::map(uint64_t vaddr, uint64_t paddr, int flags) { unmap(vaddr); pde = create_pde_if_not_exists(current_pml4, vaddr); - will_flush_tlb = false; } pde->set_address(Utilities::round_down_to_nearest_page(paddr)); if (flags & User) propagate_user(current_pml4, vaddr); + else + pde->user = false; if (flags & ReadWrite) propagate_read_write(current_pml4, vaddr); + else + pde->read_write = false; if (will_flush_tlb) flush_tlb(vaddr); } PageDirectoryEntry* VMM::find_pde(PageTable* root, uint64_t vaddr) { - uint64_t page_index, pt_index, pd_index, pdp_index; + uint64_t page_index; PageDirectoryEntry* pde; PageTable* pt = root; - decompose_vaddr(vaddr, page_index, pt_index, pd_index, pdp_index); + uint64_t indexes[3]; - uint64_t indexes[3] = {pdp_index, pd_index, pt_index}; + decompose_vaddr(vaddr, page_index, indexes[2], indexes[1], indexes[0]); for (int i = 0; i < 3; i++) // Walk through the page map level 4, page directory pointer, and page directory to find the page table. @@ -96,11 +137,13 @@ PageDirectoryEntry* VMM::find_pde(PageTable* root, uint64_t vaddr) PageDirectoryEntry* VMM::create_pde_if_not_exists(PageTable* root, uint64_t vaddr) { - uint64_t page_index, pt_index, pd_index, pdp_index; + uint64_t page_index; PageDirectoryEntry* pde; PageTable* pt = root; - decompose_vaddr(vaddr, page_index, pt_index, pd_index, pdp_index); + uint64_t indexes[3]; + + decompose_vaddr(vaddr, page_index, indexes[2], indexes[1], indexes[0]); auto pde_create_if_not_present = [&]() { pt = (PageTable*)PMM::request_page(); @@ -110,8 +153,6 @@ PageDirectoryEntry* VMM::create_pde_if_not_exists(PageTable* root, uint64_t vadd pde->present = true; }; - uint64_t indexes[3] = {pdp_index, pd_index, pt_index}; - for (int i = 0; i < 3; i++) { pde = &pt->entries[indexes[i]]; @@ -128,13 +169,13 @@ PageDirectoryEntry* VMM::create_pde_if_not_exists(PageTable* root, uint64_t vadd void VMM::propagate_read_write(PageTable* root, uint64_t vaddr) { - uint64_t page_index, pt_index, pd_index, pdp_index; + uint64_t page_index; PageDirectoryEntry* pde; PageTable* pt = root; - decompose_vaddr(vaddr, page_index, pt_index, pd_index, pdp_index); + uint64_t indexes[3]; - uint64_t indexes[3] = {pdp_index, pd_index, pt_index}; + decompose_vaddr(vaddr, page_index, indexes[2], indexes[1], indexes[0]); for (int i = 0; i < 3; i++) { @@ -156,13 +197,13 @@ void VMM::propagate_read_write(PageTable* root, uint64_t vaddr) void VMM::propagate_user(PageTable* root, uint64_t vaddr) { - uint64_t page_index, pt_index, pd_index, pdp_index; + uint64_t page_index; PageDirectoryEntry* pde; PageTable* pt = root; - decompose_vaddr(vaddr, page_index, pt_index, pd_index, pdp_index); + uint64_t indexes[3]; - uint64_t indexes[3] = {pdp_index, pd_index, pt_index}; + decompose_vaddr(vaddr, page_index, indexes[2], indexes[1], indexes[0]); for (int i = 0; i < 3; i++) { @@ -200,6 +241,11 @@ void VMM::decompose_vaddr(uint64_t vaddr, uint64_t& page_index, uint64_t& pt_ind pdp_index = vaddr & 0x1ff; } +uint64_t VMM::recompose_vaddr(uint64_t page_index, uint64_t pt_index, uint64_t pd_index, uint64_t pdp_index) +{ + return pdp_index << 39 | pd_index << 30 | pt_index << 21 | page_index << 12; +} + void VMM::install_kernel_page_directory_into_address_space(AddressSpace& space) { PageTable* space_pml4 = space.get_pml4(); diff --git a/kernel/src/sys/elf/ELFLoader.cpp b/kernel/src/sys/elf/ELFLoader.cpp index 4ca64147..03f1ae7f 100644 --- a/kernel/src/sys/elf/ELFLoader.cpp +++ b/kernel/src/sys/elf/ELFLoader.cpp @@ -8,6 +8,7 @@ #include "log/Log.h" #include "memory/Memory.h" #include "memory/MemoryManager.h" +#include "memory/VMM.h" #include "misc/utils.h" #include "std/stdlib.h" #include "std/string.h" @@ -85,13 +86,17 @@ ELFImage* ELFLoader::load_elf_from_vfs(VFS::Node* node) kdbgln("Loading loadable segment at address %lx, file size %ld, mem size %ld, permissions %s", phdr.p_vaddr, phdr.p_filesz, phdr.p_memsz, format_permissions(phdr.p_flags)); ASSERT(phdr.p_vaddr); + uint64_t pages = Utilities::get_blocks_from_size(PAGE_SIZE, (phdr.p_vaddr % PAGE_SIZE) + phdr.p_memsz); void* buffer = (void*)((uint64_t)MemoryManager::get_pages_at( - Utilities::round_down_to_nearest_page(phdr.p_vaddr), pages, - phdr.p_flags & 2 ? MAP_READ_WRITE | MAP_USER : MAP_USER) + + Utilities::round_down_to_nearest_page(phdr.p_vaddr), pages, MAP_READ_WRITE) + (phdr.p_vaddr % PAGE_SIZE)); + VFS::read(node, phdr.p_offset, phdr.p_filesz, (char*)buffer); memset((void*)((uint64_t)buffer + phdr.p_filesz), 0, phdr.p_memsz - phdr.p_filesz); + + MemoryManager::protect(buffer, pages, phdr.p_flags & 2 ? MAP_READ_WRITE | MAP_USER : MAP_USER); + image = (ELFImage*)krealloc(image, (sizeof(ELFImage) - sizeof(ELFSection)) + (image->section_count + 1) * sizeof(ELFSection)); ELFSection& section = image->sections[image->section_count]; diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index d0fad993..3eb48255 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -127,6 +127,8 @@ void Scheduler::load_user_task(const char* filename) ASSERT(new_task); memset(&new_task->regs, 0, sizeof(Context)); new_task->id = free_tid++; + new_task->address_space = AddressSpace::create(); + VMM::switch_to_user_address_space(new_task->address_space); ELFImage* image = ELFLoader::load_elf_from_filesystem( filename); // FIXME: TOCTOU? Right now, impossible, since interrupts are disabled and SMP is not a thing. But in // the future, it might be possible. @@ -153,6 +155,7 @@ void Scheduler::load_user_task(const char* filename) task_num++; kinfoln("Adding user task: loaded at %lx, tid %ld, stack at %lx, total tasks: %ld", new_task->regs.rip, new_task->id, new_task->regs.rsp, task_num); + VMM::switch_back_to_kernel_address_space(); Interrupts::pop(); } @@ -179,12 +182,21 @@ void Scheduler::reap_task(Task* task) task_num--; Task* exiting_task = task; ASSERT(task->id != 0); // WHY IN THE WORLD WOULD WE BE REAPING THE IDLE TASK? + if (exiting_task->is_user_task()) { VMM::switch_to_user_address_space(exiting_task->address_space); } kinfoln("reaping task %ld, exited with code %ld", exiting_task->id, exiting_task->exit_status); if (exiting_task->allocated_stack) MemoryManager::release_pages((void*)exiting_task->allocated_stack, TASK_PAGES_IN_STACK); if (exiting_task->image) // FIXME: Also free pages the task has mmap-ed but not munmap-ed. { - ELFLoader::release_elf_image(exiting_task->image); + // ELFLoader::release_elf_image(exiting_task->image); + kfree(exiting_task->image); + } + if (exiting_task->is_user_task()) + { + VMM::switch_back_to_kernel_address_space(); + Interrupts::push_and_enable(); + exiting_task->address_space.destroy(); + Interrupts::pop(); } for (int i = 0; i < TASK_MAX_FDS; i++) { exiting_task->files[i].close(); } delete exiting_task; @@ -313,7 +325,17 @@ void Scheduler::task_yield(Context* context) { task_save_floating(*original_task); } - if (sched_current_task->is_user_task()) { task_restore_floating(*sched_current_task); } + if (sched_current_task->is_user_task()) + { + VMM::switch_to_user_address_space(sched_current_task->address_space); + VMM::apply_address_space(); + task_restore_floating(*sched_current_task); + } + else if (!was_idle && original_task->is_user_task() && !sched_current_task->is_user_task()) + { + VMM::switch_back_to_kernel_address_space(); + VMM::apply_address_space(); + } } sched_current_task->task_time = 20; set_context_from_task(*sched_current_task, context); From 83982a24e218fc857c817cd7006e3e0b87470a02 Mon Sep 17 00:00:00 2001 From: apio Date: Thu, 13 Oct 2022 21:21:02 +0200 Subject: [PATCH 03/17] add a comment --- kernel/src/sys/elf/ELFLoader.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/src/sys/elf/ELFLoader.cpp b/kernel/src/sys/elf/ELFLoader.cpp index 03f1ae7f..91d6d554 100644 --- a/kernel/src/sys/elf/ELFLoader.cpp +++ b/kernel/src/sys/elf/ELFLoader.cpp @@ -67,7 +67,9 @@ ELFImage* ELFLoader::load_elf_from_vfs(VFS::Node* node) { Elf64_Ehdr elf_ehdr; ASSERT(VFS::read(node, 0, sizeof(elf_ehdr), (char*)&elf_ehdr) >= 0); - ASSERT(strncmp((const char*)elf_ehdr.e_ident, ELFMAG, SELFMAG) == 0); + ASSERT(strncmp((const char*)elf_ehdr.e_ident, ELFMAG, SELFMAG) == + 0); // If you haven't checked the ELF executable with check_elf_image() first, then an assertion fail is your + // fault =D ASSERT(elf_ehdr.e_ident[EI_CLASS] == ELFCLASS64); ASSERT(elf_ehdr.e_ident[EI_DATA] == ELFDATA2LSB); ASSERT(elf_ehdr.e_type == ET_EXEC); From 24272c57ef9f2439bc21f4fb4d51dd1099e035d4 Mon Sep 17 00:00:00 2001 From: apio Date: Thu, 13 Oct 2022 21:55:51 +0200 Subject: [PATCH 04/17] Almost there! --- kernel/include/memory/VMM.h | 4 ++++ kernel/src/main.cpp | 8 ++++---- kernel/src/memory/VMM.cpp | 21 +++++++++++++++++++++ kernel/src/sys/Syscall.cpp | 3 +++ kernel/src/sys/elf/ELFLoader.cpp | 6 ++++++ kernel/src/thread/Scheduler.cpp | 9 ++++++++- 6 files changed, 46 insertions(+), 5 deletions(-) diff --git a/kernel/include/memory/VMM.h b/kernel/include/memory/VMM.h index 15736615..ad736def 100644 --- a/kernel/include/memory/VMM.h +++ b/kernel/include/memory/VMM.h @@ -13,8 +13,12 @@ namespace VMM void init(); // Fetch page table from cr3 void switch_to_user_address_space(AddressSpace& space); + void switch_to_previous_user_address_space(); void switch_back_to_kernel_address_space(); + void enter_syscall_context(); + void exit_syscall_context(); + void apply_address_space(); bool is_using_kernel_address_space(); diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index 459eced6..1d1fa288 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -57,6 +57,10 @@ extern "C" void _start() kinfoln("Loaded IDT"); + PIT::initialize(1000); // 1000 times per second + + kinfoln("Prepared PIT"); + Scheduler::init(); kinfoln("Prepared scheduler"); @@ -78,10 +82,6 @@ extern "C" void _start() Init::finish_kernel_boot(); - PIT::initialize(1000); // 1000 times per second - - kinfoln("Prepared PIT"); - PIC::remap(); PIC::enable_master(0b11111100); // enable keyboard and PIT PIC::enable_slave(0b11111111); diff --git a/kernel/src/memory/VMM.cpp b/kernel/src/memory/VMM.cpp index 8f706812..05c3a7ce 100644 --- a/kernel/src/memory/VMM.cpp +++ b/kernel/src/memory/VMM.cpp @@ -22,6 +22,27 @@ void VMM::switch_to_user_address_space(AddressSpace& space) current_pml4 = user_address_space->get_pml4(); } +void VMM::switch_to_previous_user_address_space() +{ + current_pml4 = user_address_space->get_pml4(); +} + +void VMM::enter_syscall_context() +{ + if (current_pml4 != kernel_pml4) + { + current_pml4 = kernel_pml4; + apply_address_space(); + switch_to_previous_user_address_space(); + } +} + +void VMM::exit_syscall_context() +{ + if (current_pml4 != user_address_space->get_pml4()) { switch_to_previous_user_address_space(); } + apply_address_space(); +} + void VMM::apply_address_space() { asm volatile("mov %0, %%cr3" : : "r"(current_pml4)); diff --git a/kernel/src/sys/Syscall.cpp b/kernel/src/sys/Syscall.cpp index 8a3434b9..f47dc227 100644 --- a/kernel/src/sys/Syscall.cpp +++ b/kernel/src/sys/Syscall.cpp @@ -1,11 +1,13 @@ #include "sys/Syscall.h" #include "errno.h" #include "io/Serial.h" +#include "memory/VMM.h" #include "thread/Scheduler.h" void Syscall::entry(Context* context) { asm volatile("cli"); + VMM::enter_syscall_context(); switch (context->rax) { case SYS_exit: sys_exit(context, (int)context->rdi); break; @@ -24,4 +26,5 @@ void Syscall::entry(Context* context) case SYS_exec: sys_exec(context, (const char*)context->rdi); break; default: context->rax = -ENOSYS; break; } + VMM::exit_syscall_context(); } \ No newline at end of file diff --git a/kernel/src/sys/elf/ELFLoader.cpp b/kernel/src/sys/elf/ELFLoader.cpp index 91d6d554..a9d4bb2e 100644 --- a/kernel/src/sys/elf/ELFLoader.cpp +++ b/kernel/src/sys/elf/ELFLoader.cpp @@ -94,9 +94,15 @@ ELFImage* ELFLoader::load_elf_from_vfs(VFS::Node* node) Utilities::round_down_to_nearest_page(phdr.p_vaddr), pages, MAP_READ_WRITE) + (phdr.p_vaddr % PAGE_SIZE)); + VMM::apply_address_space(); + VFS::read(node, phdr.p_offset, phdr.p_filesz, (char*)buffer); memset((void*)((uint64_t)buffer + phdr.p_filesz), 0, phdr.p_memsz - phdr.p_filesz); + VMM::switch_back_to_kernel_address_space(); + VMM::apply_address_space(); + VMM::switch_to_previous_user_address_space(); + MemoryManager::protect(buffer, pages, phdr.p_flags & 2 ? MAP_READ_WRITE | MAP_USER : MAP_USER); image = (ELFImage*)krealloc(image, (sizeof(ELFImage) - sizeof(ELFSection)) + diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index 3eb48255..9e4855cd 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -55,6 +55,7 @@ void Scheduler::init() // the other registers will be saved next task switch frequency = 1000 / PIT::frequency(); + kdbgln("frequency: %ld", frequency); } void Scheduler::add_kernel_task(void (*task)(void)) @@ -182,7 +183,12 @@ void Scheduler::reap_task(Task* task) task_num--; Task* exiting_task = task; ASSERT(task->id != 0); // WHY IN THE WORLD WOULD WE BE REAPING THE IDLE TASK? - if (exiting_task->is_user_task()) { VMM::switch_to_user_address_space(exiting_task->address_space); } + if (exiting_task->is_user_task()) + { + VMM::switch_back_to_kernel_address_space(); + VMM::apply_address_space(); + VMM::switch_to_user_address_space(exiting_task->address_space); + } kinfoln("reaping task %ld, exited with code %ld", exiting_task->id, exiting_task->exit_status); if (exiting_task->allocated_stack) MemoryManager::release_pages((void*)exiting_task->allocated_stack, TASK_PAGES_IN_STACK); @@ -194,6 +200,7 @@ void Scheduler::reap_task(Task* task) if (exiting_task->is_user_task()) { VMM::switch_back_to_kernel_address_space(); + VMM::apply_address_space(); Interrupts::push_and_enable(); exiting_task->address_space.destroy(); Interrupts::pop(); From 5d41b4b113c7faa98ba66c56052892177e131bb0 Mon Sep 17 00:00:00 2001 From: apio Date: Thu, 13 Oct 2022 22:13:04 +0200 Subject: [PATCH 05/17] Almost there... exec() is not working yet. But the rest are!! --- kernel/include/sys/Syscall.h | 2 ++ kernel/src/sys/Syscall.cpp | 8 ++++++++ kernel/src/sys/exec.cpp | 32 +++++++++++++++++++++++++++----- kernel/src/sys/stdio.cpp | 21 +++++++++++++++++---- 4 files changed, 54 insertions(+), 9 deletions(-) diff --git a/kernel/include/sys/Syscall.h b/kernel/include/sys/Syscall.h index 9d9a1ce8..a5928008 100644 --- a/kernel/include/sys/Syscall.h +++ b/kernel/include/sys/Syscall.h @@ -20,6 +20,8 @@ namespace Syscall { void entry(Context* context); + + char* strdup_from_user(const char* user_string); } void sys_exit(Context* context, int status); diff --git a/kernel/src/sys/Syscall.cpp b/kernel/src/sys/Syscall.cpp index f47dc227..df373bee 100644 --- a/kernel/src/sys/Syscall.cpp +++ b/kernel/src/sys/Syscall.cpp @@ -2,6 +2,7 @@ #include "errno.h" #include "io/Serial.h" #include "memory/VMM.h" +#include "std/string.h" #include "thread/Scheduler.h" void Syscall::entry(Context* context) @@ -27,4 +28,11 @@ void Syscall::entry(Context* context) default: context->rax = -ENOSYS; break; } VMM::exit_syscall_context(); +} + +char* Syscall::strdup_from_user(const char* user_string) +{ + uint64_t phys = VMM::get_physical((uint64_t)user_string); + if (phys == (uint64_t)-1) { return nullptr; } + return strdup((const char*)phys); } \ No newline at end of file diff --git a/kernel/src/sys/exec.cpp b/kernel/src/sys/exec.cpp index 666b287e..db19fbce 100644 --- a/kernel/src/sys/exec.cpp +++ b/kernel/src/sys/exec.cpp @@ -5,30 +5,35 @@ #include "interrupts/Interrupts.h" #include "memory/MemoryManager.h" #include "memory/PMM.h" +#include "memory/VMM.h" #include "std/stdlib.h" #include "std/string.h" +#include "sys/Syscall.h" #include "sys/elf/ELFLoader.h" #include "thread/Scheduler.h" void sys_exec(Context* context, const char* pathname) { - if (!pathname) + char* kpathname = Syscall::strdup_from_user(pathname); + if (!kpathname) { context->rax = -EFAULT; return; } - kinfoln("exec(): executing %s", pathname); + kinfoln("exec(): executing %s", kpathname); - VFS::Node* program = VFS::resolve_path(pathname); + VFS::Node* program = VFS::resolve_path(kpathname); if (!program) { + kfree(kpathname); context->rax = -ENOENT; return; } if (program->type == VFS_DIRECTORY) { + kfree(kpathname); context->rax = -EISDIR; return; } @@ -36,6 +41,7 @@ void sys_exec(Context* context, const char* pathname) long memusage; if ((memusage = ELFLoader::check_elf_image(program)) < 0) { + kfree(kpathname); context->rax = -ENOEXEC; return; } @@ -43,12 +49,16 @@ void sys_exec(Context* context, const char* pathname) uint64_t allocated_stack = (uint64_t)MemoryManager::get_pages(TASK_PAGES_IN_STACK, MAP_READ_WRITE | MAP_USER); if (!allocated_stack) { + kfree(kpathname); context->rax = -ENOMEM; return; } + uint64_t allocated_stack_phys = VMM::get_physical(allocated_stack); + if ((uint64_t)memusage > PMM::get_free()) { + kfree(kpathname); MemoryManager::release_pages((void*)allocated_stack, TASK_PAGES_IN_STACK); context->rax = -ENOMEM; return; @@ -64,17 +74,29 @@ void sys_exec(Context* context, const char* pathname) ELFLoader::release_elf_image(Scheduler::current_task()->image); + MemoryManager::release_pages((void*)task->allocated_stack, TASK_PAGES_IN_STACK); + + task->address_space.destroy(); + task->address_space = AddressSpace::create(); + + VMM::switch_to_user_address_space(task->address_space); + ELFImage* image = ELFLoader::load_elf_from_vfs(program); ASSERT(image); // If check_elf_image succeeded, load_elf_from_vfs MUST succeed, unless something has gone terribly // wrong. - MemoryManager::release_pages((void*)task->allocated_stack, TASK_PAGES_IN_STACK); - task->allocated_stack = allocated_stack; + for (uint64_t i = 0; i < TASK_PAGES_IN_STACK; i++) + { + VMM::map(allocated_stack + (i * PAGE_SIZE), allocated_stack_phys + (i * PAGE_SIZE), MAP_READ_WRITE | MAP_USER); + } + Scheduler::reset_task(task, image); set_context_from_task(*task, context); + kfree(kpathname); + return; } \ No newline at end of file diff --git a/kernel/src/sys/stdio.cpp b/kernel/src/sys/stdio.cpp index 8b6f1147..522aa3b4 100644 --- a/kernel/src/sys/stdio.cpp +++ b/kernel/src/sys/stdio.cpp @@ -4,7 +4,10 @@ #include "interrupts/Context.h" #include "io/Serial.h" #include "log/Log.h" +#include "memory/VMM.h" #include "render/TextRenderer.h" +#include "std/stdlib.h" +#include "sys/Syscall.h" #include "thread/Scheduler.h" #include "thread/Task.h" @@ -79,7 +82,7 @@ void sys_write(Context* context, int fd, size_t size, const char* addr) context->rax = -EBADF; return; } - ssize_t result = current_task->files[fd].write(size, addr); + ssize_t result = current_task->files[fd].write(size, (const char*)VMM::get_physical((uint64_t)addr)); context->rax = (size_t)result; return; } @@ -99,9 +102,17 @@ void sys_open(Context* context, const char* filename, int flags) return; } - VFS::Node* node = VFS::resolve_path(filename); + char* kernel_filename = Syscall::strdup_from_user(filename); + if (!kernel_filename) + { + context->rax = -EFAULT; + return; + } + + VFS::Node* node = VFS::resolve_path(kernel_filename); if (!node) { + kfree(kernel_filename); context->rax = -ENOENT; return; } @@ -110,16 +121,18 @@ void sys_open(Context* context, const char* filename, int flags) bool can_write = (flags & OPEN_WRITE) > 0; if (!can_read && !can_write) { + kfree(kernel_filename); context->rax = -EINVAL; return; } - kdbgln("open(): opening %s %s, allocated file descriptor %d", filename, + kdbgln("open(): opening %s %s, allocated file descriptor %d", kernel_filename, (can_read && can_write) ? "rw" : can_read ? "r-" : "-w", fd); + kfree(kernel_filename); current_task->files[fd].open(node, can_read, can_write); context->rax = fd; return; @@ -143,7 +156,7 @@ void sys_read(Context* context, int fd, size_t size, char* buffer) context->rax = -EBADF; return; } - ssize_t result = current_task->files[fd].read(size, buffer); + ssize_t result = current_task->files[fd].read(size, (char*)VMM::get_physical((uint64_t)buffer)); context->rax = (size_t)result; return; } From 0c7c24993554bb4358ac54fb9db292bcdb5edd38 Mon Sep 17 00:00:00 2001 From: apio Date: Thu, 13 Oct 2022 22:20:24 +0200 Subject: [PATCH 06/17] exec is still doing some weird stuff, totally corrupting the page tables --- kernel/src/sys/exec.cpp | 6 +++--- kernel/src/thread/Scheduler.cpp | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/kernel/src/sys/exec.cpp b/kernel/src/sys/exec.cpp index db19fbce..6eeeb6e3 100644 --- a/kernel/src/sys/exec.cpp +++ b/kernel/src/sys/exec.cpp @@ -72,14 +72,14 @@ void sys_exec(Context* context, const char* pathname) // At this point, pretty much nothing can fail. - ELFLoader::release_elf_image(Scheduler::current_task()->image); - - MemoryManager::release_pages((void*)task->allocated_stack, TASK_PAGES_IN_STACK); + VMM::switch_back_to_kernel_address_space(); task->address_space.destroy(); task->address_space = AddressSpace::create(); VMM::switch_to_user_address_space(task->address_space); + VMM::apply_address_space(); + VMM::enter_syscall_context(); ELFImage* image = ELFLoader::load_elf_from_vfs(program); ASSERT(image); // If check_elf_image succeeded, load_elf_from_vfs MUST succeed, unless something has gone terribly diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index 9e4855cd..ee6fb844 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -55,7 +55,6 @@ void Scheduler::init() // the other registers will be saved next task switch frequency = 1000 / PIT::frequency(); - kdbgln("frequency: %ld", frequency); } void Scheduler::add_kernel_task(void (*task)(void)) From 26211bd49f3161e3380c5d4ad14ae86c74b7d93b Mon Sep 17 00:00:00 2001 From: apio Date: Fri, 14 Oct 2022 16:46:00 +0200 Subject: [PATCH 07/17] It (almost) works now The only thing doing weird stuff is exec(), so that's commented out and throws ENOSYS right now. But we have two user tasks running in parallel, isolated from each other! --- apps/src/sym.c | 3 ++ kernel/include/memory/AddressSpace.h | 2 + kernel/src/main.cpp | 1 + kernel/src/memory/AddressSpace.cpp | 58 ++++++++++++++++++++++++++++ kernel/src/misc/reboot.cpp | 6 +++ kernel/src/sys/exec.cpp | 19 ++++----- 6 files changed, 80 insertions(+), 9 deletions(-) diff --git a/apps/src/sym.c b/apps/src/sym.c index d5ed3927..f170c691 100644 --- a/apps/src/sym.c +++ b/apps/src/sym.c @@ -1,8 +1,11 @@ #include #include +#include int main() { + sleep(6); + FILE* syms = fopen("/sys/moon.sym", "r"); if (!syms) { diff --git a/kernel/include/memory/AddressSpace.h b/kernel/include/memory/AddressSpace.h index 082ec607..a2af46fe 100644 --- a/kernel/include/memory/AddressSpace.h +++ b/kernel/include/memory/AddressSpace.h @@ -7,6 +7,8 @@ struct AddressSpace void destroy(); + void reset(); + PageTable* get_pml4() { return m_pml4; diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index 1d1fa288..b066d9bc 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -74,6 +74,7 @@ extern "C" void _start() }); Scheduler::load_user_task("/bin/init"); + Scheduler::load_user_task("/bin/sym"); kinfoln("Prepared scheduler tasks"); diff --git a/kernel/src/memory/AddressSpace.cpp b/kernel/src/memory/AddressSpace.cpp index 541a73b4..714c1b77 100644 --- a/kernel/src/memory/AddressSpace.cpp +++ b/kernel/src/memory/AddressSpace.cpp @@ -68,5 +68,63 @@ void AddressSpace::destroy() pages_freed++; PMM::free_page(m_pml4); + kdbgln("Reclaimed %ld pages from address space!", pages_freed); +} + +void AddressSpace::reset() +{ + uint64_t pages_freed = 0; + for (int i = 0; i < 512; i++) + { + PageDirectoryEntry& pdp_pde = m_pml4->entries[i]; + if (!pdp_pde.present) continue; + if (pdp_pde.larger_pages) + { + pages_freed++; + PMM::free_page((void*)pdp_pde.get_address()); + continue; + } + PageTable* pdp = (PageTable*)pdp_pde.get_address(); + for (int j = 0; j < 511; j++) // skip the last page directory, it's the kernel one + { + PageDirectoryEntry& pd_pde = pdp->entries[j]; + if (!pd_pde.present) continue; + if (pd_pde.larger_pages) + { + pages_freed++; + PMM::free_page((void*)pd_pde.get_address()); + continue; + } + PageTable* pd = (PageTable*)pd_pde.get_address(); + for (int k = 0; k < 512; k++) + { + PageDirectoryEntry& pt_pde = pd->entries[k]; + if (!pt_pde.present) continue; + if (pt_pde.larger_pages) + { + pages_freed++; + PMM::free_page((void*)pt_pde.get_address()); + continue; + } + PageTable* pt = (PageTable*)pt_pde.get_address(); + for (int l = 0; l < 512; l++) + { + PageDirectoryEntry& pde = pt->entries[l]; + if (!pde.present) continue; + pages_freed++; + PMM::free_page((void*)pde.get_address()); + } + pages_freed++; + PMM::free_page(pt); + } + pages_freed++; + PMM::free_page(pd); + } + pages_freed++; + PMM::free_page(pdp); + } + + VMM::install_kernel_page_directory_into_address_space(*this); + kdbgln("Reclaimed %ld pages from address space!", pages_freed); } \ No newline at end of file diff --git a/kernel/src/misc/reboot.cpp b/kernel/src/misc/reboot.cpp index 30800dda..8f134556 100644 --- a/kernel/src/misc/reboot.cpp +++ b/kernel/src/misc/reboot.cpp @@ -8,6 +8,7 @@ #include "interrupts/Interrupts.h" #include "io/IO.h" #include "log/Log.h" +#include "memory/VMM.h" #include "misc/hang.h" #include "std/string.h" @@ -85,6 +86,11 @@ static void try_idt_triple_fault() [[noreturn]] void reboot() { Interrupts::disable(); + if (!VMM::is_using_kernel_address_space()) + { + VMM::switch_back_to_kernel_address_space(); + VMM::apply_address_space(); + } kinfoln("Attempting reboot using ACPI"); try_acpi_reboot(); kinfoln("Attempting reboot using keyboard RESET pulsing"); diff --git a/kernel/src/sys/exec.cpp b/kernel/src/sys/exec.cpp index 6eeeb6e3..c160b804 100644 --- a/kernel/src/sys/exec.cpp +++ b/kernel/src/sys/exec.cpp @@ -12,9 +12,12 @@ #include "sys/elf/ELFLoader.h" #include "thread/Scheduler.h" -void sys_exec(Context* context, const char* pathname) +void sys_exec(Context* context, const char*) { - char* kpathname = Syscall::strdup_from_user(pathname); + context->rax = -ENOSYS; // FIXME: Make exec() work under separate address spaces. + return; + + /*char* kpathname = Syscall::strdup_from_user(pathname); if (!kpathname) { context->rax = -EFAULT; @@ -73,13 +76,11 @@ void sys_exec(Context* context, const char* pathname) // At this point, pretty much nothing can fail. VMM::switch_back_to_kernel_address_space(); - - task->address_space.destroy(); - task->address_space = AddressSpace::create(); - - VMM::switch_to_user_address_space(task->address_space); VMM::apply_address_space(); - VMM::enter_syscall_context(); + + task->address_space.reset(); + + // VMM::switch_to_user_address_space(task->address_space); ELFImage* image = ELFLoader::load_elf_from_vfs(program); ASSERT(image); // If check_elf_image succeeded, load_elf_from_vfs MUST succeed, unless something has gone terribly @@ -98,5 +99,5 @@ void sys_exec(Context* context, const char* pathname) kfree(kpathname); - return; + return;*/ } \ No newline at end of file From 9b3c7816a3d9aef6148af4b126b71f96d3a3f1ca Mon Sep 17 00:00:00 2001 From: apio Date: Thu, 13 Oct 2022 21:23:51 +0200 Subject: [PATCH 08/17] Scheduler: pop the interrupt state when returning early from load_user_task() --- kernel/src/thread/Scheduler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index ee6fb844..20bbf9b9 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -121,6 +121,7 @@ void Scheduler::load_user_task(const char* filename) if (ELFLoader::check_elf_image_from_filesystem(filename) < 0) { kerrorln("Failed to load %s from initrd", filename); + Interrupts::pop(); return; } Task* new_task = new Task; From e21b608af4690aeee2482eb6a23c0709e0df8fa1 Mon Sep 17 00:00:00 2001 From: apio Date: Fri, 14 Oct 2022 17:21:16 +0200 Subject: [PATCH 09/17] Utilities: Start moving utilities into specific headers in a utils/ subdirectory --- kernel/include/misc/utils.h | 7 ---- kernel/include/utils/Registers.h | 52 ++++++++++++++++++++++++++++ kernel/src/interrupts/Interrupts.cpp | 4 +-- kernel/src/main.asm | 6 ++++ kernel/src/memory/VMM.cpp | 4 +-- kernel/src/thread/Scheduler.cpp | 3 +- 6 files changed, 64 insertions(+), 12 deletions(-) create mode 100644 kernel/include/utils/Registers.h diff --git a/kernel/include/misc/utils.h b/kernel/include/misc/utils.h index 7bb36f17..c7660111 100644 --- a/kernel/include/misc/utils.h +++ b/kernel/include/misc/utils.h @@ -5,8 +5,6 @@ #define PAGE_SIZE 4096 #endif -extern "C" uint64_t asm_get_rflags(); - namespace Utilities { inline uint64_t get_blocks_from_size(uint64_t blocksize, uint64_t size) @@ -14,11 +12,6 @@ namespace Utilities return (size + (blocksize - 1)) / blocksize; } - inline uint64_t get_rflags() - { - return asm_get_rflags(); - } - inline uint64_t get_top_of_stack(uint64_t bottom, uint64_t stack_pages) { return bottom + (stack_pages * PAGE_SIZE) - sizeof(uintptr_t); diff --git a/kernel/include/utils/Registers.h b/kernel/include/utils/Registers.h new file mode 100644 index 00000000..944a0ea0 --- /dev/null +++ b/kernel/include/utils/Registers.h @@ -0,0 +1,52 @@ +#pragma once + +#include + +extern "C" uintptr_t asm_get_rflags(); +extern "C" void asm_set_rflags(uintptr_t); + +inline uintptr_t read_rflags() +{ + return asm_get_rflags(); +} + +inline void write_rflags(uintptr_t value) +{ + asm_set_rflags(value); +} + +inline uintptr_t read_cr0() +{ + uintptr_t value; + asm volatile("mov %%cr0, %0" : "=r"(value)); + return value; +} + +inline uintptr_t read_cr3() +{ + uintptr_t value; + asm volatile("mov %%cr3, %0" : "=r"(value)); + return value; +} + +inline uintptr_t read_cr4() +{ + uintptr_t value; + asm volatile("mov %%cr4, %0" : "=r"(value)); + return value; +} + +template inline void write_cr0(T value) +{ + asm volatile("mov %0, %%cr0" : : "r"(value)); +} + +template inline void write_cr3(T value) +{ + asm volatile("mov %0, %%cr3" : : "r"(value)); +} + +template inline void write_cr4(T value) +{ + asm volatile("mov %0, %%cr4" : : "r"(value)); +} \ No newline at end of file diff --git a/kernel/src/interrupts/Interrupts.cpp b/kernel/src/interrupts/Interrupts.cpp index 06d40db7..b57420d8 100644 --- a/kernel/src/interrupts/Interrupts.cpp +++ b/kernel/src/interrupts/Interrupts.cpp @@ -1,6 +1,6 @@ #include "interrupts/Interrupts.h" -#include "misc/utils.h" #include "trace/StackTracer.h" +#include "utils/Registers.h" void Interrupts::disable() { @@ -29,7 +29,7 @@ void Interrupts::return_from_handler(Context* context) bool Interrupts::are_enabled() { - return (Utilities::get_rflags() & 0x200) > 0; + return (read_rflags() & 0x200) > 0; } static bool saved_interrupt_state; diff --git a/kernel/src/main.asm b/kernel/src/main.asm index 070821d7..4593a076 100644 --- a/kernel/src/main.asm +++ b/kernel/src/main.asm @@ -31,4 +31,10 @@ global asm_get_rflags asm_get_rflags: pushfq pop rax + ret + +global asm_set_rflags +asm_set_rflags: + push rdi + popfq ret \ No newline at end of file diff --git a/kernel/src/memory/VMM.cpp b/kernel/src/memory/VMM.cpp index 05c3a7ce..e481088d 100644 --- a/kernel/src/memory/VMM.cpp +++ b/kernel/src/memory/VMM.cpp @@ -6,6 +6,7 @@ #include "memory/PMM.h" #include "misc/utils.h" #include "std/string.h" +#include "utils/Registers.h" static PageTable* kernel_pml4; static PageTable* current_pml4; @@ -55,8 +56,7 @@ bool VMM::is_using_kernel_address_space() void VMM::init() { - asm volatile("mov %%cr3, %0" : "=r"(current_pml4)); - kernel_pml4 = current_pml4; + kernel_pml4 = (PageTable*)read_cr3(); } void VMM::unmap(uint64_t vaddr) diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index 20bbf9b9..948c8d1b 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -14,6 +14,7 @@ #include "sys/elf/ELFLoader.h" #include "thread/PIT.h" #include "thread/Task.h" +#include "utils/Registers.h" static uint64_t task_num = 0; @@ -70,7 +71,7 @@ void Scheduler::add_kernel_task(void (*task)(void)) new_task->regs.cs = 0x08; new_task->regs.ss = 0x10; new_task->regs.ds = 0x10; - new_task->regs.rflags = Utilities::get_rflags() | 0x200; // enable interrupts + new_task->regs.rflags = read_rflags() | 0x200; // enable interrupts new_task->task_sleep = 0; new_task->task_time = 0; new_task->cpu_time = 0; From 5abd8814e38cdd6d45dd92762efac56767ebe2b3 Mon Sep 17 00:00:00 2001 From: apio Date: Fri, 14 Oct 2022 17:26:47 +0200 Subject: [PATCH 10/17] Kernel: Continue moving utilities to a separate subdirectory --- kernel/include/misc/utils.h | 20 -------------------- kernel/include/utils/Addresses.h | 23 +++++++++++++++++++++++ kernel/src/memory/VMM.cpp | 11 ++++++----- kernel/src/sys/elf/ELFLoader.cpp | 7 ++++--- kernel/src/thread/Scheduler.cpp | 11 ++++++----- 5 files changed, 39 insertions(+), 33 deletions(-) create mode 100644 kernel/include/utils/Addresses.h diff --git a/kernel/include/misc/utils.h b/kernel/include/misc/utils.h index c7660111..cc8974e5 100644 --- a/kernel/include/misc/utils.h +++ b/kernel/include/misc/utils.h @@ -1,30 +1,10 @@ #pragma once #include -#ifndef PAGE_SIZE -#define PAGE_SIZE 4096 -#endif - namespace Utilities { inline uint64_t get_blocks_from_size(uint64_t blocksize, uint64_t size) { return (size + (blocksize - 1)) / blocksize; } - - inline uint64_t get_top_of_stack(uint64_t bottom, uint64_t stack_pages) - { - return bottom + (stack_pages * PAGE_SIZE) - sizeof(uintptr_t); - } - - inline uint64_t round_down_to_nearest_page(uint64_t addr) - { - return addr - (addr % PAGE_SIZE); - } - - inline uint64_t round_up_to_nearest_page(uint64_t addr) - { - if (addr % PAGE_SIZE) return addr + (PAGE_SIZE - (addr % PAGE_SIZE)); - return addr; - } } \ No newline at end of file diff --git a/kernel/include/utils/Addresses.h b/kernel/include/utils/Addresses.h new file mode 100644 index 00000000..e006d7a0 --- /dev/null +++ b/kernel/include/utils/Addresses.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif + +inline uintptr_t get_top_of_stack(uintptr_t bottom, uintptr_t stack_pages) +{ + return bottom + (stack_pages * PAGE_SIZE) - sizeof(uintptr_t); +} + +inline uintptr_t round_down_to_nearest_page(uintptr_t addr) +{ + return addr - (addr % PAGE_SIZE); +} + +inline uintptr_t round_up_to_nearest_page(uintptr_t addr) +{ + if (addr % PAGE_SIZE) return addr + (PAGE_SIZE - (addr % PAGE_SIZE)); + return addr; +} \ No newline at end of file diff --git a/kernel/src/memory/VMM.cpp b/kernel/src/memory/VMM.cpp index e481088d..f8087a2e 100644 --- a/kernel/src/memory/VMM.cpp +++ b/kernel/src/memory/VMM.cpp @@ -6,6 +6,7 @@ #include "memory/PMM.h" #include "misc/utils.h" #include "std/string.h" +#include "utils/Addresses.h" #include "utils/Registers.h" static PageTable* kernel_pml4; @@ -61,7 +62,7 @@ void VMM::init() void VMM::unmap(uint64_t vaddr) { - vaddr = Utilities::round_down_to_nearest_page(vaddr); + vaddr = round_down_to_nearest_page(vaddr); PageDirectoryEntry* pde = find_pde(current_pml4, vaddr); if (!pde) return; // Already unmapped @@ -88,7 +89,7 @@ void VMM::remap(uint64_t vaddr, int flags) uint64_t VMM::get_physical(uint64_t vaddr) { - PageDirectoryEntry* pde = find_pde(current_pml4, Utilities::round_down_to_nearest_page(vaddr)); + PageDirectoryEntry* pde = find_pde(current_pml4, round_down_to_nearest_page(vaddr)); if (!pde) return UINT64_MAX; // Not mapped return pde->get_address() | (vaddr % PAGE_SIZE); @@ -96,7 +97,7 @@ uint64_t VMM::get_physical(uint64_t vaddr) uint64_t VMM::get_flags(uint64_t vaddr) { - PageDirectoryEntry* pde = find_pde(current_pml4, Utilities::round_down_to_nearest_page(vaddr)); + PageDirectoryEntry* pde = find_pde(current_pml4, round_down_to_nearest_page(vaddr)); if (!pde) return 0; // Not mapped uint64_t flags = 0; @@ -107,7 +108,7 @@ uint64_t VMM::get_flags(uint64_t vaddr) void VMM::map(uint64_t vaddr, uint64_t paddr, int flags) { - vaddr = Utilities::round_down_to_nearest_page(vaddr); + vaddr = round_down_to_nearest_page(vaddr); PageDirectoryEntry* pde = find_pde(current_pml4, vaddr); bool will_flush_tlb = true; if (!pde) @@ -121,7 +122,7 @@ void VMM::map(uint64_t vaddr, uint64_t paddr, int flags) pde = create_pde_if_not_exists(current_pml4, vaddr); } - pde->set_address(Utilities::round_down_to_nearest_page(paddr)); + pde->set_address(round_down_to_nearest_page(paddr)); if (flags & User) propagate_user(current_pml4, vaddr); else pde->user = false; diff --git a/kernel/src/sys/elf/ELFLoader.cpp b/kernel/src/sys/elf/ELFLoader.cpp index a9d4bb2e..858ecc32 100644 --- a/kernel/src/sys/elf/ELFLoader.cpp +++ b/kernel/src/sys/elf/ELFLoader.cpp @@ -13,6 +13,7 @@ #include "std/stdlib.h" #include "std/string.h" #include "sys/elf/ELF.h" +#include "utils/Addresses.h" static const char* format_permissions(uint32_t flags) { @@ -90,8 +91,8 @@ ELFImage* ELFLoader::load_elf_from_vfs(VFS::Node* node) ASSERT(phdr.p_vaddr); uint64_t pages = Utilities::get_blocks_from_size(PAGE_SIZE, (phdr.p_vaddr % PAGE_SIZE) + phdr.p_memsz); - void* buffer = (void*)((uint64_t)MemoryManager::get_pages_at( - Utilities::round_down_to_nearest_page(phdr.p_vaddr), pages, MAP_READ_WRITE) + + void* buffer = (void*)((uint64_t)MemoryManager::get_pages_at(round_down_to_nearest_page(phdr.p_vaddr), + pages, MAP_READ_WRITE) + (phdr.p_vaddr % PAGE_SIZE)); VMM::apply_address_space(); @@ -193,7 +194,7 @@ void ELFLoader::release_elf_image(ELFImage* image) { ELFSection& section = image->sections[i]; kdbgln("Freeing up section %lx, was using %ld pages", section.base, section.pages); - MemoryManager::release_pages((void*)Utilities::round_down_to_nearest_page(section.base), section.pages); + MemoryManager::release_pages((void*)round_down_to_nearest_page(section.base), section.pages); } kfree(image); } \ No newline at end of file diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index 948c8d1b..5ec334bd 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -14,6 +14,7 @@ #include "sys/elf/ELFLoader.h" #include "thread/PIT.h" #include "thread/Task.h" +#include "utils/Addresses.h" #include "utils/Registers.h" static uint64_t task_num = 0; @@ -35,7 +36,7 @@ void Scheduler::init() memset(&idle_task, 0, sizeof(Task)); idle_task.id = free_tid++; idle_task.regs.rip = (uint64_t)idle_task_function; - idle_task.regs.rsp = Utilities::get_top_of_stack((uint64_t)MemoryManager::get_page(), 1); + idle_task.regs.rsp = get_top_of_stack((uint64_t)MemoryManager::get_page(), 1); idle_task.regs.cs = 0x08; idle_task.regs.ss = 0x10; idle_task.regs.rflags = (1 << 21) | (1 << 9); @@ -67,7 +68,7 @@ void Scheduler::add_kernel_task(void (*task)(void)) new_task->regs.rip = (uint64_t)task; new_task->allocated_stack = (uint64_t)MemoryManager::get_pages(TASK_PAGES_IN_STACK); // 16 KB is enough for everyone, right? - new_task->regs.rsp = Utilities::get_top_of_stack(new_task->allocated_stack, TASK_PAGES_IN_STACK); + new_task->regs.rsp = get_top_of_stack(new_task->allocated_stack, TASK_PAGES_IN_STACK); new_task->regs.cs = 0x08; new_task->regs.ss = 0x10; new_task->regs.ds = 0x10; @@ -96,7 +97,7 @@ void Scheduler::add_user_task(void* task) new_task->regs.rip = (uint64_t)task; new_task->allocated_stack = (uint64_t)MemoryManager::get_pages( TASK_PAGES_IN_STACK, MAP_READ_WRITE | MAP_USER); // 16 KB is enough for everyone, right? - new_task->regs.rsp = Utilities::get_top_of_stack(new_task->allocated_stack, TASK_PAGES_IN_STACK); + new_task->regs.rsp = get_top_of_stack(new_task->allocated_stack, TASK_PAGES_IN_STACK); new_task->regs.cs = 0x18 | 0x03; new_task->regs.ss = 0x20 | 0x03; new_task->regs.ds = 0x20 | 0x03; @@ -140,7 +141,7 @@ void Scheduler::load_user_task(const char* filename) new_task->image = image; new_task->allocated_stack = (uint64_t)MemoryManager::get_pages( TASK_PAGES_IN_STACK, MAP_READ_WRITE | MAP_USER); // 16 KB is enough for everyone, right? - new_task->regs.rsp = Utilities::get_top_of_stack(new_task->allocated_stack, TASK_PAGES_IN_STACK); + new_task->regs.rsp = get_top_of_stack(new_task->allocated_stack, TASK_PAGES_IN_STACK); new_task->regs.cs = 0x18 | 0x03; new_task->regs.ss = 0x20 | 0x03; new_task->regs.ds = 0x20 | 0x03; @@ -167,7 +168,7 @@ void Scheduler::reset_task(Task* task, ELFImage* new_image) task->state = task->Running; task->regs.rip = new_image->entry; task->image = new_image; - task->regs.rsp = Utilities::get_top_of_stack(task->allocated_stack, TASK_PAGES_IN_STACK); + task->regs.rsp = get_top_of_stack(task->allocated_stack, TASK_PAGES_IN_STACK); task->regs.cs = 0x18 | 0x03; task->regs.ss = 0x20 | 0x03; task->regs.ds = 0x20 | 0x03; From 177282d79c5ac189e2e234277436b1398837e275 Mon Sep 17 00:00:00 2001 From: apio Date: Fri, 14 Oct 2022 17:27:35 +0200 Subject: [PATCH 11/17] Use the more appropriate size_t --- kernel/include/utils/Addresses.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/include/utils/Addresses.h b/kernel/include/utils/Addresses.h index e006d7a0..23752357 100644 --- a/kernel/include/utils/Addresses.h +++ b/kernel/include/utils/Addresses.h @@ -1,12 +1,13 @@ #pragma once +#include #include #ifndef PAGE_SIZE #define PAGE_SIZE 4096 #endif -inline uintptr_t get_top_of_stack(uintptr_t bottom, uintptr_t stack_pages) +inline uintptr_t get_top_of_stack(uintptr_t bottom, size_t stack_pages) { return bottom + (stack_pages * PAGE_SIZE) - sizeof(uintptr_t); } From bb7887a29d850909caf861f82180abc1fb86c653 Mon Sep 17 00:00:00 2001 From: apio Date: Thu, 13 Oct 2022 19:19:51 +0200 Subject: [PATCH 12/17] Add basic address space infrastructure --- kernel/src/memory/VMM.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/src/memory/VMM.cpp b/kernel/src/memory/VMM.cpp index f8087a2e..374086fd 100644 --- a/kernel/src/memory/VMM.cpp +++ b/kernel/src/memory/VMM.cpp @@ -58,6 +58,7 @@ bool VMM::is_using_kernel_address_space() void VMM::init() { kernel_pml4 = (PageTable*)read_cr3(); + current_pml4 = kernel_pml4; } void VMM::unmap(uint64_t vaddr) From cdb73836b0eda3e1192b1b8042a94c608a2b74cf Mon Sep 17 00:00:00 2001 From: apio Date: Thu, 13 Oct 2022 21:14:39 +0200 Subject: [PATCH 13/17] Some more multiple address space stuff This page-faults. This is because the memory where the ELF should be is all zeroes, which the CPU tries to interpret. --- kernel/src/main.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index b066d9bc..1b43ad37 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -87,10 +87,6 @@ extern "C" void _start() PIC::enable_master(0b11111100); // enable keyboard and PIT PIC::enable_slave(0b11111111); - kinfoln("Prepared PIC"); - - Interrupts::enable(); // Task switching commences here - kinfoln("Interrupts enabled"); PCI::scan([](PCI::Device& dev) { From 81f56083c5fc9c946d36b731d379589e633285f1 Mon Sep 17 00:00:00 2001 From: apio Date: Thu, 13 Oct 2022 21:55:51 +0200 Subject: [PATCH 14/17] Almost there! --- kernel/src/thread/Scheduler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index 5ec334bd..1dd03f89 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -57,6 +57,7 @@ void Scheduler::init() // the other registers will be saved next task switch frequency = 1000 / PIT::frequency(); + kdbgln("frequency: %ld", frequency); } void Scheduler::add_kernel_task(void (*task)(void)) From 97a8a4a4a286f67e84b43a5835f3163412eaee42 Mon Sep 17 00:00:00 2001 From: apio Date: Fri, 14 Oct 2022 17:39:24 +0200 Subject: [PATCH 15/17] Solve rebase --- kernel/src/memory/VMM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/src/memory/VMM.cpp b/kernel/src/memory/VMM.cpp index 374086fd..73679674 100644 --- a/kernel/src/memory/VMM.cpp +++ b/kernel/src/memory/VMM.cpp @@ -74,7 +74,7 @@ void VMM::unmap(uint64_t vaddr) void VMM::remap(uint64_t vaddr, int flags) { - vaddr = Utilities::round_down_to_nearest_page(vaddr); + vaddr = round_down_to_nearest_page(vaddr); PageDirectoryEntry* pde = find_pde(current_pml4, vaddr); if (!pde) return; // Not mapped From e43777bd319fef69309a7931a139554dae4a8cb9 Mon Sep 17 00:00:00 2001 From: apio Date: Fri, 14 Oct 2022 18:00:33 +0200 Subject: [PATCH 16/17] Apparently, it just works now. --- kernel/src/memory/VMM.cpp | 2 +- kernel/src/sys/elf/ELFLoader.cpp | 1 + kernel/src/sys/exec.cpp | 15 ++++++--------- kernel/src/thread/Scheduler.cpp | 1 - 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/kernel/src/memory/VMM.cpp b/kernel/src/memory/VMM.cpp index 73679674..94192275 100644 --- a/kernel/src/memory/VMM.cpp +++ b/kernel/src/memory/VMM.cpp @@ -47,7 +47,7 @@ void VMM::exit_syscall_context() void VMM::apply_address_space() { - asm volatile("mov %0, %%cr3" : : "r"(current_pml4)); + write_cr3(current_pml4); } bool VMM::is_using_kernel_address_space() diff --git a/kernel/src/sys/elf/ELFLoader.cpp b/kernel/src/sys/elf/ELFLoader.cpp index 858ecc32..647f1586 100644 --- a/kernel/src/sys/elf/ELFLoader.cpp +++ b/kernel/src/sys/elf/ELFLoader.cpp @@ -95,6 +95,7 @@ ELFImage* ELFLoader::load_elf_from_vfs(VFS::Node* node) pages, MAP_READ_WRITE) + (phdr.p_vaddr % PAGE_SIZE)); + if (VMM::is_using_kernel_address_space()) { VMM::switch_to_previous_user_address_space(); } VMM::apply_address_space(); VFS::read(node, phdr.p_offset, phdr.p_filesz, (char*)buffer); diff --git a/kernel/src/sys/exec.cpp b/kernel/src/sys/exec.cpp index c160b804..a157d6e4 100644 --- a/kernel/src/sys/exec.cpp +++ b/kernel/src/sys/exec.cpp @@ -12,12 +12,12 @@ #include "sys/elf/ELFLoader.h" #include "thread/Scheduler.h" -void sys_exec(Context* context, const char*) +void sys_exec(Context* context, const char* pathname) { - context->rax = -ENOSYS; // FIXME: Make exec() work under separate address spaces. - return; + /*context->rax = -ENOSYS; // FIXME: Make exec() work under separate address spaces. + return;*/ - /*char* kpathname = Syscall::strdup_from_user(pathname); + char* kpathname = Syscall::strdup_from_user(pathname); if (!kpathname) { context->rax = -EFAULT; @@ -75,10 +75,7 @@ void sys_exec(Context* context, const char*) // At this point, pretty much nothing can fail. - VMM::switch_back_to_kernel_address_space(); - VMM::apply_address_space(); - - task->address_space.reset(); + // task->address_space.reset(); // VMM::switch_to_user_address_space(task->address_space); @@ -99,5 +96,5 @@ void sys_exec(Context* context, const char*) kfree(kpathname); - return;*/ + return; } \ No newline at end of file diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index 1dd03f89..5ec334bd 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -57,7 +57,6 @@ void Scheduler::init() // the other registers will be saved next task switch frequency = 1000 / PIT::frequency(); - kdbgln("frequency: %ld", frequency); } void Scheduler::add_kernel_task(void (*task)(void)) From 1c3377fc98fa88fd5255c0b39e9bde8b00887bc7 Mon Sep 17 00:00:00 2001 From: apio Date: Fri, 14 Oct 2022 18:17:57 +0200 Subject: [PATCH 17/17] Prepare for cloning address spaces, not there yet --- kernel/include/memory/AddressSpace.h | 10 +++- kernel/include/thread/Scheduler.h | 3 +- kernel/src/memory/AddressSpace.cpp | 69 +++++++--------------------- kernel/src/sys/exec.cpp | 4 -- kernel/src/thread/Scheduler.cpp | 10 +--- 5 files changed, 28 insertions(+), 68 deletions(-) diff --git a/kernel/include/memory/AddressSpace.h b/kernel/include/memory/AddressSpace.h index a2af46fe..b6158a07 100644 --- a/kernel/include/memory/AddressSpace.h +++ b/kernel/include/memory/AddressSpace.h @@ -7,13 +7,21 @@ struct AddressSpace void destroy(); - void reset(); + void detach(); + + AddressSpace clone(); PageTable* get_pml4() { return m_pml4; } + bool is_cloned() + { + return m_cloned; + } + private: PageTable* m_pml4; + bool m_cloned; }; \ No newline at end of file diff --git a/kernel/include/thread/Scheduler.h b/kernel/include/thread/Scheduler.h index 0b0321ac..ed2d7533 100644 --- a/kernel/include/thread/Scheduler.h +++ b/kernel/include/thread/Scheduler.h @@ -10,7 +10,8 @@ namespace Scheduler void exit(int status); void sleep(unsigned long ms); void add_kernel_task(void (*task)(void)); - void add_user_task(void* task); + + Task* create_user_task(); void load_user_task(const char* filename); diff --git a/kernel/src/memory/AddressSpace.cpp b/kernel/src/memory/AddressSpace.cpp index 714c1b77..558f09f1 100644 --- a/kernel/src/memory/AddressSpace.cpp +++ b/kernel/src/memory/AddressSpace.cpp @@ -15,6 +15,11 @@ AddressSpace AddressSpace::create() void AddressSpace::destroy() { + if (m_cloned) + { + kdbgln("Will not destroy a cloned address space, I don't own it"); + return; + } uint64_t pages_freed = 0; for (int i = 0; i < 512; i++) { @@ -71,60 +76,18 @@ void AddressSpace::destroy() kdbgln("Reclaimed %ld pages from address space!", pages_freed); } -void AddressSpace::reset() +void AddressSpace::detach() { - uint64_t pages_freed = 0; - for (int i = 0; i < 512; i++) - { - PageDirectoryEntry& pdp_pde = m_pml4->entries[i]; - if (!pdp_pde.present) continue; - if (pdp_pde.larger_pages) - { - pages_freed++; - PMM::free_page((void*)pdp_pde.get_address()); - continue; - } - PageTable* pdp = (PageTable*)pdp_pde.get_address(); - for (int j = 0; j < 511; j++) // skip the last page directory, it's the kernel one - { - PageDirectoryEntry& pd_pde = pdp->entries[j]; - if (!pd_pde.present) continue; - if (pd_pde.larger_pages) - { - pages_freed++; - PMM::free_page((void*)pd_pde.get_address()); - continue; - } - PageTable* pd = (PageTable*)pd_pde.get_address(); - for (int k = 0; k < 512; k++) - { - PageDirectoryEntry& pt_pde = pd->entries[k]; - if (!pt_pde.present) continue; - if (pt_pde.larger_pages) - { - pages_freed++; - PMM::free_page((void*)pt_pde.get_address()); - continue; - } - PageTable* pt = (PageTable*)pt_pde.get_address(); - for (int l = 0; l < 512; l++) - { - PageDirectoryEntry& pde = pt->entries[l]; - if (!pde.present) continue; - pages_freed++; - PMM::free_page((void*)pde.get_address()); - } - pages_freed++; - PMM::free_page(pt); - } - pages_freed++; - PMM::free_page(pd); - } - pages_freed++; - PMM::free_page(pdp); - } - + if (!m_cloned) return; + m_pml4 = (PageTable*)PMM::request_page(); VMM::install_kernel_page_directory_into_address_space(*this); + m_cloned = false; +} - kdbgln("Reclaimed %ld pages from address space!", pages_freed); +AddressSpace AddressSpace::clone() +{ + AddressSpace result; + result.m_pml4 = m_pml4; + result.m_cloned = true; + return result; } \ No newline at end of file diff --git a/kernel/src/sys/exec.cpp b/kernel/src/sys/exec.cpp index a157d6e4..e38dfbef 100644 --- a/kernel/src/sys/exec.cpp +++ b/kernel/src/sys/exec.cpp @@ -75,10 +75,6 @@ void sys_exec(Context* context, const char* pathname) // At this point, pretty much nothing can fail. - // task->address_space.reset(); - - // VMM::switch_to_user_address_space(task->address_space); - ELFImage* image = ELFLoader::load_elf_from_vfs(program); ASSERT(image); // If check_elf_image succeeded, load_elf_from_vfs MUST succeed, unless something has gone terribly // wrong. diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index 5ec334bd..9e90e1a3 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -87,21 +87,16 @@ void Scheduler::add_kernel_task(void (*task)(void)) new_task->id, new_task->regs.rsp, task_num); } -void Scheduler::add_user_task(void* task) +Task* Scheduler::create_user_task() { Task* new_task = new Task; ASSERT(new_task); memset(&new_task->regs, 0, sizeof(Context)); new_task->user_task = true; new_task->id = free_tid++; - new_task->regs.rip = (uint64_t)task; new_task->allocated_stack = (uint64_t)MemoryManager::get_pages( TASK_PAGES_IN_STACK, MAP_READ_WRITE | MAP_USER); // 16 KB is enough for everyone, right? new_task->regs.rsp = get_top_of_stack(new_task->allocated_stack, TASK_PAGES_IN_STACK); - new_task->regs.cs = 0x18 | 0x03; - new_task->regs.ss = 0x20 | 0x03; - new_task->regs.ds = 0x20 | 0x03; - new_task->regs.rflags = (1 << 21) | (1 << 9); // enable interrupts new_task->task_sleep = 0; new_task->task_time = 0; new_task->cpu_time = 0; @@ -110,10 +105,7 @@ void Scheduler::add_user_task(void* task) base_task->prev_task = new_task; new_task->next_task = base_task; end_task = new_task; - new_task->state = new_task->Running; task_num++; - kinfoln("Adding user task: starts at %lx, tid %ld, stack at %lx, total tasks: %ld", new_task->regs.rip, - new_task->id, new_task->regs.rsp, task_num); } void Scheduler::load_user_task(const char* filename)