1/** 2 * \file 3 * \brief Local memory allocator for init till mem_serv is ready to use 4 */ 5 6/* 7 * Copyright (c) 2007, 2008, 2009, 2011, 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, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include "init.h" 16#include <mm/mm.h> 17 18/* parameters for local memory allocator used until we spawn mem_serv */ 19#define OBJBITS_DISPATCHER (10) 20// XXX: 16MB is not enough to create tracing buffers on babybel for all cores 21#define MM_REQUIREDBITS 27 ///< Required size of memory to boot (128MB) 22#define MM_REQUIREDBYTES (1UL << MM_REQUIREDBITS) 23#define MM_MAXSIZEBITS (MM_REQUIREDBITS + 3) ///< Max size of memory in allocator 24#define MM_MINSIZEBITS BASE_PAGE_BITS ///< Min size of allocation 25#define MM_MAXCHILDBITS 1 ///< Max branching factor of BTree nodes 26#define MM_MAXDEPTH (MM_MAXSIZEBITS - MM_MINSIZEBITS + 1) ///< BTree depth 27#define MM_NNODES ((1UL << MM_MAXDEPTH) + MM_MINSIZEBITS - OBJBITS_DISPATCHER) ///< Max BTree nodes 28#define MM_NCNODES DIVIDE_ROUND_UP(MM_NNODES, 1UL << DEFAULT_CNODE_BITS) //CNodes 29 30// Number of slots placed in smallcn of mem_serv 31#define MEM_SERV_SMALLCN_SLOTS 10 32 33/// MM allocator instance data 34static struct mm mymm; 35static bool huh = false; 36 37static errval_t mymm_alloc(struct capref *ret, uint8_t bits, uint64_t minbase, 38 uint64_t maxlimit) 39{ 40 if (huh) { 41 debug_printf("%s: Called self from %p\n", __FUNCTION__, __builtin_return_address(0)); 42 while(true); 43 } 44 huh = true; 45 /* XXX: although we have calculated the space requirements for 46 * MM_MINSIZEBITS, we only ever allocate a single dispatcher from this 47 * allocator, so this should be safe */ 48 assert(bits >= OBJBITS_DISPATCHER); 49 errval_t err = mm_alloc(&mymm, bits, ret, NULL); 50 huh = false; 51 return err; 52} 53 54/** 55 * \brief Setups a local memory allocator for init to use till the memory server 56 * is ready to be used. 57 */ 58errval_t initialize_ram_alloc(void) 59{ 60 errval_t err; 61 62 /* init slot allocator */ 63 static struct slot_alloc_basecn init_slot_alloc; 64 err = slot_alloc_basecn_init(&init_slot_alloc); 65 if (err_is_fail(err)) { 66 return err_push(err, MM_ERR_SLOT_ALLOC_INIT); 67 } 68 69 /* walk bootinfo looking for suitable RAM cap to use 70 * we pick the first cap equal to MM_REQUIREDBITS, 71 * or else the next closest less than MM_MAXSIZEBITS */ 72 int mem_slot = 0; 73 struct capref mem_cap = { 74 .cnode = cnode_super, 75 .slot = 0, 76 }; 77 78 /* get destination slot for retype */ 79 genpaddr_t region_base = 0; 80 struct capref region_for_init; 81 err = slot_alloc_basecn(&init_slot_alloc, 1, ®ion_for_init); 82 if (err_is_fail(err)) { 83 DEBUG_ERR(err, "slot_alloc_basecn in initialize_ram_alloc"); 84 return err_push(err, MM_ERR_SLOT_NOSLOTS); 85 } 86 87 assert(bi != NULL); 88 for (int i = 0; i < bi->regions_length; i++) { 89 assert(!bi->regions[i].mr_consumed); 90 if (bi->regions[i].mr_type == RegionType_Empty) { 91 if (bi->regions[i].mr_bytes >= MM_REQUIREDBYTES) { 92 mem_cap.slot = mem_slot; 93 if (bi->regions[i].mr_bytes == MM_REQUIREDBYTES) { 94 bi->regions[i].mr_consumed = true; 95 region_base = bi->regions[i].mr_base; 96 break; 97 } 98 99 /* found cap bigger than required; cut off end */ 100 bi->regions[i].mr_bytes -= MM_REQUIREDBYTES; 101 // can use mr_bytes as offset here 102 err = cap_retype(region_for_init, mem_cap, 103 bi->regions[i].mr_bytes, ObjType_RAM, 104 MM_REQUIREDBYTES, 1); 105 if (err_is_fail(err)) { 106 return err_push(err, MM_ERR_CHUNK_NODE); 107 } 108 mem_cap = region_for_init; 109 region_base = bi->regions[i].mr_base + bi->regions[i].mr_bytes; 110 break; 111 } 112 mem_slot++; 113 } 114 } 115 116 if (region_base == 0) { 117 USER_PANIC("Error: no RAM capability >= %zu MB found\n", 118 MM_REQUIREDBYTES / 1024 / 1024); 119 } 120 121 /* init MM allocator */ 122 err = mm_init(&mymm, ObjType_RAM, region_base, 123 MM_REQUIREDBITS, MM_MAXCHILDBITS, NULL, 124 slot_alloc_basecn, NULL, &init_slot_alloc, true); 125 if (err_is_fail(err)) { 126 return err_push(err, MM_ERR_MM_INIT); 127 } 128 129 /* give MM allocator enough static storage for its node allocator */ 130 assert(1UL << OBJBITS_DISPATCHER == OBJSIZE_DISPATCHER); 131 static char nodebuf[SLAB_STATIC_SIZE(MM_NNODES, MM_NODE_SIZE(MM_MAXCHILDBITS))]; 132 slab_grow(&mymm.slabs, nodebuf, sizeof(nodebuf)); 133 134 /* add single RAM cap to allocator */ 135 /* XXX: can't use mm_add_multi here, as the allocator tends to choke when 136 * we add smaller regions before larger */ 137 debug_printf("using %#"PRIxGENPADDR", %zu MB for init's allocator\n", 138 region_base, MM_REQUIREDBYTES / 1024 / 1024); 139 err = mm_add(&mymm, mem_cap, MM_REQUIREDBITS, region_base); 140 if (err_is_fail(err)) { 141 return err_push(err, MM_ERR_MM_ADD); 142 } 143 144 // initialise generic RAM allocator to use local allocator 145 err = ram_alloc_set(mymm_alloc); 146 if (err_is_fail(err)) { 147 return err_push(err, LIB_ERR_RAM_ALLOC_SET); 148 } 149 150 return SYS_ERR_OK; 151} 152