alarm: Force unset_alarm to grab the CV lock
[akaros.git] / kern / include / pmap.h
index 0f6d8c2..b93158f 100644 (file)
@@ -4,20 +4,15 @@
  * Actual implementation:
  * Copyright (c) 2009 The Regents of the University of California
  * Barret Rhoden <brho@cs.berkeley.edu>
- * Kevin Klues <klueska@cs.berkeley.edu> (multiboot functions)
- * Andrew Waterman <waterman@cs.berkeley.edu> (memcpy_to/from_user)
- * Zach Anderson (zra@cs.berkeley.edu> (user_mem_strlcpy)
  * See LICENSE for details.
  *
  * Physical memory mangement, low-level virtual address space initialization and
  * management, and other things related to virtual->physical mappings.
  */
 
-#ifndef ROS_KERN_PMAP_H
-#define ROS_KERN_PMAP_H
+#pragma once
 
 #include <ros/memlayout.h>
-#include <ros/mman.h>
 #include <sys/queue.h>
 #include <multiboot.h>
 #include <atomic.h>
@@ -25,6 +20,7 @@
 #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 --
  */
 #define PADDR(kva)                                             \
 ({                                                             \
-       physaddr_t __m_kva = (physaddr_t) (kva);                \
+       physaddr_t __m_pa, __m_kva = (physaddr_t) (kva);                \
        if (__m_kva < KERNBASE)                                 \
-               panic("PADDR called with invalid kva %08lx", __m_kva);\
-       __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 = PPN(__m_pa);                           \
-       if (__m_ppn >= npages)                                  \
-               warn("KADDR called with invalid pa %08lx", __m_pa);\
-       (void*TRUSTED) (__m_pa + KERNBASE);                             \
+       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);                            \
 })
 
-extern char (SNT RO bootstacktop)[], (SNT RO bootstack)[];
-
-// List of physical pages
-extern page_t * RO CT(npages) pages;
-
-extern physaddr_t RO boot_cr3;
-extern pde_t *CT(NPDENTRIES) RO boot_pgdir;
-
-extern char *RO BND(end, maxaddrpa_ptr + IVY_KERNBASE) boot_freemem;
-
-void   multiboot_detect_memory(multiboot_info_t *COUNT(1) mbi);
-void   multiboot_print_memory_map(multiboot_info_t *COUNT(1) mbi);
-bool   enable_pse(void);
-void   vm_init(void);
-
-void   page_init(void);
-void   page_check(void);
-int        page_insert(pde_t *COUNT(NPDENTRIES) pgdir, page_t *pp, void *SNT va, int perm);
-void*COUNT(PGSIZE) page_insert_in_range(pde_t *COUNT(NPDENTRIES) pgdir, page_t *pp, 
-                             void *SNT vab, void *SNT vae, int perm);
-void   page_remove(pde_t *COUNT(NPDENTRIES) pgdir, void *SNT va);
-page_t*COUNT(1) page_lookup(pde_t SSOMELOCK*COUNT(NPDENTRIES) pgdir, void *SNT va, pte_t **pte_store);
-error_t        pagetable_remove(pde_t *COUNT(NPDENTRIES) pgdir, void *SNT va);
-void   page_decref(page_t *COUNT(1) pp);
-
-void setup_default_mtrrs(barrier_t* smp_barrier);
-void   tlb_invalidate(pde_t *COUNT(NPDENTRIES) pgdir, void *SNT va);
+#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);
 
-/* TODO: either move these, or make them take a pgdir */
-void * (DALLOC(len) user_mem_check) (env_t *env, const void *DANGEROUS va,
-                                     size_t len, int perm);
-
-void * (DALLOC(len) user_mem_assert)(env_t *env, const void *DANGEROUS va,
-                                     size_t len, int perm);
-
-size_t user_mem_strlcpy(env_t *env, char *NT COUNT(len - 1),
-                        const char *DANGEROUS va, size_t len, int perm);
-
-error_t
-memcpy_from_user(env_t* env, void* COUNT(len) dest,
-                 const void *DANGEROUS va, size_t len);
-
-error_t
-memcpy_to_user(env_t* env, void*DANGEROUS va,
-                 const void *COUNT(len) src, size_t len);
-                 
 /* Arch specific implementations for these */
-pte_t *pgdir_walk(pde_t *COUNT(NPDENTRIES) pgdir, const void *SNT va, int create);
-int get_va_perms(pde_t *COUNT(NPDENTRIES) pgdir, const void *SNT va);
-// TODO: should this be per process, per mm, per pgdir, etc?
-// - can't ask this question without knowing the "context"
-void *get_free_va_range(pde_t *pgdir, uintptr_t addr, size_t len);
-
-static inline page_t *SAFE ppn2page(size_t ppn)
+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 >= npages )
-               warn("ppn2page called with ppn (%08u) larger than npages", ppn);
+       if (ppn >= max_nr_pages)
+               warn("ppn2page called with ppn (%08lu) larger than max_nr_pages", ppn);
        return &(pages[ppn]);
 }
 
@@ -121,31 +122,49 @@ static inline physaddr_t page2pa(page_t *pp)
        return page2ppn(pp) << PGSHIFT;
 }
 
-static inline page_t*COUNT(1) pa2page(physaddr_t pa)
+static inline page_t *pa2page(physaddr_t pa)
 {
-       if (PPN(pa) >= npages)
-               warn("pa2page called with pa (0x%08x) larger than npages", pa);
-       return &pages[PPN(pa)];
+       if (LA2PPN(pa) >= max_nr_pages)
+               warn("pa2page called with pa (%p) larger than max_nr_pages", pa);
+       return &pages[LA2PPN(pa)];
 }
 
-static inline void*COUNT(PGSIZE) page2kva(page_t *pp)
+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*COUNT(PGSIZE) ppn2kva(size_t pp)
+static inline void *ppn2kva(size_t pp)
 {
        return page2kva(ppn2page(pp));
 }
 
-static inline page_t* kva2page(void* addr) 
+static inline page_t* kva2page(void* addr)
 {
        return pa2page(PADDR(addr));
 }
 
-static inline ppn_t kva2ppn(void* addr) 
+static inline ppn_t kva2ppn(void* addr)
 {
        return page2ppn(kva2page(addr));
 }
 
-#endif /* !ROS_KERN_PMAP_H */
+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>