aos/lib/aos/capabilities.c
2022-05-18 17:45:24 +02:00

889 lines
26 KiB
C

/**
* \file
* \brief Capability system user code
*/
/*
* Copyright (c) 2007-2010, 2012, 2016, ETH Zurich.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
* ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
*/
#include <stdint.h>
#include <stdbool.h>
#include <aos/aos.h>
#include <aos/cspace.h>
#include <aos/caddr.h>
#include <aos/kernel_cap_invocations.h>
#include <aos/lmp_endpoints.h>
#include <aos/aos_rpc.h>
#include <stdio.h>
/// Root CNode
#define ROOT_CNODE_INIT { \
.croot = CPTR_ROOTCN, \
.cnode = 0, \
.level = CNODE_TYPE_ROOT, }
struct cnoderef cnode_root = ROOT_CNODE_INIT;
#define TASK_CNODE_INIT { \
.croot = CPTR_ROOTCN, \
.cnode = CPTR_TASKCN_BASE, \
.level = CNODE_TYPE_OTHER, }
#define PAGE_CNODE_INIT { \
.croot = CPTR_ROOTCN, \
.cnode = CPTR_PAGECN_BASE, \
.level = CNODE_TYPE_OTHER, }
#define MODULE_CNODE_INIT { \
.croot = CPTR_ROOTCN, \
.cnode = CPTR_MODULECN_BASE, \
.level = CNODE_TYPE_OTHER, }
#define ARG_CNODE_INIT { \
.croot = CPTR_ROOTCN, \
.cnode = CPTR_ARGCN_BASE, \
.level = CNODE_TYPE_OTHER, }
/// Task CNode
struct cnoderef cnode_task = TASK_CNODE_INIT;
/// Base CNode
struct cnoderef cnode_base = {
.cnode = CPTR_BASE_PAGE_CN_BASE,
.level = CNODE_TYPE_OTHER,
.croot = CPTR_ROOTCN,
};
/// Super CNode
struct cnoderef cnode_super = {
.cnode = CPTR_SUPERCN_BASE,
.level = CNODE_TYPE_OTHER,
.croot = CPTR_ROOTCN,
};
/// Page CNode
struct cnoderef cnode_page = PAGE_CNODE_INIT;
/// Module CNode
struct cnoderef cnode_module = MODULE_CNODE_INIT;
/// Arg CNode
struct cnoderef cnode_arg = ARG_CNODE_INIT;
struct capref cap_mmstrings = {
.cnode = MODULE_CNODE_INIT,
.slot = 0
};
/// Capability to Root CNode
struct capref cap_root = {
.cnode = TASK_CNODE_INIT,
.slot = TASKCN_SLOT_ROOTCN
};
/// Capability for IRQ table
struct capref cap_irq = {
.cnode = TASK_CNODE_INIT,
.slot = TASKCN_SLOT_IRQ
};
/// Capability for Device Frame
struct capref cap_io = {
.cnode = TASK_CNODE_INIT,
.slot = TASKCN_SLOT_DEV
};
/// Capability for endpoint to self
struct capref cap_selfep = {
.cnode = TASK_CNODE_INIT,
.slot = TASKCN_SLOT_SELFEP
};
/// Capability for dispatcher
struct capref cap_dispatcher = {
.cnode = TASK_CNODE_INIT,
.slot = TASKCN_SLOT_DISPATCHER
};
/// Capability for dispatcher
struct capref cap_dispframe = {
.cnode = TASK_CNODE_INIT,
.slot = TASKCN_SLOT_DISPFRAME
};
/// Capability for ArgSpace
struct capref cap_argcn = {
.cnode = ROOT_CNODE_INIT,
.slot = ROOTCN_SLOT_ARGCN
};
/// Capability for monitor endpoint
struct capref cap_monitorep = {
.cnode = TASK_CNODE_INIT,
.slot = TASKCN_SLOT_MONITOREP
};
/// Capability for bootinfo (only in monitor)
struct capref cap_bootinfo = {
.cnode = TASK_CNODE_INIT,
.slot = TASKCN_SLOT_BOOTINFO
};
/// Capability for kernel (only in monitor)
struct capref cap_kernel = {
.cnode = TASK_CNODE_INIT,
.slot = TASKCN_SLOT_KERNELCAP
};
/// Capability for IPI sending (only in monitor)
struct capref cap_ipi = {
.cnode = TASK_CNODE_INIT,
.slot = TASKCN_SLOT_IPI
};
/// PerfMon CNode
struct capref cap_perfmon = {
.cnode = TASK_CNODE_INIT,
.slot = TASKCN_SLOT_PERF_MON
};
/// Capability for endpoint to init (only in monitor/mem_serv)
struct capref cap_initep = {
.cnode = TASK_CNODE_INIT,
.slot = TASKCN_SLOT_INITEP
};
/// Capability to the URPC frame
struct capref cap_urpc = {
.cnode = TASK_CNODE_INIT,
.slot = TASKCN_SLOT_MON_URPC
};
/// Session ID
struct capref cap_sessionid = {
.cnode = TASK_CNODE_INIT,
.slot = TASKCN_SLOT_SESSIONID
};
/// Process manager cap, allows creating domains.
struct capref cap_procmng = {
.cnode = TASK_CNODE_INIT,
.slot = TASKCN_SLOT_PROC_MNG
};
/// Domain ID cap.
struct capref cap_domainid = {
.cnode = TASK_CNODE_INIT,
.slot = TASKCN_SLOT_DOMAINID
};
/// Root PML4 VNode
struct capref cap_vroot = {
.cnode = PAGE_CNODE_INIT,
.slot = PAGECN_SLOT_VROOT,
};
static inline bool backoff(int count)
{
// very crude exponential backoff based upon core id
int yieldcnt = 2^count * disp_get_core_id();
for (int i=0; i<yieldcnt; i++) {
thread_yield();
}
return true;
}
/**
* \brief Retype a capability into one or more new capabilities, going through
* the monitor to ensure consistancy with other cores. Only necessary for
* caps that have been sent remotely.
*/
static errval_t cap_retype_remote(struct capref src_root, struct capref dest_root,
capaddr_t src, gensize_t offset, enum objtype new_type,
gensize_t objsize, size_t count, capaddr_t to,
capaddr_t slot, int to_level)
{
return LIB_ERR_NOT_IMPLEMENTED;
}
/**
* \brief Delete the given capability, going through the monitor to ensure
* consistancy with other cores. Only necessary for caps that have been sent
* remotely.
*
* \param cap Capability to be deleted
*
* Deletes (but does not revoke) the given capability, allowing the CNode slot
* to be reused.
*/
static errval_t cap_delete_remote(struct capref root, capaddr_t src, uint8_t level)
{
return LIB_ERR_NOT_IMPLEMENTED;
}
/**
* \brief Revoke (delete all copies and descendants of) the given capability,
* going through the monitor to ensure consistancy with other cores. Only
* necessary for caps that have been sent remotely.
*
* \param cap Capability to be revoked
*
* Deletes all copies and descendants of the given capability, but not the
* capability itself. If this succeeds, the capability is guaranteed to be
* the only copy in the system.
*/
static errval_t cap_revoke_remote(struct capref root, capaddr_t src, uint8_t level)
{
return LIB_ERR_NOT_IMPLEMENTED;
}
/**
* \brief Retype (part of) a capability into one or more new capabilities
*
* \param dest_start Location of first destination slot, which must be empty
* \param src Source capability to retype
* \param offset Offset into source capability
* \param new_type Kernel object type to retype to.
* \param objsize Size of created objects in bytes
* (ignored for fixed-size objects)
* \param count The number of new objects to create
*
* When retyping IRQSrc capabilities, offset and objsize represent the start
* and end of the to be created interrupt range. Count must be 1 for IRQSrc.
*
* Retypes (part of) the given source capability into a number of new
* capabilities, which may be of the same or of different type. The new
* capabilities are created in the slots starting from dest_start, which must
* all be empty and lie in the same CNode. The number of objects created is
* determined by the argument `count`.
*/
errval_t cap_retype(struct capref dest_start, struct capref src, gensize_t offset,
enum objtype new_type, gensize_t objsize, size_t count)
{
errval_t err;
// Address of destination cspace
capaddr_t dcs_addr = get_croot_addr(dest_start);
// Address of the cap to the destination CNode
capaddr_t dcn_addr = get_cnode_addr(dest_start);
// Depth/Level of destination cnode
enum cnode_type dcn_level = get_cnode_level(dest_start);
// Address of source cspace
capaddr_t scp_root = get_croot_addr(src);
// Address of source capability
capaddr_t scp_addr = get_cap_addr(src);
err = invoke_cnode_retype(cap_root, scp_root, scp_addr, offset, new_type,
objsize, count, dcs_addr, dcn_addr, dcn_level,
dest_start.slot);
if (err_no(err) == SYS_ERR_RETRY_THROUGH_MONITOR) {
struct capref src_root = get_croot_capref(src);
struct capref dest_root = get_croot_capref(dest_start);
return cap_retype_remote(src_root, dest_root, scp_addr, offset, new_type,
objsize, count, dcn_addr, dest_start.slot,
dcn_level);
} else {
return err;
}
}
/**
* \brief Create a capability
*
* \param dest Location where to create the cap, which must be empty.
* \param type Kernel object type to create.
* \param size Size of the created capability in bytes.
* (ignored for fixed-size objects)
*
* Only certain types of capabilities can be created this way. If invoked on
* a capability type, that is not creatable at runtime the error
* SYS_ERR_TYPE_NOT_CREATABLE is returned. Most capabilities have to be retyped
* from other capabilities with cap_retype().
*/
errval_t cap_create(struct capref dest, enum objtype type, size_t size)
{
errval_t err;
// Address of the cap to the destination CNode
capaddr_t dest_cnode_cptr = get_cnode_addr(dest);
enum cnode_type dest_cnode_level = get_cnode_level(dest);
err = invoke_cnode_create(cap_root, type, size, dest_cnode_cptr,
dest_cnode_level, dest.slot);
return err;
}
/**
* \brief Delete the given capability
*
* \param cap Capability to be deleted
*
* Deletes (but does not revoke) the given capability, allowing the CNode slot
* to be reused.
*/
errval_t cap_delete(struct capref cap)
{
errval_t err;
struct capref croot = get_croot_capref(cap);
capaddr_t caddr = get_cap_addr(cap);
enum cnode_type level = get_cap_level(cap);
err = invoke_cnode_delete(croot, caddr, level);
if (err_no(err) == SYS_ERR_RETRY_THROUGH_MONITOR) {
return cap_delete_remote(croot, caddr, level);
} else {
return err;
}
}
/**
* \brief Revoke (delete all copies and descendants of) the given capability
*
* \param cap Capability to be revoked
*
* Deletes all copies and descendants of the given capability, but not the
* capability itself. If this succeeds, the capability is guaranteed to be
* the only copy in the system.
*/
errval_t cap_revoke(struct capref cap)
{
errval_t err;
struct capref croot = get_croot_capref(cap);
capaddr_t caddr = get_cap_addr(cap);
enum cnode_type level = get_cap_level(cap);
err = invoke_cnode_revoke(croot, caddr, level);
if (err_no(err) == SYS_ERR_RETRY_THROUGH_MONITOR) {
return cap_revoke_remote(croot, caddr, level);
} else {
return err;
}
}
/**
* \brief Destroy a capability, i.e. delete it and free the slot.
*
* \param cap Capability to be destroyed
*/
errval_t cap_destroy(struct capref cap)
{
errval_t err;
err = cap_delete(cap);
if (err_is_fail(err)) {
return err;
}
err = slot_free(cap);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_WHILE_FREEING_SLOT);
}
return SYS_ERR_OK;
}
/**
* \brief Replace own L1 CNode
*
* \param new the replacement L1 CNode
* \param ret the slot to put the old L1 CNode
*/
errval_t root_cnode_resize(struct capref new, struct capref ret)
{
assert(get_croot_addr(new) == CPTR_ROOTCN);
assert(get_cap_level(new) == CNODE_TYPE_COUNT);
capaddr_t new_cptr = get_cap_addr(new);
assert(get_croot_addr(ret) == CPTR_ROOTCN);
assert(get_cap_level(ret) == CNODE_TYPE_COUNT);
capaddr_t retcn_ptr= get_cnode_addr(ret);
return invoke_cnode_resize(cap_root, new_cptr, retcn_ptr, ret.slot);
}
/**
* \brief Create a CNode from a given RAM capability in a specific slot
*
* \param dest location in which to place newly-created CNode cap
* \param src location of RAM capability to be retyped to new CNode
* \param cnoderef cnoderef struct, filled-in if non-NULL with relevant info
* \param slots number of slots in created CNode
* must match size of RAM capability.
*
* This function requires that dest refer to an existing but empty slot. It
* retypes the given memory to a new CNode.
*/
errval_t cnode_create_from_mem(struct capref dest, struct capref src,
enum objtype cntype, struct cnoderef *cnoderef,
size_t slots)
{
errval_t err;
if (cntype != ObjType_L1CNode &&
cntype != ObjType_L2CNode)
{
return LIB_ERR_CNODE_TYPE;
}
// Retype it to the destination
err = cap_retype(dest, src, 0, cntype, slots * OBJSIZE_CTE, 1);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_CAP_RETYPE);
}
// Construct the cnoderef to return
if (cnoderef != NULL) {
enum cnode_type ref_cntype = cntype == ObjType_L1CNode ? CNODE_TYPE_ROOT : CNODE_TYPE_OTHER;
*cnoderef = build_cnoderef(dest, ref_cntype);
}
return SYS_ERR_OK;
}
/**
* \brief Create a CNode from newly-allocated RAM in a newly-allocated slot
*
* \param ret_dest capref struct to be filled-in with location of CNode
* \param cnoderef cnoderef struct, filled-in if non-NULL with relevant info
* \param slots Minimum number of slots in created CNode
* \param retslots If non-NULL, filled in with the number of slots in created CNode
*/
errval_t cnode_create(struct capref *ret_dest, struct cnoderef *cnoderef,
cslot_t slots, cslot_t *retslots)
{
USER_PANIC("cnode_create deprecated; use cnode_create_l1, cnode_create_l2, or cnode_create_foreign_l2: %p %p %p %p\n",
__builtin_return_address(0),
#ifdef __x86_64__
__builtin_return_address(1),
__builtin_return_address(2),
__builtin_return_address(3)
#else
NULL, NULL, NULL
#endif
);
return LIB_ERR_NOT_IMPLEMENTED;
}
/**
* \brief Create a L2 CNode from newly-allocated RAM in a newly-allocated slot
*
* \param ret_dest capref struct to be filled-in with location of CNode
* \param cnoderef cnoderef struct, filled-in if non-NULL with relevant info
*
* This function always creates a L2 CNode which contains 256 capabilities
*/
errval_t cnode_create_l2(struct capref *ret_dest, struct cnoderef *cnoderef)
{
errval_t err;
// Allocate a slot in root cn for destination
assert(ret_dest != NULL);
err = slot_alloc_root(ret_dest);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_SLOT_ALLOC);
}
cslot_t retslots;
err = cnode_create_raw(*ret_dest, cnoderef, ObjType_L2CNode,
L2_CNODE_SLOTS, &retslots);
if (retslots != L2_CNODE_SLOTS) {
debug_printf("Unable to create properly sized L2 CNode: got %"PRIuCSLOT" slots instead of %"PRIuCSLOT"\n",
retslots, (cslot_t)L2_CNODE_SLOTS);
}
return err;
}
errval_t cnode_create_l1(struct capref *ret_dest, struct cnoderef *cnoderef)
{
errval_t err;
// Allocate a slot in root cn for destination
assert(ret_dest != NULL);
err = slot_alloc(ret_dest);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_SLOT_ALLOC);
}
cslot_t retslots;
err = cnode_create_raw(*ret_dest, cnoderef, ObjType_L1CNode,
L2_CNODE_SLOTS, &retslots);
if (retslots != L2_CNODE_SLOTS) {
debug_printf("Unable to create initial L1 CNode: got %"PRIuCSLOT" slots instead of %"PRIuCSLOT"\n",
retslots, (cslot_t)L2_CNODE_SLOTS);
}
return err;
}
/**
* \brief Create a CNode for another cspace from newly-allocated RAM in a
* newly-allocated slot
*
* \param dest_l1 capref to L1 (root) cnode of destination cspace
* \param dest_slot slot to fill with new cnode in destination L1 cnode
* \param cnoderef cnoderef struct, filled-in if non-NULL with relevant info
*
* This function creates a CNode which contains 256 capabilities initially
* and puts it in a slot in our cspace.
*/
errval_t cnode_create_foreign_l2(struct capref dest_l1, cslot_t dest_slot,
struct cnoderef *cnoderef)
{
errval_t err;
if (capref_is_null(dest_l1)) {
return LIB_ERR_CROOT_NULL;
}
assert(!capref_is_null(dest_l1));
struct capref dest;
dest.cnode = build_cnoderef(dest_l1, CNODE_TYPE_ROOT);
dest.slot = dest_slot;
cslot_t retslots;
err = cnode_create_raw(dest, NULL, ObjType_L2CNode, L2_CNODE_SLOTS, &retslots);
if (retslots != L2_CNODE_SLOTS) {
debug_printf("Unable to create properly sized foreign CNode: "
"got %"PRIuCSLOT" slots instead of %"PRIuCSLOT"\n",
retslots, (cslot_t)L2_CNODE_SLOTS);
}
// Create proper cnoderef for foreign L2
if (cnoderef) {
cnoderef->croot = get_cap_addr(dest_l1);
cnoderef->cnode = ROOTCN_SLOT_ADDR(dest_slot);
cnoderef->level = CNODE_TYPE_OTHER;
}
return err;
}
/**
* \brief Create a CNode from newly-allocated RAM in the given slot
*
* \param dest location in which to place CNode cap
* \param cnoderef cnoderef struct, filled-in if non-NULL with relevant info
* \param cntype, type of new cnode
* \param slots Minimum number of slots in created CNode
* \param retslots If non-NULL, filled in with the number of slots in created CNode
*
* This function requires that dest refer to an existing but empty slot. It
* allocates memory (using #ram_alloc), and retypes that memory to a new CNode.
* The intermediate ram cap is destroyed.
*/
errval_t cnode_create_raw(struct capref dest, struct cnoderef *cnoderef,
enum objtype cntype, cslot_t slots, cslot_t *retslots)
{
errval_t err;
struct capref ram;
assert(slots > 0);
if (cntype != ObjType_L1CNode &&
cntype != ObjType_L2CNode)
{
return LIB_ERR_CNODE_TYPE;
}
if (slots < L2_CNODE_SLOTS ||
(cntype == ObjType_L2CNode && slots != L2_CNODE_SLOTS))
{
return LIB_ERR_CNODE_SLOTS;
}
if (retslots != NULL) {
*retslots = slots;
}
// Allocate some memory
err = ram_alloc(&ram, slots * OBJSIZE_CTE);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_RAM_ALLOC);
}
err = cnode_create_from_mem(dest, ram, cntype, cnoderef, slots);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_CNODE_CREATE_FROM_MEM);
}
err = cap_destroy(ram);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_CAP_DESTROY);
}
return SYS_ERR_OK;
}
/**
* \brief Create CNode with a given guard
*
* \param dest Location where to place the cnode
* \param cnoderef Filled in cnoderef struct if non-NULL
* \param slots Minimum number of slots in created CNode
* \param retslots If non-NULL, filled in with the number of slots in created CNode
* \param guard The guard value to set
* \param guard_size The length of the guard in bits
*
* This function requires that dest refer to an existing but empty slot. It
* allocates memory (using #ram_alloc), and retypes that memory to a new CNode
* with the given guard value and size. An intermediate slot is used in order to
* set the guard value.
*/
errval_t cnode_create_with_guard(struct capref dest, struct cnoderef *cnoderef,
cslot_t slots, cslot_t *retslots,
uint64_t guard, uint8_t guard_size)
{
USER_PANIC("%s: GPT CNodes are deprecated\n", __FUNCTION__);
}
/**
* \brief Create a VNode in newly-allocated memory
*
* \param dest location to place new VNode cap
* \param type VNode type to create
*
* This function requires that dest refer to an existing but empty slot.
* The intermidiate ram cap is destroyed.
*/
errval_t vnode_create(struct capref dest, enum objtype type)
{
errval_t err;
struct capref ram;
err = ram_alloc_aligned(&ram, vnode_objsize(type), vnode_objsize(type));
if (err_no(err) == LIB_ERR_RAM_ALLOC_WRONG_SIZE && type != ObjType_VNode_ARM_l1) {
// can only get 4kB pages, cannot create ARM_l1, and waste 3kB for
// ARM_l2
err = ram_alloc(&ram, BASE_PAGE_SIZE);
}
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_RAM_ALLOC);
}
assert(type_is_vnode(type));
err = cap_retype(dest, ram, 0, type, vnode_objsize(type), 1);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_CAP_RETYPE);
}
err = cap_destroy(ram);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_CAP_DESTROY);
}
return SYS_ERR_OK;
}
/**
* \brief Create a Frame cap referring to newly-allocated RAM in a given slot
*
* \param dest Location to place new frame cap
* \param bytes Minimum size of frame to create
* \param retbytes If non-NULL, filled in with size of created frame
*
* This function requires that dest refer to an existing but empty slot.
* #ram_alloc is used to allocate memory. After retyping the intermediate
* ram cap is destroyed.
*
* This function will returns a special error code if ram_alloc fails
* due to the constrains on the memory server (size of cap or region
* of memory). This is to facilitate retrying with different
* constraints.
*/
errval_t frame_create(struct capref dest, size_t bytes, size_t *retbytes)
{
assert(bytes > 0);
errval_t err;
bytes = ROUND_UP(bytes, BASE_PAGE_SIZE);
struct capref ram;
err = ram_alloc(&ram, bytes);
if (err_is_fail(err)) {
if (err_no(err) == MM_ERR_NOT_FOUND ||
err_no(err) == LIB_ERR_RAM_ALLOC_WRONG_SIZE) {
return err_push(err, LIB_ERR_RAM_ALLOC_MS_CONSTRAINTS);
}
return err_push(err, LIB_ERR_RAM_ALLOC);
}
err = cap_retype(dest, ram, 0, ObjType_Frame, bytes, 1);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_CAP_RETYPE);
}
err = cap_destroy(ram);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_CAP_DESTROY);
}
if (retbytes != NULL) {
*retbytes = bytes;
}
return SYS_ERR_OK;
}
/**
* \brief Create a dispatcher capability and store it in the slot pointed to
* by 'dest'
*
* This function requires that dest refers to an existing but empty slot. It
* allocates a new RAM cap, retypes it to one of type ObjType_Dispatcher and
* stores it at the slot pointed to by the capref struct 'dest'. The intermediate
* ram cap is then destroyed.
*
* \param dest location to place new dispatcher cap
*
* \return Either SYS_ERR_OK if no error occured or an error
* indicating what went wrong otherwise.
*/
errval_t dispatcher_create(struct capref dest)
{
errval_t err;
struct capref ram;
assert(1 << log2ceil(OBJSIZE_DISPATCHER) == OBJSIZE_DISPATCHER);
size_t size = OBJSIZE_DISPATCHER;
err = ram_alloc(&ram, size);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_RAM_ALLOC);
}
err = cap_retype(dest, ram, 0, ObjType_Dispatcher, 0, 1);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_CAP_RETYPE);
}
err = cap_destroy(ram);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_CAP_DESTROY);
}
return SYS_ERR_OK;
}
/**
* \brief Create endpoint to caller on current dispatcher.
*
* \param buflen Length of incoming LMP buffer, in words
* \param retcap Pointer to capref struct, filled-in with location of cap
* \param retep Double pointer to LMP endpoint, filled-in with allocated EP
*/
errval_t endpoint_create(size_t buflen, struct capref *retcap,
struct lmp_endpoint **retep)
{
errval_t err = slot_alloc(retcap);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_SLOT_ALLOC);
}
return lmp_endpoint_create_in_slot(buflen, *retcap, retep);
}
/**
* \brief Create a Frame cap referring to newly-allocated RAM in an allocated slot
*
* \param dest Pointer to capref struct, filled-in with location of new cap
* \param bytes Minimum size of frame to create
* \param retbytes If non-NULL, filled in with size of created frame
*/
errval_t frame_alloc(struct capref *dest, size_t bytes, size_t *retbytes)
{
errval_t err = slot_alloc(dest);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_SLOT_ALLOC);
}
return frame_create(*dest, bytes, retbytes);
}
/**
* \brief Create a DevFrame cap by retyping out of given source PhysAddr cap
*
* \param dest Pointer to capref struct, filled-in with location of new cap
* \param src Cap_info struct for the source PhysAddr cap
* \param size_bits Size of created objects as a power of two
* (ignored for fixed-size objects)
*/
errval_t devframe_type(struct capref *dest, struct capref src, uint8_t bits)
{
errval_t err = slot_alloc(dest);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_SLOT_ALLOC);
}
return cap_retype(*dest, src, 0, ObjType_DevFrame, 1UL << bits, 1);
}
/**
* \brief Create an ID cap in a newly allocated slot.
*
* \param dest Pointer to capref struct, filld-in with location of new cap.
*
* The caller is responsible for revoking the cap after using it.
*/
errval_t idcap_alloc(struct capref *dest)
{
errval_t err = slot_alloc(dest);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_SLOT_ALLOC);
}
return idcap_create(*dest);
}
/**
* \brief Create an ID cap in the specified slot.
*
* \param dest Capref, where ID cap should be created.
*
* The caller is responsible for revoking the cap after using it.
*/
errval_t idcap_create(struct capref dest)
{
return cap_create(dest, ObjType_ID, 0);
}
/**
* \brief Builds a #cnoderef struct from a #capref struct using cap
* identification.
*
* \param cnoder Pointer to a cnoderef struct, fill-in by function.
* \param capr Capref to a CNode capability.
*/
errval_t cnode_build_cnoderef(struct cnoderef *cnoder, struct capref capr)
{
struct capability cap;
errval_t err = debug_cap_identify(capr, &cap);
if (err_is_fail(err)) {
return err;
}
if (cap.type != ObjType_L1CNode &&
cap.type != ObjType_L2CNode) {
return LIB_ERR_NOT_CNODE;
}
if (!cnodecmp(capr.cnode, cnode_root)) {
USER_PANIC("cnode_build_cnoderef NYI for non rootcn caprefs");
}
cnoder->croot = get_croot_addr(capr);
cnoder->cnode = capr.slot << L2_CNODE_BITS;
cnoder->level = CNODE_TYPE_OTHER;
return SYS_ERR_OK;
}