From 14a029a5f23e5fbbf03e06f4ca4eb44e786b74e3 Mon Sep 17 00:00:00 2001 From: Matthias Kruk Date: Wed, 30 Dec 2020 11:33:06 +0900 Subject: [PATCH] kernel/arch: Add vm_* functions for low-level page table handling To improve portability and separate the software and hardware sides of paging more cleanly, move the low-level page table handling into a separate file. --- kernel/arch/vm.c | 890 +++++++++++++++++++++++++++++++++++++++++++++++ kernel/arch/vm.h | 16 + 2 files changed, 906 insertions(+) create mode 100644 kernel/arch/vm.c create mode 100644 kernel/arch/vm.h diff --git a/kernel/arch/vm.c b/kernel/arch/vm.c new file mode 100644 index 0000000..22f5e97 --- /dev/null +++ b/kernel/arch/vm.c @@ -0,0 +1,890 @@ +#include +#include +#include +#include +#include "frame.h" +#include "paging.h" +#include + +static inline u32_t _legacy_entry_to_paddr(u32_t addr) +{ + return(addr & 0xfffff000); +} + +static inline u32_t _legacy_addr_to_pde(u32_t addr) +{ + return((addr >> 22) & 0x3ff); +} + +static inline u32_t _legacy_pde_to_addr(u32_t pde) +{ + return(pde << 22); +} + +static inline u32_t _legacy_pde_pte_to_addr(u32_t pde, u32_t pte) +{ + return((pde << 22) | (pte << 12)); +} + +static inline u32_t _legacy_addr_to_pte(u32_t addr) +{ + return((addr >> 12) & 0x3ff); +} + +static inline u32_t _legacy_addr_to_off(u32_t addr) +{ + return(addr & 0xfff); +} + +static inline u32_t _legacy_addr_to_page(u32_t addr) +{ + return(addr & 0xfffff000); +} + +static inline u32_t _pae_pdpte_to_addr(u32_t pdpte) +{ + return(pdpte << 30); +} + +static inline u32_t _pae_pdpte_pde_to_addr(u32_t pdpte, u32_t pde) +{ + return((pdpte << 30) | (pde << 21)); +} + +static inline u32_t _pae_pdpte_pde_pte_to_addr(u32_t pdpte, u32_t pde, u32_t pte) +{ + return((pdpte << 30) | (pde << 21) | (pte << 12)); +} + +static inline u32_t _pae_addr_to_pdpte(u32_t addr) +{ + return((addr >> 30) & 0x3); +} + +static inline u32_t _pae_addr_to_pde(u32_t addr) +{ + return((addr >> 21) & 0x1ff); +} + +static inline u32_t _pae_addr_to_pte(u32_t addr) +{ + return((addr >> 12) & 0x1ff); +} + +static inline u32_t _pae_addr_to_off(u32_t addr) +{ + return(_legacy_addr_to_off(addr)); +} + +static inline u32_t _pae_addr_to_page(u32_t addr) +{ + return(_legacy_addr_to_page(addr)); +} + +static inline u64_t _pae_entry_to_paddr(u64_t pdpte) +{ + return((pdpte & 0xfffffffffffff000LL) & 0x7fffffffffffffffLL); +} + +static int _legacy_vm_new(void **dst) +{ + struct page_table *pdir; + int pg_state; + + pdir = (struct page_table*)((u32_t)frame_alloc(sizeof(*pdir), FRAME_ALLOC_4G)); + + if(!pdir) { + return(-ENOMEM); + } + + pg_state = cpu_paging_disable(); + + memset(pdir, 0, sizeof(*pdir)); + + if(pg_state) { + cpu_paging_enable(); + } + + *dst = pdir; + return(0); +} + +static int _pae_vm_new(void **dst) +{ + struct pdpt *pdpt; + int pg_state; + + pdpt = (struct pdpt*)((u32_t)frame_alloc(sizeof(*pdpt), FRAME_ALLOC_4G)); + + if(!pdpt) { + return(-ENOMEM); + } + + pg_state = cpu_paging_disable(); + + memset(pdpt, 0, sizeof(*pdpt)); + + if(pg_state) { + cpu_paging_enable(); + } + + *dst = pdpt; + return(0); +} + +int vm_new(void **dst) +{ + extern u32_t _pg_flags; + + switch(_pg_flags & PG_MODE_MASK) { + case PG_MODE_LEGACY: + return(_legacy_vm_new(dst)); + + case PG_MODE_PAE: + return(_pae_vm_new(dst)); + + default: + return(-EFAULT); + } +} + +static int _legacy_table_free(struct page_table *table) +{ + int i; + + for(i = 0; i < PAGE_TABLE_ENTRIES; i++) { + u32_t entry; + + entry = table->pt_entries[i] & PAGE_TABLE_ADDRESS_MASK; + + if(!entry) { + continue; + } + + frame_free(entry, PAGE_SIZE); + table->pt_entries[i] = 0; + } + + return(-ENOSYS); +} + +static int _legacy_vm_free(struct page_table *pdir) +{ + int i; + int pg_state; + + pg_state = cpu_paging_disable(); + + for(i = 0; i < PAGE_TABLE_ENTRIES; i++) { + u32_t entry; + + entry = pdir->pt_entries[i] & PAGE_TABLE_ADDRESS_MASK; + + if(!entry) { + continue; + } + + if(pdir->pt_entries[i] & PAGE_ATTR_SIZE) { + /* free the frames occupied by this 4M page */ + frame_free(entry, PAGE_SIZE_LARGE); + } else { + /* free the second-level paging structure */ + + _legacy_table_free((struct page_table*)entry); + } + + pdir->pt_entries[i] = 0; + } + + if(pg_state) { + cpu_paging_enable(); + } + + frame_free((u64_t)((u32_t)pdir), PAGE_SIZE); + + return(0); +} + +static int _pae_vm_free(void *pdir) +{ + frame_free((u64_t)((u32_t)pdir), PAGE_SIZE); + + return(0); +} + +int vm_free(void *vm) +{ + extern u32_t _pg_flags; + + switch(_pg_flags & PG_MODE_MASK) { + case PG_MODE_LEGACY: + return(_legacy_vm_free(vm)); + + case PG_MODE_PAE: + return(_pae_vm_free(vm)); + + default: + return(-EFAULT); + } +} + +static int _legacy_vm_map(void *vm, const u32_t paddr, const u32_t vaddr, + const u32_t size, const page_attrs_t attrs) +{ + struct page_table *pdir; + u32_t mapped_size; + u32_t cur_paddr; + u32_t cur_vaddr; + int pg_state; + int ret_val; + + ret_val = 0; + mapped_size = 0; + cur_paddr = paddr; + cur_vaddr = vaddr; + + pdir = (struct page_table*)vm; + + pg_state = cpu_paging_disable(); + + while(mapped_size < size) { + struct page_table *table; + u32_t pde; + u32_t pte; + + pde = (u32_t)cur_vaddr >> 22; + pte = ((u32_t)cur_vaddr >> 12) & 0x3ff; + + if(!(pdir->pt_entries[pde] & PAGE_ATTR_PRESENT)) { + /* + * Satisfy the mapping with a large page, if possible + */ + if((size - mapped_size) >= PAGE_SIZE_LARGE && + ALIGNED(cur_vaddr, PAGE_SIZE_LARGE) && + ALIGNED(cur_paddr, PAGE_SIZE_LARGE)) { + pdir->pt_entries[pde] = cur_paddr | PAGE_ATTR_SIZE | + PAGE_ATTR_PRESENT | attrs; + cur_paddr += PAGE_SIZE_LARGE; + cur_vaddr += PAGE_SIZE_LARGE; + mapped_size += PAGE_SIZE_LARGE; + + /* + * The rest of the loop would attempt to populate the newly + * allocated page table, which we must skip, since it's not + * necessary in this case. + */ + continue; + } else { + table = (struct page_table*)((u32_t) + frame_alloc(sizeof(*table), + FRAME_ALLOC_4G)); + + if(!table) { + ret_val = -ENOMEM; + break; + } + + memset(table, 0, sizeof(table)); + pdir->pt_entries[pde] = (u32_t)table | + PAGE_ATTR_PRESENT | attrs; + } + } else { + table = (struct page_table*)(pdir->pt_entries[pde] & + PAGE_TABLE_ADDRESS_MASK); + } + + pdir->pt_entries[pde] |= (attrs & (PAGE_ATTR_USER | + PAGE_ATTR_WRITABLE)); + + if(pdir->pt_entries[pte] & PAGE_ATTR_PRESENT) { + ret_val = -EALREADY; + break; + } + + if(!cur_paddr) { + table->pt_entries[pte] = (u32_t)frame_alloc(1, FRAME_ALLOC_4G); + } else { + table->pt_entries[pte] = cur_paddr; + cur_paddr += PAGE_SIZE; + } + + if(!table->pt_entries[pte]) { + ret_val = -ENOMEM; + break; + } + + table->pt_entries[pte] |= PAGE_ATTR_PRESENT | attrs; + cur_vaddr += PAGE_SIZE; + mapped_size += PAGE_SIZE; + } + + if(pg_state) { + cpu_paging_enable(); + } + + return(ret_val); +} + +static int _pae_vm_map(void *vm, const u64_t paddr, const u64_t vaddr, + const u64_t size, const page_attrs_t attrs) +{ + struct pdpt *pdpt; + int ret_val; + u64_t cur_paddr; + u64_t cur_vaddr; + u64_t mapped_size; + + mapped_size = 0; + ret_val = 0; + cur_paddr = paddr; + cur_vaddr = vaddr; + pdpt = (struct pdpt*)vm; + + while(mapped_size < size) { + struct pae_page_table *dir; + struct pae_page_table *tbl; + + u32_t pdpte; + u32_t pde; + u32_t pte; + + pdpte = _pae_addr_to_pdpte(cur_vaddr); + + if(!(pdpt->pdpt_entries[pdpte] & PAGE_ATTR_PRESENT)) { + dir = (struct pae_page_table*)((u32_t)frame_alloc(PAGE_SIZE, + FRAME_ALLOC_4G)); + + if(!dir) { + ret_val = -ENOMEM; + break; + } + + memset(dir, 0, sizeof(*dir)); + pdpt->pdpt_entries[pdpte] = (unsigned)dir | PAGE_ATTR_PRESENT; + } else { + dir = (struct pae_page_table*)(u32_t)_pae_entry_to_paddr(pdpt->pdpt_entries[pdpte]); + } + + pde = _pae_addr_to_pde(cur_vaddr); + + if(!(dir->ppt_entries[pde] & PAGE_ATTR_PRESENT)) { + if(size - mapped_size > PAGE_SIZE_BIG) { + /* map a big page if we have more than 2M left to map */ + + if(!cur_paddr) { + dir->ppt_entries[pde] = frame_alloc(PAGE_SIZE_BIG, 0); + dir->ppt_entries[pde] |= + PAGE_ATTR_PRESENT | PAGE_ATTR_SIZE; + + mapped_size += PAGE_SIZE_BIG; + cur_vaddr += PAGE_SIZE_BIG; + } else { + dir->ppt_entries[pde] = cur_paddr | + PAGE_ATTR_PRESENT | PAGE_ATTR_SIZE; + } + + continue; + } else { + /* + * We have less than 2M left to map, so we need to add another + * page table to map a more granular size. + */ + tbl = (struct pae_page_table*)(unsigned)frame_alloc(PAGE_SIZE, + FRAME_ALLOC_4G); + + if(!tbl) { + ret_val = -ENOMEM; + break; + } + + dir->ppt_entries[pde] = (unsigned)tbl | PAGE_ATTR_PRESENT | + attrs; + } + } else { + tbl = (struct pae_page_table*)(addr_t) + _pae_entry_to_paddr(dir->ppt_entries[pde]); + } + + pte = _pae_addr_to_pte(cur_vaddr); + + if(!(tbl->ppt_entries[pte] & PAGE_ATTR_PRESENT)) { + u64_t page; + + if(!cur_paddr) { + page = frame_alloc(PAGE_SIZE, 0); + + if(!page) { + ret_val = -ENOMEM; + break; + } + } else { + page = cur_paddr; + cur_paddr += PAGE_SIZE; + } + + tbl->ppt_entries[pte] = page | PAGE_ATTR_PRESENT | attrs; + mapped_size += PAGE_SIZE; + } + + cur_vaddr += PAGE_SIZE; + } + + return(ret_val); +} + +int vm_map(void *vm, const u64_t paddr, const u64_t vaddr, + const u64_t size, const page_attrs_t attrs) +{ + extern u32_t _pg_flags; + + switch(_pg_flags & PG_MODE_MASK) { + case PG_MODE_LEGACY: + return(_legacy_vm_map(vm, (const u32_t)paddr, (const u32_t)vaddr, + (const u32_t)size, attrs)); + + case PG_MODE_PAE: + return(_pae_vm_map(vm, paddr, vaddr, size, attrs)); + + default: + return(-EFAULT); + } +} + +static int _legacy_vm_unmap(void *vm, const u32_t vaddr, const u32_t size) +{ + struct page_table *pdir; + u32_t unmapped_size; + u32_t cur_vaddr; + int pg_state; + + pg_state = cpu_paging_disable(); + pdir = (struct page_table*)vm; + unmapped_size = 0; + cur_vaddr = vaddr; + + while(unmapped_size < size) { + struct page_table *table; + u32_t pde; + u32_t pte; + + pde = _legacy_addr_to_pde(cur_vaddr); + + /* + * Skip until the next 4M alignment if the page table isn't present + * or if the page directory entry maps a large page. + */ + if(!(pdir->pt_entries[pde] & PAGE_ATTR_PRESENT) || + (pdir->pt_entries[pde] & PAGE_ATTR_SIZE)) { + u32_t next_vaddr; + + next_vaddr = _legacy_pde_to_addr(pde + 1); + unmapped_size += next_vaddr - cur_vaddr; + cur_vaddr = next_vaddr; + + pdir->pt_entries[pde] = 0; + continue; + } + + /* + * The page directory entry referenced a present page table. Remove + * one page from the page table (we don't care if it was ever present). + */ + table = (struct page_table*)_legacy_entry_to_paddr(pdir->pt_entries[pde]); + pte = _legacy_addr_to_pte(cur_vaddr); + + table->pt_entries[pte] = 0; + unmapped_size += PAGE_SIZE; + cur_vaddr += PAGE_SIZE; + } + + if(pg_state) { + cpu_paging_enable(); + } + + return(0); +} + +static int _pae_vm_unmap(void *vm, const u64_t vaddr, const u64_t size) +{ + struct pdpt *pdpt; + u64_t unmapped_size; + u64_t cur_vaddr; + int pg_state; + + pdpt = (struct pdpt*)vm; + cur_vaddr = vaddr; + unmapped_size = 0; + + pg_state = cpu_paging_disable(); + + while(unmapped_size < size) { + struct pae_page_table *dir; + struct pae_page_table *tbl; + u32_t pdpte; + u32_t pde; + u32_t pte; + + pdpte = _pae_addr_to_pdpte(cur_vaddr); + + if(!(pdpt->pdpt_entries[pdpte] & PAGE_ATTR_PRESENT)) { + u64_t next_vaddr; + + /* PDPT entries cannot map 1G pages */ + + next_vaddr = _pae_pdpte_to_addr(pdpte + 1); + unmapped_size += next_vaddr - cur_vaddr; + cur_vaddr = next_vaddr; + + pdpt->pdpt_entries[pdpte] = 0; + continue; + } + + dir = (struct pae_page_table*)((u32_t)_pae_entry_to_paddr(pdpt->pdpt_entries[pdpte])); + pde = _pae_addr_to_pde(cur_vaddr); + + if(!(dir->ppt_entries[pde] & PAGE_ATTR_PRESENT) || + (dir->ppt_entries[pde] & PAGE_ATTR_SIZE)) { + u64_t next_vaddr; + + next_vaddr = _pae_pdpte_pde_to_addr(pdpte, pde + 1); + unmapped_size += next_vaddr - cur_vaddr; + cur_vaddr = next_vaddr; + + dir->ppt_entries[pde] = 0; + continue; + } + + tbl = (struct pae_page_table*)((u32_t)_pae_entry_to_paddr(dir->ppt_entries[pde])); + pte = _pae_addr_to_pte(cur_vaddr); + + tbl->ppt_entries[pte] = 0; + unmapped_size += PAGE_SIZE; + cur_vaddr += PAGE_SIZE; + } + + if(pg_state) { + cpu_paging_enable(); + } + + return(0); +} + +int vm_unmap(void *vm, const u64_t vaddr, const u64_t size) +{ + extern u32_t _pg_flags; + + switch(_pg_flags & PG_MODE_MASK) { + case PG_MODE_LEGACY: + return(_legacy_vm_unmap(vm, (const u32_t)vaddr, (const u32_t)size)); + + case PG_MODE_PAE: + return(_pae_vm_unmap(vm, vaddr, size)); + + default: + return(-EFAULT); + } +} + +static int _legacy_vm_debug(void *vm) +{ + return(-ENOSYS); +} + +static void _pae_page_table_debug(struct pae_page_table *table) +{ + int i; + + for(i = 0; i < sizeof_a(table->ppt_entries); i++) { + u64_t ent; + + ent = table->ppt_entries[i]; + + if(!ent) { + continue; + } + + dbg_printf(" [%02x] %016llx\n", i, ent); + } + + return; +} + +static int _pae_vm_debug(void *vm) +{ + struct pdpt *pdpt; + int pg_state; + int pdpte; + + pdpt = (struct pdpt*)vm; + + pg_state = cpu_paging_disable(); + + for(pdpte = 0; pdpte < 4; pdpte++) { + struct pae_page_table *dir; + int pde; + + dbg_printf("PDPT[%x] = %016llx\n", pdpte, pdpt->pdpt_entries[pdpte]); + dir = (struct pae_page_table*)(u32_t)_pae_entry_to_paddr(pdpt->pdpt_entries[pdpte]); + + if(!dir) { + continue; + } + + for(pde = 0; pde < 512; pde++) { + u64_t pdeent; + + pdeent = dir->ppt_entries[pde]; + + if(!pdeent) { + continue; + } + dbg_printf("PDPT[%02x][%02x] %016llx\n", pdpte, pde, pdeent); + + if(!(pdeent & PAGE_ATTR_SIZE)) { + _pae_page_table_debug((struct pae_page_table*)(addr_t) + _pae_entry_to_paddr(pdeent)); + } + } + } + + if(pg_state) { + cpu_paging_enable(); + } + + return(0); +} + +int vm_debug(void *vm) +{ + extern u32_t _pg_flags; + + switch(_pg_flags & PG_MODE_MASK) { + case PG_MODE_LEGACY: + return(_legacy_vm_debug(vm)); + + case PG_MODE_PAE: + return(_pae_vm_debug(vm)); + + default: + return(-EFAULT); + } +} + +static void _legacy_vm_debug_pagefault(void *vm, void *addr) +{ + struct page_table *dir; + int pg_state; + int pde; + + pg_state = cpu_paging_disable(); + + dir = (struct page_table*)vm; + pde = _legacy_addr_to_pde((u32_t)addr); + + dbg_printf("#PF CR2=0x%08x CR3=0x%08x\n", addr, vm); + dbg_printf("PDE 0x%03x = 0x%08x\n", pde, dir->pt_entries[pde]); + + if(dir->pt_entries[pde] & PAGE_ATTR_PRESENT && + !(dir->pt_entries[pde] & PAGE_ATTR_SIZE)) { + struct page_table *tbl; + int pte; + + tbl = (struct page_table*)_legacy_entry_to_paddr(dir->pt_entries[pde]); + pte = _legacy_addr_to_pte((u32_t)addr); + + dbg_printf("PTE 0x%03x = 0x%08x\n", pte, tbl->pt_entries[pte]); + } + + if(pg_state) { + cpu_paging_enable(); + } + + return; +} + +static void _pae_vm_debug_pagefault(void *vm, void *addr) +{ + struct pdpt *pdpt; + int pdpte; + int pg_state; + + pg_state = cpu_paging_disable(); + + pdpt = (struct pdpt*)vm; + pdpte = _pae_addr_to_pdpte((u64_t)(unsigned)addr); + + dbg_printf("#PF CR2=0x%08x CR3=0x%08x\n", addr, vm); + dbg_printf("PDPTE 0x%03x = 0x%016llx\n", pdpte, pdpt->pdpt_entries[pdpte]); + + if(pdpt->pdpt_entries[pdpte] & PAGE_ATTR_PRESENT) { + struct pae_page_table *dir; + int pde; + + dir = (struct pae_page_table*)(addr_t) + _pae_entry_to_paddr(pdpt->pdpt_entries[pdpte]); + pde = _pae_addr_to_pde((u64_t)(unsigned)addr); + + dbg_printf("PDE 0x%03x = 0x%016llx\n", pde, dir->ppt_entries[pde]); + + if(dir->ppt_entries[pde] & PAGE_ATTR_PRESENT && + !(dir->ppt_entries[pde] & PAGE_ATTR_SIZE)) { + struct pae_page_table *tbl; + int pte; + + tbl = (struct pae_page_table*)(unsigned) + _pae_entry_to_paddr(dir->ppt_entries[pde]); + pte = _pae_addr_to_pte((u64_t)(unsigned)addr); + + dbg_printf("PTE 0x%03x = 0x%016llx\n", pte, tbl->ppt_entries[pte]); + } + } + + if(pg_state) { + cpu_paging_enable(); + } + + return; +} + +void vm_debug_pagefault(void *vm, void *addr) +{ + extern u32_t _pg_flags; + + switch(_pg_flags & PG_MODE_MASK) { + case PG_MODE_LEGACY: + _legacy_vm_debug_pagefault(vm, addr); + break; + + case PG_MODE_PAE: + _pae_vm_debug_pagefault(vm, addr); + break; + + default: + break; + } + + return; +} + +int _legacy_vm_vpxlate(struct page_table *dir, const void *virt, void **phys) +{ + struct page_table *tbl; + int pde; + int pte; + + pde = _legacy_addr_to_pde((unsigned)virt); + + if(!(dir->pt_entries[pde] & PAGE_ATTR_PRESENT)) { + return(-EFAULT); + } + + tbl = (struct page_table*)(u32_t)_legacy_entry_to_paddr(dir->pt_entries[pde]); + + if(dir->pt_entries[pde] & PAGE_ATTR_SIZE) { + *phys = (void*)tbl + ((u32_t)virt & 0x3fffff); + return(0); + } + + if(!tbl) { + return(-EFAULT); + } + + pte = _legacy_addr_to_pte((unsigned)virt); + + if(!(tbl->pt_entries[pte] & PAGE_ATTR_PRESENT)) { + return(-EFAULT); + } + + *phys = (void*)((u32_t)_legacy_entry_to_paddr(tbl->pt_entries[pte]) + + _legacy_addr_to_off((unsigned)virt)); + + return(0); +} + +int _pae_vm_vpxlate(struct pdpt *pdpt, const void *virt, void **phys) +{ + struct pae_page_table *dir; + struct pae_page_table *tbl; + u64_t entry; + int pdpte; + int pde; + int pte; + + pdpte = _pae_addr_to_pdpte((u64_t)(addr_t)virt); + + if(!(pdpt->pdpt_entries[pdpte] & PAGE_ATTR_PRESENT)) { + return(-EFAULT); + } + + dir = (struct pae_page_table*)(addr_t)_pae_addr_to_pde((u64_t)(addr_t)virt); + + if(!dir) { + return(-EFAULT); + } + + pde = _pae_addr_to_pde((u64_t)(addr_t)virt); + entry = dir->ppt_entries[pde]; + + if(!(entry & PAGE_ATTR_PRESENT)) { + return(-EFAULT); + } + + tbl = (struct pae_page_table*)(addr_t)_pae_entry_to_paddr(entry); + + if(!tbl) { + return(-EFAULT); + } + + if(entry & PAGE_ATTR_SIZE) { + *phys = (void*)tbl + ((u64_t)(addr_t)virt & 0x1fffff); + return(0); + } + + pte = _pae_addr_to_pte((u64_t)(addr_t)virt); + entry = tbl->ppt_entries[pte]; + + if(!(entry & PAGE_ATTR_PRESENT)) { + return(-EFAULT); + } + + *phys = (void*)(addr_t)_pae_entry_to_paddr(entry) + _pae_addr_to_off((u64_t)(addr_t)virt); + return(0); +} + +/* + * vm_vpxlate() - Translate a virtual address to a physical address + * + * SYNOPSIS + * int vm_vpxlate(void *vm, u64_t virt, u64_t *phys); + * + * DESCRIPTION + * The vm_vpxlate() function performs a translation of the virtual address specified by `virt' + * within the page directory pointed to by `vm' and stores the result at the address pointed + * to by `phys'. The translation is performed essentially the same way as the MMU would have + * done it, except in software. This operation is costly and should be used sparingly. + * + * RETURN VALUE + * On success, zero is returned. Otherwise, a negative error number is returned and the memory + * pointed to by `phys' is left untouched. + * + * ERRORS + * -EFAULT The page pointed to by `virt' is not present in the page directory + * -ENOSYS The current paging mode is not supported + */ +int vm_vpxlate(void *vm, const void *virt, void **phys) +{ + extern u32_t _pg_flags; + + switch(_pg_flags & PG_MODE_MASK) { + case PG_MODE_LEGACY: + return(_legacy_vm_vpxlate((struct page_table*)vm, virt, phys)); + + case PG_MODE_PAE: + return(_pae_vm_vpxlate((struct pdpt*)vm, virt, phys)); + + default: + break; + } + + return(-EFAULT); +} diff --git a/kernel/arch/vm.h b/kernel/arch/vm.h new file mode 100644 index 0000000..389bb68 --- /dev/null +++ b/kernel/arch/vm.h @@ -0,0 +1,16 @@ +#ifndef __VM_H +#define __VM_H + +#include +#include + +int vm_new(void **vm); +int vm_free(void *vm); + +int vm_map(void *vm, const u64_t paddr, const u64_t vaddr, + const u64_t size, const page_attrs_t attrs); +int vm_unmap(void *vm, const u64_t vaddr, const u64_t size); + +void vm_debug_pagefault(void *vm, void *addr); + +#endif /* __VM_H */ -- 2.47.3