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