1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13#include <autoconf.h> 14#include <sel4utils/gen_config.h> 15 16#include <inttypes.h> 17#include <sel4/sel4.h> 18#include <vka/object.h> 19#include <vka/capops.h> 20#include <sel4utils/mapping.h> 21#include <sel4utils/util.h> 22#include <vspace/mapping.h> 23 24static int map_page(vka_t *vka, vspace_map_page_fn_t map_page_fn, vspace_get_map_obj_fn map_obj_fn, 25 seL4_CPtr root, seL4_CPtr frame, void *vaddr, seL4_CapRights_t rights, 26 int cacheable, vka_object_t *objects, int *num_objects) 27{ 28 int n; 29 if (!num_objects) { 30 num_objects = &n; 31 } 32 33 if (!vka || !root) { 34 return EINVAL; 35 } 36 37 seL4_ARCH_VMAttributes attr = cacheable ? seL4_ARCH_Default_VMAttributes : 38 seL4_ARCH_Uncached_VMAttributes; 39 40 *num_objects = 0; 41 int error = map_page_fn(frame, root, (seL4_Word) vaddr, rights, attr); 42 while (error == seL4_FailedLookup) { 43 vspace_map_obj_t obj = {0}; 44 error = map_obj_fn(seL4_MappingFailedLookupLevel(), &obj); 45 /* we should not get an incorrect values for seL4_MappingFailedLookupLevel */ 46 assert(error == 0); 47 48 vka_object_t object; 49 error = vka_alloc_object(vka, obj.type, obj.size_bits, &object); 50 if (objects) { 51 objects[*num_objects] = object; 52 } 53 if (error) { 54 ZF_LOGE("Mapping structure allocation failed"); 55 return error; 56 } 57 58 error = vspace_map_obj(&obj, object.cptr, root, 59 (seL4_Word)vaddr, seL4_ARCH_Default_VMAttributes); 60 if (error == seL4_DeleteFirst) { 61 /* this is the case where the allocation of the page table needed to map in 62 * a page table for the meta data, so delete this one and continue */ 63 vka_free_object(vka, &object); 64 } else { 65 (*num_objects)++; 66 if (error) { 67 ZF_LOGE("Failed to map page table %d", error); 68 return error; 69 } 70 } 71 error = map_page_fn(frame, root, (seL4_Word) vaddr, rights, attr); 72 } 73 if (error != seL4_NoError) { 74 ZF_LOGE("Failed to map page at address %p with cap %"PRIuPTR", error: %d", vaddr, frame, error); 75 } 76 return error; 77} 78 79int sel4utils_map_page(vka_t *vka, seL4_CPtr vspace_root, seL4_CPtr frame, void *vaddr, 80 seL4_CapRights_t rights, int cacheable, vka_object_t *objects, int *num_objects) 81{ 82 return map_page(vka, seL4_ARCH_Page_Map, vspace_get_map_obj, vspace_root, frame, vaddr, rights, 83 cacheable, objects, num_objects); 84} 85 86#ifndef CONFIG_ARCH_RISCV 87int sel4utils_map_iospace_page(vka_t *vka, seL4_CPtr iospace, seL4_CPtr frame, seL4_Word vaddr, 88 seL4_CapRights_t rights, int cacheable, seL4_Word size_bits, 89 vka_object_t *pts, int *num_pts) 90{ 91 return map_page(vka, vspace_iospace_map_page, vspace_get_iospace_map_obj, iospace, frame, (void *) vaddr, rights, 92 cacheable, pts, num_pts); 93} 94#endif /* CONFIG_ARCH_RISCV */ 95#ifdef CONFIG_VTX 96 97/*map a frame into guest os's physical address space*/ 98int sel4utils_map_ept_page(vka_t *vka, seL4_CPtr pd, seL4_CPtr frame, seL4_Word vaddr, 99 seL4_CapRights_t rights, int cacheable, seL4_Word size_bits, 100 vka_object_t *pagetable, vka_object_t *pagedir, vka_object_t *pdpt) 101{ 102 vka_object_t objects[3]; 103 int num_objects; 104 int error = map_page(vka, seL4_X86_Page_MapEPT, vspace_get_ept_map_obj, pd, frame, (void *) vaddr, rights, cacheable, 105 objects, 106 &num_objects); 107 *pagetable = objects[0]; 108 *pagedir = objects[1]; 109 *pdpt = objects[2]; 110 return error; 111} 112 113#endif /* CONFIG_VTX */ 114 115/* Some more generic routines for helping with mapping */ 116void *sel4utils_dup_and_map(vka_t *vka, vspace_t *vspace, seL4_CPtr page, size_t size_bits) 117{ 118 cspacepath_t page_path; 119 cspacepath_t copy_path; 120 /* First need to copy the cap */ 121 int error = vka_cspace_alloc_path(vka, ©_path); 122 if (error != seL4_NoError) { 123 return NULL; 124 } 125 vka_cspace_make_path(vka, page, &page_path); 126 error = vka_cnode_copy(©_path, &page_path, seL4_AllRights); 127 if (error != seL4_NoError) { 128 vka_cspace_free(vka, copy_path.capPtr); 129 return NULL; 130 } 131 /* Now map it in */ 132 void *mapping = vspace_map_pages(vspace, ©_path.capPtr, NULL, seL4_AllRights, 1, size_bits, 1); 133 if (!mapping) { 134 vka_cnode_delete(©_path); 135 vka_cspace_free(vka, copy_path.capPtr); 136 return NULL; 137 } 138 return mapping; 139} 140 141void sel4utils_unmap_dup(vka_t *vka, vspace_t *vspace, void *mapping, size_t size_bits) 142{ 143 /* Grab a copy of the cap */ 144 seL4_CPtr copy = vspace_get_cap(vspace, mapping); 145 cspacepath_t copy_path; 146 assert(copy); 147 /* now free the mapping */ 148 vspace_unmap_pages(vspace, mapping, 1, size_bits, VSPACE_PRESERVE); 149 /* delete and free the cap */ 150 vka_cspace_make_path(vka, copy, ©_path); 151 vka_cnode_delete(©_path); 152 vka_cspace_free(vka, copy); 153} 154