1/* 2 * Copyright 2014, General Dynamics C4 Systems 3 * 4 * SPDX-License-Identifier: GPL-2.0-only 5 */ 6 7#include <assert.h> 8#include <types.h> 9#include <api/failures.h> 10#include <api/invocation.h> 11#include <api/syscall.h> 12#include <machine/io.h> 13#include <object/structures.h> 14#include <object/interrupt.h> 15#include <object/cnode.h> 16#include <object/notification.h> 17#include <kernel/cspace.h> 18#include <kernel/thread.h> 19#include <model/statedata.h> 20#include <machine/timer.h> 21#include <smp/ipi.h> 22 23exception_t decodeIRQControlInvocation(word_t invLabel, word_t length, 24 cte_t *srcSlot, extra_caps_t excaps, 25 word_t *buffer) 26{ 27 if (invLabel == IRQIssueIRQHandler) { 28 word_t index, depth, irq_w; 29 irq_t irq; 30 cte_t *destSlot; 31 cap_t cnodeCap; 32 lookupSlot_ret_t lu_ret; 33 exception_t status; 34 35 if (length < 3 || excaps.excaprefs[0] == NULL) { 36 current_syscall_error.type = seL4_TruncatedMessage; 37 return EXCEPTION_SYSCALL_ERROR; 38 } 39 irq_w = getSyscallArg(0, buffer); 40 irq = CORE_IRQ_TO_IRQT(0, irq_w); 41 index = getSyscallArg(1, buffer); 42 depth = getSyscallArg(2, buffer); 43 44 cnodeCap = excaps.excaprefs[0]->cap; 45 46 status = Arch_checkIRQ(irq_w); 47 if (status != EXCEPTION_NONE) { 48 return status; 49 } 50 51 if (isIRQActive(irq)) { 52 current_syscall_error.type = seL4_RevokeFirst; 53 userError("Rejecting request for IRQ %u. Already active.", (int)IRQT_TO_IRQ(irq)); 54 return EXCEPTION_SYSCALL_ERROR; 55 } 56 57 lu_ret = lookupTargetSlot(cnodeCap, index, depth); 58 if (lu_ret.status != EXCEPTION_NONE) { 59 userError("Target slot for new IRQ Handler cap invalid: cap %lu, IRQ %u.", 60 getExtraCPtr(buffer, 0), (int)IRQT_TO_IRQ(irq)); 61 return lu_ret.status; 62 } 63 destSlot = lu_ret.slot; 64 65 status = ensureEmptySlot(destSlot); 66 if (status != EXCEPTION_NONE) { 67 userError("Target slot for new IRQ Handler cap not empty: cap %lu, IRQ %u.", 68 getExtraCPtr(buffer, 0), (int)IRQT_TO_IRQ(irq)); 69 return status; 70 } 71 72 setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart); 73 return invokeIRQControl(irq, destSlot, srcSlot); 74 } else { 75 return Arch_decodeIRQControlInvocation(invLabel, length, srcSlot, excaps, buffer); 76 } 77} 78 79exception_t invokeIRQControl(irq_t irq, cte_t *handlerSlot, cte_t *controlSlot) 80{ 81 setIRQState(IRQSignal, irq); 82 cteInsert(cap_irq_handler_cap_new(IRQT_TO_IDX(irq)), controlSlot, handlerSlot); 83 84 return EXCEPTION_NONE; 85} 86 87exception_t decodeIRQHandlerInvocation(word_t invLabel, irq_t irq, 88 extra_caps_t excaps) 89{ 90 switch (invLabel) { 91 case IRQAckIRQ: 92 setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart); 93 invokeIRQHandler_AckIRQ(irq); 94 return EXCEPTION_NONE; 95 96 case IRQSetIRQHandler: { 97 cap_t ntfnCap; 98 cte_t *slot; 99 100 if (excaps.excaprefs[0] == NULL) { 101 current_syscall_error.type = seL4_TruncatedMessage; 102 return EXCEPTION_SYSCALL_ERROR; 103 } 104 ntfnCap = excaps.excaprefs[0]->cap; 105 slot = excaps.excaprefs[0]; 106 107 if (cap_get_capType(ntfnCap) != cap_notification_cap || 108 !cap_notification_cap_get_capNtfnCanSend(ntfnCap)) { 109 if (cap_get_capType(ntfnCap) != cap_notification_cap) { 110 userError("IRQSetHandler: provided cap is not an notification capability."); 111 } else { 112 userError("IRQSetHandler: caller does not have send rights on the endpoint."); 113 } 114 current_syscall_error.type = seL4_InvalidCapability; 115 current_syscall_error.invalidCapNumber = 0; 116 return EXCEPTION_SYSCALL_ERROR; 117 } 118 119 setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart); 120 invokeIRQHandler_SetIRQHandler(irq, ntfnCap, slot); 121 return EXCEPTION_NONE; 122 } 123 124 case IRQClearIRQHandler: 125 setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart); 126 invokeIRQHandler_ClearIRQHandler(irq); 127 return EXCEPTION_NONE; 128 129 default: 130 userError("IRQHandler: Illegal operation."); 131 current_syscall_error.type = seL4_IllegalOperation; 132 return EXCEPTION_SYSCALL_ERROR; 133 } 134} 135 136void invokeIRQHandler_AckIRQ(irq_t irq) 137{ 138#ifdef CONFIG_ARCH_RISCV 139 plic_complete_claim(irq); 140#else 141#if defined ENABLE_SMP_SUPPORT && defined CONFIG_ARCH_ARM 142 if (IRQ_IS_PPI(irq) && IRQT_TO_CORE(irq) != getCurrentCPUIndex()) { 143 doRemoteMaskPrivateInterrupt(IRQT_TO_CORE(irq), false, IRQT_TO_IDX(irq)); 144 return; 145 } 146#endif 147 maskInterrupt(false, irq); 148#endif 149} 150 151void invokeIRQHandler_SetIRQHandler(irq_t irq, cap_t cap, cte_t *slot) 152{ 153 cte_t *irqSlot; 154 155 irqSlot = intStateIRQNode + IRQT_TO_IDX(irq); 156 /** GHOSTUPD: "(True, gs_set_assn cteDeleteOne_'proc (-1))" */ 157 cteDeleteOne(irqSlot); 158 cteInsert(cap, slot, irqSlot); 159} 160 161void invokeIRQHandler_ClearIRQHandler(irq_t irq) 162{ 163 cte_t *irqSlot; 164 165 irqSlot = intStateIRQNode + IRQT_TO_IDX(irq); 166 /** GHOSTUPD: "(True, gs_set_assn cteDeleteOne_'proc (-1))" */ 167 cteDeleteOne(irqSlot); 168} 169 170void deletingIRQHandler(irq_t irq) 171{ 172 cte_t *slot; 173 174 slot = intStateIRQNode + IRQT_TO_IDX(irq); 175 /** GHOSTUPD: "(True, gs_set_assn cteDeleteOne_'proc (ucast cap_notification_cap))" */ 176 cteDeleteOne(slot); 177} 178 179void deletedIRQHandler(irq_t irq) 180{ 181 setIRQState(IRQInactive, irq); 182} 183 184void handleInterrupt(irq_t irq) 185{ 186 if (unlikely(IRQT_TO_IRQ(irq) > maxIRQ)) { 187 /* mask, ack and pretend it didn't happen. We assume that because 188 * the interrupt controller for the platform returned this IRQ that 189 * it is safe to use in mask and ack operations, even though it is 190 * above the claimed maxIRQ. i.e. we're assuming maxIRQ is wrong */ 191 printf("Received IRQ %d, which is above the platforms maxIRQ of %d\n", (int)IRQT_TO_IRQ(irq), (int)maxIRQ); 192 maskInterrupt(true, irq); 193 ackInterrupt(irq); 194 return; 195 } 196 switch (intStateIRQTable[IRQT_TO_IDX(irq)]) { 197 case IRQSignal: { 198 cap_t cap; 199 200 cap = intStateIRQNode[IRQT_TO_IDX(irq)].cap; 201 202 if (cap_get_capType(cap) == cap_notification_cap && 203 cap_notification_cap_get_capNtfnCanSend(cap)) { 204 sendSignal(NTFN_PTR(cap_notification_cap_get_capNtfnPtr(cap)), 205 cap_notification_cap_get_capNtfnBadge(cap)); 206 } else { 207#ifdef CONFIG_IRQ_REPORTING 208 printf("Undelivered IRQ: %d\n", (int)IRQT_TO_IRQ(irq)); 209#endif 210 } 211#ifndef CONFIG_ARCH_RISCV 212 maskInterrupt(true, irq); 213#endif 214 break; 215 } 216 217 case IRQTimer: 218#ifdef CONFIG_KERNEL_MCS 219 ackDeadlineIRQ(); 220 NODE_STATE(ksReprogram) = true; 221#else 222 timerTick(); 223 resetTimer(); 224#endif 225 break; 226 227#ifdef ENABLE_SMP_SUPPORT 228 case IRQIPI: 229 handleIPI(irq, true); 230 break; 231#endif /* ENABLE_SMP_SUPPORT */ 232 233 case IRQReserved: 234 handleReservedIRQ(irq); 235 break; 236 237 case IRQInactive: 238 /* 239 * This case shouldn't happen anyway unless the hardware or 240 * platform code is broken. Hopefully masking it again should make 241 * the interrupt go away. 242 */ 243 maskInterrupt(true, irq); 244#ifdef CONFIG_IRQ_REPORTING 245 printf("Received disabled IRQ: %d\n", (int)IRQT_TO_IRQ(irq)); 246#endif 247 break; 248 249 default: 250 /* No corresponding haskell error */ 251 fail("Invalid IRQ state"); 252 } 253 254 ackInterrupt(irq); 255} 256 257bool_t isIRQActive(irq_t irq) 258{ 259 return intStateIRQTable[IRQT_TO_IDX(irq)] != IRQInactive; 260} 261 262void setIRQState(irq_state_t irqState, irq_t irq) 263{ 264 intStateIRQTable[IRQT_TO_IDX(irq)] = irqState; 265#if defined ENABLE_SMP_SUPPORT && defined CONFIG_ARCH_ARM 266 if (IRQ_IS_PPI(irq) && IRQT_TO_CORE(irq) != getCurrentCPUIndex()) { 267 doRemoteMaskPrivateInterrupt(IRQT_TO_CORE(irq), irqState == IRQInactive, IRQT_TO_IDX(irq)); 268 return; 269 } 270#endif 271 maskInterrupt(irqState == IRQInactive, irq); 272} 273