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 15void 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 */ 37exception_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 54static 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 60static 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 69exception_t Arch_decodeIRQControlInvocation(word_t invLabel, word_t length, cte_t *srcSlot, extra_caps_t excaps, 70 word_t *buffer) 71{ 72 word_t index, depth; 73 cte_t *destSlot; 74 cap_t cnodeCap; 75 lookupSlot_ret_t lu_ret; 76 exception_t status; 77 irq_t irq; 78 word_t vector; 79 80 if (!config_set(CONFIG_IRQ_IOAPIC)) { 81 userError("IRQControl: Illegal operation."); 82 current_syscall_error.type = seL4_IllegalOperation; 83 return EXCEPTION_SYSCALL_ERROR; 84 } 85 86 /* ensure we have a valid invocation before continuing any decoding */ 87 if (invLabel != X86IRQIssueIRQHandlerIOAPIC && invLabel != X86IRQIssueIRQHandlerMSI) { 88 userError("IRQControl: Illegal operation"); 89 current_syscall_error.type = seL4_IllegalOperation; 90 return EXCEPTION_SYSCALL_ERROR; 91 } 92 93 /* check the common parameters */ 94 95 if (length < 7 || excaps.excaprefs[0] == NULL) { 96 userError("IRQControl: Truncated message"); 97 current_syscall_error.type = seL4_TruncatedMessage; 98 return EXCEPTION_SYSCALL_ERROR; 99 } 100 index = getSyscallArg(0, buffer); 101 depth = getSyscallArg(1, buffer); 102 cnodeCap = excaps.excaprefs[0]->cap; 103 irq = getSyscallArg(6, buffer); 104 if (irq > irq_user_max - irq_user_min) { 105 userError("IRQControl: Invalid irq %ld should be between 0-%ld", (long)irq, (long)(irq_user_max - irq_user_min)); 106 current_syscall_error.type = seL4_RangeError; 107 current_syscall_error.rangeErrorMin = 0; 108 current_syscall_error.rangeErrorMax = irq_user_max - irq_user_min; 109 return EXCEPTION_SYSCALL_ERROR; 110 } 111 irq += irq_user_min; 112 113 if (isIRQActive(irq)) { 114 userError("IRQControl: IRQ %d is already active.", (int)irq); 115 current_syscall_error.type = seL4_RevokeFirst; 116 return EXCEPTION_SYSCALL_ERROR; 117 } 118 119 vector = (word_t)irq + IRQ_INT_OFFSET; 120 121 lu_ret = lookupTargetSlot(cnodeCap, index, depth); 122 if (lu_ret.status != EXCEPTION_NONE) { 123 return lu_ret.status; 124 } 125 126 destSlot = lu_ret.slot; 127 128 status = ensureEmptySlot(destSlot); 129 if (status != EXCEPTION_NONE) { 130 return status; 131 } 132 133 switch (invLabel) { 134 case X86IRQIssueIRQHandlerIOAPIC: { 135 word_t ioapic = getSyscallArg(2, buffer); 136 word_t pin = getSyscallArg(3, buffer); 137 word_t level = getSyscallArg(4, buffer); 138 word_t polarity = getSyscallArg(5, buffer); 139 140 status = ioapic_decode_map_pin_to_vector(ioapic, pin, level, polarity, vector); 141 if (status != EXCEPTION_NONE) { 142 return status; 143 } 144 145 setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart); 146 return invokeIssueIRQHandlerIOAPIC(irq, ioapic, pin, level, polarity, vector, destSlot, srcSlot); 147 } 148 break; 149 case X86IRQIssueIRQHandlerMSI: { 150 word_t pci_bus = getSyscallArg(2, buffer); 151 word_t pci_dev = getSyscallArg(3, buffer); 152 word_t pci_func = getSyscallArg(4, buffer); 153 word_t handle = getSyscallArg(5, buffer); 154 x86_irq_state_t irqState; 155 /* until we support msi interrupt remaping through vt-d we ignore the 156 * vector and trust the user */ 157 158 if (pci_bus > PCI_BUS_MAX) { 159 current_syscall_error.type = seL4_RangeError; 160 current_syscall_error.rangeErrorMin = 0; 161 current_syscall_error.rangeErrorMax = PCI_BUS_MAX; 162 return EXCEPTION_SYSCALL_ERROR; 163 } 164 165 if (pci_dev > PCI_DEV_MAX) { 166 current_syscall_error.type = seL4_RangeError; 167 current_syscall_error.rangeErrorMin = 0; 168 current_syscall_error.rangeErrorMax = PCI_DEV_MAX; 169 return EXCEPTION_SYSCALL_ERROR; 170 } 171 172 if (pci_func > PCI_FUNC_MAX) { 173 current_syscall_error.type = seL4_RangeError; 174 current_syscall_error.rangeErrorMin = 0; 175 current_syscall_error.rangeErrorMax = PCI_FUNC_MAX; 176 return EXCEPTION_SYSCALL_ERROR; 177 } 178 179 irqState = x86_irq_state_irq_msi_new(pci_bus, pci_dev, pci_func, handle); 180 181 setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart); 182 return Arch_invokeIRQControl(irq, destSlot, srcSlot, irqState); 183 } 184 break; 185 default: 186 /* the check at the start of this function should guarantee we do not get here */ 187 fail("IRQControl: Illegal operation"); 188 } 189} 190