|
|
|
@ -61,172 +61,437 @@ extern struct pte paging_pt[512]; // paging_pt should NEVER be outside of this f
|
|
|
|
|
// paged address to read page tables
|
|
|
|
|
// the structures are not gurenteed to be ident mapped
|
|
|
|
|
// map them here with map_<type>(phys_addr) before useing structures
|
|
|
|
|
static struct pdpte *pdpt_mapped = (void *) (uintptr_t) 0x201000;
|
|
|
|
|
static struct pdpte *pd_mapped = (void *) (uintptr_t) 0x202000;
|
|
|
|
|
static struct pdpte *pt_mapped = (void *) (uintptr_t) 0x203000;
|
|
|
|
|
void *addr_mapped = (void *) (uintptr_t) 0x204000;
|
|
|
|
|
static struct pml4e *pml4_mapped = (void *) (uintptr_t) 0x200000;
|
|
|
|
|
static struct pdpte *pdpt_mapped = (void *) (uintptr_t) 0x201000;
|
|
|
|
|
static struct pde *pd_mapped = (void *) (uintptr_t) 0x202000;
|
|
|
|
|
static struct pte *pt_mapped = (void *) (uintptr_t) 0x203000;
|
|
|
|
|
|
|
|
|
|
static inline void invlpg(void *addr) {
|
|
|
|
|
static inline void
|
|
|
|
|
invlpg(void *addr)
|
|
|
|
|
{
|
|
|
|
|
__asm volatile("invlpg (%0)" ::"r" (addr) : "memory");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void map_pdpt(struct pdpte *phys_addr) {
|
|
|
|
|
paging_pt[1].address = (((uint64_t)phys_addr) >> 12);
|
|
|
|
|
paging_pt[1].flags = F_PRESENT | F_WRITEABLE;
|
|
|
|
|
invlpg(pdpt_mapped);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void map_pd(struct pde *phys_addr) {
|
|
|
|
|
paging_pt[2].address = (((uint64_t)phys_addr) >> 12);
|
|
|
|
|
paging_pt[2].flags = F_PRESENT | F_WRITEABLE;
|
|
|
|
|
invlpg(pd_mapped);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void map_pt(struct pte *phys_addr) {
|
|
|
|
|
paging_pt[3].address = (((uint64_t)phys_addr) >> 12);
|
|
|
|
|
paging_pt[3].flags = F_PRESENT | F_WRITEABLE;
|
|
|
|
|
invlpg(pt_mapped);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void map_addr(void *phys_addr) {
|
|
|
|
|
paging_pt[4].address = (((uint64_t)phys_addr) >> 12);
|
|
|
|
|
paging_pt[4].flags = F_PRESENT | F_WRITEABLE;
|
|
|
|
|
static void
|
|
|
|
|
load_addr(void *phys_addr)
|
|
|
|
|
{
|
|
|
|
|
static struct pte *pt = &paging_pt[4];
|
|
|
|
|
pt->address = (uint64_t)phys_addr >> 12;
|
|
|
|
|
pt->flags = F_PRESENT | F_WRITEABLE;
|
|
|
|
|
invlpg(addr_mapped);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//static int get_maxphysaddr() {
|
|
|
|
|
// uint32_t eax, ebx, ecx, edx;
|
|
|
|
|
// __cpuid(0x80000008, eax, ebx, ecx, edx);
|
|
|
|
|
// return eax & 0xFF;
|
|
|
|
|
//}
|
|
|
|
|
static void
|
|
|
|
|
load_pml4(
|
|
|
|
|
void *phys
|
|
|
|
|
) {
|
|
|
|
|
static struct pte *pt = &paging_pt[0];
|
|
|
|
|
pt->address = (uint64_t)phys >> 12;
|
|
|
|
|
pt->flags = F_PRESENT | F_WRITEABLE;
|
|
|
|
|
invlpg(pml4_mapped);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//int find_phys_addr(struct pml4e *pml4, void *virt_addr, void **phys_addr) {
|
|
|
|
|
// uint64_t pml4_offset = ((uint64_t)virt_addr) >> 39;
|
|
|
|
|
// uint64_t pdpt_offset = (((uint64_t)virt_addr) >> 30) & 0x1FF;
|
|
|
|
|
// uint64_t pd_offset = (((uint64_t)virt_addr) >> 21) & 0x1FF;
|
|
|
|
|
// uint64_t pt_offset = (((uint64_t)virt_addr) >> 12) & 0x1FF;
|
|
|
|
|
// uint64_t page_offset = (((uint64_t)virt_addr) ) & 0xFFF;
|
|
|
|
|
//
|
|
|
|
|
// if (!(pml4[pml4_offset].flags & F_PRESENT))
|
|
|
|
|
// return -1;
|
|
|
|
|
// struct pdpte *pdpt = (struct pdpte *)(pml4[pml4_offset].address << 12);
|
|
|
|
|
// if (!(pdpt[pdpt_offset].flags & F_PRESENT))
|
|
|
|
|
// return -1;
|
|
|
|
|
// struct pde *pd = (struct pde *)(pdpt[pdpt_offset].address << 12);
|
|
|
|
|
// if (!(pd[pd_offset].flags & F_PRESENT))
|
|
|
|
|
// return -1;
|
|
|
|
|
// struct pte *pt = (struct pte *)(pd[pd_offset].address << 12);
|
|
|
|
|
// if (!(pt[pt_offset].flags & F_PRESENT))
|
|
|
|
|
// return -1;
|
|
|
|
|
// *phys_addr = (void *)((pt[pt_offset].address << 12) + page_offset);
|
|
|
|
|
// return 0;
|
|
|
|
|
//}
|
|
|
|
|
static void
|
|
|
|
|
load_pdpt(
|
|
|
|
|
void *phys
|
|
|
|
|
) {
|
|
|
|
|
static struct pte *pt = &paging_pt[1];
|
|
|
|
|
pt->address = (uint64_t)phys >> 12;
|
|
|
|
|
pt->flags = F_PRESENT | F_WRITEABLE;
|
|
|
|
|
invlpg(pdpt_mapped);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *curr_alloc = (void *) 0x5000;
|
|
|
|
|
static void
|
|
|
|
|
load_pd(
|
|
|
|
|
void *phys
|
|
|
|
|
) {
|
|
|
|
|
static struct pte *pt = &paging_pt[2];
|
|
|
|
|
pt->address = (uint64_t)phys >> 12;
|
|
|
|
|
pt->flags = F_PRESENT | F_WRITEABLE;
|
|
|
|
|
invlpg(pdpt_mapped);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int map_page(struct pml4e *pml4, void *virt_addr, void *phys_addr, unsigned int flags) {
|
|
|
|
|
uint64_t pml4_offset = ((uint64_t)virt_addr) >> 39;
|
|
|
|
|
uint64_t pdpt_offset = (((uint64_t)virt_addr) >> 30) & 0x1FF;
|
|
|
|
|
uint64_t pd_offset = (((uint64_t)virt_addr) >> 21) & 0x1FF;
|
|
|
|
|
uint64_t pt_offset = (((uint64_t)virt_addr) >> 12) & 0x1FF;
|
|
|
|
|
//uint64_t page_offset = (((uint64_t)virt_addr) ) & 0xFFF;
|
|
|
|
|
static void
|
|
|
|
|
load_pt(
|
|
|
|
|
void *phys
|
|
|
|
|
) {
|
|
|
|
|
static struct pte *pt = &paging_pt[3];
|
|
|
|
|
pt->address = (uint64_t)phys >> 12;
|
|
|
|
|
pt->flags = F_PRESENT | F_WRITEABLE;
|
|
|
|
|
invlpg(pt_mapped);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(pml4[pml4_offset].flags & F_PRESENT)) {
|
|
|
|
|
#define PAG_SUCCESS 0
|
|
|
|
|
#define PAG_CANNOT_ALLOC 1
|
|
|
|
|
#define PAG_NOT_PRESENT 2
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
select_pdpt(
|
|
|
|
|
void *virt,
|
|
|
|
|
unsigned int flags,
|
|
|
|
|
struct pml4e *root,
|
|
|
|
|
struct pdpte **res,
|
|
|
|
|
bool create
|
|
|
|
|
) {
|
|
|
|
|
load_pml4(root);
|
|
|
|
|
uint64_t offset = (uint64_t)virt >> 39;
|
|
|
|
|
struct pml4e *pml4e = &pml4_mapped[offset];
|
|
|
|
|
if (!(pml4e->flags & F_PRESENT)) {
|
|
|
|
|
if (!create) {
|
|
|
|
|
return PAG_NOT_PRESENT;
|
|
|
|
|
}
|
|
|
|
|
void *new_page = alloc_phys_page();
|
|
|
|
|
map_addr(new_page);
|
|
|
|
|
memset(addr_mapped, 0, 4096);
|
|
|
|
|
pml4[pml4_offset].address = ((uint64_t)new_page) >> 12;
|
|
|
|
|
if (new_page == NULL) {
|
|
|
|
|
return PAG_CANNOT_ALLOC;
|
|
|
|
|
}
|
|
|
|
|
load_addr(new_page);
|
|
|
|
|
memset(addr_mapped, 0, PAGE_SIZE);
|
|
|
|
|
pml4e->address = ((uint64_t)new_page) >> 12;
|
|
|
|
|
pml4e->flags = F_PRESENT;
|
|
|
|
|
}
|
|
|
|
|
if (flags)
|
|
|
|
|
pml4e->flags = F_PRESENT | flags;
|
|
|
|
|
*res = (struct pdpte *)(uintptr_t)(pml4e->address << 12);
|
|
|
|
|
return PAG_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
pml4[pml4_offset].flags = F_PRESENT | flags;
|
|
|
|
|
|
|
|
|
|
struct pdpte *__pdpt = (struct pdpte *)(uintptr_t)(pml4[pml4_offset].address << 12);
|
|
|
|
|
map_pdpt(__pdpt);
|
|
|
|
|
if (!(pdpt_mapped[pdpt_offset].flags & F_PRESENT)) {
|
|
|
|
|
static int
|
|
|
|
|
select_pd(
|
|
|
|
|
void *virt,
|
|
|
|
|
unsigned int flags,
|
|
|
|
|
struct pdpte *pdpt,
|
|
|
|
|
struct pde **res,
|
|
|
|
|
bool create
|
|
|
|
|
) {
|
|
|
|
|
load_pdpt(pdpt);
|
|
|
|
|
uint64_t offset = ((uint64_t)virt >> 30) & 0x1ff;
|
|
|
|
|
struct pdpte *pdpte = &pdpt_mapped[offset];
|
|
|
|
|
if (!(pdpte->flags & F_PRESENT)) {
|
|
|
|
|
if (!create) {
|
|
|
|
|
return PAG_NOT_PRESENT;
|
|
|
|
|
}
|
|
|
|
|
void *new_page = alloc_phys_page();
|
|
|
|
|
map_addr(new_page);
|
|
|
|
|
memset(addr_mapped, 0, 4096);
|
|
|
|
|
pdpt_mapped[pdpt_offset].address = ((uint64_t)new_page) >> 12;
|
|
|
|
|
if (new_page == NULL) {
|
|
|
|
|
return PAG_CANNOT_ALLOC;
|
|
|
|
|
}
|
|
|
|
|
load_addr(new_page);
|
|
|
|
|
memset(addr_mapped, 0, PAGE_SIZE);
|
|
|
|
|
pdpte->address = ((uint64_t)new_page) >> 12;
|
|
|
|
|
pdpte->flags = F_PRESENT;
|
|
|
|
|
}
|
|
|
|
|
if (flags)
|
|
|
|
|
pdpte->flags = F_PRESENT | flags;
|
|
|
|
|
*res = (struct pde *)(uintptr_t)(pdpte->address << 12);
|
|
|
|
|
return PAG_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
pdpt_mapped[pdpt_offset].flags = F_PRESENT | flags;
|
|
|
|
|
|
|
|
|
|
struct pde *__pd = (struct pde *)(uintptr_t)(pdpt_mapped[pdpt_offset].address << 12);
|
|
|
|
|
map_pd(__pd);
|
|
|
|
|
if (!(pd_mapped[pd_offset].flags & F_PRESENT)) {
|
|
|
|
|
static int
|
|
|
|
|
select_pt(
|
|
|
|
|
void *virt,
|
|
|
|
|
unsigned int flags,
|
|
|
|
|
struct pde *pd,
|
|
|
|
|
struct pte **res,
|
|
|
|
|
bool create
|
|
|
|
|
) {
|
|
|
|
|
load_pd(pd);
|
|
|
|
|
uint64_t offset = ((uint64_t)virt >> 21) & 0x1ff;
|
|
|
|
|
struct pde *pde = &pd_mapped[offset];
|
|
|
|
|
if (!(pde->flags & F_PRESENT)) {
|
|
|
|
|
if (!create) {
|
|
|
|
|
return PAG_NOT_PRESENT;
|
|
|
|
|
}
|
|
|
|
|
void *new_page = alloc_phys_page();
|
|
|
|
|
map_addr(new_page);
|
|
|
|
|
memset(addr_mapped, 0, 4096);
|
|
|
|
|
pd_mapped[pd_offset].address = ((uint64_t)new_page) >> 12;
|
|
|
|
|
if (new_page == NULL) {
|
|
|
|
|
return PAG_CANNOT_ALLOC;
|
|
|
|
|
}
|
|
|
|
|
pd_mapped[pd_offset].flags = F_PRESENT | flags;
|
|
|
|
|
|
|
|
|
|
struct pte *__pt = (struct pte *)(uintptr_t)(pd_mapped[pd_offset].address << 12);
|
|
|
|
|
map_pt(__pt);
|
|
|
|
|
pt_mapped[pt_offset].flags = F_PRESENT | flags;
|
|
|
|
|
pt_mapped[pt_offset].address = (((uint64_t)phys_addr) >> 12);
|
|
|
|
|
|
|
|
|
|
invlpg(virt_addr);
|
|
|
|
|
return 0;
|
|
|
|
|
load_addr(new_page);
|
|
|
|
|
memset(addr_mapped, 0, PAGE_SIZE);
|
|
|
|
|
pde->address = ((uint64_t)new_page) >> 12;
|
|
|
|
|
pde->flags = F_PRESENT;
|
|
|
|
|
}
|
|
|
|
|
if (flags)
|
|
|
|
|
pde->flags = F_PRESENT | flags;
|
|
|
|
|
*res = (struct pte *)(uintptr_t)(pde->address << 12);
|
|
|
|
|
return PAG_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int unmap_page(struct pml4e *pml4, void *virt_addr) {
|
|
|
|
|
uint64_t pml4_offset = ((uint64_t)virt_addr) >> 39;
|
|
|
|
|
uint64_t pdpt_offset = (((uint64_t)virt_addr) >> 30) & 0x1FF;
|
|
|
|
|
uint64_t pd_offset = (((uint64_t)virt_addr) >> 21) & 0x1FF;
|
|
|
|
|
uint64_t pt_offset = (((uint64_t)virt_addr) >> 12) & 0x1FF;
|
|
|
|
|
//uint64_t page_offset = (((uint64_t)virt_addr) ) & 0xFFF;
|
|
|
|
|
|
|
|
|
|
if (!(pml4[pml4_offset].flags & F_PRESENT))
|
|
|
|
|
return -1;
|
|
|
|
|
struct pdpte *__pdpt = (struct pdpte *)(uintptr_t)(pml4[pml4_offset].address << 12);
|
|
|
|
|
map_pdpt(__pdpt);
|
|
|
|
|
if (!(pdpt_mapped[pdpt_offset].flags & F_PRESENT))
|
|
|
|
|
return -1;
|
|
|
|
|
struct pde *__pd = (struct pde *)(uintptr_t)(pdpt_mapped[pdpt_offset].address << 12);
|
|
|
|
|
map_pd(__pd);
|
|
|
|
|
if (!(pd_mapped[pd_offset].flags & F_PRESENT))
|
|
|
|
|
return -1;
|
|
|
|
|
struct pte *__pt = (struct pte *)(uintptr_t)(pd_mapped[pd_offset].address << 12);
|
|
|
|
|
map_pt(__pt);
|
|
|
|
|
if (!(pt_mapped[pt_offset].flags & F_PRESENT))
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
pt_mapped[pt_offset].flags = 0;
|
|
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
|
for(; i < 512; i++) {
|
|
|
|
|
if (pt_mapped[i].flags & F_PRESENT)
|
|
|
|
|
break;
|
|
|
|
|
static void
|
|
|
|
|
select_page(
|
|
|
|
|
void *virt,
|
|
|
|
|
struct pte *pt,
|
|
|
|
|
struct pte **res
|
|
|
|
|
) {
|
|
|
|
|
load_pt(pt);
|
|
|
|
|
uint64_t offset = ((uint64_t)virt >> 12) & 0x1ff;
|
|
|
|
|
struct pte *page = &pt_mapped[offset];
|
|
|
|
|
*res = page;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (i == 512)
|
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
|
|
pd_mapped[pd_offset].flags = 0;
|
|
|
|
|
|
|
|
|
|
for(i = 0; i < 512; i++) {
|
|
|
|
|
if (pd_mapped[i].flags & F_PRESENT)
|
|
|
|
|
break;
|
|
|
|
|
static inline void
|
|
|
|
|
try_unmap_pml4(void) {
|
|
|
|
|
for (int i = 0; i < 512; i++) {
|
|
|
|
|
if (pml4_mapped[i].flags & F_PRESENT)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < 512; i++) {
|
|
|
|
|
if (pml4_mapped[i].address) {
|
|
|
|
|
void *addr = (void *)(uintptr_t)(pml4_mapped[i].address << 12);
|
|
|
|
|
free_phys_page(addr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (i == 512)
|
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
|
|
pdpt_mapped[pdpt_offset].flags = 0;
|
|
|
|
|
|
|
|
|
|
for(i = 0; i < 512; i++) {
|
|
|
|
|
static inline void
|
|
|
|
|
try_unmap_pdpt(void) {
|
|
|
|
|
for (int i = 0; i < 512; i++) {
|
|
|
|
|
if (pdpt_mapped[i].flags & F_PRESENT)
|
|
|
|
|
break;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < 512; i++) {
|
|
|
|
|
if (pdpt_mapped[i].address) {
|
|
|
|
|
void *addr = (void *)(uintptr_t)(pdpt_mapped[i].address << 12);
|
|
|
|
|
free_phys_page(addr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
try_unmap_pml4();
|
|
|
|
|
}
|
|
|
|
|
if (i == 512)
|
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
|
|
pml4[pml4_offset].flags = 0;
|
|
|
|
|
static inline void
|
|
|
|
|
try_unmap_pd(void) {
|
|
|
|
|
for (int i = 0; i < 512; i++) {
|
|
|
|
|
if (pd_mapped[i].flags & F_PRESENT)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < 512; i++) {
|
|
|
|
|
if (pd_mapped[i].address) {
|
|
|
|
|
void *addr = (void *)(uintptr_t)(pd_mapped[i].address << 12);
|
|
|
|
|
free_phys_page(addr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
try_unmap_pdpt();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//TODO: Return memory used for page structures
|
|
|
|
|
static inline void
|
|
|
|
|
try_unmap_pt(void) {
|
|
|
|
|
for (int i = 0; i < 512; i++) {
|
|
|
|
|
if (pt_mapped[i].flags & F_PRESENT)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < 512; i++) {
|
|
|
|
|
if (pt_mapped[i].address) {
|
|
|
|
|
void *addr = (void *)(uintptr_t)(pt_mapped[i].address << 12);
|
|
|
|
|
free_phys_page(addr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
try_unmap_pd();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
unmap_page(
|
|
|
|
|
struct pml4e *root,
|
|
|
|
|
void *virt
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
|
|
struct pdpte *pdpt;
|
|
|
|
|
struct pde *pd;
|
|
|
|
|
struct pte *pt;
|
|
|
|
|
struct pte *page;
|
|
|
|
|
|
|
|
|
|
unsigned int df = 0;
|
|
|
|
|
|
|
|
|
|
if (select_pdpt(virt, df, root, &pdpt, false))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (select_pd(virt, df, pdpt, &pd, false))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (select_pt(virt, df, pd, &pt, false))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
select_page(virt, pt, &page);
|
|
|
|
|
|
|
|
|
|
page->address = 0;
|
|
|
|
|
page->flags = 0;
|
|
|
|
|
|
|
|
|
|
try_unmap_pt();
|
|
|
|
|
|
|
|
|
|
invlpg(virt);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
unmap_pages(
|
|
|
|
|
struct pml4e *root,
|
|
|
|
|
void *virt_start,
|
|
|
|
|
long page_count
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
|
|
uint64_t pml4_o = -1,
|
|
|
|
|
pdpt_o = -1,
|
|
|
|
|
pd_o = -1;
|
|
|
|
|
|
|
|
|
|
uint64_t pml4_n,
|
|
|
|
|
pdpt_n,
|
|
|
|
|
pd_n;
|
|
|
|
|
|
|
|
|
|
struct pdpte *pdpt = NULL;
|
|
|
|
|
struct pde *pd = NULL;
|
|
|
|
|
struct pte *pt = NULL;
|
|
|
|
|
struct pte *page = NULL;
|
|
|
|
|
|
|
|
|
|
unsigned int df = 0;
|
|
|
|
|
|
|
|
|
|
void *virt;
|
|
|
|
|
|
|
|
|
|
for (long i = 0; i < page_count; i++) {
|
|
|
|
|
|
|
|
|
|
virt = (char *)virt_start + (i * PAGE_SIZE);
|
|
|
|
|
|
|
|
|
|
pml4_n = (uint64_t) virt >> 39;
|
|
|
|
|
pdpt_n = ((uint64_t) virt >> 30) & 0x1ff;
|
|
|
|
|
pd_n = ((uint64_t) virt >> 21) & 0x1ff;
|
|
|
|
|
|
|
|
|
|
if (pdpt == NULL || pml4_o != pml4_n) {
|
|
|
|
|
if (select_pdpt(virt, df, root, &pdpt, false))
|
|
|
|
|
continue;
|
|
|
|
|
pml4_o = pml4_n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pd == NULL || pdpt_o != pdpt_n) {
|
|
|
|
|
if (select_pd(virt, df, pdpt, &pd, false))
|
|
|
|
|
continue;
|
|
|
|
|
pdpt_o = pdpt_n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pt == NULL || pd_o != pd_n) {
|
|
|
|
|
if (pt) {
|
|
|
|
|
try_unmap_pt();
|
|
|
|
|
}
|
|
|
|
|
if (select_pt(virt, df, pd, &pt, false))
|
|
|
|
|
continue;
|
|
|
|
|
pd_o = pd_n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
select_page(virt, pt, &page);
|
|
|
|
|
|
|
|
|
|
page->address = 0;
|
|
|
|
|
page->flags = 0;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pt != NULL)
|
|
|
|
|
try_unmap_pt();
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
map_page(
|
|
|
|
|
struct pml4e *root,
|
|
|
|
|
void *virt,
|
|
|
|
|
void *phys,
|
|
|
|
|
unsigned int flags
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
|
|
struct pdpte *pdpt;
|
|
|
|
|
struct pde *pd;
|
|
|
|
|
struct pte *pt;
|
|
|
|
|
struct pte *page;
|
|
|
|
|
|
|
|
|
|
unsigned int df = F_WRITEABLE;
|
|
|
|
|
|
|
|
|
|
if (select_pdpt(virt, df, root, &pdpt, true))
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
if (select_pd(virt, df, pdpt, &pd, true))
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
if (select_pt(virt, df, pd, &pt, true))
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
select_page(virt, pt, &page);
|
|
|
|
|
|
|
|
|
|
page->address = (uint64_t)phys >> 12;
|
|
|
|
|
page->flags = F_PRESENT | flags;
|
|
|
|
|
invlpg(virt);
|
|
|
|
|
|
|
|
|
|
done:
|
|
|
|
|
invlpg(virt_addr);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
map_pages(
|
|
|
|
|
struct pml4e *root,
|
|
|
|
|
void *virt_start,
|
|
|
|
|
void *phys_start,
|
|
|
|
|
unsigned int flags,
|
|
|
|
|
long page_count
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
|
|
uint64_t pml4_o = -1,
|
|
|
|
|
pdpt_o = -1,
|
|
|
|
|
pd_o = -1;
|
|
|
|
|
|
|
|
|
|
uint64_t pml4_n,
|
|
|
|
|
pdpt_n,
|
|
|
|
|
pd_n;
|
|
|
|
|
|
|
|
|
|
struct pdpte *pdpt = NULL;
|
|
|
|
|
struct pde *pd = NULL;
|
|
|
|
|
struct pte *pt = NULL;
|
|
|
|
|
struct pte *page = NULL;
|
|
|
|
|
|
|
|
|
|
void *virt, *phys;
|
|
|
|
|
|
|
|
|
|
unsigned int df = F_WRITEABLE;
|
|
|
|
|
|
|
|
|
|
long i;
|
|
|
|
|
for (i = 0; i < page_count; i++) {
|
|
|
|
|
|
|
|
|
|
virt = (char *)virt_start + (i * PAGE_SIZE);
|
|
|
|
|
phys = (char *)phys_start + (i * PAGE_SIZE);
|
|
|
|
|
|
|
|
|
|
pml4_n = (uint64_t) virt >> 39;
|
|
|
|
|
pdpt_n = ((uint64_t) virt >> 30) & 0x1ff;
|
|
|
|
|
pd_n = ((uint64_t) virt >> 21) & 0x1ff;
|
|
|
|
|
|
|
|
|
|
if (pdpt == NULL || pml4_o != pml4_n) {
|
|
|
|
|
if (select_pdpt(virt, df, root, &pdpt, true))
|
|
|
|
|
goto failed;
|
|
|
|
|
pml4_o = pml4_n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pd == NULL || pdpt_o != pdpt_n) {
|
|
|
|
|
if (select_pd(virt, df, pdpt, &pd, true))
|
|
|
|
|
goto failed;
|
|
|
|
|
pdpt_o = pdpt_n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pt == NULL || pd_o != pd_n) {
|
|
|
|
|
if (select_pt(virt, df, pd, &pt, true))
|
|
|
|
|
goto failed;
|
|
|
|
|
pd_o = pd_n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
select_page(virt, pt, &page);
|
|
|
|
|
|
|
|
|
|
page->address = (uint64_t)phys >> 12;
|
|
|
|
|
page->flags = F_PRESENT | flags;
|
|
|
|
|
invlpg(virt);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
failed:
|
|
|
|
|
|
|
|
|
|
unmap_pages(root, virt, i);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void paging_init(void) {
|
|
|
|
|
|
|
|
|
|
kernel_pml4[0].flags = F_PRESENT | F_WRITEABLE;
|
|
|
|
@ -260,21 +525,24 @@ void *mmap(void *addr, size_t len) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
void *phys = page_align(addr);
|
|
|
|
|
for (long i = 0; i < pages; i++) {
|
|
|
|
|
void *virt_temp = (char *)virt + (i * PAGE_SIZE);
|
|
|
|
|
void *phys_temp = (char *)phys + (i * PAGE_SIZE);
|
|
|
|
|
map_page(kernel_pml4, virt_temp, phys_temp, F_WRITEABLE);
|
|
|
|
|
if (map_pages(
|
|
|
|
|
kernel_pml4,
|
|
|
|
|
virt,
|
|
|
|
|
phys,
|
|
|
|
|
F_WRITEABLE,
|
|
|
|
|
pages
|
|
|
|
|
)) {
|
|
|
|
|
virtaddr_free(virt);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
map_page(kernel_pml4, virt, (void*)0x23443, F_WRITEABLE);
|
|
|
|
|
return virt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void unmap(void *addr) {
|
|
|
|
|
long pages = virtaddr_free(addr);
|
|
|
|
|
for (long i = 0; i < pages; i++) {
|
|
|
|
|
void *virt = (char *)addr + (i * PAGE_SIZE);
|
|
|
|
|
unmap_page(kernel_pml4, virt);
|
|
|
|
|
}
|
|
|
|
|
if (pages < 1)
|
|
|
|
|
return;
|
|
|
|
|
unmap_pages(kernel_pml4, addr, pages);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *alloc_pages(int count) {
|
|
|
|
@ -286,10 +554,15 @@ void *alloc_pages(int count) {
|
|
|
|
|
virtaddr_free(virt);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
|
|
|
void *virt_temp = (char *)virt + (i * PAGE_SIZE);
|
|
|
|
|
void *phys_temp = (char *)phys + (i * PAGE_SIZE);
|
|
|
|
|
map_page(kernel_pml4, virt_temp, phys_temp, F_WRITEABLE);
|
|
|
|
|
if (map_pages(
|
|
|
|
|
kernel_pml4,
|
|
|
|
|
virt,
|
|
|
|
|
phys,
|
|
|
|
|
F_WRITEABLE,
|
|
|
|
|
count
|
|
|
|
|
)) {
|
|
|
|
|
virtaddr_free(virt);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return virt;
|
|
|
|
|
}
|
|
|
|
@ -298,10 +571,7 @@ void free_page(void *virt) {
|
|
|
|
|
long pages = virtaddr_free(virt);
|
|
|
|
|
if (pages < 1)
|
|
|
|
|
return;
|
|
|
|
|
for (long i = 0; i < pages; i++) {
|
|
|
|
|
void *virt_temp = (char *)virt + (i * PAGE_SIZE);
|
|
|
|
|
unmap_page(kernel_pml4, virt_temp);
|
|
|
|
|
}
|
|
|
|
|
unmap_pages(kernel_pml4, virt, pages);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void memory_lock(void) {
|
|
|
|
@ -317,5 +587,6 @@ int kmap_page(void *virt_addr, void *phys_addr, unsigned int flags) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int kunmap_page(void *virt_addr) {
|
|
|
|
|
return unmap_page(kernel_pml4, virt_addr);
|
|
|
|
|
unmap_page(kernel_pml4, virt_addr);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|