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/** 14 * @file bootstrap.h 15 * 16 * @brief Helpers for bootstrapping an allocman on freshly running system 17 * 18 * Bootstrapping a system is hard. These helpers attempt to make it easy to start 19 * a system with a 'common' configuration. Systems that are not common should also 20 * be possible, but the code here will be able to help you less. 21 * 22 * In general to bootstrap a system you need to do the following 23 * 1. Describe the current cspace 24 * 2. Describe where resources (untypeds, slots etc) can be found 25 * 3. (maybe) create and switch to a new cspace 26 * These bootstrapping functions attempt to hide the requirements of these steps as 27 * much as possible, allowing you to substitute 'bootinfo' if you have it, otherweise 28 * requiring some minimal description. However enough internals are provided that 29 * each of these steps can be broken into if you need to describe some particularly 30 * interesting system. 31 * 32 * The allocman that gets created as a result of bootstrapping is constructed using 33 * some default 'sensible' allocators. Unfortunately if you want different allocators 34 * then there is currently no way to control that. 35 * 36 * Bootstrapping here requires some initial 'pool' of memory. This is memory that 37 * must NEVER be freed after you have bootstrapped an allocator. Be very careful 38 * you do not put this on a stack (and then free it) or have it as a global and use 39 * it multiple times. Unfortunately this pool is the 'magic' that allows the allocators 40 * to kick themselves going, and cannot be provided for you. The actual size of the pool 41 * is something you will need to work out with trial and error. 42 * 43 * With all of these methods, once they return failure you are basically 100% fucked 44 * since they make no effort to clean up after themselves if they detect failure. The 45 * ONLY sane thing you can do is log an error and terminate. 46 * 47 * See example_bootstrap.c for sample code that shows how to bootstrap in various ways 48 * 49 */ 50 51#pragma once 52 53#include <sel4/sel4.h> 54#include <string.h> 55#include <allocman/allocman.h> 56#include <allocman/cspace/simple1level.h> 57#include <allocman/cspace/two_level.h> 58#include <allocman/mspace/fixed_pool.h> 59#include <allocman/mspace/virtual_pool.h> 60#include <allocman/utspace/twinkle.h> 61#include <vspace/vspace.h> 62#include <simple/simple.h> 63#include <sel4platsupport/pmem.h> 64/** 65 * Internal data structure for storing bootstrapping information. If you need to break 66 * open the boot strapping process, then you will be given a pointer to one of these 67 * that you will interract with to finish the boot strapping 68 */ 69typedef struct bootstrap_info bootstrap_info_t; 70 71/** 72 * Every allocation manager created by these bootstrapping functions has a dual_pool 73 * as its memory manager. For the purposes of bootstrapping only the fixed pool (as 74 * passed to the boot strapping functions) is used. If you want to use a virtual pool 75 * (you almost certainly do so you don't run out of memory or have a stupidly large 76 * static pool) then this function will initial the virtual pool after the fact. The 77 * reason for this ordering is that it is expected that the creation of a vspace manager 78 * might expect an allocator, which you won't have yet if you are boot strapping. 79 * 80 * Note that there is no protection against calling this function multiple times or 81 * from trying to call it on an allocman that does not have a dual_pool as its underlying 82 * memory manager. DO NOT FUCK IT UP 83 * 84 * @param alloc Allocman whose memory manager to configure 85 * @param vstart Start of a virtual address range that will be allocated from. 86 * @param vsize Size of the virtual address range 87 * @param pd Page directory to invoke when mapping frames/page tables 88 */ 89void bootstrap_configure_virtual_pool(allocman_t *alloc, void *vstart, size_t vsize, 90 seL4_CPtr pd); 91 92/** 93 * Simplest bootstrapping method that uses all the information in seL4_BootInfo 94 * assumes you are the rootserver. This keeps using whatever cspace you are currently in. 95 * 96 * @param bi BootInfo as passed to the rootserver 97 * @param pool_size Size of the initial pool. See file comments for details 98 * @param pool Initial pool. See file comments for details 99 * 100 * @return returns NULL on error 101 */ 102allocman_t *bootstrap_use_bootinfo(seL4_BootInfo *bi, size_t pool_size, void *pool); 103 104/** 105 * Bootstraps using all the information in bootinfo, but switches to a new single 106 * level cspace. All untypeds specified in bootinfo will be moved to the new cspace, 107 * any other capabilities will be left in the old cspace. If you wish to refer to the 108 * boot cspace (most likely since it probably has capabilities you still want), then 109 * a cspace description of the old cspace can also be returned. 110 * 111 * @param bi BootInfo as passed to the rootserver 112 * @param cnode_size Number of slot bits (cnode_slots = 2^cnode_size) for the new cnode 113 * @param pool_size Size of the initial pool. See file comments for details 114 * @param pool Initial pool. See file comments for details 115 * @param old_cspace Optional location to store a description of the original cspace. You 116 * can free this memory back to the allocman when are done with it 117 * 118 * @return returns NULL on error 119 */ 120allocman_t *bootstrap_new_1level_bootinfo(seL4_BootInfo *bi, size_t cnode_size, size_t pool_size, void *pool, cspace_simple1level_t **old_cspace); 121 122/** 123 * Bootstraps using all the information in bootinfo, but switches to a new two 124 * level cspace. All untypeds specified in bootinfo will be moved to the new cspace, 125 * any other capabilities will be left in the old cspace. If you wish to refer to the 126 * boot cspace (most likely since it probably has capabilities you still want), then 127 * a cspace description of the old cspace can also be returned. 128 * 129 * @param bi BootInfo as passed to the rootserver 130 * @param l1size Number of slot bits (l1_slots = 2^l1size) for the level 1 cnode 131 * @param l2size Number of slot bits (l2_slots = 2^l2size) for the level 2 cnode 132 * @param pool_size Size of the initial pool. See file comments for details 133 * @param pool Initial pool. See file comments for details 134 * @param old_cspace Optional location to store a description of the original cspace. You 135 * can free this memory back to the allocman when are done with it 136 * 137 * @return returns NULL on error 138 */ 139allocman_t *bootstrap_new_2level_bootinfo(seL4_BootInfo *bi, size_t l1size, size_t l2size, size_t pool_size, void *pool, cspace_simple1level_t **old_cspace); 140 141/** 142 * Give an allocator all the untyped memory that simple knows about. 143 * 144 * This assumes that all the untyped caps are currently as simple thinks they are. 145 * If there have been any cspace reshuffles simple will not give allocman useable information 146 * 147 * Allocman will also try and use sel4platsupport_get_pmem_region_list to find PMEM_TYPE_RAM 148 * regions that are device untyped objects. 149 */ 150int allocman_add_simple_untypeds(allocman_t *alloc, simple_t *simple); 151 152/** 153 * Give an allocator all the untyped memory that simple knows about. 154 * 155 * This assumes that all the untyped caps are currently as simple thinks they are. 156 * If there have been any cspace reshuffles simple will not give allocman useable information 157 * 158 * If num_regions is set to 0 or region_list is NULL, Allocman will also try and use 159 * sel4platsupport_get_pmem_region_list to find PMEM_TYPE_RAM regions that are device untyped objects. 160 * Otherwise any device untyped objects that overlap with regions that are type PMEM_TYPE_RAM will be marked as ALLOCMAN_UT_DEV_MEM. 161 */ 162int allocman_add_simple_untypeds_with_regions(allocman_t *alloc, simple_t *simple, int num_regions, pmem_region_t *region_list); 163 164/** 165 * Bootstraps using all the information provided by simple, but switches to a new two 166 * level cspace. All capabilities specified by simple will be moved to the new cspace. All untypeds specified by simple are given to the allocator 167 * 168 * @param simple simple pointer to the struct 169 * @param l1size Number of slot bits (l1_slots = 2^l1size) for the level 1 cnode 170 * @param l2size Number of slot bits (l2_slots = 2^l2size) for the level 2 cnode 171 * @param pool_size Size of the initial pool. See file comments for details 172 * @param pool Initial pool. See file comments for details 173 * 174 * @return returns NULL on error 175 */ 176allocman_t *bootstrap_new_2level_simple(simple_t *simple, size_t l1size, size_t l2size, size_t pool_size, void *pool); 177 178/* As above, but 1 level */ 179allocman_t *bootstrap_new_1level_simple(simple_t *simple, size_t l1size, size_t pool_size, void *pool); 180 181/** 182 * Bootstraps into the current environment as defined by simple. This will continue 183 * to use the cspace described by simple, as well as all the untypeds it knows about 184 * 185 * @param simple Pointer to simple interface, will not be retained 186 * @param pool_size Size of the initial pool. See file comments for details 187 * @param pool Initial pool. See file comments for details 188 * 189 * @return returns NULL on error 190 */ 191allocman_t *bootstrap_use_current_simple(simple_t *simple, size_t pool_size, void *pool); 192 193/** 194 * Bootstraps an allocator that will reuse the current single level cspace (which 195 * you must describe to it). While bootstrapping should succeed, you will need to 196 * add untypeds manually to the returned allocman to make it useful. 197 * 198 * @param root_cnode Location of the cnode that is the current cspace 199 * @param cnode_size Size in slot_bits of the current cnode 200 * @param start_slot First free slot in the current cspace 201 * @param end_slot Last free slot + 1 in the current cspace 202 * @param pool_size Size of the initial pool. See file comments for details 203 * @param pool Initial pool. See file comments for details 204 * 205 * @return returns NULL on error 206 */ 207allocman_t *bootstrap_use_current_1level(seL4_CPtr root_cnode, size_t cnode_size, seL4_CPtr start_slot, seL4_CPtr end_slot, size_t pool_size, void *pool); 208 209/** 210 * Provides a description of the boot cspace if you are doing a customized 211 * bootstrapping. This MUST be set before using boostrap_new_[1|2]level 212 * 213 * @param bs Internal bootstrapping info as allocated/returned by {@link #bootstrap_create_info} 214 * @param cspace CSpace that will be used for bootstrapping purposes. The cspace only needs to exist 215 * for as long as bootstrapping is happening, it will not be used afterwards 216 * @param root_cnode Path to the root cnode of cspace. This is needed so that a cap to the old cspace 217 * can be provided in the new cspace 218 * 219 * @return returns 0 on success 220 */ 221int bootstrap_set_boot_cspace(bootstrap_info_t *bs, cspace_interface_t cspace, cspacepath_t root_cnode); 222 223/** 224 * Adds knowledge of untypeds to the bootstrapping information. These untypeds will 225 * be moved to the new cspace and be given to the untyped manager once bootstrapping 226 * has completed. 227 * 228 * @param bs Internal bootstrapping info as allocated/returned by {@link #bootstrap_create_info} 229 * @param num Number of untypeds to be added 230 * @param uts Path to each of the untypeds 231 * @param size_bits Size of each of the untypeds 232 * @param paddr Optional physical address of each of the untypeds 233 * @param isDevice whether this untyped is for a device region or not 234 * 235 * @return returns 0 on success 236 */ 237int bootstrap_add_untypeds(bootstrap_info_t *bs, size_t num, const cspacepath_t *uts, size_t *size_bits, uintptr_t *paddr, bool isDevice); 238 239/** 240 * Adds knowledge of all the untypeds of bootinfo to the bootstrapper. These will 241 * be moved to the new cspace and given to the untyped manager once bootstrapping has 242 * completed 243 * 244 * @param bs Internal bootstrapping info as allocated/returned by {@link #bootstrap_create_info} 245 * @param bi BootInfo as passed to the rootserver 246 * 247 * @return returns 0 on success 248 */ 249int bootstrap_add_untypeds_from_bootinfo(bootstrap_info_t *bs, seL4_BootInfo *bi); 250 251/** 252 * Completes bootstrapping into a new single level cspace. 253 * 254 * @param info Internal bootstrapping info as allocated/returned by {@link #bootstrap_create_info} 255 * @param cnode_size Size in slot bits of new cspace 256 * @param tcb Path to the TCB of the current thread, need to perform an invocation of seL4_TCB_SetSpace 257 * @param pd Path to the PD of the current thread. This is needed to work around seL4 restriction that 258 * requires the address space be set at the same time as the cspace 259 * @param oldroot Optional location to store a path to a cnode that is root cnode given in {@link #bootstrap_set_boot_cspace} 260 * 261 * @return returns NULL on error 262 */ 263allocman_t *bootstrap_new_1level(bootstrap_info_t *info, size_t cnode_size, cspacepath_t tcb, cspacepath_t pd, cspacepath_t *oldroot); 264 265/** 266 * Completes bootstrapping into a new two level cspace. 267 * 268 * @param info Internal bootstrapping info as allocated/returned by {@link #bootstrap_create_info} 269 * @param l1size Number of slot bits (l1_slots = 2^l1size) for the level 1 cnode 270 * @param l2size Number of slot bits (l2_slots = 2^l2size) for the level 2 cnode 271 * @param tcb Path to the TCB of the current thread, need to perform an invocation of seL4_TCB_SetSpace 272 * @param pd Path to the PD of the current thread. This is needed to work around seL4 restriction that 273 * requires the address space be set at the same time as the cspace 274 * @param oldroot Optional location to store a path to a cnode that is root cnode given in {@link #bootstrap_set_boot_cspace} 275 * 276 * @return returns NULL on error 277 */ 278allocman_t *bootstrap_new_2level(bootstrap_info_t *info, size_t l1size, size_t l2size, cspacepath_t tcb, cspacepath_t pd, cspacepath_t *oldroot); 279 280/** 281 * This function starts bootstrapping the system, and then 'breaks out' and 282 * allows you to give a description of the boot cspace as well as provide any 283 * untypeds. A new 1 or 2 level cspace can then be created. 284 * 285 * @param pool_size Size of the initial pool. See file comments for details 286 * @param pool Initial pool. See file comments for details 287 * 288 * @return returns NULL on error 289 */ 290bootstrap_info_t *bootstrap_create_info(size_t pool_size, void *pool); 291 292/** 293 * Creates an empty allocman from a starting pool. The returned allocman will not 294 * have an attached cspace or utspace. This function provides the ultimate flexibility 295 * in how you can boot strap the system (read: this does basically nothing for you). 296 297 * @param pool_size Size of the initial pool. See file comments for details 298 * @param pool Initial pool. See file comments for details 299 * 300 * @return returns NULL on error 301 */ 302allocman_t *bootstrap_create_allocman(size_t pool_size, void *pool); 303 304