1 /*
2  * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3  * Copyright 2015, 2016 Hesham Almatary <heshamelmatary@gmail.com>
4  *
5  * SPDX-License-Identifier: GPL-2.0-only
6  */
7 
8 #include <types.h>
9 #include <api/failures.h>
10 
11 #include <arch/object/interrupt.h>
12 
Arch_checkIRQ(word_t irq)13 exception_t Arch_checkIRQ(word_t irq)
14 {
15     if (irq > maxIRQ || irq == irqInvalid) {
16         current_syscall_error.type = seL4_RangeError;
17         current_syscall_error.rangeErrorMin = 1;
18         current_syscall_error.rangeErrorMax = maxIRQ;
19         userError("Rejecting request for IRQ %u. IRQ is out of range [1..maxIRQ].", (int)irq);
20         return EXCEPTION_SYSCALL_ERROR;
21     }
22     return EXCEPTION_NONE;
23 }
24 
Arch_invokeIRQControl(irq_t irq,cte_t * handlerSlot,cte_t * controlSlot,bool_t trigger)25 static exception_t Arch_invokeIRQControl(irq_t irq, cte_t *handlerSlot, cte_t *controlSlot, bool_t trigger)
26 {
27 #ifdef HAVE_SET_TRIGGER
28     setIRQTrigger(irq, trigger);
29 #endif
30     return invokeIRQControl(irq, handlerSlot, controlSlot);
31 }
32 
Arch_decodeIRQControlInvocation(word_t invLabel,word_t length,cte_t * srcSlot,word_t * buffer)33 exception_t Arch_decodeIRQControlInvocation(word_t invLabel, word_t length,
34                                             cte_t *srcSlot, word_t *buffer)
35 {
36     if (invLabel == RISCVIRQIssueIRQHandlerTrigger) {
37         if (length < 4 || current_extra_caps.excaprefs[0] == NULL) {
38             current_syscall_error.type = seL4_TruncatedMessage;
39             return EXCEPTION_SYSCALL_ERROR;
40         }
41 
42         if (!config_set(HAVE_SET_TRIGGER)) {
43             userError("This platform does not support setting the IRQ trigger");
44             current_syscall_error.type = seL4_IllegalOperation;
45             return EXCEPTION_SYSCALL_ERROR;
46         }
47 
48         word_t irq_w = getSyscallArg(0, buffer);
49         irq_t irq = (irq_t) irq_w;
50         bool_t trigger = !!getSyscallArg(1, buffer);
51         word_t index = getSyscallArg(2, buffer);
52         word_t depth = getSyscallArg(3, buffer);
53 
54         cap_t cnodeCap = current_extra_caps.excaprefs[0]->cap;
55 
56         exception_t status = Arch_checkIRQ(irq_w);
57         if (status != EXCEPTION_NONE) {
58             return status;
59         }
60 
61         if (isIRQActive(irq)) {
62             current_syscall_error.type = seL4_RevokeFirst;
63             userError("Rejecting request for IRQ %u. Already active.", (int)irq);
64             return EXCEPTION_SYSCALL_ERROR;
65         }
66 
67         lookupSlot_ret_t lu_ret = lookupTargetSlot(cnodeCap, index, depth);
68         if (lu_ret.status != EXCEPTION_NONE) {
69             userError("Target slot for new IRQ Handler cap invalid: cap %lu, IRQ %u.",
70                       getExtraCPtr(buffer, 0), (int)irq);
71             return lu_ret.status;
72         }
73 
74         cte_t *destSlot = lu_ret.slot;
75 
76         status = ensureEmptySlot(destSlot);
77         if (status != EXCEPTION_NONE) {
78             userError("Target slot for new IRQ Handler cap not empty: cap %lu, IRQ %u.",
79                       getExtraCPtr(buffer, 0), (int)irq);
80             return status;
81         }
82 
83         setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
84         return Arch_invokeIRQControl(irq, destSlot, srcSlot, trigger);
85     } else {
86         current_syscall_error.type = seL4_IllegalOperation;
87         return EXCEPTION_SYSCALL_ERROR;
88     }
89 }
90