blob: 9422a79b2be95eebd86c96e58dbe953e9a1b4eb8 [file] [log] [blame]
/*
* Copyright 2017, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
/*
* An implementation of the vspace virtual memory allocation interface, using a two
* level page table.
*
* This implementation expects malloc to work, although it only uses it for small amounts of
* memory.
*
* Stack size is constant and be configured in menuconfig.
*
* Stacks are allocated with 1 guard page between them, but they are contiguous in the vmem
* region.
*
* Allocation starts at 0x00001000.
*
* This library will allow you to map over anything that it doesn't know about, so
* make sure you tell it if you do any external mapping.
*
*/
#pragma once
#include <autoconf.h>
#include <sel4utils/gen_config.h>
#include <vspace/vspace.h>
#include <vka/vka.h>
#include <sel4utils/util.h>
#include <sel4utils/arch/vspace.h>
/* These definitions are only here so that you can take the size of them.
* TOUCHING THESE DATA STRUCTURES IN ANY WAY WILL BREAK THE WORLD
*/
#define KERNEL_RESERVED_START (ALIGN_DOWN(seL4_UserTop, PAGE_SIZE_4K))
#define VSPACE_LEVEL_SIZE BIT(VSPACE_LEVEL_BITS)
typedef struct vspace_mid_level {
/* there is a clear optimization that could be done where instead of always pointing to a
* sub table, there is the option of pointing directly to a page. This allows more
* efficient memory usage for book keeping large pages */
uintptr_t table[VSPACE_LEVEL_SIZE];
} vspace_mid_level_t;
typedef struct vspace_bottom_level {
seL4_CPtr cap[VSPACE_LEVEL_SIZE];
uintptr_t cookie[VSPACE_LEVEL_SIZE];
} vspace_bottom_level_t;
typedef int(*sel4utils_map_page_fn)(vspace_t *vspace, seL4_CPtr cap, void *vaddr, seL4_CapRights_t rights,
int cacheable, size_t size_bits);
struct sel4utils_res {
uintptr_t start;
uintptr_t end;
seL4_CapRights_t rights;
int cacheable;
int malloced;
bool rights_deferred;
struct sel4utils_res *next;
};
typedef struct sel4utils_res sel4utils_res_t;
typedef struct sel4utils_alloc_data {
seL4_CPtr vspace_root;
vka_t *vka;
vspace_mid_level_t *top_level;
uintptr_t next_bootstrap_vaddr;
uintptr_t last_allocated;
vspace_t *bootstrap;
sel4utils_map_page_fn map_page;
sel4utils_res_t *reservation_head;
bool is_empty;
} sel4utils_alloc_data_t;
static inline sel4utils_res_t *reservation_to_res(reservation_t res)
{
return (sel4utils_res_t *) res.res;
}
/**
* This is a mostly internal function for constructing a vspace. Allows a vspace to be created
* with an arbitrary function to invoke for the mapping of pages. This is useful if you want
* a vspace manager, but you do not want to use seL4 page directories
*
* @param loader vspace of the current process, used to allocate
* virtual memory book keeping.
* @param new_vspace uninitialised vspace struct to populate.
* @param data uninitialised vspace data struct to populate.
* @param vka initialised vka that this virtual memory allocator will use to
* allocate pages and pagetables. This allocator will never invoke free.
* @param vspace_root root object for the new vspace.
* @param allocated_object_fn function to call when objects are allocated. Can be null.
* @param allocated_object_cookie cookie passed when the above function is called. Can be null.
* @param map_page Function that will be called to map seL4 pages
*
* @return 0 on success.
*/
int
sel4utils_get_vspace_with_map(vspace_t *loader, vspace_t *new_vspace, sel4utils_alloc_data_t *data,
vka_t *vka, seL4_CPtr vspace_root,
vspace_allocated_object_fn allocated_object_fn, void *allocated_object_cookie, sel4utils_map_page_fn map_page);
/**
* Allows for an empty vspace to be created with an arbitrary function to invoke for the mapping of pages.
* This is useful if you want a vspace manager, but you do not want parts of the virtual address space to be
* pre-reserved e.g the kernel region. The vspace is useful for guest virtual machine-based applications.
*
* @param loader vspace of the current process, used to allocate
* virtual memory book keeping.
* @param new_vspace uninitialised vspace struct to populate.
* @param data uninitialised vspace data struct to populate.
* @param vka initialised vka that this virtual memory allocator will use to
* allocate pages and pagetables. This allocator will never invoke free.
* @param vspace_root root object for the new vspace.
* @param allocated_object_fn function to call when objects are allocated. Can be null.
* @param allocated_object_cookie cookie passed when the above function is called. Can be null.
* @param map_page Function that will be called to map seL4 pages
*
* @return 0 on success.
*/
int
sel4utils_get_empty_vspace_with_map(vspace_t *loader, vspace_t *new_vspace, sel4utils_alloc_data_t *data,
vka_t *vka, seL4_CPtr vspace_root,
vspace_allocated_object_fn allocated_object_fn, void *allocated_object_cookie, sel4utils_map_page_fn map_page);
/**
* Initialise a vspace allocator for a new address space (not the current one).
*
* @param loader vspace of the current process, used to allocate
* virtual memory book keeping.
* @param new_vspace uninitialised vspace struct to populate.
* @param data uninitialised vspace data struct to populate.
* @param vka initialised vka that this virtual memory allocator will use to
* allocate pages and pagetables. This allocator will never invoke free.
* @param vspace_root root object for the new vspace.
* @param allocated_object_fn function to call when objects are allocated. Can be null.
* @param allocated_object_cookie cookie passed when the above function is called. Can be null.
*
* @return 0 on success.
*/
int sel4utils_get_vspace(vspace_t *loader, vspace_t *new_vspace, sel4utils_alloc_data_t *data,
vka_t *vka, seL4_CPtr vspace_root, vspace_allocated_object_fn allocated_object_fn,
void *allocated_object_cookie);
/**
* Allows for an empty vspace to be created.
* This is useful if you want a vspace manager, but you do not want parts of the virtual address space to be
* pre-reserved e.g the kernel region. The vspace is useful for guest virtual machine-based applications.
*
* @param loader vspace of the current process, used to allocate
* virtual memory book keeping.
* @param new_vspace uninitialised vspace struct to populate.
* @param data uninitialised vspace data struct to populate.
* @param vka initialised vka that this virtual memory allocator will use to
* allocate pages and pagetables. This allocator will never invoke free.
* @param vspace_root root object for the new vspace.
* @param allocated_object_fn function to call when objects are allocated. Can be null.
* @param allocated_object_cookie cookie passed when the above function is called. Can be null.
*
* @return 0 on success.
*/
int sel4utils_get_empty_vspace(vspace_t *loader, vspace_t *new_vspace, sel4utils_alloc_data_t *data,
vka_t *vka, seL4_CPtr vspace_root, vspace_allocated_object_fn allocated_object_fn,
void *allocated_object_cookie);
#ifdef CONFIG_VTX
/**
* Initialise a vspace allocator for an EPT address space
*
* @param loader vspace of the current process, used to allocate
* virtual memory book keeping.
* @param new_vspace uninitialised vspace struct to populate.
* @param vka initialised vka that this virtual memory allocator will use to
* allocate pages and pagetables. This allocator will never invoke free.
* @param ept EPT page directory for the new vspace.
* @param allocated_object_fn function to call when objects are allocated. Can be null.
* @param allocated_object_cookie cookie passed when the above function is called. Can be null.
*
* @return 0 on success.
*/
int sel4utils_get_vspace_ept(vspace_t *loader, vspace_t *new_vspace, vka_t *vka,
seL4_CPtr ept, vspace_allocated_object_fn allocated_object_fn, void *allocated_object_cookie);
#endif /* CONFIG_VTX */
/**
* Initialise a vspace allocator for the current address space (this is intended
* for use a task that is not the root task but has no vspace, ie one loaded by the capDL loader).
*
* @param vspace uninitialised vspace struct to populate.
* @param data uninitialised vspace data struct to populate.
* @param vspace_root root object for the new vspace.
* @param vka initialised vka that this virtual memory allocator will use to
* allocate pages and pagetables. This allocator will never invoke free.
* @param allocated_object_fn function to call when objects are allocated. Can be null.
* @param allocated_object_cookie cookie passed when the above function is called. Can be null.
* @param existing_frames a NULL terminated list of virtual addresses for 4K frames that are
* already allocated. For larger frames, just pass in the virtual
* address range in 4K addresses. This will prevent the allocator
* from overriding these frames.
*
* @return 0 on succes.
*
*/
int sel4utils_bootstrap_vspace(vspace_t *vspace, sel4utils_alloc_data_t *data,
seL4_CPtr vspace_root, vka_t *vka,
vspace_allocated_object_fn allocated_object_fn, void *allocated_object_cookie,
void *existing_frames[]);
/**
* Initialise a vspace allocator for the current address space (this is intended
* for use by the root task). Take details of existing frames from bootinfo.
*
* @param vspace uninitialised vspace struct to populate.
* @param data uninitialised vspace data struct to populate.
* @param vspace_root root object for the new vspace.
* @param vka initialised vka that this virtual memory allocator will use to
* allocate pages and pagetables. This allocator will never invoke free.
* @param info seL4 boot info
* @param allocated_object_fn function to call when objects are allocated. Can be null.
* @param allocated_object_cookie cookie passed when the above function is called. Can be null.
*
* @return 0 on succes.
*
*/
int sel4utils_bootstrap_vspace_with_bootinfo(vspace_t *vspace, sel4utils_alloc_data_t *data,
seL4_CPtr vspace_root,
vka_t *vka, seL4_BootInfo *info, vspace_allocated_object_fn allocated_object_fn,
void *allocated_object_cookie);
/* Wrapper function that configures a vspaceator such that all allocated objects are not
* tracked.
*/
static inline int sel4utils_get_vspace_leaky(vspace_t *loader, vspace_t *new_vspace, sel4utils_alloc_data_t *data,
vka_t *vka, seL4_CPtr vspace_root)
{
return sel4utils_get_vspace(loader, new_vspace, data, vka, vspace_root,
(vspace_allocated_object_fn) NULL, NULL);
}
#ifdef CONFIG_VTX
static inline int sel4utils_get_vspace_ept_leaky(vspace_t *loader, vspace_t *new_vspace,
vka_t *vka, seL4_CPtr vspace_root)
{
return sel4utils_get_vspace_ept(loader, new_vspace, vka, vspace_root,
(vspace_allocated_object_fn) NULL, NULL);
}
#endif /* CONFIG_VTX */
static inline int sel4utils_bootstrap_vspace_with_bootinfo_leaky(vspace_t *vspace, sel4utils_alloc_data_t *data,
seL4_CPtr vspace_root,
vka_t *vka, seL4_BootInfo *info)
{
return sel4utils_bootstrap_vspace_with_bootinfo(vspace, data, vspace_root, vka, info, NULL, NULL);
}
static inline int sel4utils_bootstrap_vspace_leaky(vspace_t *vspace, sel4utils_alloc_data_t *data,
seL4_CPtr vspace_root, vka_t *vka,
void *existing_frames[])
{
return sel4utils_bootstrap_vspace(vspace, data, vspace_root, vka, NULL, NULL, existing_frames);
}
/**
* Attempts to create a new vspace reservation. Function behaves similarly to vspace_reserve_range
* except a reservation struct is passed in, instead of being malloc'ed. This is intended to be
* used during bootstrapping where malloc has not yet been setup.
* Reservations created with this function should *only* be freed with sel4utils_reserve_range_at_no_alloc
*
* Result will be aligned to 4K.
*
* @param vspace the virtual memory allocator to use.
* @param reservation Allocated reservation struct to fill out
* @param bytes the size in bytes to map.
* @param rights the rights to map the pages in with in this reservation
* @param cacheable 1 if the pages should be mapped with cacheable attributes. 0 for DMA.
* @param vaddr the virtual address of the reserved range will be returned here.
*
* @return 0 on success
*/
int sel4utils_reserve_range_no_alloc(vspace_t *vspace, sel4utils_res_t *reservation, size_t size,
seL4_CapRights_t rights, int cacheable, void **result);
/*
* @see sel4utils_reserve_range_no_alloc, however result is aligned to size_bits.
*/
int sel4utils_reserve_range_no_alloc_aligned(vspace_t *vspace, sel4utils_res_t *reservation,
size_t size, size_t size_bits, seL4_CapRights_t rights, int cacheable, void **result);
/**
* Attempts to create a new vspace reservation. Function behaves similarly to vspace_reserve_range_at
* except a reservation struct is passed in, instead of being malloc'ed. This is intended to be
* used during bootstrapping where malloc has not yet been setup.
* Reservations created with this function should *only* be freed with sel4utils_reserve_range_at_no_alloc
*
* @param vspace the virtual memory allocator to use.
* @param reservation Allocated reservation struct to fill out
* @param vaddr the virtual address to start the range at.
* @param bytes the size in bytes to map.
* @param rights the rights to map the pages in with in this reservatio
* @param cacheable 1 if the pages should be mapped with cacheable attributes. 0 for DMA.
*
* @return 0 on success
*/
int sel4utils_reserve_range_at_no_alloc(vspace_t *vspace, sel4utils_res_t *reservation, void *vaddr,
size_t size, seL4_CapRights_t rights, int cacheable);
/**
* Move and/or resizes a reservation in any direction, allowing for both start and/or end address to
* be changed. Any overlapping region will keep their reservation, any non-overlapping regions will
* be unreserved. Does not make any mapping changes.
* @param vspace the virtual memory allocator to use.
* @param reservation the reservation to move.
* @param vaddr the start virtual address to move the reservation to.
* @param bytes the size in bytes of new reservation.
* @return 0 on success, -1 if region start could not be moved, -2 if end could not be moved.
*/
int sel4utils_move_resize_reservation(vspace_t *vspace, reservation_t reservation, void *vaddr,
size_t bytes);
/*
* Copy the code and data segment (the image effectively) from current vspace
* into clone vspace. The clone vspace should be initialised.
*
* @param current the vspace to copy from.
* @param clone the vspace to copy to.
* @param reservation the previously established reservation in clone to copy.
* @return 0 on success.
*/
int sel4utils_bootstrap_clone_into_vspace(vspace_t *current, vspace_t *clone, reservation_t reserve);
/**
* Get the bounds of _executable_start and _end.
*
* @param va_start return va_start.
* @param va_end return va_end.
*/
void sel4utils_get_image_region(uintptr_t *va_start, uintptr_t *va_end);
/**
*
* @return the physical address that vaddr is mapped to.
* VKA_NO_PADDR if there is no mapping
*/
uintptr_t sel4utils_get_paddr(vspace_t *vspace, void *vaddr, seL4_Word type, seL4_Word size_bits);