| /* See COPYRIGHT for copyright information. |
| * Inlines, macros, and most function prototypes (c) the JOS project. |
| * |
| * Actual implementation: |
| * Copyright (c) 2009 The Regents of the University of California |
| * Barret Rhoden <brho@cs.berkeley.edu> |
| * See LICENSE for details. |
| * |
| * Physical memory mangement, low-level virtual address space initialization and |
| * management, and other things related to virtual->physical mappings. |
| */ |
| |
| #pragma once |
| |
| #include <ros/memlayout.h> |
| #include <sys/queue.h> |
| #include <multiboot.h> |
| #include <atomic.h> |
| #include <process.h> |
| #include <assert.h> |
| #include <page_alloc.h> |
| #include <multiboot.h> |
| #include <arch/pmap.h> |
| |
| /* This macro takes a kernel virtual address -- an address that points above |
| * KERNBASE, where the machine's maximum 256MB of physical memory is mapped -- |
| * and returns the corresponding physical address. It panics if you pass it a |
| * non-kernel virtual address. |
| */ |
| #define PADDR(kva) \ |
| ({ \ |
| physaddr_t __m_pa, __m_kva = (physaddr_t) (kva); \ |
| if (__m_kva < KERNBASE) \ |
| panic("PADDR called with invalid kva %p", __m_kva);\ |
| if(__m_kva >= KERN_LOAD_ADDR) \ |
| __m_pa = __m_kva - KERN_LOAD_ADDR; \ |
| else \ |
| __m_pa = __m_kva - KERNBASE; \ |
| __m_pa; \ |
| }) |
| |
| #define paddr_low32(p) ((uint32_t)(uintptr_t)PADDR(p)) |
| #define paddr_high32(p) ((uint32_t)((uint64_t)PADDR(p) >> 32)) |
| |
| /* This macro takes a physical address and returns the corresponding kernel |
| * virtual address. It warns if you pass an invalid physical address. */ |
| #define KADDR(pa) \ |
| ({ \ |
| physaddr_t __m_pa = (pa); \ |
| size_t __m_ppn = LA2PPN(__m_pa); \ |
| if (__m_ppn > max_nr_pages) \ |
| warn("KADDR called with invalid pa %p", __m_pa);\ |
| (void*) (__m_pa + KERNBASE); \ |
| }) |
| |
| #define KADDR_NOCHECK(pa) ((void*)(pa + KERNBASE)) |
| #define KBASEADDR(kla) KADDR(PADDR(kla)) |
| |
| extern physaddr_t max_pmem; /* Total amount of physical memory */ |
| extern size_t max_nr_pages; /* Total number of physical memory pages */ |
| extern physaddr_t max_paddr; /* Maximum addressable physical address */ |
| extern size_t nr_free_pages; |
| extern struct multiboot_info *multiboot_kaddr; |
| extern uintptr_t boot_freemem; |
| extern uintptr_t boot_freelimit; |
| |
| /* Pages are stored in an array, including for pages that we can never touch |
| * (like reserved memory from the BIOS, fake regions, etc). Pages are reference |
| * counted, and free pages are kept on a linked list. */ |
| extern struct page *pages; |
| |
| extern physaddr_t boot_cr3; |
| extern pgdir_t boot_pgdir; |
| |
| bool enable_pse(void); |
| void vm_init(void); |
| |
| void pmem_init(struct multiboot_info *mbi); |
| void *boot_alloc(size_t amt, size_t align); |
| void *boot_zalloc(size_t amt, size_t align); |
| |
| void page_check(void); |
| int page_insert(pgdir_t pgdir, struct page *page, void *va, |
| int perm); |
| void page_remove(pgdir_t pgdir, void *va); |
| page_t* page_lookup(pgdir_t pgdir, void *va, pte_t *pte_store); |
| error_t pagetable_remove(pgdir_t pgdir, void *va); |
| void page_decref(page_t *pp); |
| |
| void tlb_invalidate(pgdir_t pgdir, void *ga); |
| void tlb_flush_global(void); |
| void tlb_shootdown_global(void); |
| bool regions_collide_unsafe(uintptr_t start1, uintptr_t end1, |
| uintptr_t start2, uintptr_t end2); |
| |
| /* Arch specific implementations for these */ |
| void map_segment(pgdir_t pgdir, uintptr_t va, size_t size, physaddr_t pa, |
| int perm, int pml_shift); |
| int unmap_segment(pgdir_t pgdir, uintptr_t va, size_t size); |
| pte_t pgdir_walk(pgdir_t pgdir, const void *va, int create); |
| int get_va_perms(pgdir_t pgdir, const void *va); |
| int arch_pgdir_setup(pgdir_t boot_copy, pgdir_t *new_pd); |
| physaddr_t arch_pgdir_get_cr3(pgdir_t pd); |
| void arch_pgdir_clear(pgdir_t *pd); |
| int arch_max_jumbo_page_shift(void); |
| void arch_add_intermediate_pts(pgdir_t pgdir, uintptr_t va, size_t len); |
| |
| static inline page_t *ppn2page(size_t ppn) |
| { |
| if (ppn >= max_nr_pages) |
| warn("%s called with ppn (%p) larger than max_nr_pages (%p)", |
| __func__, ppn, max_nr_pages); |
| return &(pages[ppn]); |
| } |
| |
| static inline ppn_t page2ppn(page_t *pp) |
| { |
| return pp - pages; |
| } |
| |
| static inline physaddr_t page2pa(page_t *pp) |
| { |
| return page2ppn(pp) << PGSHIFT; |
| } |
| |
| static inline page_t *pa2page(physaddr_t pa) |
| { |
| if (LA2PPN(pa) >= max_nr_pages) |
| warn("%s called with pa (%p) larger than max_nr_pages (%p)", |
| __func__, pa, max_nr_pages); |
| return &pages[LA2PPN(pa)]; |
| } |
| |
| static inline ppn_t pa2ppn(physaddr_t pa) |
| { |
| return pa >> PGSHIFT; |
| } |
| |
| static inline void *page2kva(page_t *pp) |
| { |
| return KADDR(page2pa(pp)); |
| } |
| |
| static inline void *ppn2kva(size_t pp) |
| { |
| return page2kva(ppn2page(pp)); |
| } |
| |
| static inline page_t* kva2page(void* addr) |
| { |
| return pa2page(PADDR(addr)); |
| } |
| |
| static inline ppn_t kva2ppn(void* addr) |
| { |
| return page2ppn(kva2page(addr)); |
| } |
| |
| static inline bool is_kaddr(void *addr) |
| { |
| return (uintptr_t)addr >= KERNBASE; |
| } |
| |
| static inline unsigned long nr_pages(size_t nr_bytes) |
| { |
| return (nr_bytes >> PGSHIFT) + (PGOFF(nr_bytes) ? 1 : 0); |
| } |
| |
| /* Including here, since these ops often rely on pmap.h helpers, which rely on |
| * the generic arch/pmap.h. It's likely that many of these ops will be inlined |
| * for speed in pmap_ops. */ |
| #include <arch/pmap_ops.h> |