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 * An implementation of the vspace virtual memory allocation interface, using a two
15 * level page table.
16 *
17 * This implementation expects malloc to work, although it only uses it for small amounts of
18 * memory.
19 *
20 * Stack size is constant and be configured in menuconfig.
21 *
22 * Stacks are allocated with 1 guard page between them, but they are contiguous in the vmem
23 * region.
24 *
25 * Allocation starts at 0x00001000.
26 *
27 * This library will allow you to map over anything that it doesn't know about, so
28 * make sure you tell it if you do any external mapping.
29 *
30 */
31#pragma once
32
33#include <autoconf.h>
34#include <sel4utils/gen_config.h>
35
36#include <vspace/vspace.h>
37#include <vka/vka.h>
38#include <sel4utils/util.h>
39#include <sel4utils/arch/vspace.h>
40
41/* These definitions are only here so that you can take the size of them.
42 * TOUCHING THESE DATA STRUCTURES IN ANY WAY WILL BREAK THE WORLD
43 */
44#define KERNEL_RESERVED_START (ALIGN_DOWN(seL4_UserTop, PAGE_SIZE_4K))
45#define VSPACE_LEVEL_SIZE BIT(VSPACE_LEVEL_BITS)
46
47typedef struct vspace_mid_level {
48    /* there is a clear optimization that could be done where instead of always pointing to a
49     * sub table, there is the option of pointing directly to a page. This allows more
50     * efficient memory usage for book keeping large pages */
51    uintptr_t table[VSPACE_LEVEL_SIZE];
52} vspace_mid_level_t;
53
54typedef struct vspace_bottom_level {
55    seL4_CPtr cap[VSPACE_LEVEL_SIZE];
56    uintptr_t cookie[VSPACE_LEVEL_SIZE];
57} vspace_bottom_level_t;
58
59typedef int(*sel4utils_map_page_fn)(vspace_t *vspace, seL4_CPtr cap, void *vaddr, seL4_CapRights_t rights,
60                                    int cacheable, size_t size_bits);
61
62struct sel4utils_res {
63    uintptr_t start;
64    uintptr_t end;
65    seL4_CapRights_t rights;
66    int cacheable;
67    int malloced;
68    bool rights_deferred;
69    struct sel4utils_res *next;
70};
71
72typedef struct sel4utils_res sel4utils_res_t;
73
74typedef struct sel4utils_alloc_data {
75    seL4_CPtr vspace_root;
76    vka_t *vka;
77    vspace_mid_level_t *top_level;
78    uintptr_t next_bootstrap_vaddr;
79    uintptr_t last_allocated;
80    vspace_t *bootstrap;
81    sel4utils_map_page_fn map_page;
82    sel4utils_res_t *reservation_head;
83    bool is_empty;
84} sel4utils_alloc_data_t;
85
86static inline sel4utils_res_t *reservation_to_res(reservation_t res)
87{
88    return (sel4utils_res_t *) res.res;
89}
90
91/**
92 * This is a mostly internal function for constructing a vspace. Allows a vspace to be created
93 * with an arbitrary function to invoke for the mapping of pages. This is useful if you want
94 * a vspace manager, but you do not want to use seL4 page directories
95 *
96 * @param loader                  vspace of the current process, used to allocate
97 *                                virtual memory book keeping.
98 * @param new_vspace              uninitialised vspace struct to populate.
99 * @param data                    uninitialised vspace data struct to populate.
100 * @param vka                     initialised vka that this virtual memory allocator will use to
101 *                                allocate pages and pagetables. This allocator will never invoke free.
102 * @param vspace_root             root object for the new vspace.
103 * @param allocated_object_fn     function to call when objects are allocated. Can be null.
104 * @param allocated_object_cookie cookie passed when the above function is called. Can be null.
105 * @param map_page                Function that will be called to map seL4 pages
106 *
107 * @return 0 on success.
108 */
109int
110sel4utils_get_vspace_with_map(vspace_t *loader, vspace_t *new_vspace, sel4utils_alloc_data_t *data,
111                              vka_t *vka, seL4_CPtr vspace_root,
112                              vspace_allocated_object_fn allocated_object_fn, void *allocated_object_cookie, sel4utils_map_page_fn map_page);
113/**
114 * Allows for an empty vspace to be created with an arbitrary function to invoke for the mapping of pages.
115 * This is useful if you want a vspace manager, but you do not want parts of the virtual address space to be
116 * pre-reserved e.g the kernel region. The vspace is useful for guest virtual machine-based applications.
117 *
118 * @param loader                  vspace of the current process, used to allocate
119 *                                virtual memory book keeping.
120 * @param new_vspace              uninitialised vspace struct to populate.
121 * @param data                    uninitialised vspace data struct to populate.
122 * @param vka                     initialised vka that this virtual memory allocator will use to
123 *                                allocate pages and pagetables. This allocator will never invoke free.
124 * @param vspace_root             root object for the new vspace.
125 * @param allocated_object_fn     function to call when objects are allocated. Can be null.
126 * @param allocated_object_cookie cookie passed when the above function is called. Can be null.
127 * @param map_page                Function that will be called to map seL4 pages
128 *
129 * @return 0 on success.
130 */
131int
132sel4utils_get_empty_vspace_with_map(vspace_t *loader, vspace_t *new_vspace, sel4utils_alloc_data_t *data,
133                                    vka_t *vka, seL4_CPtr vspace_root,
134                                    vspace_allocated_object_fn allocated_object_fn, void *allocated_object_cookie, sel4utils_map_page_fn map_page);
135/**
136 * Initialise a vspace allocator for a new address space (not the current one).
137 *
138 * @param loader                  vspace of the current process, used to allocate
139 *                                virtual memory book keeping.
140 * @param new_vspace              uninitialised vspace struct to populate.
141 * @param data                    uninitialised vspace data struct to populate.
142 * @param vka                     initialised vka that this virtual memory allocator will use to
143 *                                allocate pages and pagetables. This allocator will never invoke free.
144 * @param vspace_root             root object for the new vspace.
145 * @param allocated_object_fn     function to call when objects are allocated. Can be null.
146 * @param allocated_object_cookie cookie passed when the above function is called. Can be null.
147 *
148 * @return 0 on success.
149 */
150int sel4utils_get_vspace(vspace_t *loader, vspace_t *new_vspace, sel4utils_alloc_data_t *data,
151                         vka_t *vka, seL4_CPtr vspace_root, vspace_allocated_object_fn allocated_object_fn,
152                         void *allocated_object_cookie);
153
154/**
155 * Allows for an empty vspace to be created.
156 * This is useful if you want a vspace manager, but you do not want parts of the virtual address space to be
157 * pre-reserved e.g the kernel region. The vspace is useful for guest virtual machine-based applications.
158 *
159 * @param loader                  vspace of the current process, used to allocate
160 *                                virtual memory book keeping.
161 * @param new_vspace              uninitialised vspace struct to populate.
162 * @param data                    uninitialised vspace data struct to populate.
163 * @param vka                     initialised vka that this virtual memory allocator will use to
164 *                                allocate pages and pagetables. This allocator will never invoke free.
165 * @param vspace_root             root object for the new vspace.
166 * @param allocated_object_fn     function to call when objects are allocated. Can be null.
167 * @param allocated_object_cookie cookie passed when the above function is called. Can be null.
168 *
169 * @return 0 on success.
170 */
171int sel4utils_get_empty_vspace(vspace_t *loader, vspace_t *new_vspace, sel4utils_alloc_data_t *data,
172                               vka_t *vka, seL4_CPtr vspace_root, vspace_allocated_object_fn allocated_object_fn,
173                               void *allocated_object_cookie);
174
175
176#ifdef CONFIG_VTX
177/**
178 * Initialise a vspace allocator for an EPT address space
179 *
180 * @param loader                  vspace of the current process, used to allocate
181 *                                virtual memory book keeping.
182 * @param new_vspace              uninitialised vspace struct to populate.
183 * @param vka                     initialised vka that this virtual memory allocator will use to
184 *                                allocate pages and pagetables. This allocator will never invoke free.
185 * @param ept                     EPT page directory for the new vspace.
186 * @param allocated_object_fn     function to call when objects are allocated. Can be null.
187 * @param allocated_object_cookie cookie passed when the above function is called. Can be null.
188 *
189 * @return 0 on success.
190 */
191int sel4utils_get_vspace_ept(vspace_t *loader, vspace_t *new_vspace, vka_t *vka,
192                             seL4_CPtr ept, vspace_allocated_object_fn allocated_object_fn, void *allocated_object_cookie);
193#endif /* CONFIG_VTX */
194
195/**
196 * Initialise a vspace allocator for the current address space (this is intended
197 * for use a task that is not the root task but has no vspace, ie one loaded by the capDL loader).
198 *
199 * @param vspace                  uninitialised vspace struct to populate.
200 * @param data                    uninitialised vspace data struct to populate.
201 * @param vka                     initialised vka that this virtual memory allocator will use to
202 *                                allocate pages and pagetables. This allocator will never invoke free.
203 * @param vspace_root             root object for the new vspace.
204 * @param allocated_object_fn     function to call when objects are allocated. Can be null.
205 * @param allocated_object_cookie cookie passed when the above function is called. Can be null.
206 * @param existing_frames         a NULL terminated list of virtual addresses for 4K frames that are
207 *                                already allocated. For larger frames, just pass in the virtual
208 *                                address range in 4K addresses. This will prevent the allocator
209 *                                from overriding these frames.
210 *
211 * @return 0 on succes.
212 *
213 */
214int sel4utils_bootstrap_vspace(vspace_t *vspace, sel4utils_alloc_data_t *data,
215                               seL4_CPtr vspace_root, vka_t *vka,
216                               vspace_allocated_object_fn allocated_object_fn, void *allocated_object_cookie,
217                               void *existing_frames[]);
218
219/**
220 * Initialise a vspace allocator for the current address space (this is intended
221 * for use by the root task). Take details of existing frames from bootinfo.
222 *
223 * @param vspace                  uninitialised vspace struct to populate.
224 * @param data                    uninitialised vspace data struct to populate.
225 * @param vka                     initialised vka that this virtual memory allocator will use to
226 *                                allocate pages and pagetables. This allocator will never invoke free.
227 * @param info                    seL4 boot info
228 * @param vspace_root             root object for the new vspace.
229 * @param allocated_object_fn     function to call when objects are allocated. Can be null.
230 * @param allocated_object_cookie cookie passed when the above function is called. Can be null.
231 *
232 * @return 0 on succes.
233 *
234 */
235int sel4utils_bootstrap_vspace_with_bootinfo(vspace_t *vspace, sel4utils_alloc_data_t *data,
236                                             seL4_CPtr vspace_root,
237                                             vka_t *vka, seL4_BootInfo *info, vspace_allocated_object_fn allocated_object_fn,
238                                             void *allocated_object_cookie);
239
240/* Wrapper function that configures a vspaceator such that all allocated objects are not
241 * tracked.
242 */
243static inline int sel4utils_get_vspace_leaky(vspace_t *loader, vspace_t *new_vspace, sel4utils_alloc_data_t *data,
244                                             vka_t *vka, seL4_CPtr vspace_root)
245{
246    return sel4utils_get_vspace(loader, new_vspace, data, vka, vspace_root,
247                                (vspace_allocated_object_fn) NULL, NULL);
248}
249
250#ifdef CONFIG_VTX
251static inline int sel4utils_get_vspace_ept_leaky(vspace_t *loader, vspace_t *new_vspace,
252                                                 vka_t *vka, seL4_CPtr vspace_root)
253{
254    return sel4utils_get_vspace_ept(loader, new_vspace, vka, vspace_root,
255                                    (vspace_allocated_object_fn) NULL, NULL);
256}
257#endif /* CONFIG_VTX */
258
259static inline int sel4utils_bootstrap_vspace_with_bootinfo_leaky(vspace_t *vspace, sel4utils_alloc_data_t *data,
260                                                                 seL4_CPtr vspace_root,
261                                                                 vka_t *vka, seL4_BootInfo *info)
262{
263    return sel4utils_bootstrap_vspace_with_bootinfo(vspace, data, vspace_root, vka, info, NULL, NULL);
264}
265
266static inline int sel4utils_bootstrap_vspace_leaky(vspace_t *vspace, sel4utils_alloc_data_t *data,
267                                                   seL4_CPtr vspace_root, vka_t *vka,
268                                                   void *existing_frames[])
269{
270    return sel4utils_bootstrap_vspace(vspace, data, vspace_root, vka, NULL, NULL, existing_frames);
271}
272
273/**
274 * Attempts to create a new vspace reservation. Function behaves similarly to vspace_reserve_range
275 * except a reservation struct is passed in, instead of being malloc'ed. This is intended to be
276 * used during bootstrapping where malloc has not yet been setup.
277 * Reservations created with this function should *only* be freed with sel4utils_reserve_range_at_no_alloc
278 *
279 * Result will be aligned to 4K.
280 *
281 * @param vspace the virtual memory allocator to use.
282 * @param reservation Allocated reservation struct to fill out
283 * @param bytes the size in bytes to map.
284 * @param rights the rights to map the pages in with in this reservation
285 * @param cacheable 1 if the pages should be mapped with cacheable attributes. 0 for DMA.
286 * @param vaddr the virtual address of the reserved range will be returned here.
287 *
288 * @return 0 on success
289 */
290int sel4utils_reserve_range_no_alloc(vspace_t *vspace, sel4utils_res_t *reservation, size_t size,
291                                     seL4_CapRights_t rights, int cacheable, void **result);
292
293/*
294 * @see sel4utils_reserve_range_no_alloc, however result is aligned to size_bits.
295 */
296int sel4utils_reserve_range_no_alloc_aligned(vspace_t *vspace, sel4utils_res_t *reservation,
297                                             size_t size, size_t size_bits, seL4_CapRights_t rights, int cacheable, void **result);
298
299/**
300 * Attempts to create a new vspace reservation. Function behaves similarly to vspace_reserve_range_at
301 * except a reservation struct is passed in, instead of being malloc'ed. This is intended to be
302 * used during bootstrapping where malloc has not yet been setup.
303 * Reservations created with this function should *only* be freed with sel4utils_reserve_range_at_no_alloc
304 *
305 * @param vspace the virtual memory allocator to use.
306 * @param reservation Allocated reservation struct to fill out
307 * @param vaddr the virtual address to start the range at.
308 * @param bytes the size in bytes to map.
309 * @param rights the rights to map the pages in with in this reservatio
310 * @param cacheable 1 if the pages should be mapped with cacheable attributes. 0 for DMA.
311 *
312 * @return 0 on success
313 */
314int sel4utils_reserve_range_at_no_alloc(vspace_t *vspace, sel4utils_res_t *reservation, void *vaddr,
315                                        size_t size, seL4_CapRights_t rights, int cacheable);
316
317/**
318 * Move and/or resizes a reservation in any direction, allowing for both start and/or end address to
319 * be changed. Any overlapping region will keep their reservation, any non-overlapping regions will
320 * be unreserved. Does not make any mapping changes.
321 * @param vspace the virtual memory allocator to use.
322 * @param reservation the reservation to move.
323 * @param vaddr the start virtual address to move the reservation to.
324 * @param bytes the size in bytes of new reservation.
325 * @return 0 on success, -1 if region start could not be moved, -2 if end could not be moved.
326 */
327int sel4utils_move_resize_reservation(vspace_t *vspace, reservation_t reservation, void *vaddr,
328                                      size_t bytes);
329
330/*
331 * Copy the code and data segment (the image effectively) from current vspace
332 * into clone vspace. The clone vspace should be initialised.
333 *
334 * @param current the vspace to copy from.
335 * @param clone the vspace to copy to.
336 * @param reservation the previously established reservation in clone to copy.
337 * @return 0 on success.
338 */
339int sel4utils_bootstrap_clone_into_vspace(vspace_t *current, vspace_t *clone, reservation_t reserve);
340
341/**
342 * Get the bounds of _executable_start and _end.
343 *
344 * @param va_start return va_start.
345 * @param va_end return va_end.
346 */
347void sel4utils_get_image_region(uintptr_t *va_start, uintptr_t *va_end);
348
349/**
350 *
351 * @return the physical address that vaddr is mapped to.
352 *         VKA_NO_PADDR if there is no mapping
353 */
354uintptr_t sel4utils_get_paddr(vspace_t *vspace, void *vaddr, seL4_Word type, seL4_Word size_bits);
355
356