1/* 2 * Copyright (c) 2015, ETH Zurich. 3 * All rights reserved. 4 * 5 * This file is distributed under the terms in the attached LICENSE file. 6 * If you do not find this file, copies can be found by writing to: 7 * ETH Zurich D-INFK, Universitaetstr 6, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10#include <stdio.h> 11#include <barrelfish/ram_alloc.h> 12#include "nestedpaging.h" 13 14// allocate real vnode 15static errval_t allocate_vnode(enum objtype type, struct capref *vnode, void **mapped) 16{ 17 errval_t err; 18 struct capref vnode_ram, vnode_cap; 19 err = ram_alloc(&vnode_ram, BASE_PAGE_BITS); 20 if (err_is_fail(err)) { 21 return err; 22 } 23 err = slot_alloc(&vnode_cap); 24 if (err_is_fail(err)) { 25 return err; 26 } 27 assert(type == ObjType_VNode_x86_64_pdpt || 28 type == ObjType_VNode_x86_64_pdir || 29 type == ObjType_VNode_x86_64_ptable); 30 err = cap_retype(vnode_cap, vnode_ram, 0, type, 0, 1); 31 if (err_is_fail(err)) { 32 return err; 33 } 34 err = cap_destroy(vnode_ram); 35 if (err_is_fail(err)) { 36 return err; 37 } 38 *vnode = vnode_cap; 39 40 struct capref vnode_map; 41 err = slot_alloc(&vnode_map); 42 if (err_is_fail(err)) { 43 return err; 44 } 45 err = cap_copy(vnode_map, vnode_cap); 46 if (err_is_fail(err)) { 47 return err; 48 } 49 50 assert(mapped); 51 err = vspace_map_one_frame_attr(mapped, BASE_PAGE_SIZE, vnode_map, 52 VREGION_FLAGS_READ_WRITE, NULL, NULL); 53 if (err_is_fail(err)) { 54 return err; 55 } 56 57 return SYS_ERR_OK; 58} 59 60// allocate 8kB 61// first 4kB: HW table 62// second 4kB: SW table 63static errval_t allocate_user_vnode(struct capref *vnode, void **mapped) 64{ 65 errval_t err; 66 struct capref vnode_cap; 67 err = frame_alloc(&vnode_cap, 2*BASE_PAGE_BITS); 68 if (err_is_fail(err)) { 69 return err; 70 } 71 *vnode = vnode_cap; 72 assert(mapped); 73 err = vspace_map_one_frame_attr(mapped, BASE_PAGE_SIZE, vnode_cap, 74 VREGION_FLAGS_READ_WRITE, NULL, NULL); 75 if (err_is_fail(err)) { 76 return err; 77 } 78 79 return SYS_ERR_OK; 80} 81 82 83extern errval_t vspace_add_vregion(struct vspace *vspace, struct vregion *region); 84errval_t install_user_managed_pdpt(struct pml4_entry *retentry) 85{ 86 errval_t err; 87 assert(retentry); 88 printf("Installing our own page tables\n"); 89 struct pmap *p = get_current_pmap(); 90 struct memobj m; 91 // full pml4 entry 92 m.size = 512ULL * 1024 * 1024 * 1024; 93 genvaddr_t base; 94 err = p->f.determine_addr(p, &m, m.size, &base); 95 if (err_is_fail(err)) { 96 return err; 97 } 98 printf("base: %"PRIxGENVADDR"\n", base); 99 100 struct vregion ours; 101 ours.base = base; 102 ours.size = m.size; 103 vspace_add_vregion(get_current_vspace(), &ours); 104 105 struct capref pdpt_cap; 106 void *ptable; 107 err = allocate_vnode(ObjType_VNode_x86_64_pdpt, &pdpt_cap, &ptable); 108 if (err_is_fail(err)) { 109 return err; 110 } 111 printf("pdpt mapped at %p\n", ptable); 112 113 struct capref pml4 = (struct capref) { 114 .cnode = cnode_page, 115 .slot = 0 116 }; 117 size_t pml4e = X86_64_PML4_BASE(base); 118 printf("our pml4e is: %zu\n", pml4e); 119 err = vnode_map(pml4, pdpt_cap, pml4e, PTABLE_ACCESS_DEFAULT, 0, 1); 120 if (err_is_fail(err)) { 121 return err; 122 } 123 124 // fill out retentry struct 125 retentry->addr = ptable; 126 retentry->cap = pdpt_cap; 127 retentry->entry = pml4e; 128 129 struct capref swt; 130 size_t retsize; 131 err = frame_alloc(&swt, BASE_PAGE_SIZE, &retsize); 132 if (err_is_fail(err)) { 133 return err; 134 } 135 err = vspace_map_one_frame((void**)&retentry->swtable, BASE_PAGE_SIZE, 136 swt, NULL, NULL); 137 if (err_is_fail(err)) { 138 return err; 139 } 140 141 return SYS_ERR_OK; 142} 143 144errval_t user_managed_map_frame(struct pml4_entry *pdpt, 145 genvaddr_t vaddr, 146 struct capref frame, 147 vregion_flags_t flags) 148{ 149 assert(pdpt); 150 errval_t err; 151 152 size_t pdpte = X86_64_PDPT_BASE(vaddr); 153 size_t pdire = X86_64_PDIR_BASE(vaddr); 154 size_t pte = X86_64_PTABLE_BASE(vaddr); 155 156 printf("mapping at pdpte %zu, pdire %zu, pte %zu\n", 157 pdpte, pdire, pte); 158 159 struct frame_identity fi; 160 err = frame_identify(frame, &fi); 161 162 size_t fsize = (1ULL << fi.bits); 163 size_t npages = fsize / BASE_PAGE_SIZE; 164 size_t npdires = fsize / LARGE_PAGE_SIZE; 165 size_t npdptes = fsize / HUGE_PAGE_SIZE; 166 if (npdires == 0) { npdires = 1; } 167 if (npdptes == 0) { npdptes = 1; } 168 printf("mapping %zu pages, %zu pdires, %zu pdptes\n", 169 npages, npdires, npdptes); 170 171 paging_x86_64_flags_t pmap_flags = vregion_to_pmap(flags); 172 173 assert(npdptes == 1); 174 assert(npdires <= 512); 175 176 struct frame_identity ti; 177 178 union x86_64_pdir_entry *pdir = NULL; 179 if (!pdpt->swtable[pdpte]) { 180 // need to get pdir 181 struct capref pdir_cap; 182 void *vpdir; 183 err = allocate_user_vnode(&pdir_cap, &vpdir); 184 if (err_is_fail(err)) { 185 return err; 186 } 187 err = frame_identify(pdir_cap, &ti); 188 assert(err_is_ok(err)); 189 union x86_64_pdir_entry *pdpt_ptr = pdpt->addr; 190 // map new pdir in hw pdpt 191 paging_x86_64_map_table(&pdpt_ptr[pdpte], ti.base); 192 // map new pdir in sw pdpt 193 pdpt->swtable[pdpte] = vpdir; 194 } else { 195 assert(pdpt->swtable[pdpte]); 196 pdir = pdpt->swtable[pdpte]; 197 } 198 assert(pdir); 199 union x86_64_pdir_entry *swpdir = pdir + PTABLE_SIZE; 200 201 genpaddr_t offset = 0; 202 for (int i = pdire; i < pdire + npdires; i++) { 203 void *pt = NULL; 204 if (i == 0 || i == pdire + npdires - 1) { 205 // first/last pt 206 if (!swpdir[i]) { 207 // get ptable 208 struct capref pt_cap; 209 void *vpt; 210 err = allocate_user_vnode(&pt_cap, &vpt); 211 if (err_is_fail(err)) { 212 return err; 213 } 214 err = frame_identify(pt_cap, &ti); 215 assert(err_is_ok(err)); 216 // map new ptable in hw pdir 217 paging_x86_64_map_table(&pdir[i], ti.base); 218 // map new ptable in sw pdir 219 swpdir[i] = vpt; 220 } else { 221 assert(swpdir[i]); 222 pt = swpdir[i]; 223 } 224 assert(pt); 225 226 size_t first_e = i ? 0 : pte; 227 assert(first_e < PTABLE_SIZE); 228 size_t map_here = npages < PTABLE_SIZE ? npages : PTABLE_SIZE; 229 for (int j = first_e; j < first_e + map_here; j++) { 230 paging_x86_64_map(&pt[j], fi.base + offset, pmap_flags); 231 offset += BASE_PAGE_SIZE; 232 npages -= 1; 233 } 234 } else { 235 // full leaf: map as 2M page 236 assert(swpdir[i] == NULL); 237 union x86_64_ptable_entry *pde = (union x86_64_ptable_entry *)swpdir[i]; 238 paging_x86_64_map_large(pde, fi.base + offset, pmap_flags); 239 offset += LARGE_PAGE_SIZE; 240 npages -= PTABLE_SIZE; 241 } 242 } 243 244 return SYS_ERR_OK; 245} 246