void doNormalTransfer(tcb_t *sender, word_t *sendBuffer, endpoint_t *endpoint, word_t badge, bool_t canGrant, tcb_t *receiver, word_t *receiveBuffer, bool_t diminish) { unsigned int msgTransferred; message_info_t tag; exception_t status; extra_caps_t caps; tag = messageInfoFromWord(getRegister(sender, msgInfoRegister)); if (canGrant) { status = lookupExtraCaps(sender, sendBuffer, tag); caps = current_extra_caps; if (unlikely(status != EXCEPTION_NONE)) { caps.excaprefs[0] = NULL; } } else { caps = current_extra_caps; caps.excaprefs[0] = NULL; } msgTransferred = copyMRs(sender, sendBuffer, receiver, receiveBuffer, message_info_get_msgLength(tag)); tag = transferCaps(tag, caps, endpoint, receiver, receiveBuffer, diminish); tag = message_info_set_msgLength(tag, msgTransferred); setRegister(receiver, msgInfoRegister, wordFromMessageInfo(tag)); setRegister(receiver, badgeRegister, badge); }
bool_t handleFaultReply(tcb_t *receiver, tcb_t *sender) { message_info_t tag; word_t label; fault_t fault; unsigned int length; /* These lookups are moved inward from doReplyTransfer */ tag = messageInfoFromWord(getRegister(sender, msgInfoRegister)); label = message_info_get_msgLabel(tag); length = message_info_get_msgLength(tag); fault = receiver->tcbFault; switch (fault_get_faultType(fault)) { case fault_cap_fault: return true; case fault_vm_fault: return true; case fault_unknown_syscall: { unsigned int i; register_t r; word_t v; word_t *sendBuf; sendBuf = lookupIPCBuffer(false, sender); /* Assumes n_syscallMessage > n_msgRegisters */ for (i = 0; i < length && i < n_msgRegisters; i++) { r = syscallMessage[i]; v = getRegister(sender, msgRegisters[i]); setRegister(receiver, r, sanitiseRegister(r, v)); } if (sendBuf) { for (; i < length && i < n_syscallMessage; i++) { r = syscallMessage[i]; v = sendBuf[i + 1]; setRegister(receiver, r, sanitiseRegister(r, v)); } } } return (label == 0); case fault_user_exception: { unsigned int i; register_t r; word_t v; /* Assumes n_exceptionMessage <= n_msgRegisters */ for (i = 0; i < length && i < n_exceptionMessage; i++) { r = exceptionMessage[i]; v = getRegister(sender, msgRegisters[i]); setRegister(receiver, r, sanitiseRegister(r, v)); } } return (label == 0); default: fail("Invalid fault"); } }
static exception_t handleInvocation(bool_t isCall, bool_t isBlocking) { seL4_MessageInfo_t info; cptr_t cptr; lookupCapAndSlot_ret_t lu_ret; word_t *buffer; exception_t status; word_t length; tcb_t *thread; thread = ksCurThread; info = messageInfoFromWord(getRegister(thread, msgInfoRegister)); cptr = getRegister(thread, capRegister); /* faulting section */ lu_ret = lookupCapAndSlot(thread, cptr); #if defined(DEBUG) || defined(CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES) ksKernelEntry.cap_type = cap_get_capType(lu_ret.cap); ksKernelEntry.invocation_tag = seL4_MessageInfo_get_label(info); ksKernelEntry.is_fastpath = false; #endif if (unlikely(lu_ret.status != EXCEPTION_NONE)) { userError("Invocation of invalid cap #%lu.", cptr); current_fault = fault_cap_fault_new(cptr, false); if (isBlocking) { handleFault(thread); } return EXCEPTION_NONE; } buffer = lookupIPCBuffer(false, thread); status = lookupExtraCaps(thread, buffer, info); if (unlikely(status != EXCEPTION_NONE)) { userError("Lookup of extra caps failed."); if (isBlocking) { handleFault(thread); } return EXCEPTION_NONE; } /* Syscall error/Preemptible section */ length = seL4_MessageInfo_get_length(info); if (unlikely(length > n_msgRegisters && !buffer)) { length = n_msgRegisters; } status = decodeInvocation(seL4_MessageInfo_get_label(info), length, cptr, lu_ret.slot, lu_ret.cap, current_extra_caps, isBlocking, isCall, buffer); if (unlikely(status == EXCEPTION_PREEMPTED)) { return status; } if (unlikely(status == EXCEPTION_SYSCALL_ERROR)) { if (isCall) { replyFromKernel_error(thread); } return EXCEPTION_NONE; } if (unlikely( thread_state_get_tsType(thread->tcbState) == ThreadState_Restart)) { if (isCall) { replyFromKernel_success_empty(thread); } setThreadState(thread, ThreadState_Running); } return EXCEPTION_NONE; }
static exception_t handleInvocation(bool_t isCall, bool_t isBlocking) { message_info_t info; cptr_t cptr; lookupCapAndSlot_ret_t lu_ret; word_t *buffer; exception_t status; word_t length; tcb_t *thread; thread = ksCurThread; info = messageInfoFromWord(getRegister(thread, msgInfoRegister)); cptr = getRegister(thread, capRegister); /* faulting section */ lu_ret = lookupCapAndSlot(thread, cptr); if (unlikely(lu_ret.status != EXCEPTION_NONE)) { userError("Invocation of invalid cap #%d.", (int)cptr); current_fault = fault_cap_fault_new(cptr, false); if (isBlocking) { handleFault(thread); } return EXCEPTION_NONE; } buffer = lookupIPCBuffer(false, thread); status = lookupExtraCaps(thread, buffer, info); if (unlikely(status != EXCEPTION_NONE)) { userError("Lookup of extra caps failed."); if (isBlocking) { handleFault(thread); } return EXCEPTION_NONE; } /* Syscall error/Preemptible section */ length = message_info_get_msgLength(info); if (unlikely(length > n_msgRegisters && !buffer)) { length = n_msgRegisters; } status = decodeInvocation(message_info_get_msgLabel(info), length, cptr, lu_ret.slot, lu_ret.cap, current_extra_caps, isBlocking, isCall, buffer); if (unlikely(status == EXCEPTION_PREEMPTED)) { return status; } if (unlikely(status == EXCEPTION_SYSCALL_ERROR)) { if (isCall) { replyFromKernel_error(thread); } return EXCEPTION_NONE; } if (unlikely( thread_state_get_tsType(thread->tcbState) == ThreadState_Restart)) { if (isCall) { replyFromKernel_success_empty(thread); } setThreadState(thread, ThreadState_Running); } return EXCEPTION_NONE; }
bool_t handleFaultReply(tcb_t *receiver, tcb_t *sender) { /* These lookups are moved inward from doReplyTransfer */ seL4_MessageInfo_t tag = messageInfoFromWord(getRegister(sender, msgInfoRegister)); word_t label = seL4_MessageInfo_get_label(tag); word_t length = seL4_MessageInfo_get_length(tag); seL4_Fault_t fault = receiver->tcbFault; switch (seL4_Fault_get_seL4_FaultType(fault)) { case seL4_Fault_CapFault: return true; case seL4_Fault_UnknownSyscall: copyMRsFaultReply(sender, receiver, MessageID_Syscall, MIN(length, n_syscallMessage)); return (label == 0); case seL4_Fault_UserException: copyMRsFaultReply(sender, receiver, MessageID_Exception, MIN(length, n_exceptionMessage)); return (label == 0); #ifdef CONFIG_HARDWARE_DEBUG_API case seL4_Fault_DebugException: { word_t n_instrs; if (seL4_Fault_DebugException_get_exceptionReason(fault) != seL4_SingleStep) { /* Only single-step replies are required to set message registers. */ return (label == 0); } if (length < DEBUG_REPLY_N_EXPECTED_REGISTERS) { /* A single-step reply doesn't mean much if it isn't composed of the bp * number and number of instructions to skip. But even if both aren't * set, we can still allow the thread to continue because replying * should uniformly resume thread execution, based on the general seL4 * API model. * * If it was single-step, but no reply registers were set, just * default to skipping 1 and continuing. * * On x86, bp_num actually doesn't matter for single-stepping * because single-stepping doesn't use a hardware register -- it * uses EFLAGS.TF. */ n_instrs = 1; } else { /* If the reply had all expected registers set, proceed as normal */ n_instrs = getRegister(sender, msgRegisters[0]); } syscall_error_t res; res = Arch_decodeConfigureSingleStepping(receiver, 0, n_instrs, true); if (res.type != seL4_NoError) { return false; }; configureSingleStepping(receiver, 0, n_instrs, true); /* Replying will always resume the thread: the only variant behaviour * is whether or not the thread will be resumed with stepping still * enabled. */ return (label == 0); } #endif default: return Arch_handleFaultReply(receiver, sender, seL4_Fault_get_seL4_FaultType(fault)); } }