1 /*
2 * Copyright 2014, General Dynamics C4 Systems
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7 #include <kernel/boot.h>
8 #include <model/statedata.h>
9 #include <arch/object/interrupt.h>
10 #include <arch/api/invocation.h>
11 #include <linker.h>
12 #include <plat/machine/hardware.h>
13 #include <plat/machine/pci.h>
14
Arch_irqStateInit(void)15 void Arch_irqStateInit(void)
16 {
17 int i = 0;
18 for (i = 0; i <= maxIRQ; i++) {
19 if (i == irq_timer
20 #ifdef CONFIG_IOMMU
21 || i == irq_iommu
22 #endif
23 ) {
24 x86KSIRQState[i] = x86_irq_state_irq_reserved_new();
25 } else {
26 x86KSIRQState[i] = x86_irq_state_irq_free_new();
27 }
28 }
29 }
30
31 /* for x86, the IRQIssueIRQHandler is only allowed to
32 * issue a hander for IRQ 0-15, the isa IRQs.
33 * Use getIRQHandlerIOAPIC and getIRQHandlerMSI for
34 * the IRQs >= 16. Additionally these IRQs only exist
35 * if using the legacy PIC interrupt
36 */
Arch_checkIRQ(word_t irq_w)37 exception_t Arch_checkIRQ(word_t irq_w)
38 {
39 if (config_set(CONFIG_IRQ_PIC) && irq_w >= irq_isa_min && irq_w <= irq_isa_max) {
40 return EXCEPTION_NONE;
41 }
42 if (config_set(CONFIG_IRQ_IOAPIC)) {
43 userError("IRQControl: Illegal operation");
44 current_syscall_error.type = seL4_IllegalOperation;
45 } else {
46 userError("IRQControl: IRQ %ld should be in range %ld - %ld", irq_w, (long)irq_isa_min, (long)irq_isa_max);
47 current_syscall_error.type = seL4_RangeError;
48 current_syscall_error.rangeErrorMin = irq_isa_min;
49 current_syscall_error.rangeErrorMax = irq_isa_max;
50 }
51 return EXCEPTION_SYSCALL_ERROR;
52 }
53
Arch_invokeIRQControl(irq_t irq,cte_t * handlerSlot,cte_t * controlSlot,x86_irq_state_t irqState)54 static exception_t Arch_invokeIRQControl(irq_t irq, cte_t *handlerSlot, cte_t *controlSlot, x86_irq_state_t irqState)
55 {
56 updateIRQState(irq, irqState);
57 return invokeIRQControl(irq, handlerSlot, controlSlot);
58 }
59
invokeIssueIRQHandlerIOAPIC(irq_t irq,word_t ioapic,word_t pin,word_t level,word_t polarity,word_t vector,cte_t * handlerSlot,cte_t * controlSlot)60 static exception_t invokeIssueIRQHandlerIOAPIC(irq_t irq, word_t ioapic, word_t pin, word_t level, word_t polarity,
61 word_t vector,
62 cte_t *handlerSlot, cte_t *controlSlot)
63 {
64 x86_irq_state_t irqState = x86_irq_state_irq_ioapic_new(ioapic, pin, level, polarity, 1);
65 ioapic_map_pin_to_vector(ioapic, pin, level, polarity, vector);
66 return Arch_invokeIRQControl(irq, handlerSlot, controlSlot, irqState);
67 }
68
Arch_decodeIRQControlInvocation(word_t invLabel,word_t length,cte_t * srcSlot,word_t * buffer)69 exception_t Arch_decodeIRQControlInvocation(word_t invLabel, word_t length, cte_t *srcSlot, word_t *buffer)
70 {
71 word_t index, depth;
72 cte_t *destSlot;
73 cap_t cnodeCap;
74 lookupSlot_ret_t lu_ret;
75 exception_t status;
76 irq_t irq;
77 word_t vector;
78
79 if (!config_set(CONFIG_IRQ_IOAPIC)) {
80 userError("IRQControl: Illegal operation.");
81 current_syscall_error.type = seL4_IllegalOperation;
82 return EXCEPTION_SYSCALL_ERROR;
83 }
84
85 /* ensure we have a valid invocation before continuing any decoding */
86 if (invLabel != X86IRQIssueIRQHandlerIOAPIC && invLabel != X86IRQIssueIRQHandlerMSI) {
87 userError("IRQControl: Illegal operation");
88 current_syscall_error.type = seL4_IllegalOperation;
89 return EXCEPTION_SYSCALL_ERROR;
90 }
91
92 /* check the common parameters */
93
94 if (length < 7 || current_extra_caps.excaprefs[0] == NULL) {
95 userError("IRQControl: Truncated message");
96 current_syscall_error.type = seL4_TruncatedMessage;
97 return EXCEPTION_SYSCALL_ERROR;
98 }
99 index = getSyscallArg(0, buffer);
100 depth = getSyscallArg(1, buffer);
101 cnodeCap = current_extra_caps.excaprefs[0]->cap;
102 irq = getSyscallArg(6, buffer);
103 if (irq > irq_user_max - irq_user_min) {
104 userError("IRQControl: Invalid irq %ld should be between 0-%ld", (long)irq, (long)(irq_user_max - irq_user_min));
105 current_syscall_error.type = seL4_RangeError;
106 current_syscall_error.rangeErrorMin = 0;
107 current_syscall_error.rangeErrorMax = irq_user_max - irq_user_min;
108 return EXCEPTION_SYSCALL_ERROR;
109 }
110 irq += irq_user_min;
111
112 if (isIRQActive(irq)) {
113 userError("IRQControl: IRQ %d is already active.", (int)irq);
114 current_syscall_error.type = seL4_RevokeFirst;
115 return EXCEPTION_SYSCALL_ERROR;
116 }
117
118 vector = (word_t)irq + IRQ_INT_OFFSET;
119
120 lu_ret = lookupTargetSlot(cnodeCap, index, depth);
121 if (lu_ret.status != EXCEPTION_NONE) {
122 return lu_ret.status;
123 }
124
125 destSlot = lu_ret.slot;
126
127 status = ensureEmptySlot(destSlot);
128 if (status != EXCEPTION_NONE) {
129 return status;
130 }
131
132 switch (invLabel) {
133 case X86IRQIssueIRQHandlerIOAPIC: {
134 word_t ioapic = getSyscallArg(2, buffer);
135 word_t pin = getSyscallArg(3, buffer);
136 word_t level = getSyscallArg(4, buffer);
137 word_t polarity = getSyscallArg(5, buffer);
138
139 status = ioapic_decode_map_pin_to_vector(ioapic, pin, level, polarity, vector);
140 if (status != EXCEPTION_NONE) {
141 return status;
142 }
143
144 setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
145 return invokeIssueIRQHandlerIOAPIC(irq, ioapic, pin, level, polarity, vector, destSlot, srcSlot);
146 }
147 break;
148 case X86IRQIssueIRQHandlerMSI: {
149 word_t pci_bus = getSyscallArg(2, buffer);
150 word_t pci_dev = getSyscallArg(3, buffer);
151 word_t pci_func = getSyscallArg(4, buffer);
152 word_t handle = getSyscallArg(5, buffer);
153 x86_irq_state_t irqState;
154 /* until we support msi interrupt remaping through vt-d we ignore the
155 * vector and trust the user */
156
157 if (pci_bus > PCI_BUS_MAX) {
158 current_syscall_error.type = seL4_RangeError;
159 current_syscall_error.rangeErrorMin = 0;
160 current_syscall_error.rangeErrorMax = PCI_BUS_MAX;
161 return EXCEPTION_SYSCALL_ERROR;
162 }
163
164 if (pci_dev > PCI_DEV_MAX) {
165 current_syscall_error.type = seL4_RangeError;
166 current_syscall_error.rangeErrorMin = 0;
167 current_syscall_error.rangeErrorMax = PCI_DEV_MAX;
168 return EXCEPTION_SYSCALL_ERROR;
169 }
170
171 if (pci_func > PCI_FUNC_MAX) {
172 current_syscall_error.type = seL4_RangeError;
173 current_syscall_error.rangeErrorMin = 0;
174 current_syscall_error.rangeErrorMax = PCI_FUNC_MAX;
175 return EXCEPTION_SYSCALL_ERROR;
176 }
177
178 irqState = x86_irq_state_irq_msi_new(pci_bus, pci_dev, pci_func, handle);
179
180 setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
181 return Arch_invokeIRQControl(irq, destSlot, srcSlot, irqState);
182 }
183 break;
184 default:
185 /* the check at the start of this function should guarantee we do not get here */
186 fail("IRQControl: Illegal operation");
187 }
188 }
189