1/* 2 * Copyright 2014, General Dynamics C4 Systems 3 * 4 * SPDX-License-Identifier: GPL-2.0-only 5 */ 6 7#include <types.h> 8#include <api/failures.h> 9#include <config.h> 10 11#include <arch/object/interrupt.h> 12 13static exception_t Arch_invokeIRQControl(irq_t irq, cte_t *handlerSlot, cte_t *controlSlot, bool_t trigger) 14{ 15#ifdef HAVE_SET_TRIGGER 16 setIRQTrigger(irq, trigger); 17#endif 18 return invokeIRQControl(irq, handlerSlot, controlSlot); 19} 20 21exception_t Arch_decodeIRQControlInvocation(word_t invLabel, word_t length, 22 cte_t *srcSlot, extra_caps_t excaps, 23 word_t *buffer) 24{ 25 if (invLabel == ARMIRQIssueIRQHandlerTrigger) { 26 if (length < 4 || excaps.excaprefs[0] == NULL) { 27 current_syscall_error.type = seL4_TruncatedMessage; 28 return EXCEPTION_SYSCALL_ERROR; 29 } 30 31 if (!config_set(HAVE_SET_TRIGGER)) { 32 userError("This platform does not support setting the IRQ trigger"); 33 current_syscall_error.type = seL4_IllegalOperation; 34 return EXCEPTION_SYSCALL_ERROR; 35 } 36 37 word_t irq_w = getSyscallArg(0, buffer); 38 irq_t irq = (irq_t) CORE_IRQ_TO_IRQT(0, irq_w); 39 bool_t trigger = !!getSyscallArg(1, buffer); 40 word_t index = getSyscallArg(2, buffer); 41 word_t depth = getSyscallArg(3, buffer); 42 43 cap_t cnodeCap = excaps.excaprefs[0]->cap; 44 45 exception_t status = Arch_checkIRQ(irq_w); 46 if (status != EXCEPTION_NONE) { 47 return status; 48 } 49 50#if defined ENABLE_SMP_SUPPORT 51 if (IRQ_IS_PPI(irq)) { 52 userError("Trying to get a handler on a PPI: use GetTriggerCore."); 53 return EXCEPTION_SYSCALL_ERROR; 54 } 55#endif 56 if (isIRQActive(irq)) { 57 current_syscall_error.type = seL4_RevokeFirst; 58 userError("Rejecting request for IRQ %u. Already active.", (int)IRQT_TO_IRQ(irq)); 59 return EXCEPTION_SYSCALL_ERROR; 60 } 61 62 lookupSlot_ret_t lu_ret = lookupTargetSlot(cnodeCap, index, depth); 63 if (lu_ret.status != EXCEPTION_NONE) { 64 userError("Target slot for new IRQ Handler cap invalid: cap %lu, IRQ %u.", 65 getExtraCPtr(buffer, 0), (int)IRQT_TO_IRQ(irq)); 66 return lu_ret.status; 67 } 68 69 cte_t *destSlot = lu_ret.slot; 70 71 status = ensureEmptySlot(destSlot); 72 if (status != EXCEPTION_NONE) { 73 userError("Target slot for new IRQ Handler cap not empty: cap %lu, IRQ %u.", 74 getExtraCPtr(buffer, 0), (int)IRQT_TO_IRQ(irq)); 75 return status; 76 } 77 78 setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart); 79 return Arch_invokeIRQControl(irq, destSlot, srcSlot, trigger); 80#ifdef ENABLE_SMP_SUPPORT 81 } else if (invLabel == ARMIRQIssueIRQHandlerTriggerCore) { 82 word_t irq_w = getSyscallArg(0, buffer); 83 bool_t trigger = !!getSyscallArg(1, buffer); 84 word_t index = getSyscallArg(2, buffer); 85 word_t depth = getSyscallArg(3, buffer) & 0xfful; 86 seL4_Word target = getSyscallArg(4, buffer); 87 cap_t cnodeCap = excaps.excaprefs[0]->cap; 88 exception_t status = Arch_checkIRQ(irq_w); 89 irq_t irq = CORE_IRQ_TO_IRQT(target, irq_w); 90 91 if (status != EXCEPTION_NONE) { 92 return status; 93 } 94 95 if (target >= CONFIG_MAX_NUM_NODES) { 96 current_syscall_error.type = seL4_InvalidArgument; 97 userError("Target core %lu is invalid.", target); 98 return EXCEPTION_SYSCALL_ERROR; 99 } 100 101 if (isIRQActive(irq)) { 102 current_syscall_error.type = seL4_RevokeFirst; 103 userError("Rejecting request for IRQ %u. Already active.", (int)IRQT_TO_IRQ(irq)); 104 return EXCEPTION_SYSCALL_ERROR; 105 } 106 107 lookupSlot_ret_t lu_ret = lookupTargetSlot(cnodeCap, index, depth); 108 if (lu_ret.status != EXCEPTION_NONE) { 109 userError("Target slot for new IRQ Handler cap invalid: cap %lu, IRQ %u.", 110 getExtraCPtr(buffer, 0), (int)IRQT_TO_IRQ(irq)); 111 return lu_ret.status; 112 } 113 114 cte_t *destSlot = lu_ret.slot; 115 116 status = ensureEmptySlot(destSlot); 117 if (status != EXCEPTION_NONE) { 118 userError("Target slot for new IRQ Handler cap not empty: cap %lu, IRQ %u.", 119 getExtraCPtr(buffer, 0), (int)IRQT_TO_IRQ(irq)); 120 return status; 121 } 122 123 setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart); 124 125 /* If the IRQ is not a private interrupt, then the role of the syscall is to set 126 * target core to which the shared interrupt will be physically delivered. 127 */ 128 if (!IRQ_IS_PPI(irq)) { 129 setIRQTarget(irq, target); 130 } 131 return Arch_invokeIRQControl(irq, destSlot, srcSlot, trigger); 132#endif /* ENABLE_SMP_SUPPORT */ 133 } else { 134 current_syscall_error.type = seL4_IllegalOperation; 135 return EXCEPTION_SYSCALL_ERROR; 136 } 137} 138