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 <stdio.h> 14#include <stdbool.h> 15#include <assert.h> 16#include <sel4/sel4.h> 17#include <refos/refos.h> 18#include <refos/error.h> 19#include <refos/vmlayout.h> 20#include <refos-util/walloc.h> 21#include <refos-rpc/proc_client.h> 22#include <refos-rpc/proc_client_helper.h> 23#include <data_struct/cbpool.h> 24#include <data_struct/chash.h> 25#include <refos-util/dprintf.h> 26 27static walloc_state_t _walloc_state; 28 29/* ------------------------------ Walloc-list internal interface --------------------------------*/ 30 31static void 32walloc_list_init(walloc_state_t *ws, seL4_Word startAddr, seL4_Word endAddr) 33{ 34 uint32_t sz = endAddr - startAddr; 35 if (startAddr % REFOS_PAGE_SIZE != 0) { 36 assert(!"walloc_init startAddr is not page aligned."); 37 return; 38 } 39 if (sz % REFOS_PAGE_SIZE != 0) { 40 assert(!"walloc_init size is not a multiple of PAGE_SIZE."); 41 return; 42 } 43 44 /* Initialise the bitmap pool which keeps track of allocated portions of vspace. */ 45 ws->startAddr = startAddr; 46 ws->endAddr = endAddr; 47 ws->npages = sz / REFOS_PAGE_SIZE; 48 cbpool_init(&ws->pool, ws->npages); 49 50 /* Initialise the windows list. */ 51 chash_init(&ws->windowCptrMap, WALLOC_WINDOW_CPTR_MAP_HASHSIZE); 52 53 ws->initialised = true; 54 ws->magic = WALLOC_MAGIC; 55} 56 57static void 58walloc_list_deinit(walloc_state_t *ws) 59{ 60 if (!ws->initialised) return; 61 chash_release(&ws->windowCptrMap); 62 cbpool_release(&ws->pool); 63 ws->startAddr = 0; 64 ws->endAddr = 0; 65 ws->npages = 0; 66 ws->initialised = false; 67 ws->magic = 0; 68} 69 70static seL4_Word 71walloc_list_ext(walloc_state_t *ws, int npages, seL4_CPtr *window, uint32_t permission, 72 uint32_t flags) 73{ 74 assert(ws->initialised && ws->magic == WALLOC_MAGIC); 75 if (!npages) return 0; 76 77 // Allocate window. 78 uint32_t startPage = cbpool_alloc(&ws->pool, npages); 79 if (startPage == CBPOOL_INVALID) { 80 printf("WARNING: walloc out of windows.\n"); 81 return 0; 82 } 83 assert(startPage >= 0 && startPage < ws->npages); 84 85 // Calculate the allocated window region address. 86 uint32_t regionAddr = ws->startAddr + (startPage * REFOS_PAGE_SIZE); 87 assert(regionAddr % REFOS_PAGE_SIZE == 0); 88 89 // Allocate a window at this address. 90 seL4_CPtr windowCap = proc_create_mem_window_ext(regionAddr, npages * REFOS_PAGE_SIZE, 91 permission, flags); 92 if (windowCap == 0 || REFOS_GET_ERRNO() != ESUCCESS) { 93 cbpool_free(&ws->pool, startPage, npages); 94 printf("WARNING: walloc could not create memory window.\n"); 95 assert(!"WARNING: walloc could not create procserv memory window.\n"); 96 return 0; 97 } 98 99 // Book keep this allocated window cap. 100 int err = chash_set(&ws->windowCptrMap, startPage, (chash_item_t) windowCap); 101 assert(!err); 102 (void) err; 103 104 if (window != NULL) { 105 (*window) = windowCap; 106 } 107 return regionAddr; 108} 109 110static seL4_Word 111walloc_list(walloc_state_t *ws, int npages, seL4_CPtr *window) 112{ 113 return walloc_ext(npages, window, PROC_WINDOW_PERMISSION_READWRITE, 0x0); 114} 115 116static uint32_t 117walloc_list_get_start_page(walloc_state_t *ws, seL4_Word vaddr) 118{ 119 assert(ws->initialised && ws->magic == WALLOC_MAGIC); 120 assert(vaddr >= ws->startAddr && vaddr <= ws->endAddr); 121 uint32_t startPage = (vaddr - ws->startAddr) / REFOS_PAGE_SIZE; 122 assert(startPage >= 0 && startPage < ws->npages); 123 return startPage; 124} 125 126static seL4_CPtr 127walloc_list_get_window_at_vaddr(walloc_state_t *ws, seL4_Word vaddr) 128{ 129 assert(ws->initialised && ws->magic == WALLOC_MAGIC); 130 seL4_CPtr windowCap = (seL4_CPtr) 131 chash_get(&ws->windowCptrMap, walloc_list_get_start_page(ws, vaddr)); 132 return windowCap; 133} 134 135static void 136walloc_list_free(walloc_state_t *ws, uint32_t addr, int npages) 137{ 138 assert(ws->initialised && ws->magic == WALLOC_MAGIC); 139 if (!npages) return; 140 cbpool_free(&ws->pool, walloc_list_get_start_page(ws, addr), npages); 141 seL4_CPtr windowCap = walloc_get_window_at_vaddr(addr); 142 if (windowCap) { 143 proc_delete_mem_window(windowCap); 144 seL4_CNode_Revoke(REFOS_CSPACE, windowCap, REFOS_CSPACE_DEPTH); 145 csfree_delete(windowCap); 146 chash_remove(&ws->windowCptrMap, walloc_list_get_start_page(ws, addr)); 147 } 148} 149 150/* --------------------------- Userland simplified walloc interface -----------------------------*/ 151 152void 153walloc_init(seL4_Word startAddr, seL4_Word endAddr) 154{ 155 walloc_list_init(&_walloc_state, startAddr, endAddr); 156} 157 158void 159walloc_deinit(void) 160{ 161 walloc_list_deinit(&_walloc_state); 162} 163 164seL4_Word 165walloc(int npages, seL4_CPtr *window) 166{ 167 return walloc_list(&_walloc_state, npages, window); 168} 169 170seL4_Word 171walloc_ext(int npages, seL4_CPtr *window, uint32_t permission, uint32_t flags) 172{ 173 return walloc_list_ext(&_walloc_state, npages, window, permission, flags); 174} 175 176seL4_CPtr 177walloc_get_window_at_vaddr(seL4_Word vaddr) 178{ 179 return walloc_list_get_window_at_vaddr(&_walloc_state, vaddr); 180} 181 182void 183walloc_free(uint32_t addr, int npages) 184{ 185 walloc_list_free(&_walloc_state, addr, npages); 186}