bond/arch/paging.c

92 lines
2.5 KiB
C

#include <mm/phys.h>
#include <common/libkern.h>
#include <arch/pmap.h>
#include <ke/status.h>
#include "paging.h"
mm_paddr page_alloc_zero()
{
return 0;
}
/* map physical memory to virtual */
// XXX: this should undo stuff if pages are not enough
// TODO: use huge pages later (2MB + 1GB)
static int
_map_page(arch_pml4e *pml4, mm_paddr paddr, mm_paddr vaddr, uint attr)
{
int uspace = vaddr < ARCH_ML_KSPACE_START;
if (uspace && (vaddr > ARCH_ML_USPACE_END)) {
BRUTE("non-canonical vaddr");
}
/* must be 4k aligned */
if((paddr & (ARCH_KPAGE_SZ - 1)) != 0 ||
(vaddr & (ARCH_KPAGE_SZ - 1)) != 0 ){
BRUTE("addresses not aligned");
}
mm_paddr alloc_pt;
arch_pml4e *pml4_ent = pml4 + PML4_ENTRY_NUM(vaddr);
if (*pml4_ent == 0) {
alloc_pt = page_alloc_zero();
if (!alloc_pt) {
BRUTE("not enough pages");
}
arch_write_page_entry(pml4_ent, alloc_pt, PML4E_ATTR_RW | PML4E_ATTR_P | (uspace ? PML4E_ATTR_US : 0));
}
arch_pdpte *pdpt_ent = (arch_pdpte*)arch_pmap_map(*pml4_ent, ARCH_KPAGE_SZ) + PDPT_ENTRY_NUM(vaddr);
if (*pdpt_ent == 0) {
alloc_pt = page_alloc_zero();
if (!alloc_pt) {
BRUTE("not enough pages");
}
arch_write_page_entry(pdpt_ent, alloc_pt, PDPTE_ATTR_RW | PDPTE_ATTR_P | (uspace ? PDPTE_ATTR_US : 0));
}
arch_pde *pde_ent = (arch_pdpte*)arch_pmap_map(*pdpt_ent, ARCH_KPAGE_SZ) + PD_ENTRY_NUM(vaddr);
if (*pde_ent == 0) {
alloc_pt = page_alloc_zero();
if (!alloc_pt) {
BRUTE("not enough pages");
}
arch_write_page_entry(pde_ent, alloc_pt, PDE_ATTR_RW | PDE_ATTR_P | (uspace ? PDE_ATTR_US : 0));
}
arch_pte *pte_ent = (arch_pdpte*)arch_pmap_map(*pde_ent, ARCH_KPAGE_SZ) + PT_ENTRY_NUM(vaddr);
if (*pte_ent != 0) {
BRUTE("vaddr 0x%p is already mapped", (void*)vaddr);
}
uint64 pattr = 0;
pattr |= (attr & ARCH_VADDR_ATTR_PRESENT ? PTE_ATTR_P : 0);
pattr |= (attr & ARCH_VADDR_ATTR_NX ? PTE_ATTR_NX : 0);
pattr |= (attr & ARCH_VADDR_ATTR_READONLY ? 0 : PTE_ATTR_RW);
pattr |= (attr & ARCH_VADDR_ATTR_UNCACHED ? PTE_ATTR_PCD : 0);
arch_write_page_entry(pte_ent, paddr, pattr);
return S_OK;
}
int
arch_map_vaddr(void * base, mm_paddr paddr, uintptr vaddr, usize sz, uint attr)
{
if ((sz & (ARCH_KPAGE_SZ - 1)) != 0) {
BRUTE("Unaligned size");
}
for(mm_paddr caddr = paddr; caddr < paddr + sz; caddr += ARCH_KPAGE_SZ) {
_map_page(base, paddr, vaddr, attr);
}
return S_OK;
}