blob: 8a39dce11b1a53437beeb25be30d1c249ab1771a [file] [log] [blame]
/*
* Copyright 2017, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <sel4utils/gen_config.h>
#include <assert.h>
#include <stddef.h>
#include <vka/object.h>
#include <vspace/page.h>
typedef struct vspace vspace_t;
typedef struct reservation {
void *res;
} reservation_t;
/**
* Configuration for vspace_new_pages functions
*/
typedef struct vspace_new_pages_config {
/* If `NULL` then the mapping will be created at any available virtual
address. If vaddr is not `NULL` than the mapping will be at
that virtual address if successful. */
void *vaddr;
/* Number of pages to be created and mapped */
size_t num_pages;
/* Number of bits for each page */
size_t size_bits;
/* Whether frames used to create pages can be device untyped or regular untyped */
bool can_use_dev;
} vspace_new_pages_config_t;
/**
* Returns a default configuration based on supplied parameters that can be passed to vspace_new_pages_with_config
* or vspace_new_pages_at_vaddr_with_config.
* @param num_pages number of pages in reservation
* @param size_bits size bits of each page
* @param config config struct to save configuration into
* @return 0 on success.
*/
static inline int default_vspace_new_pages_config(size_t num_pages, size_t size_bits,
vspace_new_pages_config_t *config)
{
if (num_pages == 0) {
ZF_LOGW("attempt to create 0 pages");
return -1;
}
config->vaddr = NULL;
config->num_pages = num_pages;
config->size_bits = size_bits;
config->can_use_dev = false;
return 0;
}
/**
* Set vaddr of the config
* @param vaddr vaddr to set. See documentation on vspace_new_pages_config_t.
* @param config config struct to save configuration into
* @return 0 on success.
*/
static inline int vspace_new_pages_config_set_vaddr(void *vaddr, vspace_new_pages_config_t *config)
{
config->vaddr = vaddr;
return 0;
}
/**
* Set whether can use device untyped
* @param can_use_dev `true` if can use device untyped. See documentation on vspace_new_pages_config_t.
* @param config config struct to save configuration into
* @return 0 on success.
*/
static inline int vspace_new_pages_config_use_device_ut(bool can_use_dev, vspace_new_pages_config_t *config)
{
config->can_use_dev = can_use_dev;
return 0;
}
/* IMPLEMENTATION INDEPENDANT FUNCTIONS - implemented by calling the implementation specific
* function pointers */
/**
* Reserve a range to map memory into later, aligned to 4K.
* Regions will be aligned to 4K boundaries.
*
* @param vspace the virtual memory allocator to use.
* @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 a reservation to use when mapping pages in the range.
*/
reservation_t vspace_reserve_range(vspace_t *vspace, size_t bytes,
seL4_CapRights_t rights, int cacheable, void **vaddr);
/**
* Share memory from one vspace to another.
*
* Make duplicate mappings of the from vspace in a contiguous region in the
* to vspace. Pages are expected to already be mapped in the from vspace, or an error
* will be returned.
*
* @param from vspace to share memory from
* @param to vspace to share memory to
* @param start address to start sharing at
* @param num_pages number of pages to share
* @param size_bits size of pages in bits
* @param rights rights to map pages into the to vspace with.
* @param cacheable cacheable attribute to map pages into the vspace with
*
* @return address of shared region in to, NULL on failure.
*/
void *vspace_share_mem(vspace_t *from, vspace_t *to, void *start, int num_pages,
size_t size_bits, seL4_CapRights_t rights, int cacheable);
/**
* Create a virtually contiguous area of mapped pages.
* This could be for shared memory or just allocating some pages.
* Depending on the config passed in, this will create a reservation or
* use an existing reservation
* @param vspace the virtual memory allocator used.
* @param config configuration for this function. See vspace_new_pages_config_t.
* @param rights the rights to map the pages in with
* @return vaddr at the start of the contiguous region
* NULL on failure.
*/
void *vspace_new_pages_with_config(vspace_t *vspace, vspace_new_pages_config_t *config, seL4_CapRights_t rights);
/**
* Create a stack. The determines stack size.
*
* @param vspace the virtual memory allocator used.
* @param n_pages number of 4k pages to allocate for the stack.
* A 4k guard page will also be reserved in the address space
* to prevent code from running off the created stack.
*
* @return virtual address of the top of the created stack.
* NULL on failure.
*/
void *vspace_new_sized_stack(vspace_t *vspace, size_t n_pages);
/**
* Callback invoked when accessing a page through vspace_access_page_with_callback
*
* @param access_addr address being accessed in source vspace.
* @param vaddr the virtual address of the mapped page in the destination vspace.
* @param pointer to cookie/data the caller wants passed onto the callback
*
* @return integer result defined by the callback implementation
*/
typedef int (*vspace_access_callback_fn)(void *access_addr, void *vaddr, void *cookie);
/**
* Access a page from one vspace in another.
*
* Duplicate a page mapping out of the 'from' vspace into the 'to' vspace for subsequent access
* by a caller defined callback function. The page will be unmapped after the callback function
* has been executed. Pages are expected to already be mapped in the 'from' vspace, or an error
* will be returned.
*
* @param from vspace to access page from
* @param to vspace to map page into
* @param access_addr address to access
* @param size_bits size of page in bits
* @param rights rights to map page into the 'to' vspace with.
* @param cacheable cacheable attribute to map page into the vspace with
* @param callback callback function to pass mapped vaddr onto
* @param cookie pointer to cookie/data the caller wants passed onto the callback
*
* @return -1 on error, otherwise the integer result of the callback function
*/
int vspace_access_page_with_callback(vspace_t *from, vspace_t *to, void *access_addr, size_t size_bits,
seL4_CapRights_t rights, int cacheable, vspace_access_callback_fn callback, void *cookie);
static inline void *vspace_new_stack(vspace_t *vspace)
{
return vspace_new_sized_stack(vspace, BYTES_TO_4K_PAGES(CONFIG_SEL4UTILS_STACK_SIZE));
}
/**
* Free a stack. This will only free virtual resources, not physical resources.
*
* @param vspace the virtual memory allocator used.
* @param stack_top the top of the stack as returned by vspace_new_stack.
* @param n_pages number of 4k pages that were allocated for stack.
*
*/
void vspace_free_sized_stack(vspace_t *vspace, void *stack_top, size_t n_pages);
static inline void vspace_free_stack(vspace_t *vspace, void *stack_top)
{
vspace_free_sized_stack(vspace, stack_top, BYTES_TO_4K_PAGES(CONFIG_SEL4UTILS_STACK_SIZE));
}
/**
* Create an IPC buffer.
*
* @param[in] vspace the virtual memory allocator used.
* @param[out] page capability to that the IPC buffer was mapped in with
*
* @return vaddr of the mapped in IPC buffer
* NULL on failure.
*/
void *vspace_new_ipc_buffer(vspace_t *vspace, seL4_CPtr *page);
/**
* Free an IPC buffer. This will only free virtual resources, not physical resources.
*
*
* @param vspace the virtual memory allocator used.
* @param addr address the IPC buffer was mapped in to.
*
*/
void vspace_free_ipc_buffer(vspace_t *vspace, void *addr);
/* IMPLEMENTATION SPECIFIC FUNCTIONS - function pointers of the vspace used */
typedef void *(*vspace_new_pages_fn)(vspace_t *vspace, seL4_CapRights_t rights,
size_t num_pages, size_t size_bits);
typedef void *(*vspace_map_pages_fn)(vspace_t *vspace,
seL4_CPtr caps[], uintptr_t cookies[], seL4_CapRights_t rights,
size_t num_pages, size_t size_bits, int cacheable);
/**
* Create a virtually contiguous area of mapped pages, at the specified virtual address.
*
* This is designed for elf loading, where virtual addresses are chosen for you.
* The vspace allocator will not allow this address to be reused unless you free it.
*
* This function will FAIL if the virtual address range requested is not free.
*
*
* @param vspace the virtual memory allocator used.
* @param vaddr the virtual address to start allocation at.
* @param num_pages the number of pages to allocate and map.
* @param size_bits size of the pages to allocate and map, in bits.
* @param reservation reservation to the range the allocation will take place in.
* @param can_use_dev whether the underlying allocator can allocate object from ram device_untyped
* (Setting this to true is normally safe unless when creating IPC buffers.)
* @return seL4_NoError on success, -1 otherwise.
*/
typedef int (*vspace_new_pages_at_vaddr_fn)(vspace_t *vspace, void *vaddr, size_t num_pages,
size_t size_bits, reservation_t reservation, bool can_use_dev);
/**
* Map in existing page capabilities, using contiguos virtual memory at the specified virtual address.
*
* This will FAIL if the virtual address is already mapped in.
*`
* @param vspace the virtual memory allocator used.
* @param seL4_CPtr caps array of caps to map in
* @param uintptr_t cookies array of allocation cookies. Populate this if you want the vspace to
* be able to free the caps for you with a vka. NULL acceptable.
* @param size_bits size, in bits, of an individual page -- all pages must be the same size.
* @param num_pages the number of pages to map in (must correspond to the size of the array).
* @param reservation reservation to the range the allocation will take place in.
*
* @return seL4_NoError on success. -1 on failure.
*/
typedef int (*vspace_map_pages_at_vaddr_fn)(vspace_t *vspace, seL4_CPtr caps[], uintptr_t cookies[],
void *vaddr, size_t num_pages,
size_t size_bits, reservation_t reservation);
/**
* Map in existing page capabilities, using contiguos virtual memory at the specified virtual address.
* Mapping is performed with the rights given by the caller if the reservation given has no rights
* associated with it.
*
* This will FAIL if the virtual address is already mapped in.
*`
* @param vspace the virtual memory allocator used.
* @param seL4_CPtr caps array of caps to map in
* @param uintptr_t cookies array of allocation cookies. Populate this if you want the vspace to
* be able to free the caps for you with a vka. NULL acceptable.
* @param size_bits size, in bits, of an individual page -- all pages must be the same size.
* @param num_pages the number of pages to map in (must correspond to the size of the array).
* @param rights the rights to map the pages in.
* @param reservation reservation to the range the allocation will take place in.
*
* @return seL4_NoError on success. -1 on failure.
*/
typedef int (*vspace_deferred_rights_map_pages_at_vaddr_fn)(vspace_t *vspace, seL4_CPtr caps[], uintptr_t cookies[],
void *vaddr, size_t num_pages,
size_t size_bits, seL4_CapRights_t rights, reservation_t reservation);
/* potential values for vspace_unmap_pages */
#define VSPACE_FREE ((vka_t *) 0xffffffff)
#define VSPACE_PRESERVE ((vka_t *) 0)
/**
* Unmap in existing page capabilities that use contiguos virtual memory.
*
* This function can also free the cslots and frames that back the virtual memory in the region.
* This can be done by the internal vka that the vspace was created with, or the user can provide
* a vka to free with. The vka must be the same vka that the frame object and cslot were allocated with.
*
* Reservations are preserved.
*
* @param vspace the virtual memory allocator used.
* @param vaddr the start of the contiguous region.
* @param size_bits size, in bits, of an individual page -- all pages must be the same size.
* @param num_pages the number of pages to map in (must correspond to the size of the array).
* @param free interface to free frame objects and cslots with, options:
* + VSPACE_FREE to free the frames/cslots with the vspace internal vka,
* + VSPACE_PRESERVE to not free the frames/cslots or
* + a pointer to a custom vka to free the frames/cslots with.
*
*/
typedef void (*vspace_unmap_pages_fn)(vspace_t *vspace, void *vaddr, size_t num_pages,
size_t size_bits, vka_t *free);
/**
* Tear down a vspace, freeing any memory allocated by the vspace itself.
*
* Like vspace_unmap_pages this function can also free the frames and cslots backing
* the vspace, if a vka is provided.
*
* When using this function to tear down all backing frames/cslots the user MUST make sure
* that any frames/cslots not allocated by the vka being used to free have already been unmapped
* from the vspace *or* that the cookies for these custom mappings are set to 0.
* If this is not done the vspace will attempt to use the wrong vka to free
* frames and cslots resulting in allocator corruption.
*
* To completely free a vspace the user should also free any objects/cslots that the vspace
* called vspace_allocated_object_fn on, as the vspace has essentially delegated control
* of these objects/cslots to the user.
*
* @param vspace the vspace to tear down.
* @param free vka to use to free the cslots/frames, options:
* + VSPACE_FREE to use the internal vka,
* + VSPACE_PRESERVE to not free the frames/cslots,
* + a pointer to a custom vka to free the frames/cslots with.
*/
typedef void (*vspace_tear_down_fn)(vspace_t *vspace, vka_t *free);
/**
* Reserve a range to map memory into later.
* Regions will be aligned to 4K boundaries.
*
* @param vspace the virtual memory allocator to use.
* @param bytes the size in bytes to map.
* @param size_bits size to align the range to
* @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 a reservation to use when mapping pages in the range.
*/
typedef reservation_t (*vspace_reserve_range_aligned_fn)(vspace_t *vspace, size_t bytes, size_t size_bits,
seL4_CapRights_t rights, int cacheable, void **vaddr);
/**
* Reserve a range to map memory in to later at a specific address.
* Regions will be aligned to 4K boundaries.
*
* @param vspace the virtual memory allocator to use.
* @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 reservation
* @param cacheable 1 if the pages should be mapped with cacheable attributes. 0 for DMA.
*
* @return a reservation to use when mapping pages in the range.
*/
typedef reservation_t (*vspace_reserve_range_at_fn)(vspace_t *vspace, void *vaddr,
size_t bytes, seL4_CapRights_t rights, int cacheable);
/**
* Reserve a range to map memory in to later at a specific address.
* The rights of the memory within the range are deferred to when performing the mapping.
* Regions will be aligned to 4K boundaries.
*
* @param vspace the virtual memory allocator to use.
* @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 reservation
* @param cacheable 1 if the pages should be mapped with cacheable attributes. 0 for DMA.
*
* @return a reservation to use when mapping pages in the range.
*/
typedef reservation_t (*vspace_reserve_deferred_rights_range_at_fn)(vspace_t *vspace, void *vaddr,
size_t bytes, int cacheable);
/**
* Free a reservation.
*
* This will not touch any pages, but will unreserve any reserved addresses in the reservation.
*
* @param vspace the virtual memory allocator to use.
* @param reservation the reservation to free.
*/
typedef void (*vspace_free_reservation_fn)(vspace_t *vspace, reservation_t reservation);
/**
* Free a reservation by vaddr.
*
* This will not touch any pages, but will unreserve any reserved addresses in the reservation.
*
* @param vspace the virtual memory allocator to use.
* @param vaddr a vaddr in the reservation (will free entire reservation).
*/
typedef void (*vspace_free_reservation_by_vaddr_fn)(vspace_t *vspace, void *vaddr);
/**
* Get the capability mapped at a virtual address.
*
*
* @param vspace the virtual memory allocator to use.
* @param vaddr the virtual address to get the cap for.
*
* @return the cap mapped to this virtual address, 0 otherwise.
*/
typedef seL4_CPtr(*vspace_get_cap_fn)(vspace_t *vspace, void *vaddr);
/**
* Get the vka allocation cookie for an the frame mapped at a virtual address.
*
* @param vspace the virtual memory allocator to use.
* @param vaddr the virtual address to get the cap for.
*
* @return the allocation cookie mapped to this virtual address, 0 otherwise.
*/
typedef uintptr_t (*vspace_get_cookie_fn)(vspace_t *vspace, void *vaddr);
/**
* Function that the vspace allocator will call if it allocates any memory.
* This allows the user to clean up the allocation at a later time.
*
* If this function is null, it will not be called.
*
* @param vspace the virtual memory space allocator to use.
* @param allocated_object_cookie A cookie provided by the user when the vspace allocator is
* initialised --> vspace->allocated_object_cookie/
* @param object the object that was allocated.
*/
typedef void (*vspace_allocated_object_fn)(void *allocated_object_cookie, vka_object_t object);
/* @return the page directory for this vspace
*/
typedef seL4_CPtr(*vspace_get_root_fn)(vspace_t *vspace);
/**
* Share memory from one vspace to another at a specific address. Pages are expected
* to already be mapped in the from vspace, or an error will be returned.
*
* @param from vspace to share memory from
* @param to vspace to share memory to
* @param start address to start sharing at
* @param num_pages number of pages to share
* @param size_bits size of pages in bits
* @param vaddr vaddr to start sharing memory at
* @param reservation reservation for that vaddr.
*
* @return 0 on success
*/
typedef int (*vspace_share_mem_at_vaddr_fn)(vspace_t *from, vspace_t *to, void *start, int num_pages, size_t size_bits,
void *vaddr, reservation_t res);
/* Portable virtual memory allocation interface */
struct vspace {
void *data;
vspace_new_pages_fn new_pages;
vspace_map_pages_fn map_pages;
vspace_new_pages_at_vaddr_fn new_pages_at_vaddr;
vspace_map_pages_at_vaddr_fn map_pages_at_vaddr;
vspace_deferred_rights_map_pages_at_vaddr_fn deferred_rights_map_pages_at_vaddr;
vspace_unmap_pages_fn unmap_pages;
vspace_tear_down_fn tear_down;
vspace_reserve_range_aligned_fn reserve_range_aligned;
vspace_reserve_range_at_fn reserve_range_at;
vspace_reserve_deferred_rights_range_at_fn reserve_deferred_rights_range_at;
vspace_free_reservation_fn free_reservation;
vspace_free_reservation_by_vaddr_fn free_reservation_by_vaddr;
vspace_get_cap_fn get_cap;
vspace_get_root_fn get_root;
vspace_get_cookie_fn get_cookie;
vspace_share_mem_at_vaddr_fn share_mem_at_vaddr;
vspace_allocated_object_fn allocated_object;
void *allocated_object_cookie;
};
/* convenient wrappers */
/**
* Create a virtually contiguous area of mapped pages.
* This could be for shared memory or just allocating some pages.
*
* @param vspace the virtual memory allocator used.
* @param rights the rights to map the pages in with
* @param num_pages the number of pages to allocate and map.
* @param size_bits size of the pages to allocate and map, in bits.
*
* @return vaddr at the start of the contiguous region
* NULL on failure.
*/
static inline void *vspace_new_pages(vspace_t *vspace, seL4_CapRights_t rights,
size_t num_pages, size_t size_bits)
{
if (vspace == NULL) {
ZF_LOGE("vspace is NULL.");
return NULL;
}
if (vspace->new_pages == NULL) {
ZF_LOGE("Supplied vspace doesn't implement new_pages().");
return NULL;
}
if (num_pages == 0) {
ZF_LOGE("Called with num_pages == 0. Intentional?");
return NULL;
}
if (!sel4_valid_size_bits(size_bits)) {
ZF_LOGE("Invalid size_bits %zu", size_bits);
return NULL;
}
return vspace->new_pages(vspace, rights, num_pages, size_bits);
}
/**
* Map in existing page capabilities, using contiguos virtual memory.
*
* @param vspace the virtual memory allocator used.
* @param seL4_CPtr caps array of caps to map in
* @param uint32_t cookies array of allocation cookies. Populate this if you want the vspace to
* be able to free the caps for you with a vka. NULL acceptable.
* @param rights the rights to map the pages in with
* @param size_bits size, in bits, of an individual page -- all pages must be the same size.
* @param num_pages the number of pages to map in (must correspond to the size of the array).
* @param cacheable 1 if the pages should be mapped with cacheable attributes. 0 for DMA.
*
* @return vaddr at the start of the device mapping
* NULL on failure.
*/
static inline void *vspace_map_pages(vspace_t *vspace, seL4_CPtr caps[], uintptr_t cookies[],
seL4_CapRights_t rights, size_t num_pages, size_t size_bits,
int cacheable)
{
if (vspace == NULL) {
ZF_LOGE("vspace is NULL.");
return NULL;
}
if (vspace->new_pages == NULL) {
ZF_LOGE("Supplied vspace doesn't implement map_pages().");
return NULL;
}
if (num_pages == 0) {
ZF_LOGE("Called with num_pages == 0. Intentional?");
return NULL;
}
if (!sel4_valid_size_bits(size_bits)) {
ZF_LOGE("Invalid size_bits %zu", size_bits);
return NULL;
}
return vspace->map_pages(vspace, caps, cookies, rights,
num_pages, size_bits, cacheable);
}
static inline int vspace_new_pages_at_vaddr_with_config(vspace_t *vspace, vspace_new_pages_config_t *config,
reservation_t res)
{
if (vspace == NULL) {
ZF_LOGE("vspace is NULL");
return -1;
}
if (res.res == NULL) {
ZF_LOGE("reservation is required");
}
return vspace->new_pages_at_vaddr(vspace, config->vaddr, config->num_pages, config->size_bits, res,
config->can_use_dev);
}
static inline int vspace_new_pages_at_vaddr(vspace_t *vspace, void *vaddr, size_t num_pages, size_t size_bits,
reservation_t reservation)
{
if (vspace == NULL) {
ZF_LOGE("vspace is NULL");
return -1;
}
if (vspace->new_pages_at_vaddr == NULL) {
ZF_LOGE("Unimplemented");
return -1;
}
vspace_new_pages_config_t config;
if (default_vspace_new_pages_config(num_pages, size_bits, &config)) {
ZF_LOGE("Failed to create config");
return -1;
}
if (vspace_new_pages_config_set_vaddr(vaddr, &config)) {
ZF_LOGE("Failed to set vaddr");
return -1;
}
return vspace_new_pages_at_vaddr_with_config(vspace, &config, reservation);
}
static inline int vspace_map_pages_at_vaddr(vspace_t *vspace, seL4_CPtr caps[], uintptr_t cookies[], void *vaddr,
size_t num_pages, size_t size_bits, reservation_t reservation)
{
if (vspace == NULL) {
ZF_LOGE("vspace is NULL");
return -1;
}
if (num_pages == 0) {
ZF_LOGW("Attempt to map 0 pages");
return -1;
}
if (vaddr == NULL) {
ZF_LOGW("Mapping NULL");
}
if (vspace->map_pages_at_vaddr == NULL) {
ZF_LOGW("Unimplemented\n");
return -1;
}
return vspace->map_pages_at_vaddr(vspace, caps, cookies, vaddr, num_pages, size_bits, reservation);
}
static inline int vspace_deferred_rights_map_pages_at_vaddr(vspace_t *vspace, seL4_CPtr caps[], uintptr_t cookies[],
void *vaddr, size_t num_pages, size_t size_bits,
seL4_CapRights_t rights, reservation_t reservation)
{
if (vspace == NULL) {
ZF_LOGE("vspace is NULL");
return -1;
}
if (num_pages == 0) {
ZF_LOGW("Attempt to map 0 pages");
return -1;
}
if (vaddr == NULL) {
ZF_LOGW("Mapping NULL");
}
if (vspace->deferred_rights_map_pages_at_vaddr == NULL) {
ZF_LOGW("Unimplemented\n");
return -1;
}
return vspace->deferred_rights_map_pages_at_vaddr(vspace, caps, cookies, vaddr, num_pages,
size_bits, rights, reservation);
}
static inline void vspace_unmap_pages(vspace_t *vspace, void *vaddr, size_t num_pages, size_t size_bits, vka_t *vka)
{
if (vspace == NULL) {
ZF_LOGE("vspace is NULL");
return;
}
if (num_pages == 0) {
printf("Num pages : %zu\n", num_pages);
ZF_LOGW("Attempt to unmap 0 pages");
return;
}
if (vaddr == NULL) {
ZF_LOGW("Attempt to unmap NULL\n");
}
if (vspace->unmap_pages == NULL) {
ZF_LOGE("Not implemented\n");
return;
}
vspace->unmap_pages(vspace, vaddr, num_pages, size_bits, vka);
}
static inline void vspace_tear_down(vspace_t *vspace, vka_t *vka)
{
if (vspace == NULL) {
ZF_LOGE("vspace is NULL");
return;
}
if (vspace->tear_down == NULL) {
ZF_LOGE("Not implemented");
return;
}
vspace->tear_down(vspace, vka);
}
static inline reservation_t vspace_reserve_range_aligned(vspace_t *vspace, size_t bytes, size_t size_bits,
seL4_CapRights_t rights, int cacheable, void **vaddr)
{
reservation_t error = { .res = 0 };
if (vspace == NULL) {
ZF_LOGE("vspace is NULL");
return error;
}
if (vspace->reserve_range_aligned == NULL) {
ZF_LOGE("Not implemented");
return error;
}
if (bytes == 0) {
ZF_LOGE("Attempt to reserve 0 length range");
return error;
}
if (vaddr == NULL) {
ZF_LOGE("Cannot store result at NULL");
return error;
}
return vspace->reserve_range_aligned(vspace, bytes, size_bits, rights, cacheable, vaddr);
}
static inline reservation_t vspace_reserve_range_at(vspace_t *vspace, void *vaddr,
size_t bytes, seL4_CapRights_t rights, int cacheable)
{
reservation_t error = { .res = 0 };
if (vspace == NULL) {
ZF_LOGE("vspace is NULL");
return error;
}
if (vspace->reserve_range_at == NULL) {
ZF_LOGE("Not implemented");
return error;
}
if (bytes == 0) {
ZF_LOGE("Attempt to reserve 0 length range");
return error;
}
return vspace->reserve_range_at(vspace, vaddr, bytes, rights, cacheable);
}
static inline reservation_t vspace_reserve_deferred_rights_range_at(vspace_t *vspace, void *vaddr,
size_t bytes, int cacheable)
{
reservation_t error = { .res = 0 };
if (vspace == NULL) {
ZF_LOGE("vspace is NULL");
return error;
}
if (vspace->reserve_deferred_rights_range_at == NULL) {
ZF_LOGE("Not implemented");
return error;
}
if (bytes == 0) {
ZF_LOGE("Attempt to reserve 0 length range");
return error;
}
return vspace->reserve_deferred_rights_range_at(vspace, vaddr, bytes, cacheable);
}
static inline void vspace_free_reservation(vspace_t *vspace, reservation_t reservation)
{
if (vspace == NULL) {
ZF_LOGE("vspace is NULL");
return;
}
if (vspace->free_reservation == NULL) {
ZF_LOGE("Not implemented");
return;
}
vspace->free_reservation(vspace, reservation);
}
static inline void vspace_free_reservation_by_vaddr(vspace_t *vspace, void *vaddr)
{
if (vspace == NULL) {
ZF_LOGE("vspace is NULL");
return;
}
if (vspace->free_reservation_by_vaddr == NULL) {
ZF_LOGE("Not implemented");
return;
}
vspace->free_reservation_by_vaddr(vspace, vaddr);
}
static inline seL4_CPtr vspace_get_cap(vspace_t *vspace, void *vaddr)
{
if (vspace == NULL) {
ZF_LOGE("vspace is NULL");
return seL4_CapNull;
}
if (vaddr == NULL) {
ZF_LOGW("Warning: null address");
}
if (vspace->get_cap == NULL) {
ZF_LOGE("Not implemented\n");
return seL4_CapNull;
}
return vspace->get_cap(vspace, vaddr);
}
static inline uintptr_t vspace_get_cookie(vspace_t *vspace, void *vaddr)
{
if (vspace == NULL) {
ZF_LOGE("vspace is NULL");
return 0;
}
if (vaddr == NULL) {
/* only warn as someone might do this intentionally? */
ZF_LOGW("Warning: null address");
}
if (vspace->get_cookie == NULL) {
ZF_LOGE("Not implemented");
return 0;
}
return vspace->get_cookie(vspace, vaddr);
}
/* Helper functions */
static inline void vspace_maybe_call_allocated_object(vspace_t *vspace, vka_object_t object)
{
if (vspace == NULL) {
ZF_LOGF("vspace is NULL");
}
if (vspace->allocated_object != NULL) {
vspace->allocated_object(vspace->allocated_object_cookie, object);
}
}
static inline seL4_CPtr vspace_get_root(vspace_t *vspace)
{
if (vspace == NULL) {
ZF_LOGE("vspace is NULL");
return seL4_CapNull;
}
if (vspace->get_root == NULL) {
ZF_LOGE("Not implemented");
return seL4_CapNull;
}
return vspace->get_root(vspace);
}
static inline int vspace_share_mem_at_vaddr(vspace_t *from, vspace_t *to, void *start, int num_pages,
size_t size_bits, void *vaddr, reservation_t res)
{
if (num_pages == 0) {
/* nothing to do */
return -1;
} else if (num_pages < 0) {
ZF_LOGE("Attempted to share %d pages\n", num_pages);
return -1;
}
if (from == NULL) {
ZF_LOGE("From vspace does not exist");
return -1;
}
if (to == NULL) {
ZF_LOGE("To vspace does not exist");
return -1;
}
if (vaddr == NULL) {
ZF_LOGE("Cannot share memory at NULL");
return -1;
}
if (from->share_mem_at_vaddr == NULL) {
ZF_LOGE("Not implemented for this vspace\n");
return -1;
}
return from->share_mem_at_vaddr(from, to, start, num_pages, size_bits, vaddr, res);
}