mirror of
https://github.com/justinian/jsix.git
synced 2025-12-09 16:04:32 -08:00
Initial work on swapping page tables per process
This commit is contained in:
@@ -219,6 +219,31 @@ page_manager::init(
|
|||||||
new (&g_kernel_memory_manager) kutil::memory_manager(
|
new (&g_kernel_memory_manager) kutil::memory_manager(
|
||||||
reinterpret_cast<void *>(end),
|
reinterpret_cast<void *>(end),
|
||||||
mm_grow_callback);
|
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
|
void
|
||||||
@@ -255,9 +280,11 @@ page_manager::dump_blocks()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
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 *
|
page_block *
|
||||||
@@ -345,10 +372,11 @@ page_manager::consolidate_blocks()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void *
|
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<void *>(address);
|
void *ret = reinterpret_cast<void *>(address);
|
||||||
page_table *pml4 = get_pml4();
|
if (pml4 == nullptr)
|
||||||
|
pml4 = get_pml4();
|
||||||
|
|
||||||
while (count) {
|
while (count) {
|
||||||
kassert(m_free, "page_manager::map_pages ran out of free pages!");
|
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_flags::mapped;
|
||||||
page_block::insert(m_used, block);
|
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;
|
address += n * page_size;
|
||||||
count -= n;
|
count -= n;
|
||||||
|
|||||||
@@ -26,13 +26,46 @@ public:
|
|||||||
/// Offset from physical where page tables are mapped.
|
/// Offset from physical where page tables are mapped.
|
||||||
static const addr_t page_offset = 0xffffff8000000000;
|
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();
|
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<page_table *>((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<addr_t>(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.
|
/// Allocate and map pages into virtual memory.
|
||||||
/// \arg address The virtual address at which to map the pages
|
/// \arg address The virtual address at which to map the pages
|
||||||
/// \arg count The number of pages to map
|
/// \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
|
/// \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
|
/// Allocate and map contiguous pages into virtual memory, with
|
||||||
/// a constant offset from their physical address.
|
/// a constant offset from their physical address.
|
||||||
@@ -70,8 +103,9 @@ public:
|
|||||||
/// Log the current free/used block lists.
|
/// Log the current free/used block lists.
|
||||||
void dump_blocks();
|
void dump_blocks();
|
||||||
|
|
||||||
/// Dump the current PML4 to the console
|
/// Dump the given or current PML4 to the console
|
||||||
void dump_pml4();
|
/// \arg pml4 The page table to use, null for the current one
|
||||||
|
void dump_pml4(page_table *pml4 = nullptr);
|
||||||
|
|
||||||
/// Get the system page manager.
|
/// Get the system page manager.
|
||||||
/// \returns A pointer to the system page manager
|
/// \returns A pointer to the system page manager
|
||||||
@@ -108,23 +142,6 @@ private:
|
|||||||
/// to the cache.
|
/// to the cache.
|
||||||
void consolidate_blocks();
|
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<page_table *>((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<addr_t>(pml4) - page_offset;
|
|
||||||
__asm__ __volatile__ ( "mov %0, %%cr3" :: "r" (p & ~0xfffull) );
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Helper function to allocate a new page table. If table entry `i` in
|
/// 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
|
/// table `base` is empty, allocate a new page table and point `base[i]` at
|
||||||
/// it.
|
/// it.
|
||||||
@@ -163,6 +180,8 @@ private:
|
|||||||
/// \returns The number of pages retrieved
|
/// \returns The number of pages retrieved
|
||||||
size_t pop_pages(size_t count, addr_t *address);
|
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_free; ///< Free pages list
|
||||||
page_block *m_used; ///< In-use pages list
|
page_block *m_used; ///< In-use pages list
|
||||||
|
|
||||||
|
|||||||
@@ -4,18 +4,13 @@
|
|||||||
#include "gdt.h"
|
#include "gdt.h"
|
||||||
#include "interrupts.h"
|
#include "interrupts.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "page_manager.h"
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
|
|
||||||
scheduler scheduler::s_instance(nullptr);
|
scheduler scheduler::s_instance(nullptr);
|
||||||
static const uint32_t quantum = 5000000;
|
static const uint32_t quantum = 2000000;
|
||||||
|
|
||||||
const int stack_size = 0x1000;
|
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 taskA();
|
||||||
extern "C" void taskB();
|
extern "C" void taskB();
|
||||||
@@ -29,19 +24,18 @@ scheduler::scheduler(lapic *apic) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
static process
|
static process
|
||||||
create_process(uint16_t pid, void *stack0, void *stack3, void (*rip)())
|
create_process(uint16_t pid, void (*rip)())
|
||||||
{
|
{
|
||||||
uint64_t flags;
|
uint64_t flags;
|
||||||
__asm__ __volatile__ ( "pushf; pop %0" : "=r" (flags) );
|
__asm__ __volatile__ ( "pushf; pop %0" : "=r" (flags) );
|
||||||
|
|
||||||
// This is a hack for now, until we get a lot more set up.
|
uint16_t kcs = (1 << 3) | 0; // Kernel CS is GDT entry 1, ring 0
|
||||||
// I just want to see task switching working inside ring0 first
|
uint16_t cs = (5 << 3) | 3; // User CS is GDT entry 5, ring 3
|
||||||
uint16_t kcs = (1 << 3) | 0;
|
|
||||||
uint16_t cs = (5 << 3) | 3;
|
|
||||||
|
|
||||||
uint16_t kss = (2 << 3) | 0;
|
uint16_t kss = (2 << 3) | 0; // Kernel SS is GDT entry 2, ring 0
|
||||||
uint16_t ss = (4 << 3) | 3;
|
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);
|
void *sp0 = kutil::offset_pointer(stack0, stack_size);
|
||||||
cpu_state *state = reinterpret_cast<cpu_state *>(sp0) - 1;
|
cpu_state *state = reinterpret_cast<cpu_state *>(sp0) - 1;
|
||||||
kutil::memset(state, 0, sizeof(cpu_state));
|
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->rflags = 0x202; // testing. TODO: 0x202
|
||||||
state->rip = reinterpret_cast<uint64_t>(rip);
|
state->rip = reinterpret_cast<uint64_t>(rip);
|
||||||
|
|
||||||
void *sp3 = kutil::offset_pointer(stack3, stack_size);
|
page_table *pml4 = page_manager::get()->create_process_map();
|
||||||
state->user_rsp = reinterpret_cast<uint64_t>(sp3);
|
state->user_rsp = page_manager::initial_stack;
|
||||||
|
|
||||||
log::debug(logs::task, "Creating PID %d:", pid);
|
log::debug(logs::task, "Creating PID %d:", pid);
|
||||||
log::debug(logs::task, " RSP0 %016lx", state);
|
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<addr_t>(state)};
|
return {pid, reinterpret_cast<addr_t>(state), pml4};
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -68,9 +63,9 @@ scheduler::start()
|
|||||||
|
|
||||||
m_apic->enable_timer(isr::isrTimer, 128, quantum, false);
|
m_apic->enable_timer(isr::isrTimer, 128, quantum, false);
|
||||||
|
|
||||||
m_processes.append({0, 0}); // The kernel idle task
|
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, &taskAstack0[0], &taskAstack3[0], &taskA));
|
m_processes.append(create_process(1, &taskA));
|
||||||
m_processes.append(create_process(2, &taskBstack0[0], &taskBstack3[0], &taskB));
|
m_processes.append(create_process(2, &taskB));
|
||||||
}
|
}
|
||||||
|
|
||||||
addr_t
|
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
|
// Set rsp0 to after the end of the about-to-be-popped cpu state
|
||||||
tss_set_stack(0, rsp0 + sizeof(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);
|
m_apic->reset_timer(quantum);
|
||||||
return rsp0;
|
return rsp0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,14 @@
|
|||||||
#include "kutil/vector.h"
|
#include "kutil/vector.h"
|
||||||
|
|
||||||
class lapic;
|
class lapic;
|
||||||
|
struct page_table;
|
||||||
|
|
||||||
|
|
||||||
struct process
|
struct process
|
||||||
{
|
{
|
||||||
uint16_t pid;
|
uint16_t pid;
|
||||||
addr_t rsp;
|
addr_t rsp;
|
||||||
|
page_table *pml4;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user