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
Arch_invokeIRQControl(irq_t irq,cte_t * handlerSlot,cte_t * controlSlot,bool_t trigger)13 static 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
Arch_decodeIRQControlInvocation(word_t invLabel,word_t length,cte_t * srcSlot,word_t * buffer)21 exception_t Arch_decodeIRQControlInvocation(word_t invLabel, word_t length,
22 cte_t *srcSlot, word_t *buffer)
23 {
24 if (invLabel == ARMIRQIssueIRQHandlerTrigger) {
25 if (length < 4 || current_extra_caps.excaprefs[0] == NULL) {
26 current_syscall_error.type = seL4_TruncatedMessage;
27 return EXCEPTION_SYSCALL_ERROR;
28 }
29
30 if (!config_set(HAVE_SET_TRIGGER)) {
31 userError("This platform does not support setting the IRQ trigger");
32 current_syscall_error.type = seL4_IllegalOperation;
33 return EXCEPTION_SYSCALL_ERROR;
34 }
35
36 word_t irq_w = getSyscallArg(0, buffer);
37 irq_t irq = (irq_t) CORE_IRQ_TO_IRQT(0, irq_w);
38 bool_t trigger = !!getSyscallArg(1, buffer);
39 word_t index = getSyscallArg(2, buffer);
40 word_t depth = getSyscallArg(3, buffer);
41
42 cap_t cnodeCap = current_extra_caps.excaprefs[0]->cap;
43
44 exception_t status = Arch_checkIRQ(irq_w);
45 if (status != EXCEPTION_NONE) {
46 return status;
47 }
48
49 #if defined ENABLE_SMP_SUPPORT
50 if (IRQ_IS_PPI(irq)) {
51 userError("Trying to get a handler on a PPI: use GetTriggerCore.");
52 current_syscall_error.type = seL4_IllegalOperation;
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 = current_extra_caps.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