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 <allocman/mspace/virtual_pool.h> 14#include <allocman/allocman.h> 15#include <allocman/util.h> 16#include <stdlib.h> 17#include <sel4/sel4.h> 18#include <sel4utils/mapping.h> 19#include <vka/kobject_t.h> 20#include <vspace/mapping.h> 21#include <string.h> 22 23/* This allocator deliberately does not use the vspace library to manage mappings to prevent 24 * circular dependencies between the vspace library and the allocator */ 25 26static int _add_page(allocman_t *alloc, seL4_CPtr pd, void *vaddr) 27{ 28 cspacepath_t frame_path; 29 seL4_Word frame_cookie; 30 int error; 31 error = allocman_cspace_alloc(alloc, &frame_path); 32 if (error) { 33 ZF_LOGV("Failed to allocate slot"); 34 return error; 35 } 36 frame_cookie = allocman_utspace_alloc(alloc, seL4_PageBits, seL4_ARCH_4KPage, &frame_path, true, &error); 37 if (error) { 38 allocman_cspace_free(alloc, &frame_path); 39 ZF_LOGV("Failed to allocate frame"); 40 return error; 41 } 42 while ((error = seL4_ARCH_Page_Map(frame_path.capPtr, pd, (seL4_Word) vaddr, seL4_AllRights, 43 seL4_ARCH_Default_VMAttributes)) == seL4_FailedLookup) { 44 cspacepath_t path; 45 error = allocman_cspace_alloc(alloc, &path); 46 if (error) { 47 ZF_LOGV("Failed to allocate slot"); 48 break; 49 } 50 seL4_Word failed_bits = seL4_MappingFailedLookupLevel(); 51 vspace_map_obj_t obj; 52 error = vspace_get_map_obj(failed_bits, &obj); 53 assert(error == 0); 54 55 seL4_Word cookie = allocman_utspace_alloc(alloc, obj.size_bits, obj.type, &path, false, &error); 56 if (error) { 57 allocman_cspace_free(alloc, &path); 58 ZF_LOGV("Failed to allocate paging structure"); 59 break; 60 } 61 error = vspace_map_obj(&obj, path.capPtr, pd, (seL4_Word) vaddr, seL4_ARCH_Default_VMAttributes); 62 if (error != seL4_NoError) { 63 allocman_utspace_free(alloc, cookie, seL4_PageTableBits); 64 allocman_cspace_free(alloc, &path); 65 break; 66 } 67 } 68 if (error != seL4_NoError) { 69 allocman_cspace_free(alloc, &frame_path); 70 allocman_utspace_free(alloc, frame_cookie, seL4_PageBits); 71 return error; 72 } 73 /* zero the memory in case we were allocated from a device range */ 74 memset(vaddr, 0, PAGE_SIZE_4K); 75 return 0; 76} 77 78static k_r_malloc_header_t *_morecore(size_t cookie, mspace_k_r_malloc_t *k_r_malloc, size_t new_units) 79{ 80 size_t new_size; 81 k_r_malloc_header_t *new_header; 82 mspace_virtual_pool_t *virtual_pool = (mspace_virtual_pool_t*)cookie; 83 new_size = new_units * sizeof(k_r_malloc_header_t); 84 85 if (virtual_pool->pool_ptr + new_size > virtual_pool->pool_limit) { 86 ZF_LOGV("morecore out of virtual pool"); 87 return NULL; 88 } 89 while (virtual_pool->pool_ptr + new_size > virtual_pool->pool_top) { 90 int error; 91 error = _add_page(virtual_pool->morecore_alloc, virtual_pool->pd, virtual_pool->pool_top); 92 if (error) { 93 ZF_LOGV("morecore failed to add page"); 94 return NULL; 95 } 96 virtual_pool->pool_top += PAGE_SIZE_4K; 97 } 98 new_header = (k_r_malloc_header_t*)virtual_pool->pool_ptr; 99 virtual_pool->pool_ptr += new_size; 100 return new_header; 101} 102 103void mspace_virtual_pool_create(mspace_virtual_pool_t *virtual_pool, struct mspace_virtual_pool_config config) 104{ 105 virtual_pool->pool_ptr = config.vstart; 106 virtual_pool->pool_top = virtual_pool->pool_ptr; 107 virtual_pool->pool_limit = config.vstart + config.size; 108 virtual_pool->morecore_alloc = NULL; 109 virtual_pool->pd = config.pd; 110 mspace_k_r_malloc_init(&virtual_pool->k_r_malloc, (size_t)virtual_pool, _morecore); 111} 112 113void *_mspace_virtual_pool_alloc(struct allocman *alloc, void *_virtual_pool, size_t bytes, int *error) 114{ 115 void *ret; 116 mspace_virtual_pool_t *virtual_pool = (mspace_virtual_pool_t*)_virtual_pool; 117 virtual_pool->morecore_alloc = alloc; 118 ret = mspace_k_r_malloc_alloc(&virtual_pool->k_r_malloc, bytes); 119 virtual_pool->morecore_alloc = NULL; 120 SET_ERROR(error, (ret == NULL) ? 1 : 0); 121 return ret; 122} 123 124void _mspace_virtual_pool_free(struct allocman *alloc, void *_virtual_pool, void *ptr, size_t bytes) 125{ 126 mspace_virtual_pool_t *virtual_pool = (mspace_virtual_pool_t*)_virtual_pool; 127 virtual_pool->morecore_alloc = alloc; 128 mspace_k_r_malloc_free(&virtual_pool->k_r_malloc, ptr); 129 virtual_pool->morecore_alloc = NULL; 130} 131