1/*
2 * Copyright 2014, General Dynamics C4 Systems
3 *
4 * This software may be distributed and modified according to the terms of
5 * the GNU General Public License version 2. Note that NO WARRANTY is provided.
6 * See "LICENSE_GPLv2.txt" for details.
7 *
8 * @TAG(GD_GPL)
9 */
10
11#include <types.h>
12#include <api/failures.h>
13
14#include <arch/object/interrupt.h>
15
16static exception_t
17Arch_invokeIRQControl(irq_t irq, cte_t *handlerSlot, cte_t *controlSlot, bool_t trigger)
18{
19#ifdef HAVE_SET_TRIGGER
20    setIRQTrigger(irq, trigger);
21#endif
22    return invokeIRQControl(irq, handlerSlot, controlSlot);
23}
24
25exception_t
26Arch_decodeIRQControlInvocation(word_t invLabel, word_t length,
27                                cte_t *srcSlot, extra_caps_t excaps,
28                                word_t *buffer)
29{
30    if (invLabel == ARMIRQIssueIRQHandlerTrigger) {
31        if (length < 4 || excaps.excaprefs[0] == NULL) {
32            current_syscall_error.type = seL4_TruncatedMessage;
33            return EXCEPTION_SYSCALL_ERROR;
34        }
35
36        if (!config_set(HAVE_SET_TRIGGER)) {
37            userError("This platform does not support setting the IRQ trigger");
38            current_syscall_error.type = seL4_IllegalOperation;
39            return EXCEPTION_SYSCALL_ERROR;
40        }
41
42        word_t irq_w = getSyscallArg(0, buffer);
43        irq_t irq = (irq_t) irq_w;
44        bool_t trigger = !!getSyscallArg(1, buffer);
45        word_t index = getSyscallArg(2, buffer);
46        word_t depth = getSyscallArg(3, buffer);
47
48        cap_t cnodeCap = excaps.excaprefs[0]->cap;
49
50        exception_t status = Arch_checkIRQ(irq_w);
51        if (status != EXCEPTION_NONE) {
52            return status;
53        }
54
55        if (isIRQActive(irq)) {
56            current_syscall_error.type = seL4_RevokeFirst;
57            userError("Rejecting request for IRQ %u. Already active.", (int)irq);
58            return EXCEPTION_SYSCALL_ERROR;
59        }
60
61        lookupSlot_ret_t lu_ret = lookupTargetSlot(cnodeCap, index, depth);
62        if (lu_ret.status != EXCEPTION_NONE) {
63            userError("Target slot for new IRQ Handler cap invalid: cap %lu, IRQ %u.",
64                      getExtraCPtr(buffer, 0), (int)irq);
65            return lu_ret.status;
66        }
67
68        cte_t *destSlot = lu_ret.slot;
69
70        status = ensureEmptySlot(destSlot);
71        if (status != EXCEPTION_NONE) {
72            userError("Target slot for new IRQ Handler cap not empty: cap %lu, IRQ %u.",
73                      getExtraCPtr(buffer, 0), (int)irq);
74            return status;
75        }
76
77        setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
78        return Arch_invokeIRQControl(irq, destSlot, srcSlot, trigger);
79    } else {
80        current_syscall_error.type = seL4_IllegalOperation;
81        return EXCEPTION_SYSCALL_ERROR;
82    }
83}
84