You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

127 lines
3.0 KiB
C

/* Copyright (C) 2021 fef <owo@fef.moe>. All rights reserved. */
#include <arch/page.h>
#include <arch/trap.h>
#include <gay/cdefs.h>
#include <gay/config.h>
#include <gay/errno.h>
#include <gay/kprintf.h>
#include <gay/mm.h>
#include <gay/systm.h>
#include <gay/types.h>
#include <string.h>
/*
* Initial Page Directory Pointer Table and Page Map Level 4 Table for the
* assembly startup routine (see setup64.S). Used for statically mapping the
* lowest 2 GB of physical memory into the -2 GB virtual area.
*/
__asmlink x86_pdpt_t _pdpt0;
__asmlink x86_pml4t_t _pml4t;
int map_page(uintptr_t phys, void *virt, enum pflags flags)
{
flags |= P_PRESENT;
x86_pml4te_t *pml4e = X86_PML4TE(virt);
if (!pml4e->flags.present) {
void *page = get_pages(0, M_ATOMIC);
if (page == nil)
return -ENOMEM;
pml4e->val = __p(page) | P_PRESENT | P_RW;
}
return 0;
}
/*
* The only difference between this and map_page() is that we can't allocate
* new pages using get_pages() but have to use __early_get_page() instead here.
* So, all we need to do is ensure that map_page() doesn't need to allocate new
* pages when we call it, which it only does if pflags does not have P_HUGE
* set and the page table doesn't exist (present bit in the page directory is
* clear). Therefore, we just need to make sure that, if P_HUGE is *not*
* set, the page table is already allocated and marked as present in the page
* directory.
*/
void __early_map_page(uintptr_t phys, void *virt, enum pflags pflags)
{
}
uintptr_t unmap_page(void *virt)
{
}
enum pflags get_pflags(void *page)
{
}
int set_pflags(void *page, enum pflags pflags)
{
}
void x86_isr_page_fault(trap_frame_t *frame, u32 error_code)
{
void *address;
__asm__ volatile(
" mov %%cr2, %0 \n"
: "=r"(address)
:
);
const char *space;
if (error_code & X86_PF_USER)
space = "user";
else
space = "kernel";
const char *rwx;
if (error_code & X86_PF_WRITE)
rwx = "write to";
else if (error_code & X86_PF_INSTR)
rwx = "exec at";
else
rwx = "read from";
const char *present;
if (error_code & X86_PF_PRESENT)
present = "";
else
present = " non-mapped";
kprintf("\n########## B O N K ##########\n");
kprintf("Illegal %s %s%s address %p!\n", space, rwx, present, address);
print_regs(frame);
panic("Page fault");
}
vm_paddr_t vtophys(void *virt)
{
x86_pml4te_t *pml4te = X86_PML4TE(virt);
if (!pml4te->flags.present)
return (vm_paddr_t)-1;
x86_pdpte_t *pdpte = X86_PDPTE(virt);
if (!pdpte->flags.present)
return (vm_paddr_t)-1;
if (pdpte->flags.huge) {
vm_paddr_t phys_base = pdpte->val & X86_PMAP_MASK;
return phys_base + ((vm_paddr_t)virt % (1 << X86_PDPT_SHIFT));
}
x86_pdte_t *pdte = X86_PDTE(virt);
if (!pdte->flags.present)
return (vm_paddr_t)-1;
if (pdte->flags.huge) {
vm_paddr_t phys_base = pdte->val & X86_PMAP_MASK;
return phys_base + ((vm_paddr_t)virt % (1 << X86_PDT_SHIFT));
}
x86_pte_t *pte = X86_PTE(virt);
if (!pte->flags.present)
return (vm_paddr_t)-1;
vm_paddr_t phys_base = pte->val & X86_PMAP_MASK;
return phys_base + ((vm_paddr_t)virt % (1 << X86_PT_SHIFT));
}