Here's the code:
Code: Select all
#include "vmem.h"
#include "kprint.h"
#include <stdint.h>
#define BASE_VADDR 0xc0000000
#define PDE_ENTRIES 1024
#define PTE_ENTRIES 1024
#define PAGE_TABLES 1024
typedef uint32_t pde_t;
typedef uint32_t pte_t;
typedef pde_t pd_t[PDE_ENTRIES];
typedef pte_t pt_t[PTE_ENTRIES];
typedef pt_t pt_arr[PDE_ENTRIES];
extern "C" pd_t _pd;
extern "C" pt_t _pt_arr[PAGE_TABLES];
template<typename T>
void inline clear_bit(T &block, int bit){
block &= ~(T)(1u << bit);
}
template<typename T>
void inline set_bit(T &block, int bit){
block |= 1u << bit;
}
template<typename T>
void inline set_bit(T &block, int bit, bool val){
if(val)
set_bit(block, bit);
else
clear_bit(block, bit);
}
uint32_t get_pd_index(void *vaddr){
return (uint32_t)vaddr >> 22;
}
uint32_t get_pt_index(void *vaddr){
return ((uint32_t)vaddr >> 12) & 0x3ff;
}
void clear_pde(pde_t &pde){
pde = 0u;
}
void clear_pte(pte_t &pte){
pte = 0u;
}
void clear_pd(pd_t pd){
for(int i = 0;i < PDE_ENTRIES;i++)
clear_pde(pd[i]);
}
void clear_pt(pt_t pt){
for(int i = 0;i < PTE_ENTRIES;i++)
clear_pte(pt[i]);
}
void set_pde_addr(uint32_t &pde, void *paddr){
pde = (pde & 0xfffu) | ((uint32_t)paddr & ~0xfffu);
}
void set_pte_addr(uint32_t &pte, void *paddr){
pte = (pte & 0xfffu) | ((uint32_t)paddr & ~0xfffu);
}
void inline set_pde_present(pde_t &pde, bool present){
set_bit(pde, 0, present);
}
void inline set_pde_user(pde_t &pde, bool user){
set_bit(pde, 2, user);
}
void inline set_pde_writable(pde_t &pde, bool writable){
set_bit(pde, 1, writable);
}
void inline set_pte_present(pte_t &pte, bool present){
set_bit(pte, 0, present);
}
void inline set_pte_user(pte_t &pte, bool user){
set_bit(pte, 2, user);
}
void inline set_pte_writable(pte_t &pte, bool writable){
set_bit(pte, 1, writable);
}
void mmap(void *vaddr, void *paddr, unsigned int length,
bool user,
bool write){
int i = 0;
while(length >= PAGESIZE){
int pd_index = get_pd_index(vaddr);
int pt_index = get_pt_index(vaddr);
set_pde_present(_pd[pd_index], true);
set_pde_user(_pd[pd_index], user);
set_pde_writable(_pd[pd_index], write);
set_pte_present(_pt_arr[pd_index][pt_index], true);
set_pte_user(_pt_arr[pd_index][pt_index], user);
set_pte_writable(_pt_arr[pd_index][pt_index], write);
set_pte_addr(_pt_arr[pd_index][pt_index], paddr);
bool debug = true;
if(debug){
kprintf("PDE: %x PD Index: %x\n", (unsigned int)_pd[pd_index], pd_index);
kprintf("PTE: %x PT Index: %x\n", (unsigned int)_pt_arr[pd_index][pt_index],
pt_index);
i++;
if(i > 4) return;
}
length -= PAGESIZE;
vaddr = (void*)((uintptr_t)vaddr + PAGESIZE);
paddr = (void*)((uintptr_t)paddr + PAGESIZE);
}
}
void load_pd(uintptr_t paddr){
kprintf("PD Addr: %x ", (unsigned int)paddr);
asm("hlt");
asm(
"mov eax, %0\n"
"mov cr3, eax\n"
"mov eax, cr0\n"
"or eax, 0x80000000\n"
"mov cr0, eax\n"
:: "r"(paddr));
asm("hlt");
};
void init_vmem(){
clear_pd(_pd);
for(int i = 0;i < PAGE_TABLES;i++){
uintptr_t pt_addr = (uintptr_t)&_pt_arr[i] + 0x40000000;
clear_pt(_pt_arr[i]);
set_pde_addr(_pd[i], (void*)pt_addr);
//kprintf("PT: %x ", (unsigned int)pt_addr);
}
// Direct map first MB.
mmap((void*)0, (void*)0, 0x100000, false, true);
// Map 64 MB (ie kernel) from vaddr 0xc0000000 to paddr 0
mmap((void*)0xc0000000, (void*)0, 0x4000000);
load_pd((uintptr_t)_pd + 0x40000000);
}
Code: Select all
c0b36000 B _pd
c0b37000 B _pt_arr