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
13exception_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
25static 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
33exception_t Arch_decodeIRQControlInvocation(word_t invLabel, word_t length,
34                                            cte_t *srcSlot, extra_caps_t excaps,
35                                            word_t *buffer)
36{
37    if (invLabel == RISCVIRQIssueIRQHandlerTrigger) {
38        if (length < 4 || excaps.excaprefs[0] == NULL) {
39            current_syscall_error.type = seL4_TruncatedMessage;
40            return EXCEPTION_SYSCALL_ERROR;
41        }
42
43        if (!config_set(HAVE_SET_TRIGGER)) {
44            userError("This platform does not support setting the IRQ trigger");
45            current_syscall_error.type = seL4_IllegalOperation;
46            return EXCEPTION_SYSCALL_ERROR;
47        }
48
49        word_t irq_w = getSyscallArg(0, buffer);
50        irq_t irq = (irq_t) irq_w;
51        bool_t trigger = !!getSyscallArg(1, buffer);
52        word_t index = getSyscallArg(2, buffer);
53        word_t depth = getSyscallArg(3, buffer);
54
55        cap_t cnodeCap = excaps.excaprefs[0]->cap;
56
57        exception_t status = Arch_checkIRQ(irq_w);
58        if (status != EXCEPTION_NONE) {
59            return status;
60        }
61
62        if (isIRQActive(irq)) {
63            current_syscall_error.type = seL4_RevokeFirst;
64            userError("Rejecting request for IRQ %u. Already active.", (int)irq);
65            return EXCEPTION_SYSCALL_ERROR;
66        }
67
68        lookupSlot_ret_t lu_ret = lookupTargetSlot(cnodeCap, index, depth);
69        if (lu_ret.status != EXCEPTION_NONE) {
70            userError("Target slot for new IRQ Handler cap invalid: cap %lu, IRQ %u.",
71                      getExtraCPtr(buffer, 0), (int)irq);
72            return lu_ret.status;
73        }
74
75        cte_t *destSlot = lu_ret.slot;
76
77        status = ensureEmptySlot(destSlot);
78        if (status != EXCEPTION_NONE) {
79            userError("Target slot for new IRQ Handler cap not empty: cap %lu, IRQ %u.",
80                      getExtraCPtr(buffer, 0), (int)irq);
81            return status;
82        }
83
84        setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
85        return Arch_invokeIRQControl(irq, destSlot, srcSlot, trigger);
86    } else {
87        current_syscall_error.type = seL4_IllegalOperation;
88        return EXCEPTION_SYSCALL_ERROR;
89    }
90}
91