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