481 lines
16 KiB
C
481 lines
16 KiB
C
/**
|
|
* \file
|
|
* \brief Architecture independent capability invocations
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 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.
|
|
*/
|
|
|
|
#ifndef INVOCATIONS_H
|
|
#define INVOCATIONS_H
|
|
|
|
#include <barrelfish_kpi/dispatcher_shared.h>
|
|
#include <barrelfish_kpi/distcaps.h> // for distcap_state_t
|
|
#include <aos/caddr.h>
|
|
|
|
#include <aos/invocations_arch.h>
|
|
|
|
__BEGIN_DECLS
|
|
|
|
static inline errval_t invoke_ram_noop(struct capref ram)
|
|
{
|
|
return cap_invoke1(ram, RAMCmd_Noop).error;
|
|
}
|
|
|
|
/**
|
|
* \brief Create a capability.
|
|
*
|
|
* Create a new capability of type 'type' and size 'objbits'. The new cap will
|
|
* be placed in the slot 'dest_slot' of the CNode located at 'dest_cnode_cptr'
|
|
* in the address space rooted at 'root'.
|
|
*
|
|
* See also cap_create(), which wraps this.
|
|
*
|
|
* \param root Capability of the CNode to invoke.
|
|
* \param type Kernel object type to create.
|
|
* \param objsize Size of created object
|
|
* (ignored for fixed-size objects)
|
|
* \param dest_cnode_cptr Address of CNode cap, where newly created cap will be
|
|
* placed into.
|
|
* \param dest_level Depth/level of destination CNode.
|
|
* \param dest_slot Slot in CNode cap to place new cap.
|
|
*
|
|
* \return Error code
|
|
*/
|
|
static inline errval_t invoke_cnode_create(struct capref root,
|
|
enum objtype type, size_t objsize,
|
|
capaddr_t dest_cnode_cptr,
|
|
enum cnode_type dest_level,
|
|
capaddr_t dest_slot)
|
|
{
|
|
assert(dest_cnode_cptr != CPTR_NULL);
|
|
return cap_invoke6(root, CNodeCmd_Create, type, objsize, dest_cnode_cptr,
|
|
dest_level, dest_slot).error;
|
|
}
|
|
|
|
/**
|
|
* \brief "Mint" a capability.
|
|
*
|
|
* Copies CPtr 'from' into slot 'slot' in the CNode, addressed by 'to', within
|
|
* the address space, rooted at 'root' and with 'tobits' and 'frombits' address
|
|
* bits of 'to' and 'from' valid, respectively.
|
|
*
|
|
* See also cap_mint(), which wraps this.
|
|
*
|
|
* \param root Capability of the source cspace root CNode to invoke
|
|
* \param to_cspace Destination cspace cap address relative to source cspace
|
|
* \param to Destination CNode address relative to destination cspace
|
|
* \param slot Slot in destination CNode cap to place copy into
|
|
* \param from Address of cap to copy.
|
|
* \param tolevel Level/depth of 'to'.
|
|
* \param fromlevel Level/depth of 'from'.
|
|
* \param param1 1st cap-dependent parameter.
|
|
* \param param2 2nd cap-dependent parameter.
|
|
*
|
|
* \return Error code
|
|
*/
|
|
static inline errval_t invoke_cnode_mint(struct capref root, capaddr_t to_cspace,
|
|
capaddr_t to, capaddr_t slot,
|
|
capaddr_t from_cspace, capaddr_t from,
|
|
enum cnode_type tolevel,
|
|
enum cnode_type fromlevel,
|
|
uint64_t param1, uint64_t param2)
|
|
{
|
|
return cap_invoke10(root, CNodeCmd_Mint, to_cspace, to, slot, from_cspace,
|
|
from, tolevel, fromlevel, param1, param2).error;
|
|
}
|
|
|
|
/**
|
|
* \brief Copy a capability.
|
|
*
|
|
* Copies CPtr 'from' into slot 'slot' in the CNode, addressed by 'to', within
|
|
* the address space, rooted at 'root' and with 'tobits' and 'frombits' address
|
|
* bits of 'to' and 'from' valid, respectively.
|
|
*
|
|
* See also cap_copy(), which wraps this.
|
|
*
|
|
* \param root Capability of the source cspace root CNode to invoke
|
|
* \param to_cspace Capability address of destination root cnode relative
|
|
* to our cspace
|
|
* \param to CNode address to place copy into relative to
|
|
* destination cspace.
|
|
* \param slot Slot in CNode cap to place copy into.
|
|
* \param from_cspace Capability address of source root cnode relative
|
|
* to our cspace
|
|
* \param from Address of cap to copy.
|
|
* \param tolevel Level/depth of 'to'.
|
|
* \param fromlevel Level/depth of 'from'.
|
|
*
|
|
* \return Error code
|
|
*/
|
|
static inline errval_t invoke_cnode_copy(struct capref root, capaddr_t to_cspace,
|
|
capaddr_t to, capaddr_t slot,
|
|
capaddr_t from_cspace, capaddr_t from,
|
|
enum cnode_type tolevel,
|
|
enum cnode_type fromlevel)
|
|
{
|
|
return cap_invoke8(root, CNodeCmd_Copy, to_cspace, to, slot, from_cspace,
|
|
from, tolevel, fromlevel).error;
|
|
}
|
|
|
|
/**
|
|
* \brief Delete a capability.
|
|
*
|
|
* Delete the capability pointed to by 'cap', with 'bits' address bits
|
|
* of it valid, from the address space rooted at 'root'.
|
|
*
|
|
* \param root Capability of the CNode to invoke
|
|
* \param cap Address of cap to delete.
|
|
* \param level Level/depth of 'cap'.
|
|
*
|
|
* \return Error code
|
|
*/
|
|
static inline errval_t invoke_cnode_delete(struct capref root, capaddr_t cap,
|
|
enum cnode_type level)
|
|
{
|
|
return cap_invoke3(root, CNodeCmd_Delete, cap, level).error;
|
|
}
|
|
|
|
static inline errval_t invoke_cnode_revoke(struct capref root, capaddr_t cap,
|
|
enum cnode_type level)
|
|
{
|
|
return cap_invoke3(root, CNodeCmd_Revoke, cap, level).error;
|
|
}
|
|
|
|
static inline errval_t invoke_cnode_get_state(struct capref root, capaddr_t cap,
|
|
enum cnode_type level, distcap_state_t *ret)
|
|
{
|
|
struct sysret sysret = cap_invoke3(root, CNodeCmd_GetState, cap, level);
|
|
|
|
assert(ret != NULL);
|
|
if (err_is_ok(sysret.error)) {
|
|
*ret = sysret.value;
|
|
}
|
|
else {
|
|
*ret = 0;
|
|
}
|
|
return sysret.error;
|
|
}
|
|
|
|
|
|
/**
|
|
* \brief Get the size of a L1 CNode in bytes.
|
|
*
|
|
* \param root Size of this L1 CNode will be returned
|
|
* \param ret Result will be stored here in bytes.
|
|
*
|
|
* \return Error code
|
|
*/
|
|
static inline errval_t invoke_cnode_get_size(struct capref root, size_t * ret)
|
|
{
|
|
struct sysret sys_ret = cap_invoke1(root, CNodeCmd_GetSize);
|
|
if(err_is_ok(sys_ret.error)){
|
|
*ret = sys_ret.value;
|
|
} else {
|
|
*ret = 0;
|
|
}
|
|
|
|
return sys_ret.error;
|
|
}
|
|
|
|
static inline errval_t invoke_cnode_resize(struct capref root, capaddr_t new_cptr,
|
|
capaddr_t retcn_ptr, cslot_t retslot)
|
|
{
|
|
return cap_invoke4(root, CNodeCmd_Resize, new_cptr, retcn_ptr, retslot).error;
|
|
}
|
|
|
|
static inline errval_t invoke_vnode_unmap(struct capref cap,
|
|
capaddr_t mapping_addr,
|
|
enum cnode_type level)
|
|
{
|
|
return cap_invoke3(cap, VNodeCmd_Unmap, mapping_addr, level).error;
|
|
}
|
|
|
|
static inline errval_t invoke_vnode_modify_flags(struct capref cap,
|
|
size_t entry, size_t num_pages,
|
|
size_t attr)
|
|
{
|
|
return cap_invoke4(cap, VNodeCmd_ModifyFlags, entry, num_pages, attr).error;
|
|
}
|
|
|
|
static inline errval_t invoke_vnode_copy_remap(struct capref ptable, capaddr_t slot,
|
|
capaddr_t src, enum cnode_type srclevel,
|
|
size_t flags, size_t offset, size_t pte_count,
|
|
capaddr_t mcn_addr, cslot_t mapping_slot,
|
|
enum cnode_type mcn_level)
|
|
{
|
|
return cap_invoke10(ptable, VNodeCmd_CopyRemap, slot, src, srclevel, flags,
|
|
offset, pte_count, mcn_addr, mapping_slot, mcn_level).error;
|
|
}
|
|
|
|
/**
|
|
* \brief Return the physical address of a kernel control block
|
|
*
|
|
* KCB identify is special because we do not have a valid implementation of
|
|
* mem_to_local_phys() in user space, which means we cannot use get_address()
|
|
* on a KCB's struct capability in user space.
|
|
*
|
|
* \param kcb CSpace address of kernel control block capability
|
|
* \param ret frame_identity struct filled in with relevant data
|
|
*
|
|
* \return Error code
|
|
*/
|
|
static inline errval_t invoke_kcb_identify(struct capref kcb,
|
|
struct frame_identity *ret)
|
|
{
|
|
assert(ret != NULL);
|
|
assert(get_croot_addr(kcb) == CPTR_ROOTCN);
|
|
|
|
ret->base = 0;
|
|
ret->bytes = 0;
|
|
ret->pasid = 0;
|
|
|
|
return cap_invoke2(kcb, KCBCmd_Identify, (uintptr_t)ret).error;
|
|
}
|
|
|
|
/**
|
|
* \brief Return capability representation of a given CSpace address
|
|
*
|
|
* \param cap CSpace address of capability
|
|
* \param ret capability struct filled in with relevant data
|
|
*
|
|
* \return Error code
|
|
*/
|
|
static inline errval_t invoke_cap_identify(struct capref cap,
|
|
struct capability *ret)
|
|
{
|
|
struct capref croot = get_croot_capref(cap);
|
|
return cap_invoke4(croot, CNodeCmd_CapIdentify,
|
|
get_cap_addr(cap), get_cap_level(cap),
|
|
(uintptr_t)ret).error;
|
|
}
|
|
|
|
static inline errval_t invoke_vnode_identify(struct capref vnode,
|
|
struct vnode_identity *ret)
|
|
{
|
|
errval_t err;
|
|
struct capability retcap;
|
|
err = invoke_cap_identify(vnode, &retcap);
|
|
|
|
assert(ret != NULL);
|
|
|
|
ret->base = 0;
|
|
ret->type = 0;
|
|
|
|
if (err_is_ok(err) && type_is_vnode(retcap.type)) {
|
|
ret->base = get_address(&retcap);
|
|
ret->type = retcap.type;
|
|
} else if (err_is_ok(err)) {
|
|
err = SYS_ERR_INVALID_SOURCE_TYPE;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* \brief Cleans all dirty bits in a page table.
|
|
*/
|
|
static inline errval_t invoke_clean_dirty_bits(struct capref vnode, size_t* how_many)
|
|
{
|
|
|
|
struct sysret ret = cap_invoke1(vnode, VNodeCmd_CleanDirtyBits);
|
|
if (how_many != NULL) {
|
|
*how_many = ret.value;
|
|
}
|
|
return ret.error;
|
|
}
|
|
|
|
/**
|
|
* \brief Modify mapping flags on parts of a mapping
|
|
*
|
|
* \param mapping CSpace address of mapping capability
|
|
* \param off Offset (in #pages) of the first page to get new set of flags
|
|
* from the first page in the mapping identified by `frame`
|
|
* \param pages Number of pages that should get new set of flags
|
|
* \param flags New set of flags
|
|
* \param va_hint Hint for selective TLB flushing
|
|
*
|
|
* \return Error code
|
|
*/
|
|
static inline errval_t invoke_mapping_modify_flags(struct capref mapping,
|
|
size_t offset,
|
|
size_t pages,
|
|
size_t flags,
|
|
genvaddr_t va_hint)
|
|
{
|
|
return cap_invoke5(mapping, MappingCmd_Modify, offset,
|
|
pages, flags, va_hint).error;
|
|
}
|
|
|
|
/**
|
|
* \brief Setup a dispatcher, possibly making it runnable
|
|
*
|
|
* \param dispatcher Address of dispatcher capability relative to own
|
|
* cspace
|
|
* \param domdispatcher Address of existing dispatcher for domain ID relative
|
|
* to own cspace
|
|
* \param cspace Root of CSpace for new dispatcher relative to own
|
|
* cspace
|
|
* \param vspace Root of VSpace for new dispatcher relative to cspace
|
|
* for new dispatcher.
|
|
* \param dispframe Frame capability for dispatcher structure relative to
|
|
* cspace for new dispatcher.
|
|
* \param run Make runnable if true
|
|
*
|
|
* Need to either supply caprefs for all or none of cspace, vspace, dispframe
|
|
* and domdispatcher.
|
|
*
|
|
* \return Error code
|
|
*/
|
|
static inline errval_t
|
|
invoke_dispatcher(struct capref dispatcher, struct capref domdispatcher,
|
|
struct capref cspace, struct capref vspace,
|
|
struct capref dispframe, bool run)
|
|
{
|
|
assert(get_croot_addr(dispatcher) == CPTR_ROOTCN);
|
|
assert(capref_is_null(cspace) || get_croot_addr(cspace) == CPTR_ROOTCN);
|
|
assert(capref_is_null(domdispatcher) || get_croot_addr(domdispatcher) == CPTR_ROOTCN);
|
|
assert(capref_is_null(vspace) || get_croot_addr(vspace) == get_cap_addr(cspace));
|
|
assert(capref_is_null(dispframe) || get_croot_addr(dispframe) == get_cap_addr(cspace));
|
|
|
|
capaddr_t root_caddr = get_cap_addr(cspace);
|
|
uint8_t root_level = get_cap_level(cspace);
|
|
capaddr_t vtree_caddr = get_cap_addr(vspace);
|
|
capaddr_t disp_caddr = get_cap_addr(dispframe);
|
|
capaddr_t dd_caddr = get_cap_addr(domdispatcher);
|
|
|
|
return cap_invoke7(dispatcher, DispatcherCmd_Setup, root_caddr,
|
|
root_level, vtree_caddr, disp_caddr, run,
|
|
dd_caddr).error;
|
|
}
|
|
|
|
static inline errval_t invoke_dispatcher_stop(struct capref dispatcher)
|
|
{
|
|
return cap_invoke1(dispatcher, DispatcherCmd_Stop).error;
|
|
}
|
|
|
|
|
|
static inline errval_t
|
|
invoke_dispatcher_properties(struct capref dispatcher,
|
|
enum task_type type, unsigned long deadline,
|
|
unsigned long wcet, unsigned long period,
|
|
unsigned long release, unsigned short weight)
|
|
{
|
|
return cap_invoke7(dispatcher, DispatcherCmd_Properties, type, deadline,
|
|
wcet, period, release, weight).error;
|
|
}
|
|
|
|
|
|
static inline errval_t invoke_dispatcher_dump_ptables(struct capref dispcap, lvaddr_t vaddr)
|
|
{
|
|
return cap_invoke2(dispcap, DispatcherCmd_DumpPTables, vaddr).error;
|
|
}
|
|
|
|
static inline errval_t invoke_dispatcher_dump_capabilities(struct capref dispcap)
|
|
{
|
|
return cap_invoke1(dispcap, DispatcherCmd_DumpCapabilities).error;
|
|
}
|
|
|
|
/**
|
|
* IRQ manipulations
|
|
*/
|
|
static inline errval_t invoke_irqdest_connect(struct capref irqcap, struct capref epcap)
|
|
{
|
|
struct sysret ret = cap_invoke2(irqcap, IRQDestCmd_Connect, get_cap_addr(epcap));
|
|
return ret.error;
|
|
}
|
|
|
|
static inline errval_t invoke_irqdest_get_vector(struct capref irqcap, uint64_t * out_vec)
|
|
{
|
|
struct sysret ret = cap_invoke1(irqcap, IRQDestCmd_GetVector);
|
|
*out_vec = ret.value;
|
|
return ret.error;
|
|
}
|
|
|
|
static inline errval_t invoke_irqdest_get_cpu(struct capref irqcap, uint64_t * out_cpu)
|
|
{
|
|
struct sysret ret = cap_invoke1(irqcap, IRQDestCmd_GetCpu);
|
|
*out_cpu = ret.value;
|
|
return ret.error;
|
|
}
|
|
|
|
static inline errval_t invoke_irqsrc_get_vec_start(struct capref irqcap, uint64_t * out_vec)
|
|
{
|
|
struct sysret ret = cap_invoke1(irqcap, IRQSrcCmd_GetVecStart);
|
|
*out_vec = ret.value;
|
|
return ret.error;
|
|
}
|
|
|
|
static inline errval_t invoke_irqsrc_get_vec_end(struct capref irqcap, uint64_t * out_vec)
|
|
{
|
|
struct sysret ret = cap_invoke1(irqcap, IRQSrcCmd_GetVecEnd);
|
|
*out_vec = ret.value;
|
|
return ret.error;
|
|
}
|
|
|
|
/**
|
|
* Allocate a free entry in the vector table and return it as dest_cap.
|
|
* Set vec_hint to a positive value, and the allocator will force
|
|
* that vector to be allocated.
|
|
*/
|
|
static inline errval_t invoke_irqtable_alloc_dest_cap(struct capref irqcap,
|
|
struct capref dest_cap,
|
|
int vec_hint
|
|
)
|
|
{
|
|
uint8_t dcn_level = get_cnode_level(dest_cap);
|
|
capaddr_t dcn_addr = get_cnode_addr(dest_cap);
|
|
struct sysret ret = cap_invoke5(irqcap, IRQTableCmd_AllocDestCap,
|
|
dcn_level, dcn_addr, dest_cap.slot, vec_hint);
|
|
return ret.error;
|
|
}
|
|
|
|
/**
|
|
* Deprecated. Use invoke_irqtable_alloc_dest_cap
|
|
*/
|
|
static inline errval_t invoke_irqtable_alloc_vector(struct capref irqcap, int *retirq)
|
|
{
|
|
struct sysret ret = cap_invoke1(irqcap, IRQTableCmd_Alloc);
|
|
if (err_is_ok(ret.error)) {
|
|
*retirq = ret.value;
|
|
} else {
|
|
*retirq = 0;
|
|
}
|
|
return ret.error;
|
|
}
|
|
|
|
static inline errval_t invoke_irqtable_set(struct capref irqcap, int irq,
|
|
struct capref ep)
|
|
{
|
|
return cap_invoke3(irqcap, IRQTableCmd_Set, irq, get_cap_addr(ep)).error;
|
|
}
|
|
|
|
static inline errval_t invoke_irqtable_delete(struct capref irqcap, int irq)
|
|
{
|
|
return cap_invoke2(irqcap, IRQTableCmd_Delete, irq).error;
|
|
}
|
|
|
|
/**
|
|
* \brief do a kernel cap invocation to get the core id
|
|
*/
|
|
static inline errval_t invoke_kernel_get_core_id(struct capref kern_cap,
|
|
coreid_t *core_id)
|
|
{
|
|
assert(core_id != NULL);
|
|
|
|
struct sysret sysret = cap_invoke1(kern_cap, KernelCmd_Get_core_id);
|
|
if (sysret.error == SYS_ERR_OK) {
|
|
*core_id = sysret.value;
|
|
}
|
|
return sysret.error;
|
|
}
|
|
|
|
__END_DECLS
|
|
|
|
#endif // INVOCATIONS_H
|