| /* |
| * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230) |
| * |
| * SPDX-License-Identifier: BSD-2-Clause |
| */ |
| |
| #pragma once |
| |
| #include <autoconf.h> |
| #include <sel4vka/gen_config.h> |
| |
| #include <sel4/sel4.h> |
| #include <sel4/types.h> |
| #ifdef CONFIG_DEBUG_BUILD |
| #include <sel4debug/debug.h> |
| #endif |
| #include <assert.h> |
| #include <stdint.h> |
| #include <utils/util.h> |
| #include <vka/cspacepath_t.h> |
| |
| /** |
| * Allocate a slot in a cspace. |
| * |
| * @param data cookie for the underlying allocator |
| * @param res pointer to a cptr to store the allocated slot |
| * @return 0 on success |
| */ |
| typedef int (*vka_cspace_alloc_fn)(void *data, seL4_CPtr *res); |
| |
| /** |
| * Convert an allocated cptr to a cspacepath, for use in |
| * operations such as Untyped_Retype |
| * |
| * @param data cookie for the underlying allocator |
| * @param slot a cslot allocated by the cspace alloc function |
| * @param res pointer to a cspacepath struct to fill out |
| */ |
| typedef void (*vka_cspace_make_path_fn)(void *data, seL4_CPtr slot, cspacepath_t *res); |
| |
| /** |
| * Free an allocated cslot |
| * |
| * @param data cookie for the underlying allocator |
| * @param slot a cslot allocated by the cspace alloc function |
| */ |
| typedef void (*vka_cspace_free_fn)(void *data, seL4_CPtr slot); |
| |
| /** |
| * Allocate a portion of an untyped into an object |
| * |
| * @param data cookie for the underlying allocator |
| * @param dest path to an empty cslot to place the cap to the allocated object |
| * @param type the seL4 object type to allocate (as passed to Untyped_Retype) |
| * @param size_bits the size of the object to allocate (as passed to Untyped_Retype) |
| * @param res pointer to a location to store the cookie representing this allocation |
| * @return 0 on success |
| */ |
| typedef int (*vka_utspace_alloc_fn)(void *data, const cspacepath_t *dest, seL4_Word type, seL4_Word size_bits, |
| seL4_Word *res); |
| |
| /** |
| * Allocate a portion of an untyped into an object |
| * |
| * @param data cookie for the underlying allocator |
| * @param dest path to an empty cslot to place the cap to the allocated object |
| * @param type the seL4 object type to allocate (as passed to Untyped_Retype) |
| * @param size_bits the size of the object to allocate (as passed to Untyped_Retype) |
| * @param paddr The desired physical address that this object should start at |
| * @param cookie pointer to a location to store the cookie representing this allocation |
| * @return 0 on success |
| */ |
| typedef int (*vka_utspace_alloc_at_fn)(void *data, const cspacepath_t *dest, seL4_Word type, seL4_Word size_bits, |
| uintptr_t paddr, seL4_Word *cookie); |
| |
| /** |
| * Allocate a portion of an untyped into an object |
| * |
| * @param data cookie for the underlying allocator |
| * @param dest path to an empty cslot to place the cap to the allocated object |
| * @param type the seL4 object type to allocate (as passed to Untyped_Retype) |
| * @param size_bits the size of the object to allocate (as passed to Untyped_Retype) |
| * @param can_use_dev whether the allocator can use device untyped instead of regular untyped |
| * @param res pointer to a location to store the cookie representing this allocation |
| * @return 0 on success |
| */ |
| typedef int (*vka_utspace_alloc_maybe_device_fn)(void *data, const cspacepath_t *dest, seL4_Word type, |
| seL4_Word size_bits, bool can_use_dev, seL4_Word *res); |
| |
| /** |
| * Free a portion of an allocated untyped. Is the responsibility of the caller to |
| * have already deleted the object (by deleting all capabilities) first |
| * |
| * @param data cookie for the underlying allocator |
| * @param type the seL4 object type that was allocated (as passed to Untyped_Retype) |
| * @param size_bits the size of the object that was allocated (as passed to Untyped_Retype) |
| * @param target cookie to the allocation as given by the utspace alloc function |
| */ |
| typedef void (*vka_utspace_free_fn)(void *data, seL4_Word type, seL4_Word size_bits, seL4_Word target); |
| |
| /** |
| * Request the physical address of an object. |
| * |
| * @param data cookie for the underlying allocator |
| * @param target cookie to the allocation as given by the utspace alloc function |
| * @param type the seL4 object type that was allocated (as passed to Untyped_Retype) |
| * @param size_bits the size of the object that was allocated (as passed to Untyped_Retype) |
| * @return paddr of object, or VKA_NO_PADDR on error |
| */ |
| typedef uintptr_t (*vka_utspace_paddr_fn)(void *data, seL4_Word target, seL4_Word type, seL4_Word size_bits); |
| |
| #define VKA_NO_PADDR 1 |
| |
| /* |
| * Generic Virtual Kernel Allocator (VKA) data structure. |
| * |
| * This is similar in concept to the Linux VFS structures, but for |
| * the seL4 kernel object allocator instead of the Linux file system. |
| * |
| * Alternatively, you can think of this as a abstract class in an |
| * OO hierarchy, of which has several implementations. |
| */ |
| |
| typedef struct vka { |
| void *data; |
| vka_cspace_alloc_fn cspace_alloc; |
| vka_cspace_make_path_fn cspace_make_path; |
| vka_utspace_alloc_fn utspace_alloc; |
| vka_utspace_alloc_maybe_device_fn utspace_alloc_maybe_device; |
| vka_utspace_alloc_at_fn utspace_alloc_at; |
| vka_cspace_free_fn cspace_free; |
| vka_utspace_free_fn utspace_free; |
| vka_utspace_paddr_fn utspace_paddr; |
| } vka_t; |
| |
| static inline int vka_cspace_alloc(vka_t *vka, seL4_CPtr *res) |
| { |
| if (!vka) { |
| ZF_LOGE("vka is NULL"); |
| return -1; |
| } |
| |
| if (!res) { |
| ZF_LOGE("res is NULL"); |
| return -1; |
| } |
| |
| if (!vka->cspace_alloc) { |
| ZF_LOGE("Unimplemented"); |
| return -1; |
| } |
| |
| return vka->cspace_alloc(vka->data, res); |
| } |
| |
| static inline void vka_cspace_make_path(vka_t *vka, seL4_CPtr slot, cspacepath_t *res) |
| { |
| |
| if (!res) { |
| ZF_LOGF("res is NULL"); |
| } |
| |
| if (!vka) { |
| ZF_LOGF("vka is NULL"); |
| } |
| |
| if (!vka->cspace_make_path) { |
| ZF_LOGF("Unimplmented"); |
| } |
| |
| vka->cspace_make_path(vka->data, slot, res); |
| } |
| |
| /* |
| * Wrapper functions to make calls more convenient |
| */ |
| static inline int vka_cspace_alloc_path(vka_t *vka, cspacepath_t *res) |
| { |
| seL4_CPtr slot; |
| int error = vka_cspace_alloc(vka, &slot); |
| |
| if (error == seL4_NoError) { |
| vka_cspace_make_path(vka, slot, res); |
| } |
| |
| return error; |
| } |
| |
| static inline void vka_cspace_free(vka_t *vka, seL4_CPtr slot) |
| { |
| #ifdef CONFIG_DEBUG_BUILD |
| if (debug_cap_is_valid(slot)) { |
| ZF_LOGF("slot is not free: call vka_cnode_delete first"); |
| /* this terminates the system */ |
| } |
| #endif |
| |
| if (!vka->cspace_free) { |
| ZF_LOGE("Not implemented"); |
| return; |
| } |
| |
| vka->cspace_free(vka->data, slot); |
| } |
| |
| static inline void vka_cspace_free_path(vka_t *vka, cspacepath_t path) |
| { |
| vka_cspace_free(vka, path.capPtr); |
| } |
| |
| static inline int vka_utspace_alloc(vka_t *vka, const cspacepath_t *dest, seL4_Word type, seL4_Word size_bits, |
| seL4_Word *res) |
| { |
| if (!vka) { |
| ZF_LOGE("vka is NULL"); |
| return -1; |
| } |
| |
| if (!res) { |
| ZF_LOGE("res is NULL"); |
| return -1; |
| } |
| |
| if (!vka->utspace_alloc) { |
| ZF_LOGE("Not implemented"); |
| return -1; |
| } |
| |
| return vka->utspace_alloc(vka->data, dest, type, size_bits, res); |
| } |
| |
| static inline int vka_utspace_alloc_maybe_device(vka_t *vka, const cspacepath_t *dest, seL4_Word type, |
| seL4_Word size_bits, bool can_use_dev, seL4_Word *res) |
| { |
| if (!vka) { |
| ZF_LOGE("vka is NULL"); |
| return -1; |
| } |
| |
| if (!res) { |
| ZF_LOGE("res is NULL"); |
| return -1; |
| } |
| |
| if (!vka->utspace_alloc_maybe_device) { |
| ZF_LOGE("Not implemented"); |
| return -1; |
| } |
| |
| return vka->utspace_alloc_maybe_device(vka->data, dest, type, size_bits, can_use_dev, res); |
| } |
| |
| static inline int vka_utspace_alloc_at(vka_t *vka, const cspacepath_t *dest, seL4_Word type, seL4_Word size_bits, |
| uintptr_t paddr, seL4_Word *cookie) |
| { |
| if (!vka) { |
| ZF_LOGE("vka is NULL"); |
| return -1; |
| } |
| if (!cookie) { |
| ZF_LOGE("cookie is NULL"); |
| return -1; |
| } |
| if (!vka->utspace_alloc_at) { |
| ZF_LOGE("Not implemented"); |
| return -1; |
| } |
| |
| return vka->utspace_alloc_at(vka->data, dest, type, size_bits, paddr, cookie); |
| } |
| |
| static inline void vka_utspace_free(vka_t *vka, seL4_Word type, seL4_Word size_bits, seL4_Word target) |
| { |
| if (!vka) { |
| ZF_LOGE("vka is NULL"); |
| return ; |
| } |
| |
| if (!vka->utspace_free) { |
| #ifndef CONFIG_LIB_VKA_ALLOW_MEMORY_LEAKS |
| ZF_LOGF("Not implemented"); |
| /* This terminates the system */ |
| #endif |
| return; |
| } |
| |
| vka->utspace_free(vka->data, type, size_bits, target); |
| } |
| |
| static inline uintptr_t vka_utspace_paddr(vka_t *vka, seL4_Word target, seL4_Word type, seL4_Word size_bits) |
| { |
| |
| if (!vka) { |
| ZF_LOGE("vka is NULL"); |
| return VKA_NO_PADDR; |
| } |
| |
| if (!vka->utspace_paddr) { |
| ZF_LOGE("Not implemented"); |
| return VKA_NO_PADDR; |
| } |
| |
| return vka->utspace_paddr(vka->data, target, type, size_bits); |
| } |
| |