|  | /* See COPYRIGHT for copyright information. */ | 
|  | #include <arch/arch.h> | 
|  | #include <arch/mmu.h> | 
|  |  | 
|  | #include <error.h> | 
|  | #include <sys/queue.h> | 
|  |  | 
|  | #include <assert.h> | 
|  | #include <atomic.h> | 
|  | #include <env.h> | 
|  | #include <kmalloc.h> | 
|  | #include <page_alloc.h> | 
|  | #include <pmap.h> | 
|  | #include <stdio.h> | 
|  | #include <string.h> | 
|  |  | 
|  | #warning "convert pgdir* to pgdir_t" | 
|  | pgdir_t *boot_pgdir; // Virtual address of boot time page directory | 
|  | physaddr_t boot_cr3; // Physical address of boot time page directory | 
|  |  | 
|  | // -------------------------------------------------------------- | 
|  | // Set up initial memory mappings and turn on MMU. | 
|  | // -------------------------------------------------------------- | 
|  |  | 
|  | void vm_init(void) | 
|  | { | 
|  | // we already set up our page tables before jumping | 
|  | // into the kernel, so there's not much going on here | 
|  |  | 
|  | extern pte_t l1pt[NPTENTRIES]; | 
|  | boot_pgdir = l1pt; | 
|  | boot_cr3 = PADDR(boot_pgdir); | 
|  | } | 
|  |  | 
|  | // Given 'pgdir', a pointer to a page directory, pgdir_walk returns | 
|  | // a pointer to the page table entry (PTE) for linear address 'va'. | 
|  | // This requires walking the two-level page table structure. | 
|  | // | 
|  | // If the relevant page table doesn't exist in the page directory, then: | 
|  | //    - If create == 0, pgdir_walk returns NULL. | 
|  | //    - Otherwise, pgdir_walk tries to allocate a new page table | 
|  | //	with page_alloc.  If this fails, pgdir_walk returns NULL. | 
|  | //    - Otherwise, pgdir_walk returns a pointer into the new page table. | 
|  | // | 
|  | // This is boot_pgdir_walk, but using page_alloc() instead of boot_alloc(). | 
|  | // Unlike boot_pgdir_walk, pgdir_walk can fail. | 
|  | pte_t *pgdir_walk(pgdir_t *pgdir, const void *va, int create) | 
|  | { | 
|  | pte_t *ppte; | 
|  | pte_t *pt; | 
|  |  | 
|  | pt = pgdir; | 
|  | for (int i = 0; i < NPTLEVELS - 1; i++) { | 
|  | // this code relies upon the fact that all page tables are the | 
|  | // same size | 
|  | uintptr_t idx = (uintptr_t)va >> | 
|  | (L1PGSHIFT - i * (L1PGSHIFT - L2PGSHIFT)); | 
|  | idx = idx & (NPTENTRIES - 1); | 
|  |  | 
|  | ppte = &pt[idx]; | 
|  |  | 
|  | if (*ppte & PTE_E) | 
|  | return ppte; | 
|  |  | 
|  | if (!(*ppte & PTE_T)) { | 
|  | if (!create) | 
|  | return NULL; | 
|  |  | 
|  | page_t *new_table; | 
|  | if (kpage_alloc(&new_table)) | 
|  | return NULL; | 
|  | memset(page2kva(new_table), 0, PGSIZE); | 
|  |  | 
|  | *ppte = PTD(page2pa(new_table)); | 
|  | } | 
|  |  | 
|  | pt = (pte_t *)KADDR(PTD_ADDR(*ppte)); | 
|  | } | 
|  |  | 
|  | uintptr_t idx = (uintptr_t)va >> | 
|  | (L1PGSHIFT - (NPTLEVELS - 1) * (L1PGSHIFT - L2PGSHIFT)); | 
|  | idx = idx & (NPTENTRIES - 1); | 
|  | return &pt[idx]; | 
|  | } | 
|  |  | 
|  | /* Returns the effective permissions for PTE_U, PTE_W, and PTE_P on a given | 
|  | * virtual address. */ | 
|  | int get_va_perms(pgdir_t *pgdir, const void *va) | 
|  | { | 
|  | pte_t *pte = pgdir_walk(pgdir, va, 0); | 
|  | return pte == NULL ? 0 : (*pte & (PTE_PERM | PTE_E)); | 
|  | } | 
|  |  | 
|  | void page_check(void) | 
|  | { | 
|  | } | 
|  |  | 
|  | uintptr_t gva2gpa(struct proc *p, uintptr_t cr3, uintptr_t gva) | 
|  | { | 
|  | panic("Unimplemented"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int arch_pgdir_setup(pgdir_t boot_copy, pgdir_t *new_pd) | 
|  | { | 
|  | pte_t *kpt = kpage_alloc_addr(); | 
|  | if (!kpt) | 
|  | return -ENOMEM; | 
|  | memcpy(kpt, (pte_t *)boot_copy, PGSIZE); | 
|  |  | 
|  | /* TODO: VPT/UVPT mappings */ | 
|  |  | 
|  | *new_pd = (pgdir_t)kpt; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | physaddr_t arch_pgdir_get_cr3(pgdir_t pd) | 
|  | { | 
|  | return PADDR((pte_t *)pd); | 
|  | } | 
|  |  | 
|  | void arch_pgdir_clear(pgdir_t *pd) | 
|  | { | 
|  | *pd = 0; | 
|  | } | 
|  |  | 
|  | /* Returns the page shift of the largest jumbo supported */ | 
|  | int arch_max_jumbo_page_shift(void) | 
|  | { | 
|  | #warning "What jumbo page sizes does RISC support?" | 
|  | return PGSHIFT; | 
|  | } | 
|  |  | 
|  | #warning                                                                       \ | 
|  | "Not sure where you do your PT destruction.  Be sure to not unmap any intermediate page tables for kernel mappings.  At least not the PML(n-1) maps" | 
|  |  | 
|  | void arch_add_intermediate_pts(pgdir_t pgdir, uintptr_t va, size_t len) | 
|  | { | 
|  | #error "Implement me" | 
|  | } | 
|  |  | 
|  | void map_segment(pgdir_t pgdir, uintptr_t va, size_t size, physaddr_t pa, | 
|  | int perm, int pml_shift) | 
|  | { | 
|  | #error "Implement me" | 
|  | } | 
|  |  | 
|  | int unmap_segment(pgdir_t pgdir, uintptr_t va, size_t size) | 
|  | { | 
|  | #error "Implement me" | 
|  | } |