/* * Copyright 2014, General Dynamics C4 Systems * * SPDX-License-Identifier: GPL-2.0-only */ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_KERNEL_MCS #include #include #endif #include #include #include #include #include #include #include #include word_t getObjectSize(word_t t, word_t userObjSize) { if (t >= seL4_NonArchObjectTypeCount) { return Arch_getObjectSize(t); } else { switch (t) { case seL4_TCBObject: return seL4_TCBBits; case seL4_EndpointObject: return seL4_EndpointBits; case seL4_NotificationObject: return seL4_NotificationBits; case seL4_CapTableObject: return seL4_SlotBits + userObjSize; case seL4_UntypedObject: return userObjSize; #ifdef CONFIG_KERNEL_MCS case seL4_SchedContextObject: return userObjSize; case seL4_ReplyObject: return seL4_ReplyBits; #endif default: fail("Invalid object type"); return 0; } } } deriveCap_ret_t deriveCap(cte_t *slot, cap_t cap) { deriveCap_ret_t ret; if (isArchCap(cap)) { return Arch_deriveCap(slot, cap); } switch (cap_get_capType(cap)) { case cap_zombie_cap: ret.status = EXCEPTION_NONE; ret.cap = cap_null_cap_new(); break; case cap_irq_control_cap: ret.status = EXCEPTION_NONE; ret.cap = cap_null_cap_new(); break; case cap_untyped_cap: ret.status = ensureNoChildren(slot); if (ret.status != EXCEPTION_NONE) { ret.cap = cap_null_cap_new(); } else { ret.cap = cap; } break; #ifndef CONFIG_KERNEL_MCS case cap_reply_cap: ret.status = EXCEPTION_NONE; ret.cap = cap_null_cap_new(); break; #endif default: ret.status = EXCEPTION_NONE; ret.cap = cap; } return ret; } finaliseCap_ret_t finaliseCap(cap_t cap, bool_t final, bool_t exposed) { finaliseCap_ret_t fc_ret; if (isArchCap(cap)) { return Arch_finaliseCap(cap, final); } switch (cap_get_capType(cap)) { case cap_endpoint_cap: if (final) { cancelAllIPC(EP_PTR(cap_endpoint_cap_get_capEPPtr(cap))); } fc_ret.remainder = cap_null_cap_new(); fc_ret.cleanupInfo = cap_null_cap_new(); return fc_ret; case cap_notification_cap: if (final) { notification_t *ntfn = NTFN_PTR(cap_notification_cap_get_capNtfnPtr(cap)); #ifdef CONFIG_KERNEL_MCS schedContext_unbindNtfn(SC_PTR(notification_ptr_get_ntfnSchedContext(ntfn))); #endif unbindMaybeNotification(ntfn); cancelAllSignals(ntfn); } fc_ret.remainder = cap_null_cap_new(); fc_ret.cleanupInfo = cap_null_cap_new(); return fc_ret; case cap_reply_cap: #ifdef CONFIG_KERNEL_MCS if (final) { reply_t *reply = REPLY_PTR(cap_reply_cap_get_capReplyPtr(cap)); if (reply && reply->replyTCB) { switch (thread_state_get_tsType(reply->replyTCB->tcbState)) { case ThreadState_BlockedOnReply: reply_remove(reply, reply->replyTCB); break; case ThreadState_BlockedOnReceive: reply_unlink(reply, reply->replyTCB); break; default: fail("Invalid tcb state"); } } } fc_ret.remainder = cap_null_cap_new(); fc_ret.cleanupInfo = cap_null_cap_new(); return fc_ret; #endif case cap_null_cap: case cap_domain_cap: fc_ret.remainder = cap_null_cap_new(); fc_ret.cleanupInfo = cap_null_cap_new(); return fc_ret; } if (exposed) { fail("finaliseCap: failed to finalise immediately."); } switch (cap_get_capType(cap)) { case cap_cnode_cap: { if (final) { fc_ret.remainder = Zombie_new( 1ul << cap_cnode_cap_get_capCNodeRadix(cap), cap_cnode_cap_get_capCNodeRadix(cap), cap_cnode_cap_get_capCNodePtr(cap) ); fc_ret.cleanupInfo = cap_null_cap_new(); return fc_ret; } break; } case cap_thread_cap: { if (final) { tcb_t *tcb; cte_t *cte_ptr; tcb = TCB_PTR(cap_thread_cap_get_capTCBPtr(cap)); SMP_COND_STATEMENT(remoteTCBStall(tcb);) cte_ptr = TCB_PTR_CTE_PTR(tcb, tcbCTable); unbindNotification(tcb); #ifdef CONFIG_KERNEL_MCS if (tcb->tcbSchedContext) { schedContext_completeYieldTo(tcb->tcbSchedContext->scYieldFrom); schedContext_unbindTCB(tcb->tcbSchedContext, tcb); } #endif suspend(tcb); #ifdef CONFIG_DEBUG_BUILD tcbDebugRemove(tcb); #endif Arch_prepareThreadDelete(tcb); fc_ret.remainder = Zombie_new( tcbArchCNodeEntries, ZombieType_ZombieTCB, CTE_REF(cte_ptr) ); fc_ret.cleanupInfo = cap_null_cap_new(); return fc_ret; } break; } #ifdef CONFIG_KERNEL_MCS case cap_sched_context_cap: if (final) { sched_context_t *sc = SC_PTR(cap_sched_context_cap_get_capSCPtr(cap)); schedContext_unbindAllTCBs(sc); schedContext_unbindNtfn(sc); if (sc->scReply) { assert(call_stack_get_isHead(sc->scReply->replyNext)); sc->scReply->replyNext = call_stack_new(0, false); sc->scReply = NULL; } if (sc->scYieldFrom) { schedContext_completeYieldTo(sc->scYieldFrom); } /* mark the sc as no longer valid */ sc->scRefillMax = 0; fc_ret.remainder = cap_null_cap_new(); fc_ret.cleanupInfo = cap_null_cap_new(); return fc_ret; } break; #endif case cap_zombie_cap: fc_ret.remainder = cap; fc_ret.cleanupInfo = cap_null_cap_new(); return fc_ret; case cap_irq_handler_cap: if (final) { irq_t irq = IDX_TO_IRQT(cap_irq_handler_cap_get_capIRQ(cap)); deletingIRQHandler(irq); fc_ret.remainder = cap_null_cap_new(); fc_ret.cleanupInfo = cap; return fc_ret; } break; } fc_ret.remainder = cap_null_cap_new(); fc_ret.cleanupInfo = cap_null_cap_new(); return fc_ret; } bool_t CONST hasCancelSendRights(cap_t cap) { switch (cap_get_capType(cap)) { case cap_endpoint_cap: return cap_endpoint_cap_get_capCanSend(cap) && cap_endpoint_cap_get_capCanReceive(cap) && cap_endpoint_cap_get_capCanGrantReply(cap) && cap_endpoint_cap_get_capCanGrant(cap); default: return false; } } bool_t CONST sameRegionAs(cap_t cap_a, cap_t cap_b) { switch (cap_get_capType(cap_a)) { case cap_untyped_cap: if (cap_get_capIsPhysical(cap_b)) { word_t aBase, bBase, aTop, bTop; aBase = (word_t)WORD_PTR(cap_untyped_cap_get_capPtr(cap_a)); bBase = (word_t)cap_get_capPtr(cap_b); aTop = aBase + MASK(cap_untyped_cap_get_capBlockSize(cap_a)); bTop = bBase + MASK(cap_get_capSizeBits(cap_b)); return (aBase <= bBase) && (bTop <= aTop) && (bBase <= bTop); } break; case cap_endpoint_cap: if (cap_get_capType(cap_b) == cap_endpoint_cap) { return cap_endpoint_cap_get_capEPPtr(cap_a) == cap_endpoint_cap_get_capEPPtr(cap_b); } break; case cap_notification_cap: if (cap_get_capType(cap_b) == cap_notification_cap) { return cap_notification_cap_get_capNtfnPtr(cap_a) == cap_notification_cap_get_capNtfnPtr(cap_b); } break; case cap_cnode_cap: if (cap_get_capType(cap_b) == cap_cnode_cap) { return (cap_cnode_cap_get_capCNodePtr(cap_a) == cap_cnode_cap_get_capCNodePtr(cap_b)) && (cap_cnode_cap_get_capCNodeRadix(cap_a) == cap_cnode_cap_get_capCNodeRadix(cap_b)); } break; case cap_thread_cap: if (cap_get_capType(cap_b) == cap_thread_cap) { return cap_thread_cap_get_capTCBPtr(cap_a) == cap_thread_cap_get_capTCBPtr(cap_b); } break; case cap_reply_cap: if (cap_get_capType(cap_b) == cap_reply_cap) { #ifdef CONFIG_KERNEL_MCS return cap_reply_cap_get_capReplyPtr(cap_a) == cap_reply_cap_get_capReplyPtr(cap_b); #else return cap_reply_cap_get_capTCBPtr(cap_a) == cap_reply_cap_get_capTCBPtr(cap_b); #endif } break; case cap_domain_cap: if (cap_get_capType(cap_b) == cap_domain_cap) { return true; } break; case cap_irq_control_cap: if (cap_get_capType(cap_b) == cap_irq_control_cap || cap_get_capType(cap_b) == cap_irq_handler_cap) { return true; } break; case cap_irq_handler_cap: if (cap_get_capType(cap_b) == cap_irq_handler_cap) { return (word_t)cap_irq_handler_cap_get_capIRQ(cap_a) == (word_t)cap_irq_handler_cap_get_capIRQ(cap_b); } break; #ifdef CONFIG_KERNEL_MCS case cap_sched_context_cap: if (cap_get_capType(cap_b) == cap_sched_context_cap) { return (cap_sched_context_cap_get_capSCPtr(cap_a) == cap_sched_context_cap_get_capSCPtr(cap_b)) && (cap_sched_context_cap_get_capSCSizeBits(cap_a) == cap_sched_context_cap_get_capSCSizeBits(cap_b)); } break; case cap_sched_control_cap: if (cap_get_capType(cap_b) == cap_sched_control_cap) { return true; } break; #endif default: if (isArchCap(cap_a) && isArchCap(cap_b)) { return Arch_sameRegionAs(cap_a, cap_b); } break; } return false; } bool_t CONST sameObjectAs(cap_t cap_a, cap_t cap_b) { if (cap_get_capType(cap_a) == cap_untyped_cap) { return false; } if (cap_get_capType(cap_a) == cap_irq_control_cap && cap_get_capType(cap_b) == cap_irq_handler_cap) { return false; } if (isArchCap(cap_a) && isArchCap(cap_b)) { return Arch_sameObjectAs(cap_a, cap_b); } return sameRegionAs(cap_a, cap_b); } cap_t CONST updateCapData(bool_t preserve, word_t newData, cap_t cap) { if (isArchCap(cap)) { return Arch_updateCapData(preserve, newData, cap); } switch (cap_get_capType(cap)) { case cap_endpoint_cap: if (!preserve && cap_endpoint_cap_get_capEPBadge(cap) == 0) { return cap_endpoint_cap_set_capEPBadge(cap, newData); } else { return cap_null_cap_new(); } case cap_notification_cap: if (!preserve && cap_notification_cap_get_capNtfnBadge(cap) == 0) { return cap_notification_cap_set_capNtfnBadge(cap, newData); } else { return cap_null_cap_new(); } case cap_cnode_cap: { word_t guard, guardSize; seL4_CNode_CapData_t w = { .words = { newData } }; guardSize = seL4_CNode_CapData_get_guardSize(w); if (guardSize + cap_cnode_cap_get_capCNodeRadix(cap) > wordBits) { return cap_null_cap_new(); } else { cap_t new_cap; guard = seL4_CNode_CapData_get_guard(w) & MASK(guardSize); new_cap = cap_cnode_cap_set_capCNodeGuard(cap, guard); new_cap = cap_cnode_cap_set_capCNodeGuardSize(new_cap, guardSize); return new_cap; } } default: return cap; } } cap_t CONST maskCapRights(seL4_CapRights_t cap_rights, cap_t cap) { if (isArchCap(cap)) { return Arch_maskCapRights(cap_rights, cap); } switch (cap_get_capType(cap)) { case cap_null_cap: case cap_domain_cap: case cap_cnode_cap: case cap_untyped_cap: case cap_irq_control_cap: case cap_irq_handler_cap: case cap_zombie_cap: case cap_thread_cap: #ifdef CONFIG_KERNEL_MCS case cap_sched_context_cap: case cap_sched_control_cap: #endif return cap; case cap_endpoint_cap: { cap_t new_cap; new_cap = cap_endpoint_cap_set_capCanSend( cap, cap_endpoint_cap_get_capCanSend(cap) & seL4_CapRights_get_capAllowWrite(cap_rights)); new_cap = cap_endpoint_cap_set_capCanReceive( new_cap, cap_endpoint_cap_get_capCanReceive(cap) & seL4_CapRights_get_capAllowRead(cap_rights)); new_cap = cap_endpoint_cap_set_capCanGrant( new_cap, cap_endpoint_cap_get_capCanGrant(cap) & seL4_CapRights_get_capAllowGrant(cap_rights)); new_cap = cap_endpoint_cap_set_capCanGrantReply( new_cap, cap_endpoint_cap_get_capCanGrantReply(cap) & seL4_CapRights_get_capAllowGrantReply(cap_rights)); return new_cap; } case cap_notification_cap: { cap_t new_cap; new_cap = cap_notification_cap_set_capNtfnCanSend( cap, cap_notification_cap_get_capNtfnCanSend(cap) & seL4_CapRights_get_capAllowWrite(cap_rights)); new_cap = cap_notification_cap_set_capNtfnCanReceive(new_cap, cap_notification_cap_get_capNtfnCanReceive(cap) & seL4_CapRights_get_capAllowRead(cap_rights)); return new_cap; } case cap_reply_cap: { cap_t new_cap; new_cap = cap_reply_cap_set_capReplyCanGrant( cap, cap_reply_cap_get_capReplyCanGrant(cap) & seL4_CapRights_get_capAllowGrant(cap_rights)); return new_cap; } default: fail("Invalid cap type"); /* Sentinel for invalid enums */ } } cap_t createObject(object_t t, void *regionBase, word_t userSize, bool_t deviceMemory) { /* Handle architecture-specific objects. */ if (t >= (object_t) seL4_NonArchObjectTypeCount) { return Arch_createObject(t, regionBase, userSize, deviceMemory); } /* Create objects. */ switch ((api_object_t)t) { case seL4_TCBObject: { tcb_t *tcb; tcb = TCB_PTR((word_t)regionBase + TCB_OFFSET); /** AUXUPD: "(True, ptr_retyps 1 (Ptr ((ptr_val \tcb) - ctcb_offset) :: (cte_C[5]) ptr) o (ptr_retyp \tcb))" */ /* Setup non-zero parts of the TCB. */ Arch_initContext(&tcb->tcbArch.tcbContext); #ifndef CONFIG_KERNEL_MCS tcb->tcbTimeSlice = CONFIG_TIME_SLICE; #endif tcb->tcbDomain = ksCurDomain; #ifndef CONFIG_KERNEL_MCS /* Initialize the new TCB to the current core */ SMP_COND_STATEMENT(tcb->tcbAffinity = getCurrentCPUIndex()); #endif #ifdef CONFIG_DEBUG_BUILD strlcpy(TCB_PTR_DEBUG_PTR(tcb)->tcbName, "child of: '", TCB_NAME_LENGTH); strlcat(TCB_PTR_DEBUG_PTR(tcb)->tcbName, TCB_PTR_DEBUG_PTR(NODE_STATE(ksCurThread))->tcbName, TCB_NAME_LENGTH); strlcat(TCB_PTR_DEBUG_PTR(tcb)->tcbName, "'", TCB_NAME_LENGTH); tcbDebugAppend(tcb); #endif /* CONFIG_DEBUG_BUILD */ return cap_thread_cap_new(TCB_REF(tcb)); } case seL4_EndpointObject: /** AUXUPD: "(True, ptr_retyp (Ptr (ptr_val \regionBase) :: endpoint_C ptr))" */ return cap_endpoint_cap_new(0, true, true, true, true, EP_REF(regionBase)); case seL4_NotificationObject: /** AUXUPD: "(True, ptr_retyp (Ptr (ptr_val \regionBase) :: notification_C ptr))" */ return cap_notification_cap_new(0, true, true, NTFN_REF(regionBase)); case seL4_CapTableObject: /** AUXUPD: "(True, ptr_arr_retyps (2 ^ (unat \userSize)) (Ptr (ptr_val \regionBase) :: cte_C ptr))" */ /** GHOSTUPD: "(True, gs_new_cnodes (unat \userSize) (ptr_val \regionBase) (4 + unat \userSize))" */ return cap_cnode_cap_new(userSize, 0, 0, CTE_REF(regionBase)); case seL4_UntypedObject: /* * No objects need to be created; instead, just insert caps into * the destination slots. */ return cap_untyped_cap_new(0, !!deviceMemory, userSize, WORD_REF(regionBase)); #ifdef CONFIG_KERNEL_MCS case seL4_SchedContextObject: memzero(regionBase, BIT(userSize)); return cap_sched_context_cap_new(SC_REF(regionBase), userSize); case seL4_ReplyObject: memzero(regionBase, 1UL << seL4_ReplyBits); return cap_reply_cap_new(REPLY_REF(regionBase), true); #endif default: fail("Invalid object type"); } } void createNewObjects(object_t t, cte_t *parent, slot_range_t slots, void *regionBase, word_t userSize, bool_t deviceMemory) { word_t objectSize; void *nextFreeArea; word_t i; word_t totalObjectSize UNUSED; /* ghost check that we're visiting less bytes than the max object size */ objectSize = getObjectSize(t, userSize); totalObjectSize = slots.length << objectSize; /** GHOSTUPD: "(gs_get_assn cap_get_capSizeBits_'proc \ghost'state = 0 \ \totalObjectSize <= gs_get_assn cap_get_capSizeBits_'proc \ghost'state, id)" */ /* Create the objects. */ nextFreeArea = regionBase; for (i = 0; i < slots.length; i++) { /* Create the object. */ /** AUXUPD: "(True, typ_region_bytes (ptr_val \ nextFreeArea + ((\ i) << unat (\ objectSize))) (unat (\ objectSize)))" */ cap_t cap = createObject(t, (void *)((word_t)nextFreeArea + (i << objectSize)), userSize, deviceMemory); /* Insert the cap into the user's cspace. */ insertNewCap(parent, &slots.cnode[slots.offset + i], cap); /* Move along to the next region of memory. been merged into a formula of i */ } } #ifdef CONFIG_KERNEL_MCS exception_t decodeInvocation(word_t invLabel, word_t length, cptr_t capIndex, cte_t *slot, cap_t cap, extra_caps_t excaps, bool_t block, bool_t call, bool_t canDonate, bool_t firstPhase, word_t *buffer) #else exception_t decodeInvocation(word_t invLabel, word_t length, cptr_t capIndex, cte_t *slot, cap_t cap, extra_caps_t excaps, bool_t block, bool_t call, word_t *buffer) #endif { if (isArchCap(cap)) { return Arch_decodeInvocation(invLabel, length, capIndex, slot, cap, excaps, call, buffer); } switch (cap_get_capType(cap)) { case cap_null_cap: userError("Attempted to invoke a null cap #%lu.", capIndex); current_syscall_error.type = seL4_InvalidCapability; current_syscall_error.invalidCapNumber = 0; return EXCEPTION_SYSCALL_ERROR; case cap_zombie_cap: userError("Attempted to invoke a zombie cap #%lu.", capIndex); current_syscall_error.type = seL4_InvalidCapability; current_syscall_error.invalidCapNumber = 0; return EXCEPTION_SYSCALL_ERROR; case cap_endpoint_cap: if (unlikely(!cap_endpoint_cap_get_capCanSend(cap))) { userError("Attempted to invoke a read-only endpoint cap #%lu.", capIndex); current_syscall_error.type = seL4_InvalidCapability; current_syscall_error.invalidCapNumber = 0; return EXCEPTION_SYSCALL_ERROR; } setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart); #ifdef CONFIG_KERNEL_MCS return performInvocation_Endpoint( EP_PTR(cap_endpoint_cap_get_capEPPtr(cap)), cap_endpoint_cap_get_capEPBadge(cap), cap_endpoint_cap_get_capCanGrant(cap), cap_endpoint_cap_get_capCanGrantReply(cap), block, call, canDonate); #else return performInvocation_Endpoint( EP_PTR(cap_endpoint_cap_get_capEPPtr(cap)), cap_endpoint_cap_get_capEPBadge(cap), cap_endpoint_cap_get_capCanGrant(cap), cap_endpoint_cap_get_capCanGrantReply(cap), block, call); #endif case cap_notification_cap: { if (unlikely(!cap_notification_cap_get_capNtfnCanSend(cap))) { userError("Attempted to invoke a read-only notification cap #%lu.", capIndex); current_syscall_error.type = seL4_InvalidCapability; current_syscall_error.invalidCapNumber = 0; return EXCEPTION_SYSCALL_ERROR; } setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart); return performInvocation_Notification( NTFN_PTR(cap_notification_cap_get_capNtfnPtr(cap)), cap_notification_cap_get_capNtfnBadge(cap)); } #ifdef CONFIG_KERNEL_MCS case cap_reply_cap: setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart); return performInvocation_Reply( NODE_STATE(ksCurThread), REPLY_PTR(cap_reply_cap_get_capReplyPtr(cap)), cap_reply_cap_get_capReplyCanGrant(cap)); #else case cap_reply_cap: if (unlikely(cap_reply_cap_get_capReplyMaster(cap))) { userError("Attempted to invoke an invalid reply cap #%lu.", capIndex); current_syscall_error.type = seL4_InvalidCapability; current_syscall_error.invalidCapNumber = 0; return EXCEPTION_SYSCALL_ERROR; } setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart); return performInvocation_Reply( TCB_PTR(cap_reply_cap_get_capTCBPtr(cap)), slot, cap_reply_cap_get_capReplyCanGrant(cap)); #endif case cap_thread_cap: #ifdef CONFIG_KERNEL_MCS if (unlikely(firstPhase)) { userError("Cannot invoke thread capabilities in the first phase of an invocation"); current_syscall_error.type = seL4_InvalidCapability; current_syscall_error.invalidCapNumber = 0; return EXCEPTION_SYSCALL_ERROR; } #endif return decodeTCBInvocation(invLabel, length, cap, slot, excaps, call, buffer); case cap_domain_cap: #ifdef CONFIG_KERNEL_MCS if (unlikely(firstPhase)) { userError("Cannot invoke domain capabilities in the first phase of an invocation"); current_syscall_error.type = seL4_InvalidCapability; current_syscall_error.invalidCapNumber = 0; return EXCEPTION_SYSCALL_ERROR; } #endif return decodeDomainInvocation(invLabel, length, excaps, buffer); case cap_cnode_cap: #ifdef CONFIG_KERNEL_MCS if (unlikely(firstPhase)) { userError("Cannot invoke cnode capabilities in the first phase of an invocation"); current_syscall_error.type = seL4_InvalidCapability; current_syscall_error.invalidCapNumber = 0; return EXCEPTION_SYSCALL_ERROR; } #endif return decodeCNodeInvocation(invLabel, length, cap, excaps, buffer); case cap_untyped_cap: return decodeUntypedInvocation(invLabel, length, slot, cap, excaps, call, buffer); case cap_irq_control_cap: return decodeIRQControlInvocation(invLabel, length, slot, excaps, buffer); case cap_irq_handler_cap: return decodeIRQHandlerInvocation(invLabel, IDX_TO_IRQT(cap_irq_handler_cap_get_capIRQ(cap)), excaps); #ifdef CONFIG_KERNEL_MCS case cap_sched_control_cap: if (unlikely(firstPhase)) { userError("Cannot invoke sched control capabilities in the first phase of an invocation"); current_syscall_error.type = seL4_InvalidCapability; current_syscall_error.invalidCapNumber = 0; return EXCEPTION_SYSCALL_ERROR; } return decodeSchedControlInvocation(invLabel, cap, length, excaps, buffer); case cap_sched_context_cap: if (unlikely(firstPhase)) { userError("Cannot invoke sched context capabilities in the first phase of an invocation"); current_syscall_error.type = seL4_InvalidCapability; current_syscall_error.invalidCapNumber = 0; return EXCEPTION_SYSCALL_ERROR; } return decodeSchedContextInvocation(invLabel, cap, excaps, buffer); #endif default: fail("Invalid cap type"); } } #ifdef CONFIG_KERNEL_MCS exception_t performInvocation_Endpoint(endpoint_t *ep, word_t badge, bool_t canGrant, bool_t canGrantReply, bool_t block, bool_t call, bool_t canDonate) { sendIPC(block, call, badge, canGrant, canGrantReply, canDonate, NODE_STATE(ksCurThread), ep); return EXCEPTION_NONE; } #else exception_t performInvocation_Endpoint(endpoint_t *ep, word_t badge, bool_t canGrant, bool_t canGrantReply, bool_t block, bool_t call) { sendIPC(block, call, badge, canGrant, canGrantReply, NODE_STATE(ksCurThread), ep); return EXCEPTION_NONE; } #endif exception_t performInvocation_Notification(notification_t *ntfn, word_t badge) { sendSignal(ntfn, badge); return EXCEPTION_NONE; } #ifdef CONFIG_KERNEL_MCS exception_t performInvocation_Reply(tcb_t *thread, reply_t *reply, bool_t canGrant) { doReplyTransfer(thread, reply, canGrant); return EXCEPTION_NONE; } #else exception_t performInvocation_Reply(tcb_t *thread, cte_t *slot, bool_t canGrant) { doReplyTransfer(NODE_STATE(ksCurThread), thread, slot, canGrant); return EXCEPTION_NONE; } #endif