diff options
author | Andrew Waterman <andrew@sifive.com> | 2021-03-17 00:30:12 -0700 |
---|---|---|
committer | Andrew Waterman <andrew@sifive.com> | 2021-03-25 22:21:06 -0700 |
commit | b9eba474fb52dbf205c7b466af458397a7487216 (patch) | |
tree | e203753f33c579d163b9c94bffa1d50c92c21b65 /pk/mmap.c | |
parent | 0b5ef9cf755811e6a8a2901585f3ecb5604e55f1 (diff) | |
download | pk-b9eba474fb52dbf205c7b466af458397a7487216.zip pk-b9eba474fb52dbf205c7b466af458397a7487216.tar.gz pk-b9eba474fb52dbf205c7b466af458397a7487216.tar.bz2 |
pk: support >2 GiB of user memory for RV64
Previously, the pk would always run from virtual address MEM_START.
Instead, remap it into the negative virtual addresses, allowing user
processes to expand beyond MEM_START.
Diffstat (limited to 'pk/mmap.c')
-rw-r--r-- | pk/mmap.c | 35 |
1 files changed, 21 insertions, 14 deletions
@@ -10,6 +10,8 @@ #include <stdbool.h> #include <errno.h> +uintptr_t kva2pa_offset; + typedef struct vmr_t { struct vmr_t* next; uintptr_t addr; @@ -68,7 +70,9 @@ static uintptr_t __page_alloc() node->next = NULL; page_freelist_depth--; - return (uintptr_t)memset((void*)addr, 0, RISCV_PGSIZE); + memset((void*)pa2kva(addr), 0, RISCV_PGSIZE); + + return addr; } static uintptr_t __page_alloc_assert() @@ -103,7 +107,7 @@ static vmr_t* __vmr_alloc(uintptr_t addr, size_t length, file_t* file, size_t offset, unsigned refcnt, int prot) { if (vmr_freelist_head == NULL) { - vmr_t* new_vmrs = (vmr_t*)__page_alloc(); + vmr_t* new_vmrs = (vmr_t*)pa2kva(__page_alloc()); if (new_vmrs == NULL) return NULL; @@ -161,7 +165,7 @@ static size_t pt_idx(uintptr_t addr, int level) static pte_t* __walk_internal(uintptr_t addr, int create, int level) { - pte_t* t = root_page_table; + pte_t* t = (pte_t*)pa2kva(root_page_table); for (int i = RISCV_PGLEVELS - 1; i > level; i--) { size_t idx = pt_idx(addr, i); if (unlikely(!(t[idx] & PTE_V))) { @@ -174,7 +178,7 @@ static pte_t* __walk_internal(uintptr_t addr, int create, int level) return 0; } } - t = (pte_t*)(pte_ppn(t[idx]) << RISCV_PGSHIFT); + t = (pte_t*)pa2kva(pte_ppn(t[idx]) << RISCV_PGSHIFT); } return &t[pt_idx(addr, level)]; } @@ -251,8 +255,8 @@ static int __handle_page_fault(uintptr_t vaddr, int prot) return -1; else if (!(*pte & PTE_V)) { - uintptr_t kva = __page_alloc_assert(); - uintptr_t ppn = kva / RISCV_PGSIZE; + uintptr_t ppn = __page_alloc_assert() / RISCV_PGSIZE; + uintptr_t kva = pa2kva(ppn * RISCV_PGSIZE); vmr_t* v = (vmr_t*)*pte; *pte = pte_create(ppn, prot_to_type(PROT_READ|PROT_WRITE, 0)); @@ -488,6 +492,10 @@ void populate_mapping(const void* start, size_t size, int prot) uintptr_t pk_vm_init() { + // PA space must fit within half of VA space + uintptr_t user_size = -KVA_START; + mem_size = MIN(mem_size, user_size); + extern char _end; first_free_page = ROUNDUP((uintptr_t)&_end, RISCV_PGSIZE); free_pages = (mem_size - (first_free_page - MEM_START)) / RISCV_PGSIZE; @@ -498,19 +506,18 @@ uintptr_t pk_vm_init() next_free_page = freelist_node_array_size / RISCV_PGSIZE; root_page_table = (void*)__page_alloc_assert(); - __map_kernel_range(MEM_START, MEM_START, mem_size, PROT_READ|PROT_WRITE|PROT_EXEC); + __map_kernel_range(KVA_START, MEM_START, mem_size, PROT_READ|PROT_WRITE|PROT_EXEC); - current.mmap_max = current.brk_max = MEM_START; - - size_t mem_pages = mem_size >> RISCV_PGSHIFT; - size_t stack_size = MIN(mem_pages >> 5, 2048) * RISCV_PGSIZE; - size_t stack_bottom = __do_mmap(current.mmap_max - stack_size, stack_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0); - kassert(stack_bottom != (uintptr_t)-1); - current.stack_top = stack_bottom + stack_size; + current.mmap_max = current.brk_max = user_size; flush_tlb(); write_csr(sptbr, ((uintptr_t)root_page_table >> RISCV_PGSHIFT) | SATP_MODE_CHOICE); uintptr_t kernel_stack_top = __page_alloc_assert() + RISCV_PGSIZE; + + // relocate + kva2pa_offset = KVA_START - MEM_START; + page_freelist_node_array = (void*)pa2kva(page_freelist_node_array); + return kernel_stack_top; } |