/* Like getReceiveSlots, this is specialised for single-cap transfer. */ static message_info_t transferCaps(message_info_t info, extra_caps_t caps, endpoint_t *endpoint, tcb_t *receiver, word_t *receiveBuffer, bool_t diminish) { unsigned int i; cte_t* destSlot; info = message_info_set_msgExtraCaps(info, 0); info = message_info_set_msgCapsUnwrapped(info, 0); if (likely(!caps.excaprefs[0] || !receiveBuffer)) { return info; } destSlot = getReceiveSlots(receiver, receiveBuffer); for (i = 0; i < seL4_MsgMaxExtraCaps && caps.excaprefs[i] != NULL; i++) { cte_t *slot = caps.excaprefs[i]; cap_t cap = slot->cap; if (cap_get_capType(cap) == cap_endpoint_cap && EP_PTR(cap_endpoint_cap_get_capEPPtr(cap)) == endpoint) { /* If this is a cap to the endpoint on which the message was sent, * only transfer the badge, not the cap. */ setExtraBadge(receiveBuffer, cap_endpoint_cap_get_capEPBadge(cap), i); info = message_info_set_msgCapsUnwrapped(info, message_info_get_msgCapsUnwrapped(info) | (1 << i)); } else { deriveCap_ret_t dc_ret; if (!destSlot) { break; } if (diminish) { dc_ret = deriveCap(slot, maskCapRights(noWrite, cap)); } else { dc_ret = deriveCap(slot, cap); } if (dc_ret.status != EXCEPTION_NONE) { break; } if (cap_get_capType(dc_ret.cap) == cap_null_cap) { break; } cteInsert(dc_ret.cap, slot, destSlot); destSlot = NULL; } } return message_info_set_msgExtraCaps(info, i); }
exception_t decodeSetTCB(cap_t cap, unsigned int length, word_t* buffer, extra_caps_t extraCaps) { cap_t tcbCap; cte_t *tcbSlot; deriveCap_ret_t dc_ret; if ( extraCaps.excaprefs[0] == NULL) { userError("VCPU SetTCB: Truncated message."); current_syscall_error.type = seL4_TruncatedMessage; return EXCEPTION_SYSCALL_ERROR; } tcbSlot = extraCaps.excaprefs[0]; tcbCap = extraCaps.excaprefs[0]->cap; dc_ret = deriveCap(tcbSlot, tcbCap); if (dc_ret.status != EXCEPTION_NONE) { return dc_ret.status; } tcbCap = dc_ret.cap; if (cap_get_capType(tcbCap) != cap_thread_cap) { userError("TCB cap is not a TCB cap."); current_syscall_error.type = seL4_IllegalOperation; return EXCEPTION_SYSCALL_ERROR; } setThreadState(ksCurThread, ThreadState_Restart); return invokeSetTCB(VCPU_PTR(cap_vcpu_cap_get_capVCPUPtr(cap)), TCB_PTR(cap_thread_cap_get_capTCBPtr(tcbCap))); }
exception_t decodeSetIPCBuffer(cap_t cap, unsigned int length, cte_t* slot, extra_caps_t extraCaps, word_t *buffer) { cptr_t cptr_bufferPtr; cap_t bufferCap; cte_t *bufferSlot; if (length < 1 || extraCaps.excaprefs[0] == NULL) { userError("TCB SetIPCBuffer: Truncated message."); current_syscall_error.type = seL4_TruncatedMessage; return EXCEPTION_SYSCALL_ERROR; } cptr_bufferPtr = getSyscallArg(0, buffer); bufferSlot = extraCaps.excaprefs[0]; bufferCap = extraCaps.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(ksCurThread, ThreadState_Restart); return invokeTCB_ThreadControl( TCB_PTR(cap_thread_cap_get_capTCBPtr(cap)), slot, 0, 0, /* used to be prioInvalid, but it doesn't matter */ 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, unsigned int length, cte_t* slot, extra_caps_t extraCaps, 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 || extraCaps.excaprefs[0] == NULL || extraCaps.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 = extraCaps.excaprefs[0]; cRootCap = extraCaps.excaprefs[0]->cap; vRootSlot = extraCaps.excaprefs[1]; vRootCap = extraCaps.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 && (!config_set(CONFIG_ALLOW_NULL_CSPACE) || cap_get_capType(cRootCap) != cap_null_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(ksCurThread, ThreadState_Restart); return invokeTCB_ThreadControl( TCB_PTR(cap_thread_cap_get_capTCBPtr(cap)), slot, faultEP, 0, /* used to be prioInvalid, but it doesn't matter */ cRootCap, cRootSlot, vRootCap, vRootSlot, 0, cap_null_cap_new(), NULL, thread_control_update_space); }
exception_t decodeTCBConfigure(cap_t cap, unsigned int 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; unsigned int prio; word_t cRootData, vRootData, bufferAddr; 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); prio = 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 = prio & MASK(8); if (prio > ksCurThread->tcbPriority) { userError("TCB Configure: Requested priority %d too high (max %d).", (int)prio, (int)(ksCurThread->tcbPriority)); current_syscall_error.type = seL4_IllegalOperation; return EXCEPTION_SYSCALL_ERROR; } if (bufferAddr == 0) { bufferSlot = NULL; } else { exception_t e; dc_ret = deriveCap(bufferSlot, bufferCap); if (dc_ret.status != EXCEPTION_NONE) { return dc_ret.status; } bufferCap = dc_ret.cap; 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 && (!config_set(CONFIG_ALLOW_NULL_CSPACE) || cap_get_capType(cRootCap) != cap_null_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(ksCurThread, ThreadState_Restart); return invokeTCB_ThreadControl( TCB_PTR(cap_thread_cap_get_capTCBPtr(cap)), slot, faultEP, prio, cRootCap, cRootSlot, vRootCap, vRootSlot, bufferAddr, bufferCap, bufferSlot, thread_control_update_all); }
BOOT_CODE bool_t create_initial_thread( cap_t root_cnode_cap, cap_t it_pd_cap, vptr_t ui_v_entry, vptr_t bi_frame_vptr, vptr_t ipcbuf_vptr, cap_t ipcbuf_cap ) { pptr_t pptr; cap_t cap; tcb_t* tcb; deriveCap_ret_t dc_ret; /* allocate TCB */ pptr = alloc_region(TCB_BLOCK_SIZE_BITS); if (!pptr) { printf("Kernel init failed: Unable to allocate tcb for initial thread\n"); return false; } memzero((void*)pptr, 1 << TCB_BLOCK_SIZE_BITS); tcb = TCB_PTR(pptr + TCB_OFFSET); tcb->tcbTimeSlice = CONFIG_TIME_SLICE; Arch_initContext(&tcb->tcbArch.tcbContext); /* derive a copy of the IPC buffer cap for inserting */ dc_ret = deriveCap(SLOT_PTR(pptr_of_cap(root_cnode_cap), BI_CAP_IT_IPCBUF), ipcbuf_cap); if (dc_ret.status != EXCEPTION_NONE) { printf("Failed to derive copy of IPC Buffer\n"); return false; } /* initialise TCB (corresponds directly to abstract specification) */ cteInsert( root_cnode_cap, SLOT_PTR(pptr_of_cap(root_cnode_cap), BI_CAP_IT_CNODE), SLOT_PTR(pptr, tcbCTable) ); cteInsert( it_pd_cap, SLOT_PTR(pptr_of_cap(root_cnode_cap), BI_CAP_IT_VSPACE), SLOT_PTR(pptr, tcbVTable) ); cteInsert( dc_ret.cap, SLOT_PTR(pptr_of_cap(root_cnode_cap), BI_CAP_IT_IPCBUF), SLOT_PTR(pptr, tcbBuffer) ); tcb->tcbIPCBuffer = ipcbuf_vptr; setRegister(tcb, capRegister, bi_frame_vptr); setNextPC(tcb, ui_v_entry); /* initialise TCB */ tcb->tcbPriority = seL4_MaxPrio; setupReplyMaster(tcb); setThreadState(tcb, ThreadState_Running); ksSchedulerAction = SchedulerAction_ResumeCurrentThread; ksCurThread = ksIdleThread; ksCurDomain = ksDomSchedule[ksDomScheduleIdx].domain; ksDomainTime = ksDomSchedule[ksDomScheduleIdx].length; assert(ksCurDomain < CONFIG_NUM_DOMAINS && ksDomainTime > 0); /* initialise current thread pointer */ switchToThread(tcb); /* initialises ksCurThread */ /* create initial thread's TCB cap */ cap = cap_thread_cap_new(TCB_REF(tcb)); write_slot(SLOT_PTR(pptr_of_cap(root_cnode_cap), BI_CAP_IT_TCB), cap); #ifdef DEBUG setThreadName(tcb, "rootserver"); #endif return true; }