1/* 2 * Copyright 2016, 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(D61_BSD) 11 */ 12 13#include "../../common.h" 14#include "../../state.h" 15#include "pagedir.h" 16#include <sel4utils/mapping.h> 17 18/*! @file 19 @brief Static page directory allocator. 20 21 This procserv module is responsible for allocation and deallocation of client kernel page 22 directory objects, and root cnode objects. Because these objects are really big, continually 23 allocating and re-allocating them could fail due to memory fragmentation. 24*/ 25 26#define PD_ID_BASE 1 27 28void 29pd_init(struct pd_list *pdlist) 30{ 31 assert(pdlist); 32 33 /* Initialise the allocation pool. */ 34 dprintf("Initialising static Page Directory pool (sized %d)...\n", PD_MAX); 35 cpool_init(&pdlist->PDpool, PD_ID_BASE, PD_ID_BASE + PD_MAX); 36 37 /* Statically allocate the page directories. */ 38 for (int i = 0; i < PD_MAX; i++) { 39 40 /* Allocate the kernel vspace_root. */ 41 int error = vka_alloc_vspace_root(&procServ.vka, &pdlist->pd[i]); 42 if (error) { 43 ROS_ERROR("Failed to allocate vspace root. error %d\n", error); 44 assert(!"Procserv initialisation failed. Try lowering CONFIG_PROCSERV_MAX_VSPACES."); 45 return; 46 } 47 assert(pdlist->pd[i].cptr != 0); 48 49 /* If we are on mainline, we need to assign a kernel ASID. ASID Pools have been removed 50 from the newer experimental kernels. */ 51 #ifndef CONFIG_KERNEL_STABLE 52 #ifndef CONFIG_X86_64 53 error = seL4_ARCH_ASIDPool_Assign(seL4_CapInitThreadASIDPool, pdlist->pd[i].cptr); 54 assert(error == seL4_NoError); 55 #endif 56 #endif 57 58 /* Allocate the kernel Root CNode object. */ 59 error = vka_alloc_cnode_object(&procServ.vka, REFOS_CSPACE_RADIX, &pdlist->cnode[i]); 60 if (error) { 61 ROS_ERROR("Failed to allocate Root CNode. error %d\n", error); 62 assert(!"Procserv initialisation failed. Try lowering CONFIG_PROCSERV_MAX_VSPACES."); 63 return; 64 } 65 assert(pdlist->cnode[i].cptr != 0); 66 } 67} 68 69struct pd_info 70pd_assign(struct pd_list *pdlist) 71{ 72 assert(pdlist); 73 struct pd_info info; 74 uint32_t pdID = cpool_alloc(&pdlist->PDpool); 75 if (!pdID) { 76 info.kpdObject = 0; 77 info.kcnodeObject = 0; 78 return info; 79 } 80 info.kpdObject = pdlist->pd[pdID - 1].cptr; 81 info.kcnodeObject = pdlist->cnode[pdID - 1].cptr; 82 return info; 83} 84 85void 86pd_free(struct pd_list *pdlist, seL4_CPtr pdPtr) 87{ 88 assert(pdlist); 89 90 /* First, we loop through our list and find the associated vka object with this given cptr. */ 91 int idx = -1; 92 for (int i = 0; i < PD_MAX; i++) { 93 if (pdlist->pd[i].cptr == pdPtr) { 94 idx = i; 95 break; 96 } 97 } 98 99 if (idx == -1) { 100 /* Could not find the given cptr. */ 101 ROS_WARNING("pd_free failed: no such page directory cptr %d\n", pdPtr); 102 return; 103 } 104 105 if (cpool_check(&pdlist->PDpool, idx + 1)) { 106 /* Already free. */ 107 ROS_WARNING("pd_free failed: page directory cptr %d is already free.\n", pdPtr); 108 return; 109 } 110 111 /* Delete all derived caps from this PD. */ 112 cspacepath_t cpath; 113 vka_cspace_make_path(&procServ.vka, pdPtr, &cpath); 114 vka_cnode_revoke(&cpath); 115 116 /* Delete this PD's associated root CNode. */ 117 vka_cspace_make_path(&procServ.vka, pdlist->cnode[idx].cptr, &cpath); 118 vka_cnode_revoke(&cpath); 119 vka_cnode_delete(&cpath); 120 vka_free_object(&procServ.vka, &pdlist->cnode[idx]); 121 122 /* Allocate a new kernel Root CNode object. */ 123 int error = vka_alloc_cnode_object(&procServ.vka, REFOS_CSPACE_RADIX, &pdlist->cnode[idx]); 124 if (error) { 125 ROS_ERROR("Failed to re-allocate Root CNode. error %d\n", error); 126 return; 127 } 128 129 /* Put it back into the allocation pool. */ 130 cpool_free(&pdlist->PDpool, idx + 1); 131} 132