exception_t decodeIRQControlInvocation(word_t invLabel, word_t length, cte_t *srcSlot, extra_caps_t excaps, word_t *buffer) { if (invLabel == IRQIssueIRQHandler) { word_t index, depth, irq_w; irq_t irq; cte_t *destSlot; cap_t cnodeCap; lookupSlot_ret_t lu_ret; exception_t status; if (length < 3 || excaps.excaprefs[0] == NULL) { current_syscall_error.type = seL4_TruncatedMessage; return EXCEPTION_SYSCALL_ERROR; } irq_w = getSyscallArg(0, buffer); irq = (irq_t) irq_w; index = getSyscallArg(1, buffer); depth = getSyscallArg(2, buffer); cnodeCap = excaps.excaprefs[0]->cap; status = Arch_checkIRQ(irq); if (status != EXCEPTION_NONE) { return status; } if (isIRQActive(irq)) { current_syscall_error.type = seL4_RevokeFirst; userError("Rejecting request for IRQ %u. Already active.", (int)irq); return EXCEPTION_SYSCALL_ERROR; } lu_ret = lookupTargetSlot(cnodeCap, index, depth); if (lu_ret.status != EXCEPTION_NONE) { userError("Target slot for new IRQ Handler cap invalid: cap %lu, IRQ %u.", getExtraCPtr(buffer, 0), (int)irq); return lu_ret.status; } destSlot = lu_ret.slot; status = ensureEmptySlot(destSlot); if (status != EXCEPTION_NONE) { userError("Target slot for new IRQ Handler cap not empty: cap %lu, IRQ %u.", getExtraCPtr(buffer, 0), (int)irq); return status; } setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart); return invokeIRQControl(irq, destSlot, srcSlot); } else { return Arch_decodeIRQControlInvocation(invLabel, length, srcSlot, excaps, buffer); } }
exception_t Arch_decodeIRQControlInvocation(word_t invLabel, word_t length, cte_t *srcSlot, extra_caps_t excaps, word_t *buffer) { word_t index, depth; cte_t *destSlot; cap_t cnodeCap; lookupSlot_ret_t lu_ret; exception_t status; irq_t irq; word_t vector; if (!config_set(CONFIG_IRQ_IOAPIC)) { userError("IRQControl: Illegal operation."); current_syscall_error.type = seL4_IllegalOperation; return EXCEPTION_SYSCALL_ERROR; } /* check the common parameters */ if (length < 7 || excaps.excaprefs[0] == NULL) { userError("IRQControl: Truncated message"); current_syscall_error.type = seL4_TruncatedMessage; return EXCEPTION_SYSCALL_ERROR; } index = getSyscallArg(0, buffer); depth = getSyscallArg(1, buffer); cnodeCap = excaps.excaprefs[0]->cap; irq = getSyscallArg(6, buffer); if (irq > irq_user_max - irq_user_min) { userError("IRQControl: Invalid irq %ld should be between 0-%ld", (long)irq, (long)(irq_user_max - irq_user_min - 1)); current_syscall_error.type = seL4_RangeError; current_syscall_error.rangeErrorMin = 0; current_syscall_error.rangeErrorMax = irq_user_max - irq_user_min; return EXCEPTION_SYSCALL_ERROR; } irq += irq_user_min; vector = (word_t)irq + IRQ_INT_OFFSET; lu_ret = lookupTargetSlot(cnodeCap, index, depth); if (lu_ret.status != EXCEPTION_NONE) { return lu_ret.status; } destSlot = lu_ret.slot; status = ensureEmptySlot(destSlot); if (status != EXCEPTION_NONE) { return status; } switch (invLabel) { case X86IRQIssueIRQHandlerIOAPIC: { word_t ioapic = getSyscallArg(2, buffer); word_t pin = getSyscallArg(3, buffer); word_t level = getSyscallArg(4, buffer); word_t polarity = getSyscallArg(5, buffer); if (isIRQActive(irq)) { userError("IOAPICGet: IRQ %d is already active.", (int)irq); current_syscall_error.type = seL4_RevokeFirst; return EXCEPTION_SYSCALL_ERROR; } status = ioapic_decode_map_pin_to_vector(ioapic, pin, level, polarity, vector); if (status != EXCEPTION_NONE) { return status; } setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart); return invokeIssueIRQHandlerIOAPIC(irq, ioapic, pin, level, polarity, vector, destSlot, srcSlot); } break; case X86IRQIssueIRQHandlerMSI: { word_t pci_bus = getSyscallArg(2, buffer); word_t pci_dev = getSyscallArg(3, buffer); word_t pci_func = getSyscallArg(4, buffer); word_t handle = getSyscallArg(5, buffer); x86_irq_state_t irqState; /* until we support msi interrupt remaping through vt-d we ignore the * vector and trust the user */ (void)vector; if (isIRQActive(irq)) { current_syscall_error.type = seL4_RevokeFirst; return EXCEPTION_SYSCALL_ERROR; } if (pci_bus > PCI_BUS_MAX) { current_syscall_error.type = seL4_RangeError; current_syscall_error.rangeErrorMin = 0; current_syscall_error.rangeErrorMax = PCI_BUS_MAX; return EXCEPTION_SYSCALL_ERROR; } if (pci_dev > PCI_DEV_MAX) { current_syscall_error.type = seL4_RangeError; current_syscall_error.rangeErrorMin = 0; current_syscall_error.rangeErrorMax = PCI_DEV_MAX; return EXCEPTION_SYSCALL_ERROR; } if (pci_func > PCI_FUNC_MAX) { current_syscall_error.type = seL4_RangeError; current_syscall_error.rangeErrorMin = 0; current_syscall_error.rangeErrorMax = PCI_FUNC_MAX; return EXCEPTION_SYSCALL_ERROR; } irqState = x86_irq_state_irq_msi_new(pci_bus, pci_dev, pci_func, handle); setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart); return Arch_invokeIRQControl(irq, destSlot, srcSlot, irqState); } break; default: userError("IRQControl: Illegal operation."); current_syscall_error.type = seL4_IllegalOperation; return EXCEPTION_SYSCALL_ERROR; } }