#include <config.h>
#include <types.h>
#include <api/failures.h>
#include <api/invocation.h>
#include <api/syscall.h>
#include <api/shared_types.h>
#include <machine/io.h>
#include <object/structures.h>
#include <object/objecttype.h>
#include <object/cnode.h>
#include <object/tcb.h>
#include <kernel/cspace.h>
#include <kernel/thread.h>
#include <kernel/vspace.h>
#include <model/statedata.h>
#include <util.h>
#include <string.h>
#include <stdint.h>
#include <arch/smp/ipi_inline.h>
#define NULL_PRIO 0
static exception_t
checkPrio(prio_t prio)
{
prio_t mcp;
mcp = NODE_STATE(ksCurThread)->tcbMCP;
assert(mcp <= seL4_MaxPrio);
if (prio > mcp) {
current_syscall_error.type = seL4_RangeError;
current_syscall_error.rangeErrorMin = seL4_MinPrio;
current_syscall_error.rangeErrorMax = mcp;
return EXCEPTION_SYSCALL_ERROR;
}
return EXCEPTION_NONE;
}
static inline void
addToBitmap(word_t cpu, word_t dom, word_t prio)
{
word_t l1index;
l1index = prio_to_l1index(prio);
NODE_STATE_ON_CORE(ksReadyQueuesL1Bitmap[dom], cpu) |= BIT(l1index);
NODE_STATE_ON_CORE(ksReadyQueuesL2Bitmap[dom][l1index], cpu) |= BIT(prio & MASK(wordRadix));
}
static inline void
removeFromBitmap(word_t cpu, word_t dom, word_t prio)
{
word_t l1index;
l1index = prio_to_l1index(prio);
NODE_STATE_ON_CORE(ksReadyQueuesL2Bitmap[dom][l1index], cpu) &= ~BIT(prio & MASK(wordRadix));
if (unlikely(!NODE_STATE_ON_CORE(ksReadyQueuesL2Bitmap[dom][l1index], cpu))) {
NODE_STATE_ON_CORE(ksReadyQueuesL1Bitmap[dom], cpu) &= ~BIT(l1index);
}
}
void
tcbSchedEnqueue(tcb_t *tcb)
{
if (!thread_state_get_tcbQueued(tcb->tcbState)) {
tcb_queue_t queue;
dom_t dom;
prio_t prio;
word_t idx;
dom = tcb->tcbDomain;
prio = tcb->tcbPriority;
idx = ready_queues_index(dom, prio);
queue = NODE_STATE_ON_CORE(ksReadyQueues[idx], tcb->tcbAffinity);
if (!queue.end) {
queue.end = tcb;
addToBitmap(SMP_TERNARY(tcb->tcbAffinity, 0), dom, prio);
} else {
queue.head->tcbSchedPrev = tcb;
}
tcb->tcbSchedPrev = NULL;
tcb->tcbSchedNext = queue.head;
queue.head = tcb;
NODE_STATE_ON_CORE(ksReadyQueues[idx], tcb->tcbAffinity) = queue;
thread_state_ptr_set_tcbQueued(&tcb->tcbState, true);
}
}
void
tcbSchedAppend(tcb_t *tcb)
{
if (!thread_state_get_tcbQueued(tcb->tcbState)) {
tcb_queue_t queue;
dom_t dom;
prio_t prio;
word_t idx;
dom = tcb->tcbDomain;
prio = tcb->tcbPriority;
idx = ready_queues_index(dom, prio);
queue = NODE_STATE_ON_CORE(ksReadyQueues[idx], tcb->tcbAffinity);
if (!queue.head) {
queue.head = tcb;
addToBitmap(SMP_TERNARY(tcb->tcbAffinity, 0), dom, prio);
} else {
queue.end->tcbSchedNext = tcb;
}
tcb->tcbSchedPrev = queue.end;
tcb->tcbSchedNext = NULL;
queue.end = tcb;
NODE_STATE_ON_CORE(ksReadyQueues[idx], tcb->tcbAffinity) = queue;
thread_state_ptr_set_tcbQueued(&tcb->tcbState, true);
}
}
void
tcbSchedDequeue(tcb_t *tcb)
{
if (thread_state_get_tcbQueued(tcb->tcbState)) {
tcb_queue_t queue;
dom_t dom;
prio_t prio;
word_t idx;
dom = tcb->tcbDomain;
prio = tcb->tcbPriority;
idx = ready_queues_index(dom, prio);
queue = NODE_STATE_ON_CORE(ksReadyQueues[idx], tcb->tcbAffinity);
if (tcb->tcbSchedPrev) {
tcb->tcbSchedPrev->tcbSchedNext = tcb->tcbSchedNext;
} else {
queue.head = tcb->tcbSchedNext;
if (likely(!tcb->tcbSchedNext)) {
removeFromBitmap(SMP_TERNARY(tcb->tcbAffinity, 0), dom, prio);
}
}
if (tcb->tcbSchedNext) {
tcb->tcbSchedNext->tcbSchedPrev = tcb->tcbSchedPrev;
} else {
queue.end = tcb->tcbSchedPrev;
}
NODE_STATE_ON_CORE(ksReadyQueues[idx], tcb->tcbAffinity) = queue;
thread_state_ptr_set_tcbQueued(&tcb->tcbState, false);
}
}
tcb_queue_t
tcbEPAppend(tcb_t *tcb, tcb_queue_t queue)
{
if (!queue.head) {
queue.head = tcb;
} else {
queue.end->tcbEPNext = tcb;
}
tcb->tcbEPPrev = queue.end;
tcb->tcbEPNext = NULL;
queue.end = tcb;
return queue;
}
tcb_queue_t
tcbEPDequeue(tcb_t *tcb, tcb_queue_t queue)
{
if (tcb->tcbEPPrev) {
tcb->tcbEPPrev->tcbEPNext = tcb->tcbEPNext;
} else {
queue.head = tcb->tcbEPNext;
}
if (tcb->tcbEPNext) {
tcb->tcbEPNext->tcbEPPrev = tcb->tcbEPPrev;
} else {
queue.end = tcb->tcbEPPrev;
}
return queue;
}
cptr_t PURE
getExtraCPtr(word_t *bufferPtr, word_t i)
{
return (cptr_t)bufferPtr[seL4_MsgMaxLength + 2 + i];
}
void
setExtraBadge(word_t *bufferPtr, word_t badge,
word_t i)
{
bufferPtr[seL4_MsgMaxLength + 2 + i] = badge;
}
void
setupCallerCap(tcb_t *sender, tcb_t *receiver)
{
cte_t *replySlot, *callerSlot;
cap_t masterCap UNUSED, callerCap UNUSED;
setThreadState(sender, ThreadState_BlockedOnReply);
replySlot = TCB_PTR_CTE_PTR(sender, tcbReply);
masterCap = replySlot->cap;
assert(cap_get_capType(masterCap) == cap_reply_cap);
assert(cap_reply_cap_get_capReplyMaster(masterCap));
assert(TCB_PTR(cap_reply_cap_get_capTCBPtr(masterCap)) == sender);
callerSlot = TCB_PTR_CTE_PTR(receiver, tcbCaller);
callerCap = callerSlot->cap;
assert(cap_get_capType(callerCap) == cap_null_cap);
cteInsert(cap_reply_cap_new(false, TCB_REF(sender)),
replySlot, callerSlot);
}
void
deleteCallerCap(tcb_t *receiver)
{
cte_t *callerSlot;
callerSlot = TCB_PTR_CTE_PTR(receiver, tcbCaller);
cteDeleteOne(callerSlot);
}
extra_caps_t current_extra_caps;
exception_t
lookupExtraCaps(tcb_t* thread, word_t *bufferPtr, seL4_MessageInfo_t info)
{
lookupSlot_raw_ret_t lu_ret;
cptr_t cptr;
word_t i, length;
if (!bufferPtr) {
current_extra_caps.excaprefs[0] = NULL;
return EXCEPTION_NONE;
}
length = seL4_MessageInfo_get_extraCaps(info);
for (i = 0; i < length; i++) {
cptr = getExtraCPtr(bufferPtr, i);
lu_ret = lookupSlot(thread, cptr);
if (lu_ret.status != EXCEPTION_NONE) {
current_fault = seL4_Fault_CapFault_new(cptr, false);
return lu_ret.status;
}
current_extra_caps.excaprefs[i] = lu_ret.slot;
}
if (i < seL4_MsgMaxExtraCaps) {
current_extra_caps.excaprefs[i] = NULL;
}
return EXCEPTION_NONE;
}
word_t
copyMRs(tcb_t *sender, word_t *sendBuf, tcb_t *receiver,
word_t *recvBuf, word_t n)
{
word_t i;
for (i = 0; i < n && i < n_msgRegisters; i++) {
setRegister(receiver, msgRegisters[i],
getRegister(sender, msgRegisters[i]));
}
if (!recvBuf || !sendBuf) {
return i;
}
for (; i < n; i++) {
recvBuf[i + 1] = sendBuf[i + 1];
}
return i;
}
#if CONFIG_MAX_NUM_NODES > 1
void
remoteQueueUpdate(tcb_t *tcb)
{
if (tcb->tcbAffinity != getCurrentCPUIndex() && tcb->tcbDomain == ksCurDomain) {
tcb_t *targetCurThread = NODE_STATE_ON_CORE(ksCurThread, tcb->tcbAffinity);
if (targetCurThread == NODE_STATE_ON_CORE(ksIdleThread, tcb->tcbAffinity) ||
tcb->tcbPriority > targetCurThread->tcbPriority) {
ARCH_NODE_STATE(ipiReschedulePending) |= BIT(tcb->tcbAffinity);
}
}
}
void
remoteTCBStall(tcb_t *tcb)
{
if (tcb->tcbAffinity != getCurrentCPUIndex() &&
NODE_STATE_ON_CORE(ksCurThread, tcb->tcbAffinity) == tcb) {
doRemoteStall(tcb->tcbAffinity);
ARCH_NODE_STATE(ipiReschedulePending) |= BIT(tcb->tcbAffinity);
}
}
static exception_t
invokeTCB_SetAffinity(tcb_t *thread, word_t affinity)
{
Arch_migrateTCB(thread);
tcbSchedDequeue(thread);
thread->tcbAffinity = affinity;
if (isRunnable(thread)) {
SCHED_APPEND(thread);
}
if (thread == NODE_STATE(ksCurThread)) {
rescheduleRequired();
}
return EXCEPTION_NONE;
}
static exception_t
decodeSetAffinity(cap_t cap, word_t length, word_t *buffer)
{
tcb_t *tcb;
word_t affinity;
if (length < 1) {
userError("TCB SetAffinity: Truncated message.");
current_syscall_error.type = seL4_TruncatedMessage;
return EXCEPTION_SYSCALL_ERROR;
}
tcb = TCB_PTR(cap_thread_cap_get_capTCBPtr(cap));
affinity = getSyscallArg(0, buffer);
if (affinity >= ksNumCPUs) {
userError("TCB SetAffinity: Requested CPU does not exist.");
current_syscall_error.type = seL4_IllegalOperation;
return EXCEPTION_SYSCALL_ERROR;
}
setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
return invokeTCB_SetAffinity(tcb, affinity);
}
#endif
#ifdef CONFIG_HARDWARE_DEBUG_API
static exception_t
invokeConfigureSingleStepping(word_t *buffer, arch_tcb_t *context,
uint16_t bp_num, word_t n_instrs)
{
bool_t bp_was_consumed;
bp_was_consumed = configureSingleStepping(context, bp_num, n_instrs, false);
if (n_instrs == 0) {
unsetBreakpointUsedFlag(context, bp_num);
setMR(NODE_STATE(ksCurThread), buffer, 0, false);
} else {
setBreakpointUsedFlag(context, bp_num);
setMR(NODE_STATE(ksCurThread), buffer, 0, bp_was_consumed);
}
return EXCEPTION_NONE;
}
static exception_t
decodeConfigureSingleStepping(cap_t cap, word_t *buffer)
{
uint16_t bp_num;
word_t n_instrs;
tcb_t *tcb;
arch_tcb_t *context;
syscall_error_t syserr;
tcb = TCB_PTR(cap_thread_cap_get_capTCBPtr(cap));
context = &tcb->tcbArch;
bp_num = getSyscallArg(0, buffer);
n_instrs = getSyscallArg(1, buffer);
syserr = Arch_decodeConfigureSingleStepping(context, bp_num, n_instrs, false);
if (syserr.type != seL4_NoError) {
current_syscall_error = syserr;
return EXCEPTION_SYSCALL_ERROR;
}
setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
return invokeConfigureSingleStepping(buffer, context, bp_num, n_instrs);
}
static exception_t
invokeSetBreakpoint(arch_tcb_t *context, uint16_t bp_num,
word_t vaddr, word_t type, word_t size, word_t rw)
{
setBreakpoint(context, bp_num, vaddr, type, size, rw);
setBreakpointUsedFlag(context, bp_num);
return EXCEPTION_NONE;
}
static exception_t
decodeSetBreakpoint(cap_t cap, word_t *buffer)
{
uint16_t bp_num;
word_t vaddr, type, size, rw;
tcb_t *tcb;
arch_tcb_t *context;
syscall_error_t error;
tcb = TCB_PTR(cap_thread_cap_get_capTCBPtr(cap));
bp_num = getSyscallArg(0, buffer);
vaddr = getSyscallArg(1, buffer);
type = getSyscallArg(2, buffer);
size = getSyscallArg(3, buffer);
rw = getSyscallArg(4, buffer);
if (vaddr >= (word_t)kernelBase) {
userError("Debug: Invalid address %lx: bp addresses must be userspace "
"addresses.",
vaddr);
current_syscall_error.type = seL4_InvalidArgument;
current_syscall_error.invalidArgumentNumber = 1;
return EXCEPTION_SYSCALL_ERROR;
}
if (type != seL4_InstructionBreakpoint && type != seL4_DataBreakpoint) {
userError("Debug: Unknown breakpoint type %lx.", type);
current_syscall_error.type = seL4_InvalidArgument;
current_syscall_error.invalidArgumentNumber = 2;
return EXCEPTION_SYSCALL_ERROR;
} else if (type == seL4_InstructionBreakpoint) {
if (size != 0) {
userError("Debug: Instruction bps must have size of 0.");
current_syscall_error.type = seL4_InvalidArgument;
current_syscall_error.invalidArgumentNumber = 3;
return EXCEPTION_SYSCALL_ERROR;
}
if (rw != seL4_BreakOnRead) {
userError("Debug: Instruction bps must be break-on-read.");
current_syscall_error.type = seL4_InvalidArgument;
current_syscall_error.invalidArgumentNumber = 4;
return EXCEPTION_SYSCALL_ERROR;
}
if (bp_num >= seL4_FirstWatchpoint
&& seL4_FirstBreakpoint != seL4_FirstWatchpoint) {
userError("Debug: Can't specify a watchpoint ID with type seL4_InstructionBreakpoint.");
current_syscall_error.type = seL4_InvalidArgument;
current_syscall_error.invalidArgumentNumber = 2;
return EXCEPTION_SYSCALL_ERROR;
}
} else if (type == seL4_DataBreakpoint) {
if (size == 0) {
userError("Debug: Data bps cannot have size of 0.");
current_syscall_error.type = seL4_InvalidArgument;
current_syscall_error.invalidArgumentNumber = 3;
return EXCEPTION_SYSCALL_ERROR;
}
if (bp_num < seL4_FirstWatchpoint) {
userError("Debug: Data watchpoints cannot specify non-data watchpoint ID.");
current_syscall_error.type = seL4_InvalidArgument;
current_syscall_error.invalidArgumentNumber = 2;
return EXCEPTION_SYSCALL_ERROR;
}
} else if (type == seL4_SoftwareBreakRequest) {
userError("Debug: Use a software breakpoint instruction to trigger a "
"software breakpoint.");
current_syscall_error.type = seL4_InvalidArgument;
current_syscall_error.invalidArgumentNumber = 2;
return EXCEPTION_SYSCALL_ERROR;
}
if (rw != seL4_BreakOnRead && rw != seL4_BreakOnWrite
&& rw != seL4_BreakOnReadWrite) {
userError("Debug: Unknown access-type %lu.", rw);
current_syscall_error.type = seL4_InvalidArgument;
current_syscall_error.invalidArgumentNumber = 3;
return EXCEPTION_SYSCALL_ERROR;
}
if (size != 0 && size != 1 && size != 2 && size != 4 && size != 8) {
userError("Debug: Invalid size %lu.", size);
current_syscall_error.type = seL4_InvalidArgument;
current_syscall_error.invalidArgumentNumber = 3;
return EXCEPTION_SYSCALL_ERROR;
}
if (size > 0 && vaddr & (size - 1)) {
userError("Debug: Unaligned data watchpoint address %lx (size %lx) "
"rejected.\n",
vaddr, size);
current_syscall_error.type = seL4_AlignmentError;
return EXCEPTION_SYSCALL_ERROR;
}
context = &tcb->tcbArch;
error = Arch_decodeSetBreakpoint(context, bp_num, vaddr, type, size, rw);
if (error.type != seL4_NoError) {
current_syscall_error = error;
return EXCEPTION_SYSCALL_ERROR;
}
setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
return invokeSetBreakpoint(context, bp_num,
vaddr, type, size, rw);
}
static exception_t
invokeGetBreakpoint(word_t *buffer, arch_tcb_t *context, uint16_t bp_num)
{
getBreakpoint_t res;
res = getBreakpoint(context, bp_num);
setMR(NODE_STATE(ksCurThread), buffer, 0, res.vaddr);
setMR(NODE_STATE(ksCurThread), buffer, 1, res.type);
setMR(NODE_STATE(ksCurThread), buffer, 2, res.size);
setMR(NODE_STATE(ksCurThread), buffer, 3, res.rw);
setMR(NODE_STATE(ksCurThread), buffer, 4, res.is_enabled);
return EXCEPTION_NONE;
}
static exception_t
decodeGetBreakpoint(cap_t cap, word_t *buffer)
{
tcb_t *tcb;
uint16_t bp_num;
arch_tcb_t *context;
syscall_error_t error;
tcb = TCB_PTR(cap_thread_cap_get_capTCBPtr(cap));
bp_num = getSyscallArg(0, buffer);
context = &tcb->tcbArch;
error = Arch_decodeGetBreakpoint(context, bp_num);
if (error.type != seL4_NoError) {
current_syscall_error = error;
return EXCEPTION_SYSCALL_ERROR;
}
setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
return invokeGetBreakpoint(buffer, context, bp_num);
}
static exception_t
invokeUnsetBreakpoint(arch_tcb_t *context, uint16_t bp_num)
{
unsetBreakpoint(context, bp_num);
unsetBreakpointUsedFlag(context, bp_num);
return EXCEPTION_NONE;
}
static exception_t
decodeUnsetBreakpoint(cap_t cap, word_t *buffer)
{
tcb_t *tcb;
uint16_t bp_num;
arch_tcb_t *context;
syscall_error_t error;
tcb = TCB_PTR(cap_thread_cap_get_capTCBPtr(cap));
bp_num = getSyscallArg(0, buffer);
context = &tcb->tcbArch;
error = Arch_decodeUnsetBreakpoint(context, bp_num);
if (error.type != seL4_NoError) {
current_syscall_error = error;
return EXCEPTION_SYSCALL_ERROR;
}
setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
return invokeUnsetBreakpoint(context, bp_num);
}
#endif
exception_t
decodeTCBInvocation(word_t invLabel, word_t length, cap_t cap,
cte_t* slot, extra_caps_t excaps, bool_t call,
word_t *buffer)
{
SMP_COND_STATEMENT(remoteTCBStall(TCB_PTR(cap_thread_cap_get_capTCBPtr(cap)));)
switch (invLabel) {
case TCBReadRegisters:
return decodeReadRegisters(cap, length, call, buffer);
case TCBWriteRegisters:
return decodeWriteRegisters(cap, length, buffer);
case TCBCopyRegisters:
return decodeCopyRegisters(cap, length, excaps, buffer);
case TCBSuspend:
setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
return invokeTCB_Suspend(
TCB_PTR(cap_thread_cap_get_capTCBPtr(cap)));
case TCBResume:
setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
return invokeTCB_Resume(
TCB_PTR(cap_thread_cap_get_capTCBPtr(cap)));
case TCBConfigure:
return decodeTCBConfigure(cap, length, slot, excaps, buffer);
case TCBSetPriority:
return decodeSetPriority(cap, length, buffer);
case TCBSetMCPriority:
return decodeSetMCPriority(cap, length, buffer);
case TCBSetIPCBuffer:
return decodeSetIPCBuffer(cap, length, slot, excaps, buffer);
case TCBSetSpace:
return decodeSetSpace(cap, length, slot, excaps, buffer);
case TCBBindNotification:
return decodeBindNotification(cap, excaps);
case TCBUnbindNotification:
return decodeUnbindNotification(cap);
#if CONFIG_MAX_NUM_NODES > 1
case TCBSetAffinity:
return decodeSetAffinity(cap, length, buffer);
#endif
#ifdef CONFIG_VTX
case TCBSetEPTRoot:
return decodeSetEPTRoot(cap, excaps);
#endif
#ifdef CONFIG_HARDWARE_DEBUG_API
case TCBConfigureSingleStepping:
return decodeConfigureSingleStepping(cap, buffer);
case TCBSetBreakpoint:
return decodeSetBreakpoint(cap, buffer);
case TCBGetBreakpoint:
return decodeGetBreakpoint(cap, buffer);
case TCBUnsetBreakpoint:
return decodeUnsetBreakpoint(cap, buffer);
#endif
default:
userError("TCB: Illegal operation.");
current_syscall_error.type = seL4_IllegalOperation;
return EXCEPTION_SYSCALL_ERROR;
}
}
enum CopyRegistersFlags {
CopyRegisters_suspendSource = 0,
CopyRegisters_resumeTarget = 1,
CopyRegisters_transferFrame = 2,
CopyRegisters_transferInteger = 3
};
exception_t
decodeCopyRegisters(cap_t cap, word_t length,
extra_caps_t excaps, word_t *buffer)
{
word_t transferArch;
tcb_t *srcTCB;
cap_t source_cap;
word_t flags;
if (length < 1 || excaps.excaprefs[0] == NULL) {
userError("TCB CopyRegisters: Truncated message.");
current_syscall_error.type = seL4_TruncatedMessage;
return EXCEPTION_SYSCALL_ERROR;
}
flags = getSyscallArg(0, buffer);
transferArch = Arch_decodeTransfer(flags >> 8);
source_cap = excaps.excaprefs[0]->cap;
if (cap_get_capType(source_cap) == cap_thread_cap) {
srcTCB = TCB_PTR(cap_thread_cap_get_capTCBPtr(source_cap));
} else {
userError("TCB CopyRegisters: Invalid source TCB.");
current_syscall_error.type = seL4_InvalidCapability;
current_syscall_error.invalidCapNumber = 1;
return EXCEPTION_SYSCALL_ERROR;
}
setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
return invokeTCB_CopyRegisters(
TCB_PTR(cap_thread_cap_get_capTCBPtr(cap)), srcTCB,
flags & BIT(CopyRegisters_suspendSource),
flags & BIT(CopyRegisters_resumeTarget),
flags & BIT(CopyRegisters_transferFrame),
flags & BIT(CopyRegisters_transferInteger),
transferArch);
}
enum ReadRegistersFlags {
ReadRegisters_suspend = 0
};
exception_t
decodeReadRegisters(cap_t cap, word_t length, bool_t call,
word_t *buffer)
{
word_t transferArch, flags, n;
tcb_t* thread;
if (length < 2) {
userError("TCB ReadRegisters: Truncated message.");
current_syscall_error.type = seL4_TruncatedMessage;
return EXCEPTION_SYSCALL_ERROR;
}
flags = getSyscallArg(0, buffer);
n = getSyscallArg(1, buffer);
if (n < 1 || n > n_frameRegisters + n_gpRegisters) {
userError("TCB ReadRegisters: Attempted to read an invalid number of registers (%d).",
(int)n);
current_syscall_error.type = seL4_RangeError;
current_syscall_error.rangeErrorMin = 1;
current_syscall_error.rangeErrorMax = n_frameRegisters +
n_gpRegisters;
return EXCEPTION_SYSCALL_ERROR;
}
transferArch = Arch_decodeTransfer(flags >> 8);
thread = TCB_PTR(cap_thread_cap_get_capTCBPtr(cap));
if (thread == NODE_STATE(ksCurThread)) {
userError("TCB ReadRegisters: Attempted to read our own registers.");
current_syscall_error.type = seL4_IllegalOperation;
return EXCEPTION_SYSCALL_ERROR;
}
setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
return invokeTCB_ReadRegisters(
TCB_PTR(cap_thread_cap_get_capTCBPtr(cap)),
flags & BIT(ReadRegisters_suspend),
n, transferArch, call);
}
enum WriteRegistersFlags {
WriteRegisters_resume = 0
};
exception_t
decodeWriteRegisters(cap_t cap, word_t length, word_t *buffer)
{
word_t flags, w;
word_t transferArch;
tcb_t* thread;
if (length < 2) {
userError("TCB WriteRegisters: Truncated message.");
current_syscall_error.type = seL4_TruncatedMessage;
return EXCEPTION_SYSCALL_ERROR;
}
flags = getSyscallArg(0, buffer);
w = getSyscallArg(1, buffer);
if (length - 2 < w) {
userError("TCB WriteRegisters: Message too short for requested write size (%d/%d).",
(int)(length - 2), (int)w);
current_syscall_error.type = seL4_TruncatedMessage;
return EXCEPTION_SYSCALL_ERROR;
}
transferArch = Arch_decodeTransfer(flags >> 8);
thread = TCB_PTR(cap_thread_cap_get_capTCBPtr(cap));
if (thread == NODE_STATE(ksCurThread)) {
userError("TCB WriteRegisters: Attempted to write our own registers.");
current_syscall_error.type = seL4_IllegalOperation;
return EXCEPTION_SYSCALL_ERROR;
}
setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
return invokeTCB_WriteRegisters(thread,
flags & BIT(WriteRegisters_resume),
w, transferArch, buffer);
}
exception_t
decodeTCBConfigure(cap_t cap, word_t length, cte_t* slot,
extra_caps_t rootCaps, word_t *buffer)
{
cte_t *bufferSlot, *cRootSlot, *vRootSlot;
cap_t bufferCap, cRootCap, vRootCap;
deriveCap_ret_t dc_ret;
cptr_t faultEP;
seL4_PrioProps_t props;
prio_t prio, mcp;
word_t cRootData, vRootData, bufferAddr;
exception_t status;
if (length < 5 || rootCaps.excaprefs[0] == NULL
|| rootCaps.excaprefs[1] == NULL
|| rootCaps.excaprefs[2] == NULL) {
userError("TCB Configure: Truncated message.");
current_syscall_error.type = seL4_TruncatedMessage;
return EXCEPTION_SYSCALL_ERROR;
}
faultEP = getSyscallArg(0, buffer);
props = prioPropsFromWord(getSyscallArg(1, buffer));
cRootData = getSyscallArg(2, buffer);
vRootData = getSyscallArg(3, buffer);
bufferAddr = getSyscallArg(4, buffer);
cRootSlot = rootCaps.excaprefs[0];
cRootCap = rootCaps.excaprefs[0]->cap;
vRootSlot = rootCaps.excaprefs[1];
vRootCap = rootCaps.excaprefs[1]->cap;
bufferSlot = rootCaps.excaprefs[2];
bufferCap = rootCaps.excaprefs[2]->cap;
prio = seL4_PrioProps_get_prio(props);
mcp = seL4_PrioProps_get_mcp(props);
status = checkPrio(prio);
if (status != EXCEPTION_NONE) {
userError("TCB Configure: Requested priority %lu too high (max %lu).",
(unsigned long) prio, (unsigned long) NODE_STATE(ksCurThread)->tcbMCP);
return status;
}
status = checkPrio(mcp);
if (status != EXCEPTION_NONE) {
userError("TCB Configure: Requested maximum controlled priority %lu too high (max %lu),",
(unsigned long) mcp, (unsigned long) NODE_STATE(ksCurThread)->tcbMCP);
return status;
}
if (bufferAddr == 0) {
bufferSlot = NULL;
} else {
dc_ret = deriveCap(bufferSlot, bufferCap);
if (dc_ret.status != EXCEPTION_NONE) {
return dc_ret.status;
}
bufferCap = dc_ret.cap;
exception_t e = checkValidIPCBuffer(bufferAddr, bufferCap);
if (e != EXCEPTION_NONE) {
return e;
}
}
if (slotCapLongRunningDelete(
TCB_PTR_CTE_PTR(cap_thread_cap_get_capTCBPtr(cap), tcbCTable)) ||
slotCapLongRunningDelete(
TCB_PTR_CTE_PTR(cap_thread_cap_get_capTCBPtr(cap), tcbVTable))) {
userError("TCB Configure: CSpace or VSpace currently being deleted.");
current_syscall_error.type = seL4_IllegalOperation;
return EXCEPTION_SYSCALL_ERROR;
}
if (cRootData != 0) {
cRootCap = updateCapData(false, cRootData, cRootCap);
}
dc_ret = deriveCap(cRootSlot, cRootCap);
if (dc_ret.status != EXCEPTION_NONE) {
return dc_ret.status;
}
cRootCap = dc_ret.cap;
if (cap_get_capType(cRootCap) != cap_cnode_cap) {
userError("TCB Configure: CSpace cap is invalid.");
current_syscall_error.type = seL4_IllegalOperation;
return EXCEPTION_SYSCALL_ERROR;
}
if (vRootData != 0) {
vRootCap = updateCapData(false, vRootData, vRootCap);
}
dc_ret = deriveCap(vRootSlot, vRootCap);
if (dc_ret.status != EXCEPTION_NONE) {
return dc_ret.status;
}
vRootCap = dc_ret.cap;
if (!isValidVTableRoot(vRootCap)) {
userError("TCB Configure: VSpace cap is invalid.");
current_syscall_error.type = seL4_IllegalOperation;
return EXCEPTION_SYSCALL_ERROR;
}
setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
return invokeTCB_ThreadControl(
TCB_PTR(cap_thread_cap_get_capTCBPtr(cap)), slot,
faultEP, mcp, prio,
cRootCap, cRootSlot,
vRootCap, vRootSlot,
bufferAddr, bufferCap,
bufferSlot, thread_control_update_all);
}
exception_t
decodeSetPriority(cap_t cap, word_t length, word_t *buffer)
{
prio_t newPrio;
exception_t status;
if (length < 1) {
userError("TCB SetPriority: Truncated message.");
current_syscall_error.type = seL4_TruncatedMessage;
return EXCEPTION_SYSCALL_ERROR;
}
newPrio = getSyscallArg(0, buffer);
status = checkPrio(newPrio);
if (status != EXCEPTION_NONE) {
userError("TCB SetPriority: Requested priority %lu too high (max %lu).",
(unsigned long) newPrio, (unsigned long) NODE_STATE(ksCurThread)->tcbMCP);
return status;
}
setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
return invokeTCB_ThreadControl(
TCB_PTR(cap_thread_cap_get_capTCBPtr(cap)), NULL,
0, NULL_PRIO, newPrio,
cap_null_cap_new(), NULL,
cap_null_cap_new(), NULL,
0, cap_null_cap_new(),
NULL, thread_control_update_priority);
}
exception_t
decodeSetMCPriority(cap_t cap, word_t length, word_t *buffer)
{
prio_t newMcp;
exception_t status;
if (length < 1) {
userError("TCB SetMCPriority: Truncated message.");
current_syscall_error.type = seL4_TruncatedMessage;
return EXCEPTION_SYSCALL_ERROR;
}
newMcp = getSyscallArg(0, buffer);
status = checkPrio(newMcp);
if (status != EXCEPTION_NONE) {
userError("TCB SetMCPriority: Requested maximum controlled priority %lu too high (max %lu).",
(unsigned long) newMcp, (unsigned long) NODE_STATE(ksCurThread)->tcbMCP);
return status;
}
setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
return invokeTCB_ThreadControl(
TCB_PTR(cap_thread_cap_get_capTCBPtr(cap)), NULL,
0, newMcp, NULL_PRIO,
cap_null_cap_new(), NULL,
cap_null_cap_new(), NULL,
0, cap_null_cap_new(),
NULL, thread_control_update_mcp);
}
exception_t
decodeSetIPCBuffer(cap_t cap, word_t length, cte_t* slot,
extra_caps_t excaps, word_t *buffer)
{
cptr_t cptr_bufferPtr;
cap_t bufferCap;
cte_t *bufferSlot;
if (length < 1 || excaps.excaprefs[0] == NULL) {
userError("TCB SetIPCBuffer: Truncated message.");
current_syscall_error.type = seL4_TruncatedMessage;
return EXCEPTION_SYSCALL_ERROR;
}
cptr_bufferPtr = getSyscallArg(0, buffer);
bufferSlot = excaps.excaprefs[0];
bufferCap = excaps.excaprefs[0]->cap;
if (cptr_bufferPtr == 0) {
bufferSlot = NULL;
} else {
exception_t e;
deriveCap_ret_t dc_ret;
dc_ret = deriveCap(bufferSlot, bufferCap);
if (dc_ret.status != EXCEPTION_NONE) {
return dc_ret.status;
}
bufferCap = dc_ret.cap;
e = checkValidIPCBuffer(cptr_bufferPtr, bufferCap);
if (e != EXCEPTION_NONE) {
return e;
}
}
setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
return invokeTCB_ThreadControl(
TCB_PTR(cap_thread_cap_get_capTCBPtr(cap)), slot,
0, NULL_PRIO, NULL_PRIO,
cap_null_cap_new(), NULL,
cap_null_cap_new(), NULL,
cptr_bufferPtr, bufferCap,
bufferSlot, thread_control_update_ipc_buffer);
}
exception_t
decodeSetSpace(cap_t cap, word_t length, cte_t* slot,
extra_caps_t excaps, word_t *buffer)
{
cptr_t faultEP;
word_t cRootData, vRootData;
cte_t *cRootSlot, *vRootSlot;
cap_t cRootCap, vRootCap;
deriveCap_ret_t dc_ret;
if (length < 3 || excaps.excaprefs[0] == NULL
|| excaps.excaprefs[1] == NULL) {
userError("TCB SetSpace: Truncated message.");
current_syscall_error.type = seL4_TruncatedMessage;
return EXCEPTION_SYSCALL_ERROR;
}
faultEP = getSyscallArg(0, buffer);
cRootData = getSyscallArg(1, buffer);
vRootData = getSyscallArg(2, buffer);
cRootSlot = excaps.excaprefs[0];
cRootCap = excaps.excaprefs[0]->cap;
vRootSlot = excaps.excaprefs[1];
vRootCap = excaps.excaprefs[1]->cap;
if (slotCapLongRunningDelete(
TCB_PTR_CTE_PTR(cap_thread_cap_get_capTCBPtr(cap), tcbCTable)) ||
slotCapLongRunningDelete(
TCB_PTR_CTE_PTR(cap_thread_cap_get_capTCBPtr(cap), tcbVTable))) {
userError("TCB SetSpace: CSpace or VSpace currently being deleted.");
current_syscall_error.type = seL4_IllegalOperation;
return EXCEPTION_SYSCALL_ERROR;
}
if (cRootData != 0) {
cRootCap = updateCapData(false, cRootData, cRootCap);
}
dc_ret = deriveCap(cRootSlot, cRootCap);
if (dc_ret.status != EXCEPTION_NONE) {
return dc_ret.status;
}
cRootCap = dc_ret.cap;
if (cap_get_capType(cRootCap) != cap_cnode_cap) {
userError("TCB SetSpace: Invalid CNode cap.");
current_syscall_error.type = seL4_IllegalOperation;
return EXCEPTION_SYSCALL_ERROR;
}
if (vRootData != 0) {
vRootCap = updateCapData(false, vRootData, vRootCap);
}
dc_ret = deriveCap(vRootSlot, vRootCap);
if (dc_ret.status != EXCEPTION_NONE) {
return dc_ret.status;
}
vRootCap = dc_ret.cap;
if (!isValidVTableRoot(vRootCap)) {
userError("TCB SetSpace: Invalid VSpace cap.");
current_syscall_error.type = seL4_IllegalOperation;
return EXCEPTION_SYSCALL_ERROR;
}
setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
return invokeTCB_ThreadControl(
TCB_PTR(cap_thread_cap_get_capTCBPtr(cap)), slot,
faultEP,
NULL_PRIO, NULL_PRIO,
cRootCap, cRootSlot,
vRootCap, vRootSlot,
0, cap_null_cap_new(), NULL, thread_control_update_space);
}
exception_t
decodeDomainInvocation(word_t invLabel, word_t length, extra_caps_t excaps, word_t *buffer)
{
word_t domain;
cap_t tcap;
if (unlikely(invLabel != DomainSetSet)) {
current_syscall_error.type = seL4_IllegalOperation;
return EXCEPTION_SYSCALL_ERROR;
}
if (unlikely(length == 0)) {
userError("Domain Configure: Truncated message.");
current_syscall_error.type = seL4_TruncatedMessage;
return EXCEPTION_SYSCALL_ERROR;
} else {
domain = getSyscallArg(0, buffer);
if (domain >= CONFIG_NUM_DOMAINS) {
userError("Domain Configure: invalid domain (%lu >= %u).",
domain, CONFIG_NUM_DOMAINS);
current_syscall_error.type = seL4_InvalidArgument;
current_syscall_error.invalidArgumentNumber = 0;
return EXCEPTION_SYSCALL_ERROR;
}
}
if (unlikely(excaps.excaprefs[0] == NULL)) {
userError("Domain Configure: Truncated message.");
current_syscall_error.type = seL4_TruncatedMessage;
return EXCEPTION_SYSCALL_ERROR;
}
tcap = excaps.excaprefs[0]->cap;
if (unlikely(cap_get_capType(tcap) != cap_thread_cap)) {
userError("Domain Configure: thread cap required.");
current_syscall_error.type = seL4_InvalidArgument;
current_syscall_error.invalidArgumentNumber = 1;
return EXCEPTION_SYSCALL_ERROR;
}
setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
setDomain(TCB_PTR(cap_thread_cap_get_capTCBPtr(tcap)), domain);
return EXCEPTION_NONE;
}
exception_t
decodeBindNotification(cap_t cap, extra_caps_t excaps)
{
notification_t *ntfnPtr;
tcb_t *tcb;
cap_t ntfn_cap;
if (excaps.excaprefs[0] == NULL) {
userError("TCB BindNotification: Truncated message.");
current_syscall_error.type = seL4_TruncatedMessage;
return EXCEPTION_SYSCALL_ERROR;
}
tcb = TCB_PTR(cap_thread_cap_get_capTCBPtr(cap));
if (tcb->tcbBoundNotification) {
userError("TCB BindNotification: TCB already has a bound notification.");
current_syscall_error.type = seL4_IllegalOperation;
return EXCEPTION_SYSCALL_ERROR;
}
ntfn_cap = excaps.excaprefs[0]->cap;
if (cap_get_capType(ntfn_cap) == cap_notification_cap) {
ntfnPtr = NTFN_PTR(cap_notification_cap_get_capNtfnPtr(ntfn_cap));
} else {
userError("TCB BindNotification: Notification is invalid.");
current_syscall_error.type = seL4_IllegalOperation;
return EXCEPTION_SYSCALL_ERROR;
}
if (!cap_notification_cap_get_capNtfnCanReceive(ntfn_cap)) {
userError("TCB BindNotification: Insufficient access rights");
current_syscall_error.type = seL4_IllegalOperation;
return EXCEPTION_SYSCALL_ERROR;
}
if ((tcb_t*)notification_ptr_get_ntfnQueue_head(ntfnPtr)
|| (tcb_t*)notification_ptr_get_ntfnBoundTCB(ntfnPtr)) {
userError("TCB BindNotification: Notification cannot be bound.");
current_syscall_error.type = seL4_IllegalOperation;
return EXCEPTION_SYSCALL_ERROR;
}
setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
return invokeTCB_NotificationControl(tcb, ntfnPtr);
}
exception_t
decodeUnbindNotification(cap_t cap)
{
tcb_t *tcb;
tcb = TCB_PTR(cap_thread_cap_get_capTCBPtr(cap));
if (!tcb->tcbBoundNotification) {
userError("TCB UnbindNotification: TCB already has no bound Notification.");
current_syscall_error.type = seL4_IllegalOperation;
return EXCEPTION_SYSCALL_ERROR;
}
setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
return invokeTCB_NotificationControl(tcb, NULL);
}
exception_t
invokeTCB_Suspend(tcb_t *thread)
{
suspend(thread);
return EXCEPTION_NONE;
}
exception_t
invokeTCB_Resume(tcb_t *thread)
{
restart(thread);
return EXCEPTION_NONE;
}
exception_t
invokeTCB_ThreadControl(tcb_t *target, cte_t* slot,
cptr_t faultep, prio_t mcp, prio_t priority,
cap_t cRoot_newCap, cte_t *cRoot_srcSlot,
cap_t vRoot_newCap, cte_t *vRoot_srcSlot,
word_t bufferAddr, cap_t bufferCap,
cte_t *bufferSrcSlot,
thread_control_flag_t updateFlags)
{
exception_t e;
cap_t tCap = cap_thread_cap_new((word_t)target);
if (updateFlags & thread_control_update_space) {
target->tcbFaultHandler = faultep;
}
if (updateFlags & thread_control_update_mcp) {
setMCPriority(target, mcp);
}
if (updateFlags & thread_control_update_priority) {
setPriority(target, priority);
}
if (updateFlags & thread_control_update_space) {
cte_t *rootSlot;
rootSlot = TCB_PTR_CTE_PTR(target, tcbCTable);
e = cteDelete(rootSlot, true);
if (e != EXCEPTION_NONE) {
return e;
}
if (sameObjectAs(cRoot_newCap, cRoot_srcSlot->cap) &&
sameObjectAs(tCap, slot->cap)) {
cteInsert(cRoot_newCap, cRoot_srcSlot, rootSlot);
}
}
if (updateFlags & thread_control_update_space) {
cte_t *rootSlot;
rootSlot = TCB_PTR_CTE_PTR(target, tcbVTable);
e = cteDelete(rootSlot, true);
if (e != EXCEPTION_NONE) {
return e;
}
if (sameObjectAs(vRoot_newCap, vRoot_srcSlot->cap) &&
sameObjectAs(tCap, slot->cap)) {
cteInsert(vRoot_newCap, vRoot_srcSlot, rootSlot);
}
}
if (updateFlags & thread_control_update_ipc_buffer) {
cte_t *bufferSlot;
bufferSlot = TCB_PTR_CTE_PTR(target, tcbBuffer);
e = cteDelete(bufferSlot, true);
if (e != EXCEPTION_NONE) {
return e;
}
target->tcbIPCBuffer = bufferAddr;
#ifdef CONFIG_ARCH_ARM
#if defined(CONFIG_IPC_BUF_GLOBALS_FRAME)
#elif defined(CONFIG_IPC_BUF_TPIDRURW)
setRegister(target, TPIDRURW, bufferAddr);
#else
#error "Unknown IPC buffer strategy"
#endif
#endif
if (bufferSrcSlot && sameObjectAs(bufferCap, bufferSrcSlot->cap) &&
sameObjectAs(tCap, slot->cap)) {
cteInsert(bufferCap, bufferSrcSlot, bufferSlot);
}
}
return EXCEPTION_NONE;
}
exception_t
invokeTCB_CopyRegisters(tcb_t *dest, tcb_t *tcb_src,
bool_t suspendSource, bool_t resumeTarget,
bool_t transferFrame, bool_t transferInteger,
word_t transferArch)
{
if (suspendSource) {
suspend(tcb_src);
}
if (resumeTarget) {
restart(dest);
}
if (transferFrame) {
word_t i;
word_t v;
word_t pc;
for (i = 0; i < n_frameRegisters; i++) {
v = getRegister(tcb_src, frameRegisters[i]);
setRegister(dest, frameRegisters[i], v);
}
pc = getRestartPC(dest);
setNextPC(dest, pc);
}
if (transferInteger) {
word_t i;
word_t v;
for (i = 0; i < n_gpRegisters; i++) {
v = getRegister(tcb_src, gpRegisters[i]);
setRegister(dest, gpRegisters[i], v);
}
}
#ifdef CONFIG_ARCH_X86_64
if (dest != NODE_STATE(ksCurThread)) {
setRegister(dest, Error, 0);
}
#endif
return Arch_performTransfer(transferArch, tcb_src, dest);
}
exception_t
invokeTCB_ReadRegisters(tcb_t *tcb_src, bool_t suspendSource,
word_t n, word_t arch, bool_t call)
{
word_t i, j;
exception_t e;
tcb_t *thread;
thread = NODE_STATE(ksCurThread);
if (suspendSource) {
suspend(tcb_src);
}
e = Arch_performTransfer(arch, tcb_src, NODE_STATE(ksCurThread));
if (e != EXCEPTION_NONE) {
return e;
}
if (call) {
word_t *ipcBuffer;
ipcBuffer = lookupIPCBuffer(true, thread);
setRegister(thread, badgeRegister, 0);
for (i = 0; i < n && i < n_frameRegisters && i < n_msgRegisters; i++) {
setRegister(thread, msgRegisters[i],
getRegister(tcb_src, frameRegisters[i]));
}
if (ipcBuffer != NULL && i < n && i < n_frameRegisters) {
for (; i < n && i < n_frameRegisters; i++) {
ipcBuffer[i + 1] = getRegister(tcb_src, frameRegisters[i]);
}
}
j = i;
for (i = 0; i < n_gpRegisters && i + n_frameRegisters < n
&& i + n_frameRegisters < n_msgRegisters; i++) {
setRegister(thread, msgRegisters[i + n_frameRegisters],
getRegister(tcb_src, gpRegisters[i]));
}
if (ipcBuffer != NULL && i < n_gpRegisters
&& i + n_frameRegisters < n) {
for (; i < n_gpRegisters && i + n_frameRegisters < n; i++) {
ipcBuffer[i + n_frameRegisters + 1] =
getRegister(tcb_src, gpRegisters[i]);
}
}
setRegister(thread, msgInfoRegister, wordFromMessageInfo(
seL4_MessageInfo_new(0, 0, 0, i + j)));
}
setThreadState(thread, ThreadState_Running);
return EXCEPTION_NONE;
}
exception_t
invokeTCB_WriteRegisters(tcb_t *dest, bool_t resumeTarget,
word_t n, word_t arch, word_t *buffer)
{
word_t i;
word_t pc;
exception_t e;
e = Arch_performTransfer(arch, NODE_STATE(ksCurThread), dest);
if (e != EXCEPTION_NONE) {
return e;
}
if (n > n_frameRegisters + n_gpRegisters) {
n = n_frameRegisters + n_gpRegisters;
}
for (i = 0; i < n_frameRegisters && i < n; i++) {
setRegister(dest, frameRegisters[i],
sanitiseRegister(frameRegisters[i],
getSyscallArg(i + 2, buffer), dest));
}
for (i = 0; i < n_gpRegisters && i + n_frameRegisters < n; i++) {
setRegister(dest, gpRegisters[i],
sanitiseRegister(gpRegisters[i],
getSyscallArg(i + n_frameRegisters + 2,
buffer), dest));
}
#ifdef CONFIG_ARCH_X86_64
if (dest != NODE_STATE(ksCurThread)) {
setRegister(dest, Error, 0);
}
#endif
pc = getRestartPC(dest);
setNextPC(dest, pc);
if (resumeTarget) {
restart(dest);
}
return EXCEPTION_NONE;
}
exception_t
invokeTCB_NotificationControl(tcb_t *tcb, notification_t *ntfnPtr)
{
if (ntfnPtr) {
bindNotification(tcb, ntfnPtr);
} else {
unbindNotification(tcb);
}
return EXCEPTION_NONE;
}
#ifdef CONFIG_DEBUG_BUILD
void
setThreadName(tcb_t *tcb, const char *name)
{
strlcpy(tcb->tcbName, name, TCB_NAME_LENGTH);
}
#endif
word_t
setMRs_syscall_error(tcb_t *thread, word_t *receiveIPCBuffer)
{
switch (current_syscall_error.type) {
case seL4_InvalidArgument:
return setMR(thread, receiveIPCBuffer, 0,
current_syscall_error.invalidArgumentNumber);
case seL4_InvalidCapability:
return setMR(thread, receiveIPCBuffer, 0,
current_syscall_error.invalidCapNumber);
case seL4_IllegalOperation:
return 0;
case seL4_RangeError:
setMR(thread, receiveIPCBuffer, 0,
current_syscall_error.rangeErrorMin);
return setMR(thread, receiveIPCBuffer, 1,
current_syscall_error.rangeErrorMax);
case seL4_AlignmentError:
return 0;
case seL4_FailedLookup:
setMR(thread, receiveIPCBuffer, 0,
current_syscall_error.failedLookupWasSource ? 1 : 0);
return setMRs_lookup_failure(thread, receiveIPCBuffer,
current_lookup_fault, 1);
case seL4_TruncatedMessage:
case seL4_DeleteFirst:
case seL4_RevokeFirst:
return 0;
case seL4_NotEnoughMemory:
return setMR(thread, receiveIPCBuffer, 0,
current_syscall_error.memoryLeft);
default:
fail("Invalid syscall error");
}
}