page table allocation functionality

This commit is contained in:
uosfz 2025-04-23 18:25:06 +02:00
parent fad7eaea3a
commit b94c694061
Signed by: uosfz
SSH key fingerprint: SHA256:FlktuluyhTQg3jHZNLKwxOOC5hbfrUXM0tz3IA3lGJo
2 changed files with 55 additions and 17 deletions

View file

@ -10,6 +10,9 @@ void init_gdt();
void init_idt(); void init_idt();
// --- paging --- // --- paging ---
//
// We don't use the PAT functionality. We set all bits (writethrough, cache_disable, PAT) to 0.
// For access protection we only use MTRRs.
void init_paging(void); void init_paging(void);
@ -62,6 +65,8 @@ bool pt_map_range(struct vpn virt, struct ppn phys, uint64_t num_pages,
bool pt_map_range_current(struct vpn virt, struct ppn phys, uint64_t num_pages, bool pt_map_range_current(struct vpn virt, struct ppn phys, uint64_t num_pages,
bool writable, bool supervisor, bool global); bool writable, bool supervisor, bool global);
void pt_free(struct ppn root);
struct mem_range { struct mem_range {
struct vpn vpn_start; struct vpn vpn_start;
struct pt_entry entry_start; struct pt_entry entry_start;

View file

@ -3,7 +3,8 @@
#include "x86_64/asm.h" #include "x86_64/asm.h"
#include "x86_64/mem.h" #include "x86_64/mem.h"
#include "std.h" // remove later, this is only for interrupt handler #include "std.h"
#include "ram.h"
static uint64_t gdt[3]; static uint64_t gdt[3];
@ -102,6 +103,24 @@ void init_idt() {
// --- paging --- // --- paging ---
void init_paging() {
// assert paging enabled (PG)
ASSERT((get_cr0() >> 31) & 1ull);
// assert PAE enabled (this should never be disabled in 64-bit mode)
ASSERT((get_cr4() >> 5) & 1ull);
// PSE is ignored in long mode
// ASSERT((get_cr4() >> 4) & 1ull);
// TODO check that everything is setup correctly
// - CR0.WP
// - Long-Mode Active (EFER.LMA)
// - PAT index 000 points to default strategy
// - See if NX bits are used and decide if we want to
// - See of MPK is used and decide if we want to
// - SMEP/SMAP?
// - ...
}
#define MSR_PAT 0x277 #define MSR_PAT 0x277
enum page_attr get_pa(uint8_t index) { enum page_attr get_pa(uint8_t index) {
@ -117,21 +136,6 @@ enum page_attr get_pa(uint8_t index) {
return value; return value;
} }
void set_pa(uint8_t index, enum page_attr attr) {
ASSERT(index < 8);
ASSERT(attr == PA_UC
|| attr == PA_WC
|| attr == PA_WT
|| attr == PA_WP
|| attr == PA_WB
|| attr == PA_UCMINUS);
uint64_t value = readmsr(MSR_PAT);
uint64_t mask = 0x7ull << (index << 3);
value &= ~mask; // clear bits
value |= (uint64_t)attr << (index << 3);
writemsr(MSR_PAT, value);
}
uint64_t pt_entry_pack(const struct pt_entry *ent_in) { uint64_t pt_entry_pack(const struct pt_entry *ent_in) {
uint64_t retval = (uint64_t)ent_in->present uint64_t retval = (uint64_t)ent_in->present
| ((uint64_t)ent_in->writable) << 1 | ((uint64_t)ent_in->writable) << 1
@ -257,6 +261,9 @@ static struct ppn get_cr3_ppn(void) {
#define NUM_LEVELS 4 #define NUM_LEVELS 4
// TODO for inspection, we need to accumulate permissions over all levels
// (upper supervisor bit will mean lower PTs are also supervisor, even without their bit set)
static uint64_t *pt_get_leaf_ptr(struct vpn vpn, struct ppn cr3, bool alloc) { static uint64_t *pt_get_leaf_ptr(struct vpn vpn, struct ppn cr3, bool alloc) {
uint64_t va_value = va_to_value(va_from_vpn(vpn)); uint64_t va_value = va_to_value(va_from_vpn(vpn));
int level = NUM_LEVELS; int level = NUM_LEVELS;
@ -277,7 +284,22 @@ static uint64_t *pt_get_leaf_ptr(struct vpn vpn, struct ppn cr3, bool alloc) {
if (!ent.present) { if (!ent.present) {
if (alloc) { if (alloc) {
TODO(); bool success = ram_alloc_frame(&ent.ppn, RAM_PAGE_NORMAL);
ASSERT(success);
ent.level = level;
ent.present = true;
// maximum privileges in upper level
ent.writable = true;
ent.supervisor = false;
ent.writethrough = false;
ent.cache_disable = false;
ent.accessed = false;
ent.dirty = false;
ent.global = false; // TODO should this be true for lower global mappings? probably
ent.hugepage = false;
ent.pat_bit = false;
// add into page table
*entry_ptr = pt_entry_pack(&ent);
} else { } else {
return NULL; return NULL;
} }
@ -329,6 +351,11 @@ bool pt_map_single(struct vpn virt, struct ppn phys,
// disable caching bits because we want to use MTRRs // disable caching bits because we want to use MTRRs
ent.pat_bit = false; ent.pat_bit = false;
// additional sanity check to avoid double mapping
struct pt_entry ent;
pt_entry_unpack(*leaf_ptr, 1, &ent);
ASSERT(!ent.present);
*leaf_ptr = pt_entry_pack(&ent); *leaf_ptr = pt_entry_pack(&ent);
return true; return true;
} }
@ -345,6 +372,7 @@ bool pt_map_range(struct vpn virt, struct ppn phys, uint64_t num_pages,
{ {
for (uint64_t i = 0; i < num_pages; i++) { for (uint64_t i = 0; i < num_pages; i++) {
// TODO error handling: what to do if it fails in the middle? // TODO error handling: what to do if it fails in the middle?
// TODO huge pages
pt_map_single(virt, phys, writable, supervisor, global, cr3); pt_map_single(virt, phys, writable, supervisor, global, cr3);
virt = vpn_from_pagenum(vpn_to_pagenum(virt) + 1); virt = vpn_from_pagenum(vpn_to_pagenum(virt) + 1);
phys = ppn_from_pagenum(ppn_to_pagenum(phys) + 1); phys = ppn_from_pagenum(ppn_to_pagenum(phys) + 1);
@ -358,6 +386,11 @@ bool pt_map_range_current(struct vpn virt, struct ppn phys, uint64_t num_pages,
return pt_map_range(virt, phys, num_pages, writable, supervisor, global, get_cr3_ppn()); return pt_map_range(virt, phys, num_pages, writable, supervisor, global, get_cr3_ppn());
} }
void pt_free(struct ppn root) {
// this assumes single ownership
TODO();
}
// --- range finder --- // --- range finder ---
void mem_range_print(const struct mem_range *mr) { void mem_range_print(const struct mem_range *mr) {