diff --git a/src/kernel/page_manager.cpp b/src/kernel/page_manager.cpp index f8b2ee9..8b61293 100644 --- a/src/kernel/page_manager.cpp +++ b/src/kernel/page_manager.cpp @@ -219,6 +219,31 @@ page_manager::init( new (&g_kernel_memory_manager) kutil::memory_manager( reinterpret_cast(end), mm_grow_callback); + + m_kernel_pml4 = get_pml4(); +} + +page_table * +page_manager::create_process_map() +{ + page_table *table = get_table_page(); + kutil::memcpy(table, m_kernel_pml4, page_size); + + // Create the initial user stack + map_pages( + initial_stack - (initial_stack_pages * page_size), + initial_stack_pages, + true, // This is the ring3 stack, user = true + table); + + return table; +} + +void +page_manager::delete_process_map(page_table *table) +{ + // TODO: recurse table entries and mark them free + unmap_pages(table, 1); } void @@ -255,9 +280,11 @@ page_manager::dump_blocks() } void -page_manager::dump_pml4() +page_manager::dump_pml4(page_table *pml4) { - get_pml4()->dump(); + if (pml4 == nullptr) + pml4 = get_pml4(); + pml4->dump(); } page_block * @@ -345,10 +372,11 @@ page_manager::consolidate_blocks() } void * -page_manager::map_pages(addr_t address, size_t count) +page_manager::map_pages(addr_t address, size_t count, bool user, page_table *pml4) { void *ret = reinterpret_cast(address); - page_table *pml4 = get_pml4(); + if (pml4 == nullptr) + pml4 = get_pml4(); while (count) { kassert(m_free, "page_manager::map_pages ran out of free pages!"); @@ -365,7 +393,10 @@ page_manager::map_pages(addr_t address, size_t count) page_block_flags::mapped; page_block::insert(m_used, block); - page_in(pml4, phys, address, n); + log::debug(logs::memory, "Paging in %d pages at p:%016lx to v:%016lx into %016lx table", + n, phys, address, pml4); + + page_in(pml4, phys, address, n, user); address += n * page_size; count -= n; diff --git a/src/kernel/page_manager.h b/src/kernel/page_manager.h index 88d8897..032a086 100644 --- a/src/kernel/page_manager.h +++ b/src/kernel/page_manager.h @@ -26,13 +26,46 @@ public: /// Offset from physical where page tables are mapped. static const addr_t page_offset = 0xffffff8000000000; + /// Initial process thread's stack address + static const addr_t initial_stack = 0x0000800000000000; + + /// Initial process thread's stack size, in pages + static const unsigned initial_stack_pages = 1; + page_manager(); + /// Helper to read the PML4 table from CR3. + /// \returns A pointer to the current PML4 table. + static inline page_table * get_pml4() + { + addr_t pml4 = 0; + __asm__ __volatile__ ( "mov %%cr3, %0" : "=r" (pml4) ); + return reinterpret_cast((pml4 & ~0xfffull) + page_offset); + } + + /// Helper to set the PML4 table pointer in CR3. + /// \arg pml4 A pointer to the PML4 table to install. + static inline void set_pml4(page_table *pml4) + { + addr_t p = reinterpret_cast(pml4) - page_offset; + __asm__ __volatile__ ( "mov %0, %%cr3" :: "r" (p & ~0xfffull) ); + } + + /// Allocate but don't switch to a new PML4 table. This table + /// should only have global kernel pages mapped. + /// \returns A pointer to the PML4 table + page_table * create_process_map(); + + /// Deallocate a process' PML4 table. + void delete_process_map(page_table *table); + /// Allocate and map pages into virtual memory. /// \arg address The virtual address at which to map the pages /// \arg count The number of pages to map + /// \arg user True is this memory is user-accessible + /// \arg pml4 The pml4 to map into - null for the current one /// \returns A pointer to the start of the mapped region - void * map_pages(addr_t address, size_t count); + void * map_pages(addr_t address, size_t count, bool user = false, page_table *pml4 = nullptr); /// Allocate and map contiguous pages into virtual memory, with /// a constant offset from their physical address. @@ -70,8 +103,9 @@ public: /// Log the current free/used block lists. void dump_blocks(); - /// Dump the current PML4 to the console - void dump_pml4(); + /// Dump the given or current PML4 to the console + /// \arg pml4 The page table to use, null for the current one + void dump_pml4(page_table *pml4 = nullptr); /// Get the system page manager. /// \returns A pointer to the system page manager @@ -108,23 +142,6 @@ private: /// to the cache. void consolidate_blocks(); - /// Helper to read the PML4 table from CR3. - /// \returns A pointer to the current PML4 table. - static inline page_table * get_pml4() - { - addr_t pml4 = 0; - __asm__ __volatile__ ( "mov %%cr3, %0" : "=r" (pml4) ); - return reinterpret_cast((pml4 & ~0xfffull) + page_offset); - } - - /// Helper to set the PML4 table pointer in CR3. - /// \arg pml4 A pointer to the PML4 table to install. - static inline void set_pml4(page_table *pml4) - { - addr_t p = reinterpret_cast(pml4) - page_offset; - __asm__ __volatile__ ( "mov %0, %%cr3" :: "r" (p & ~0xfffull) ); - } - /// Helper function to allocate a new page table. If table entry `i` in /// table `base` is empty, allocate a new page table and point `base[i]` at /// it. @@ -163,6 +180,8 @@ private: /// \returns The number of pages retrieved size_t pop_pages(size_t count, addr_t *address); + page_table *m_kernel_pml4; ///< The PML4 of just kernel pages + page_block *m_free; ///< Free pages list page_block *m_used; ///< In-use pages list diff --git a/src/kernel/scheduler.cpp b/src/kernel/scheduler.cpp index 5188a70..24174d1 100644 --- a/src/kernel/scheduler.cpp +++ b/src/kernel/scheduler.cpp @@ -4,18 +4,13 @@ #include "gdt.h" #include "interrupts.h" #include "log.h" +#include "page_manager.h" #include "scheduler.h" scheduler scheduler::s_instance(nullptr); -static const uint32_t quantum = 5000000; +static const uint32_t quantum = 2000000; const int stack_size = 0x1000; -char taskAstack0[stack_size]; -char taskAstack3[stack_size]; -char taskBstack0[stack_size]; -char taskBstack3[stack_size]; - -uint64_t taskAcount = 0; extern "C" void taskA(); extern "C" void taskB(); @@ -29,19 +24,18 @@ scheduler::scheduler(lapic *apic) : } static process -create_process(uint16_t pid, void *stack0, void *stack3, void (*rip)()) +create_process(uint16_t pid, void (*rip)()) { uint64_t flags; __asm__ __volatile__ ( "pushf; pop %0" : "=r" (flags) ); - // This is a hack for now, until we get a lot more set up. - // I just want to see task switching working inside ring0 first - uint16_t kcs = (1 << 3) | 0; - uint16_t cs = (5 << 3) | 3; + uint16_t kcs = (1 << 3) | 0; // Kernel CS is GDT entry 1, ring 0 + uint16_t cs = (5 << 3) | 3; // User CS is GDT entry 5, ring 3 - uint16_t kss = (2 << 3) | 0; - uint16_t ss = (4 << 3) | 3; + uint16_t kss = (2 << 3) | 0; // Kernel SS is GDT entry 2, ring 0 + uint16_t ss = (4 << 3) | 3; // User SS is GDT entry 4, ring 3 + void *stack0 = kutil::malloc(stack_size); void *sp0 = kutil::offset_pointer(stack0, stack_size); cpu_state *state = reinterpret_cast(sp0) - 1; kutil::memset(state, 0, sizeof(cpu_state)); @@ -51,14 +45,15 @@ create_process(uint16_t pid, void *stack0, void *stack3, void (*rip)()) state->rflags = 0x202; // testing. TODO: 0x202 state->rip = reinterpret_cast(rip); - void *sp3 = kutil::offset_pointer(stack3, stack_size); - state->user_rsp = reinterpret_cast(sp3); + page_table *pml4 = page_manager::get()->create_process_map(); + state->user_rsp = page_manager::initial_stack; log::debug(logs::task, "Creating PID %d:", pid); log::debug(logs::task, " RSP0 %016lx", state); - log::debug(logs::task, " RSP3 %016lx", sp3); + log::debug(logs::task, " RSP3 %016lx", state->user_rsp); + log::debug(logs::task, " PML4 %016lx", pml4); - return {pid, reinterpret_cast(state)}; + return {pid, reinterpret_cast(state), pml4}; } void @@ -68,9 +63,9 @@ scheduler::start() m_apic->enable_timer(isr::isrTimer, 128, quantum, false); - m_processes.append({0, 0}); // The kernel idle task - m_processes.append(create_process(1, &taskAstack0[0], &taskAstack3[0], &taskA)); - m_processes.append(create_process(2, &taskBstack0[0], &taskBstack3[0], &taskB)); + m_processes.append({0, 0, page_manager::get_pml4()}); // The kernel idle task, also the thread we're in now + m_processes.append(create_process(1, &taskA)); + m_processes.append(create_process(2, &taskB)); } addr_t @@ -85,6 +80,10 @@ scheduler::tick(addr_t rsp0) // Set rsp0 to after the end of the about-to-be-popped cpu state tss_set_stack(0, rsp0 + sizeof(cpu_state)); + // Swap page tables + page_table *pml4 = m_processes[m_current].pml4; + page_manager::set_pml4(pml4); + m_apic->reset_timer(quantum); return rsp0; } diff --git a/src/kernel/scheduler.h b/src/kernel/scheduler.h index 13b1938..9893fad 100644 --- a/src/kernel/scheduler.h +++ b/src/kernel/scheduler.h @@ -5,12 +5,14 @@ #include "kutil/vector.h" class lapic; +struct page_table; struct process { uint16_t pid; addr_t rsp; + page_table *pml4; };