Use a direct address for P4 rather than a pointer

This commit is contained in:
Thomas Lovén 2018-02-20 14:02:47 +01:00
parent 8711fee390
commit 36c517dd82
6 changed files with 97 additions and 87 deletions

View File

@ -26,20 +26,24 @@
#ifndef __ASSEMBLER__ #ifndef __ASSEMBLER__
#include <stddef.h> #include <stddef.h>
extern uint64_t kernel_P4;
void *memcpy(void *dst, const void *src, size_t n); void *memcpy(void *dst, const void *src, size_t n);
void *memset(void *s, int c, size_t n); void *memset(void *s, int c, size_t n);
void *memmove(void *dest, const void *src, size_t n); void *memmove(void *dest, const void *src, size_t n);
int memcmp(const void *s1, const void *s2, size_t n); int memcmp(const void *s1, const void *s2, size_t n);
size_t strlen(const char *s); size_t strlen(const char *s);
void pmm_free(uintptr_t page); void pmm_free(uint64_t page);
uintptr_t pmm_alloc(); uint64_t pmm_alloc();
uintptr_t pmm_calloc(); uint64_t pmm_calloc();
uintptr_t vmm_get_page(void *P4, uintptr_t addr); uint64_t vmm_get_page(uint64_t P4, uint64_t addr);
int vmm_set_page(void *P4, uintptr_t addr, uintptr_t page, uint16_t flags); #define PAGE_EXIST(p) ((p) != (uint64_t)-1)
int touch_page(void *P4, uintptr_t addr, uint16_t flags); int vmm_set_page(uint64_t P4, uint64_t addr, uint64_t page, uint16_t flags);
void free_page(void *P4, uintptr_t addr, int free); int touch_page(uint64_t P4, uint64_t addr, uint16_t flags);
void free_page(uint64_t P4, uint64_t addr, int free);
extern union PTE BootP4; extern union PTE BootP4;
extern int kernel_start, kernel_end; extern int kernel_start, kernel_end;

View File

@ -2,25 +2,29 @@
#include <multiboot.h> #include <multiboot.h>
#include <debug.h> #include <debug.h>
uint64_t kernel_P4;
void memory_init() void memory_init()
{ {
uintptr_t start, end; kernel_P4 = (uint64_t)&BootP4;
uint64_t start, end;
uint32_t type, i = 0; uint32_t type, i = 0;
debug_info("Parsing memory map\n"); debug_info("Parsing memory map\n");
while(!multiboot_get_memory_area(i++, &start, &end, &type)) while(!multiboot_get_memory_area(i++, &start, &end, &type))
{ {
debug("0x%016x-0x%016x (%d)\n", start, end, type); debug("0x%016x-0x%016x (%d)\n", start, end, type);
for(uintptr_t p = start; p < end; p += PAGE_SIZE) for(uint64_t p = start; p < end; p += PAGE_SIZE)
{ {
if(p >= V2P(&kernel_start) && p < V2P(&kernel_end)) if(p >= V2P(&kernel_start) && p < V2P(&kernel_end))
continue; continue;
uintptr_t page = vmm_get_page(&BootP4, (uintptr_t)P2V(p)); uint64_t addr = (uint64_t)P2V(p);
if(page == (uintptr_t)-1 || !(page & PAGE_PRESENT)) uint64_t page = vmm_get_page(kernel_P4, addr);
if(!PAGE_EXIST(page) || !(page & PAGE_PRESENT))
{ {
uint16_t flags = PAGE_GLOBAL | PAGE_HUGE | PAGE_WRITE; uint16_t flags = PAGE_GLOBAL | PAGE_HUGE | PAGE_WRITE;
touch_page(&BootP4, (uintptr_t)P2V(p), flags); touch_page(kernel_P4, addr, flags);
vmm_set_page(&BootP4, (uintptr_t)P2V(p), p, flags | PAGE_PRESENT); vmm_set_page(kernel_P4, addr, p, flags | PAGE_PRESENT);
} }
if(type == MMAP_FREE) if(type == MMAP_FREE)

View File

@ -1,25 +1,25 @@
#include <memory.h> #include <memory.h>
uintptr_t first = 0; uint64_t first = 0;
void pmm_free(uintptr_t page) void pmm_free(uint64_t page)
{ {
page = (uintptr_t)P2V(page); page = (uint64_t)P2V(page);
*(uintptr_t *)page = first; *(uint64_t *)page = first;
first = page; first = page;
} }
uintptr_t pmm_alloc() uint64_t pmm_alloc()
{ {
uintptr_t page = first; uint64_t page = first;
first = page?*(uintptr_t *)page:0; first = page?*(uint64_t *)page:0;
page = (uintptr_t)(page?V2P(page):0); page = (uint64_t)(page?V2P(page):0);
return page; return page;
} }
uintptr_t pmm_calloc() uint64_t pmm_calloc()
{ {
uintptr_t page = pmm_alloc(); uint64_t page = pmm_alloc();
memset(P2V(page), 0, 0x1000); memset(P2V(page), 0, 0x1000);
return page; return page;
} }

View File

@ -15,19 +15,19 @@ struct {
TEST(alloc_returns_freed_page) TEST(alloc_returns_freed_page)
{ {
pmm_free(V2P(&mem[0])); pmm_free(V2P(&mem[0]));
uintptr_t a = pmm_alloc(); uint64_t a = pmm_alloc();
ASSERT_EQ_PTR(a, V2P(&mem[0])); ASSERT_EQ_PTR(a, V2P(&mem[0]));
} }
TEST(alloc_returns_0_if_no_free_pages) TEST(alloc_returns_0_if_no_free_pages)
{ {
uintptr_t a = pmm_alloc(); uint64_t a = pmm_alloc();
ASSERT_EQ_PTR(a, 0); ASSERT_EQ_PTR(a, 0);
} }
TEST(alloc_zero_after_all_free_pages) TEST(alloc_zero_after_all_free_pages)
{ {
pmm_free(V2P(&mem[0])); pmm_free(V2P(&mem[0]));
pmm_alloc(); pmm_alloc();
uintptr_t a = pmm_alloc(); uint64_t a = pmm_alloc();
ASSERT_EQ_PTR(a, 0); ASSERT_EQ_PTR(a, 0);
} }
@ -35,7 +35,7 @@ TEST(alloc_two_pages___first_page_is_not_zero)
{ {
pmm_free(V2P(&mem[0])); pmm_free(V2P(&mem[0]));
pmm_free(V2P(&mem[1])); pmm_free(V2P(&mem[1]));
uintptr_t a = pmm_alloc(); uint64_t a = pmm_alloc();
pmm_alloc(); pmm_alloc();
ASSERT_NEQ_PTR(a, 0); ASSERT_NEQ_PTR(a, 0);
} }
@ -44,14 +44,14 @@ TEST(alloc_two_pages___second_page_is_not_zero)
pmm_free(V2P(&mem[0])); pmm_free(V2P(&mem[0]));
pmm_free(V2P(&mem[1])); pmm_free(V2P(&mem[1]));
pmm_alloc(); pmm_alloc();
uintptr_t a = pmm_alloc(); uint64_t a = pmm_alloc();
ASSERT_NEQ_PTR(a, 0); ASSERT_NEQ_PTR(a, 0);
} }
TEST(alloc_two_pages___doesnt_return_same_page_twice) TEST(alloc_two_pages___doesnt_return_same_page_twice)
{ {
pmm_free(V2P(&mem[0])); pmm_free(V2P(&mem[0]));
pmm_free(V2P(&mem[1])); pmm_free(V2P(&mem[1]));
uintptr_t a = pmm_alloc(); uint64_t a = pmm_alloc();
uintptr_t b = pmm_alloc(); uint64_t b = pmm_alloc();
ASSERT_NEQ_PTR(a, b); ASSERT_NEQ_PTR(a, b);
} }

View File

@ -1,21 +1,21 @@
#include <memory.h> #include <memory.h>
#define FLAGS_MASK (PAGE_SIZE-1) #define FLAGS_MASK (PAGE_SIZE-1)
#define MASK_FLAGS(addr) ((uintptr_t)addr & ~FLAGS_MASK) #define MASK_FLAGS(addr) ((uint64_t)addr & ~FLAGS_MASK)
union PTE { union PTE {
uint64_t value; uint64_t value;
struct { struct {
uintptr_t present:1; uint64_t present:1;
uintptr_t write:1; uint64_t write:1;
uintptr_t user:1; uint64_t user:1;
uintptr_t write_through:1; uint64_t write_through:1;
uintptr_t nocache:1; uint64_t nocache:1;
uintptr_t accessed:1; uint64_t accessed:1;
uintptr_t dirty:1; uint64_t dirty:1;
uintptr_t huge:1; uint64_t huge:1;
uintptr_t global:1; uint64_t global:1;
uintptr_t flags:3; uint64_t flags:3;
}; };
}; };
@ -25,7 +25,7 @@ union PTE {
#define P2e(pt, addr) PT(P3e(pt, addr).value)[P2_OFFSET(addr)] #define P2e(pt, addr) PT(P3e(pt, addr).value)[P2_OFFSET(addr)]
#define P1e(pt, addr) PT(P2e(pt, addr).value)[P1_OFFSET(addr)] #define P1e(pt, addr) PT(P2e(pt, addr).value)[P1_OFFSET(addr)]
int page_exists(void *P4, uintptr_t addr) static int page_exists(uint64_t P4, uint64_t addr)
{ {
if(P4 if(P4
&& P4e(P4, addr).present && P4e(P4, addr).present
@ -36,7 +36,7 @@ int page_exists(void *P4, uintptr_t addr)
return 0; return 0;
} }
uintptr_t vmm_get_page(void *P4, uintptr_t addr) uint64_t vmm_get_page(uint64_t P4, uint64_t addr)
{ {
if(page_exists(P4, addr)) if(page_exists(P4, addr))
if(P2e(P4, addr).huge) if(P2e(P4, addr).huge)
@ -47,7 +47,7 @@ uintptr_t vmm_get_page(void *P4, uintptr_t addr)
return -1; return -1;
} }
int vmm_set_page(void *P4, uintptr_t addr, uintptr_t page, uint16_t flags) int vmm_set_page(uint64_t P4, uint64_t addr, uint64_t page, uint16_t flags)
{ {
if(flags & PAGE_HUGE) if(flags & PAGE_HUGE)
{ {
@ -69,7 +69,7 @@ int vmm_set_page(void *P4, uintptr_t addr, uintptr_t page, uint16_t flags)
return 0; return 0;
} }
int touch_page(void *P4, uintptr_t addr, uint16_t flags) int touch_page(uint64_t P4, uint64_t addr, uint16_t flags)
{ {
if(!P4) return -1; if(!P4) return -1;
@ -96,7 +96,7 @@ int touch_page(void *P4, uintptr_t addr, uint16_t flags)
return 0; return 0;
} }
void free_page(void *P4, uintptr_t addr, int free) void free_page(uint64_t P4, uint64_t addr, int free)
{ {
if(!page_exists(P4, addr)) if(!page_exists(P4, addr))
return; return;

View File

@ -8,13 +8,14 @@
#include "vmm.c" #include "vmm.c"
void *data; void *data;
uintptr_t *p4, *p3, *p2, *p1; uint64_t *p4, *p3, *p2, *p1;
uint64_t P4;
#define ADDR1234 ((1UL<<39) + (2UL<<30) + (3UL<<21) + (4UL<<12)) #define ADDR1234 ((1UL<<39) + (2UL<<30) + (3UL<<21) + (4UL<<12))
#define BUILD_PT(o4, o3, o2) \ #define BUILD_PT(o4, o3, o2) \
p4[(o4)] = (uintptr_t)p3; p4[(o4)] |= PAGE_PRESENT; \ p4[(o4)] = (uint64_t)p3; p4[(o4)] |= PAGE_PRESENT; \
p3[(o3)] = (uintptr_t)p2; p3[(o3)] |= PAGE_PRESENT; \ p3[(o3)] = (uint64_t)p2; p3[(o3)] |= PAGE_PRESENT; \
p2[(o2)] = (uintptr_t)p1; p2[(o2)] |= PAGE_PRESENT; p2[(o2)] = (uint64_t)p1; p2[(o2)] |= PAGE_PRESENT;
BEFORE() BEFORE()
{ {
@ -23,6 +24,7 @@ BEFORE()
p3 = &p4[512]; p3 = &p4[512];
p2 = &p4[1024]; p2 = &p4[1024];
p1 = &p4[1536]; p1 = &p4[1536];
P4 = (uint64_t)p4;
} }
AFTER() AFTER()
{ {
@ -34,7 +36,7 @@ TEST(get_page_returns_correct_address)
BUILD_PT(0,0,0); BUILD_PT(0,0,0);
p1[0] = 0x1234567890ABC000 | PAGE_PRESENT; p1[0] = 0x1234567890ABC000 | PAGE_PRESENT;
uintptr_t ret = vmm_get_page(p4, 0); uint64_t ret = vmm_get_page(P4, 0);
ASSERT_EQ_PTR(ret, 0x1234567890ABC000 | PAGE_PRESENT); ASSERT_EQ_PTR(ret, 0x1234567890ABC000 | PAGE_PRESENT);
} }
@ -43,7 +45,7 @@ TEST(get_page_ignores_flags)
BUILD_PT(0,0,0); BUILD_PT(0,0,0);
p1[0] = 0x1234567890ABC000 | PAGE_PRESENT; p1[0] = 0x1234567890ABC000 | PAGE_PRESENT;
uintptr_t ret = vmm_get_page(p4, 0); uint64_t ret = vmm_get_page(P4, 0);
ASSERT_EQ_PTR(ret, 0x1234567890ABC000 | PAGE_PRESENT); ASSERT_EQ_PTR(ret, 0x1234567890ABC000 | PAGE_PRESENT);
} }
@ -52,27 +54,27 @@ TEST(get_page_works_for_different_address)
BUILD_PT(1,2,3) BUILD_PT(1,2,3)
p1[4] = 0x34567890ABCDE000 | PAGE_PRESENT; p1[4] = 0x34567890ABCDE000 | PAGE_PRESENT;
uintptr_t ret = vmm_get_page(p4, ADDR1234); uint64_t ret = vmm_get_page(P4, ADDR1234);
ASSERT_EQ_PTR(ret, 0x34567890ABCDE000 | PAGE_PRESENT); ASSERT_EQ_PTR(ret, 0x34567890ABCDE000 | PAGE_PRESENT);
} }
TEST(get_page_fails_if_PTE_not_present) TEST(get_page_fails_if_PTE_not_present)
{ {
BUILD_PT(0,0,0); BUILD_PT(0,0,0);
p2[0] = (uintptr_t)p1; p2[0] = (uint64_t)p1;
p1[0] = 0x1234567890ABC000 | PAGE_PRESENT; p1[0] = 0x1234567890ABC000 | PAGE_PRESENT;
uintptr_t ret = vmm_get_page(p4, 0); uint64_t ret = vmm_get_page(P4, 0);
ASSERT_EQ_PTR(ret, -1); ASSERT_EQ_PTR(ret, -1);
} }
TEST(get_page_gets_2mb_pages) TEST(get_page_gets_2mb_pages)
{ {
p4[1] = (uintptr_t)p3; p4[1] |= PAGE_PRESENT; p4[1] = (uint64_t)p3; p4[1] |= PAGE_PRESENT;
p3[2] = (uintptr_t)p2; p3[2] |= PAGE_PRESENT; p3[2] = (uint64_t)p2; p3[2] |= PAGE_PRESENT;
p2[3] = 0x1234567890A00000 | PAGE_HUGE | PAGE_PRESENT; p2[3] = 0x1234567890A00000 | PAGE_HUGE | PAGE_PRESENT;
uintptr_t ret = vmm_get_page(p4, ADDR1234); uint64_t ret = vmm_get_page(P4, ADDR1234);
ASSERT_EQ_PTR(ret, 0x1234567890A00000 | PAGE_HUGE | PAGE_PRESENT); ASSERT_EQ_PTR(ret, 0x1234567890A00000 | PAGE_HUGE | PAGE_PRESENT);
} }
@ -80,7 +82,7 @@ TEST(set_page_sets_page)
{ {
BUILD_PT(0,0,0); BUILD_PT(0,0,0);
vmm_set_page(p4, 0, 0x1234567890ABC000, PAGE_PRESENT); vmm_set_page(P4, 0, 0x1234567890ABC000, PAGE_PRESENT);
ASSERT_EQ_PTR(p1[0], 0x1234567890ABC000 | PAGE_PRESENT); ASSERT_EQ_PTR(p1[0], 0x1234567890ABC000 | PAGE_PRESENT);
} }
@ -88,25 +90,25 @@ TEST(set_page_returns_success_if_working)
{ {
BUILD_PT(0,0,0); BUILD_PT(0,0,0);
int retval = vmm_set_page(p4, 0, 0x1234567890ABC000, PAGE_PRESENT); int retval = vmm_set_page(P4, 0, 0x1234567890ABC000, PAGE_PRESENT);
ASSERT_EQ_INT(retval, 0); ASSERT_EQ_INT(retval, 0);
} }
TEST(set_page_fails_if_PT_missing) TEST(set_page_fails_if_PT_missing)
{ {
BUILD_PT(0,0,0); BUILD_PT(0,0,0);
p3[0] = (uintptr_t)p2; p3[0] = (uint64_t)p2;
int retval = vmm_set_page(p4, 0, 0x1234567890ABC000, PAGE_PRESENT); int retval = vmm_set_page(P4, 0, 0x1234567890ABC000, PAGE_PRESENT);
ASSERT_NEQ_INT(retval, 0); ASSERT_NEQ_INT(retval, 0);
} }
TEST(set_page_sets_2mb_pages) TEST(set_page_sets_2mb_pages)
{ {
p4[1] = (uintptr_t)p3; p4[1] |= PAGE_PRESENT; p4[1] = (uint64_t)p3; p4[1] |= PAGE_PRESENT;
p3[2] = (uintptr_t)p2; p3[2] |= PAGE_PRESENT; p3[2] = (uint64_t)p2; p3[2] |= PAGE_PRESENT;
vmm_set_page(p4, (1UL<<39)+(2UL<<30)+(3UL<<21), 0x1234567890A00000, PAGE_HUGE | PAGE_PRESENT); vmm_set_page(P4, (1UL<<39)+(2UL<<30)+(3UL<<21), 0x1234567890A00000, PAGE_HUGE | PAGE_PRESENT);
ASSERT_EQ_PTR(p2[3], 0x1234567890A00000 | PAGE_HUGE | PAGE_PRESENT); ASSERT_EQ_PTR(p2[3], 0x1234567890A00000 | PAGE_HUGE | PAGE_PRESENT);
} }
@ -114,52 +116,52 @@ TEST(set_page_does_not_overwrite_4kb_pages_with_2mb)
{ {
BUILD_PT(0,0,0); BUILD_PT(0,0,0);
int retval = vmm_set_page(p4, 0, 0, PAGE_HUGE | PAGE_PRESENT); int retval = vmm_set_page(P4, 0, 0, PAGE_HUGE | PAGE_PRESENT);
ASSERT_NEQ_INT(retval, 0); ASSERT_NEQ_INT(retval, 0);
} }
uintptr_t pmm_calloc() uint64_t pmm_calloc()
{ {
uintptr_t *pages[] = {p3, p2, p1}; uint64_t *pages[] = {p3, p2, p1};
static int counter=0; static int counter=0;
if(counter >= 3) return 0; if(counter >= 3) return 0;
return (uintptr_t)pages[counter++]; return (uint64_t)pages[counter++];
} }
TEST(touch_page_adds_P3) TEST(touch_page_adds_P3)
{ {
touch_page(p4, ADDR1234, 0); touch_page(P4, ADDR1234, 0);
ASSERT_EQ_PTR(p4[1], (uintptr_t)p3 | PAGE_PRESENT); ASSERT_EQ_PTR(p4[1], (uint64_t)p3 | PAGE_PRESENT);
} }
TEST(touch_page_adds_P2) TEST(touch_page_adds_P2)
{ {
touch_page(p4, ADDR1234, 0); touch_page(P4, ADDR1234, 0);
ASSERT_EQ_PTR(p3[2], (uintptr_t)p2 | PAGE_PRESENT); ASSERT_EQ_PTR(p3[2], (uint64_t)p2 | PAGE_PRESENT);
} }
TEST(touch_page_adds_P1) TEST(touch_page_adds_P1)
{ {
touch_page(p4, ADDR1234, 0); touch_page(P4, ADDR1234, 0);
ASSERT_EQ_PTR(p2[3], (uintptr_t)p1 | PAGE_PRESENT); ASSERT_EQ_PTR(p2[3], (uint64_t)p1 | PAGE_PRESENT);
} }
TEST(touch_page_sets_flags) TEST(touch_page_sets_flags)
{ {
touch_page(p4, 0, PAGE_WRITE); touch_page(P4, 0, PAGE_WRITE);
ASSERT_EQ_PTR(p2[0], (uintptr_t)p1 | PAGE_WRITE | PAGE_PRESENT); ASSERT_EQ_PTR(p2[0], (uint64_t)p1 | PAGE_WRITE | PAGE_PRESENT);
} }
TEST(touch_page_fails_if_out_of_pages) TEST(touch_page_fails_if_out_of_pages)
{ {
pmm_calloc(); pmm_calloc();
int retval = touch_page(p4, 0, 0); int retval = touch_page(P4, 0, 0);
ASSERT_NEQ_INT(retval, 0); ASSERT_NEQ_INT(retval, 0);
} }
TEST(touch_page_stops_at_P2_for_huge_pages) TEST(touch_page_stops_at_P2_for_huge_pages)
{ {
touch_page(p4, 0, PAGE_HUGE); touch_page(P4, 0, PAGE_HUGE);
ASSERT_EQ_PTR(p2[0], 0); ASSERT_EQ_PTR(p2[0], 0);
} }
@ -168,7 +170,7 @@ TEST(free_page_unsets_page)
BUILD_PT(1,2,3); BUILD_PT(1,2,3);
p1[4] = PAGE_PRESENT; p1[4] = PAGE_PRESENT;
free_page(p4, ADDR1234, 0); free_page(P4, ADDR1234, 0);
ASSERT_EQ_PTR(p1[4], 0); ASSERT_EQ_PTR(p1[4], 0);
} }
@ -177,7 +179,7 @@ TEST(free_page_unsets_P2_entry_if_P1_is_empty)
BUILD_PT(1,2,3); BUILD_PT(1,2,3);
p1[4] = PAGE_PRESENT; p1[4] = PAGE_PRESENT;
free_page(p4, ADDR1234, 1); free_page(P4, ADDR1234, 1);
ASSERT_EQ_PTR(p2[3], 0); ASSERT_EQ_PTR(p2[3], 0);
} }
@ -186,7 +188,7 @@ TEST(free_page_does_not_unset_P2_entry_if_not_asked_to)
BUILD_PT(1,2,3); BUILD_PT(1,2,3);
p1[4] = PAGE_PRESENT; p1[4] = PAGE_PRESENT;
free_page(p4, ADDR1234, 0); free_page(P4, ADDR1234, 0);
ASSERT_NEQ_PTR(p2[3], 0); ASSERT_NEQ_PTR(p2[3], 0);
} }
@ -196,7 +198,7 @@ TEST(free_page_does_not_unset_P2_entry_if_P1_is_not_empty)
p1[4] = PAGE_PRESENT; p1[4] = PAGE_PRESENT;
p1[0] = PAGE_PRESENT; p1[0] = PAGE_PRESENT;
free_page(p4, ADDR1234, 1); free_page(P4, ADDR1234, 1);
ASSERT_NEQ_PTR(p2[3], 0); ASSERT_NEQ_PTR(p2[3], 0);
} }
@ -207,13 +209,13 @@ TEST(free_page_does_not_stop_if_P2_pointed_page_is_not_empty)
p1[4] = PAGE_PRESENT; p1[4] = PAGE_PRESENT;
p1[0] = PAGE_PRESENT; p1[0] = PAGE_PRESENT;
free_page(p4, ADDR1234, 1); free_page(P4, ADDR1234, 1);
ASSERT_EQ_PTR(p2[3], 0); ASSERT_EQ_PTR(p2[3], 0);
} }
uintptr_t freed[] = {0,0,0,0,0}; uint64_t freed[] = {0,0,0,0,0};
void pmm_free(uintptr_t page) void pmm_free(uint64_t page)
{ {
static int counter = 0; static int counter = 0;
freed[counter++] = page; freed[counter++] = page;
@ -223,7 +225,7 @@ TEST(free_page_returns_P1_to_PMM_if_empty)
BUILD_PT(1,2,3); BUILD_PT(1,2,3);
p1[4] = PAGE_PRESENT; p1[4] = PAGE_PRESENT;
free_page(p4, ADDR1234, 1); free_page(P4, ADDR1234, 1);
ASSERT_EQ_PTR(freed[0], p1); ASSERT_EQ_PTR(freed[0], p1);
} }