1/** 2 * \file 3 * \brief Slot management for the memory allocator. 4 */ 5 6/* 7 * Copyright (c) 2007, 2008, 2016, ETH Zurich. 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include <barrelfish/barrelfish.h> 16#include <mm/mm.h> 17#include <mm/slot_alloc.h> 18#include <stdio.h> 19 20static errval_t rootcn_alloc(void *st, uint8_t reqbits, struct capref *ret) 21{ 22 return mm_alloc(st, reqbits, ret, NULL); 23} 24 25/// Allocate a new cnode if needed 26errval_t slot_prealloc_refill(struct slot_prealloc *this) 27{ 28 uint8_t refill = !this->current; 29 errval_t err; 30 31 if (this->meta[refill].free == L2_CNODE_SLOTS) { 32 return SYS_ERR_OK; // Nop 33 } 34 35 // Allocate a ram cap 36 struct capref ram_cap; 37 err = mm_alloc(this->mm, L2_CNODE_BITS + OBJBITS_CTE, &ram_cap, NULL); 38 if (err_is_fail(err)) { 39 return err_push(err, MM_ERR_SLOT_MM_ALLOC); 40 } 41 42 // Retype to and build the next cnode 43 struct capref cnode_cap; 44 err = slot_alloc_root(&cnode_cap); 45 if (err_no(err) == LIB_ERR_SLOT_ALLOC_NO_SPACE) { 46 // resize root slot allocator (and rootcn) 47 err = root_slot_allocator_refill(rootcn_alloc, this->mm); 48 if (err_is_fail(err)) { 49 return err_push(err, LIB_ERR_ROOTSA_RESIZE); 50 } 51 // retry slot_alloc_root 52 err = slot_alloc_root(&cnode_cap); 53 } 54 if (err_is_fail(err)) { 55 return err_push(err, LIB_ERR_SLOT_ALLOC); 56 } 57 58 err = cnode_create_from_mem(cnode_cap, ram_cap, ObjType_L2CNode, 59 &this->meta[refill].cap.cnode, L2_CNODE_SLOTS); 60 if (err_is_fail(err)) { 61 return err_push(err, LIB_ERR_CNODE_CREATE); 62 } 63 64 // Set the metadata 65 this->meta[refill].cap.slot = 0; 66 this->meta[refill].free = L2_CNODE_SLOTS; 67 68 return SYS_ERR_OK; 69} 70 71errval_t slot_alloc_prealloc(void *inst, uint64_t nslots, struct capref *ret) 72{ 73 struct slot_prealloc *this = inst; 74 assert(nslots <= (1UL << this->maxslotbits)); 75 76 /* Check if enough space */ 77 if (this->meta[this->current].free < nslots) { 78 // Allocate from next cnode 79 this->current = !this->current; 80 } 81 82 if (this->meta[this->current].free < nslots) { 83 return MM_ERR_SLOT_NOSLOTS; 84 } 85 86 /* Return next slot and update */ 87 *ret = this->meta[this->current].cap; 88 this->meta[this->current].cap.slot += nslots; 89 this->meta[this->current].free -= nslots; 90 91 return SYS_ERR_OK; 92} 93 94/** 95 * \brief Initialise preallocating slot allocator instance 96 * 97 * \param this Pointer to area for instance data 98 * \param maxslotbits Maximum size of each allocation (in bits) 99 * \param initial_cnode First cap in an empty cnode to start allocating from 100 * \param initial_space Number of slots free in initial cnode 101 * \param ram_mm Memory allocator to use for RAM caps when creating new CNodes 102 */ 103errval_t slot_prealloc_init(struct slot_prealloc *this, uint8_t maxslotbits, 104 struct capref initial_cnode, uint64_t initial_space, 105 struct mm *ram_mm) 106{ 107 this->maxslotbits = maxslotbits; 108 this->mm = ram_mm; 109 110 assert(initial_space == L2_CNODE_SLOTS); 111 if (initial_space != L2_CNODE_SLOTS) { 112 debug_printf("Initial CNode for 2 level preallocating slot allocator needs to be 16kB"); 113 return LIB_ERR_SLOT_ALLOC_INIT; 114 } 115 116 this->current = 0; 117 this->meta[0].cap = initial_cnode; 118 this->meta[0].free = initial_space; 119 this->meta[1].free = 0; 120 121 return SYS_ERR_OK; 122} 123 124errval_t slot_alloc_basecn_init(struct slot_alloc_basecn *this) 125{ 126 // Use ROOTCN_SLOT_SLOT_ALLOC0 as CNode fore basecn allocator 127 this->cap.cnode.croot = CPTR_ROOTCN; 128 this->cap.cnode.cnode = ROOTCN_SLOT_ADDR(ROOTCN_SLOT_SLOT_ALLOC0); 129 this->cap.cnode.level = CNODE_TYPE_OTHER; 130 this->cap.slot = 0; 131 this->free = L2_CNODE_SLOTS; 132 133 return SYS_ERR_OK; 134} 135 136errval_t slot_alloc_basecn(void *inst, uint64_t nslots, struct capref *ret) 137{ 138 struct slot_alloc_basecn *this = inst; 139 errval_t err; 140 141 if (nslots > this->free) { 142 /* XXX: Special case for init, need to get memory from basecn */ 143 struct capref ram; 144 err = ram_alloc(&ram, L2_CNODE_BITS + OBJBITS_CTE); 145 if (err_is_fail(err)) { 146 DEBUG_ERR(err, "ram_alloc in slot_alloc_basecn cannot allocate L2 " 147 "CNode-sized ram cap"); 148 return err_push(err, LIB_ERR_RAM_ALLOC); 149 } 150 151 /* to conform with 2 level cspace: put new cnode into rootcn */ 152 struct capref cnode; 153 err = slot_alloc_root(&cnode); 154 if (err_is_fail(err)) { 155 DEBUG_ERR(err, "allocating root cnode slot"); 156 return err_push(err, LIB_ERR_SLOT_ALLOC); 157 } 158 159 err = cnode_create_from_mem(cnode, ram, ObjType_L2CNode, 160 &this->cap.cnode, L2_CNODE_SLOTS); 161 if (err_is_fail(err)) { 162 return err_push(err, LIB_ERR_CNODE_CREATE); 163 } 164 165 this->cap.slot = 0; 166 this->free = L2_CNODE_SLOTS; 167 } 168 169 assert(nslots <= this->free); 170 *ret = this->cap; 171 this->cap.slot += nslots; 172 this->free -= nslots; 173 174 return SYS_ERR_OK; 175} 176 177/// Requires an instance of range_slot_allocator 178errval_t slot_alloc_dynamic(void *alloc, uint64_t nslots, struct capref *ret) 179{ 180 return range_slot_alloc(alloc, nslots, ret); 181} 182 183errval_t slot_refill_dynamic(void *alloc) 184{ 185 return range_slot_alloc_refill(alloc, L2_CNODE_SLOTS); 186} 187