1 /*
2  * Copyright 2014, General Dynamics C4 Systems
3  *
4  * SPDX-License-Identifier: GPL-2.0-only
5  */
6 
7 #pragma once
8 
9 #include <config.h>
10 #include <types.h>
11 #include <util.h>
12 
13 #include <arch/object/structures.h>
14 #include <arch/model/statedata.h>
15 #include <arch/kernel/apic.h>
16 #include <machine/interrupt.h>
17 #include <plat/machine/acpi.h>
18 #include <plat/machine/ioapic.h>
19 #include <plat/machine/pic.h>
20 #include <plat/machine/intel-vtd.h>
21 
handleReservedIRQ(irq_t irq)22 static inline void handleReservedIRQ(irq_t irq)
23 {
24 #ifdef CONFIG_IOMMU
25     if (irq == irq_iommu) {
26         vtd_handle_fault();
27         return;
28     }
29 #endif
30 
31 #ifdef CONFIG_IRQ_REPORTING
32     printf("Received unhandled reserved IRQ: %d\n", (int)irq);
33 #endif
34 }
35 
receivePendingIRQ(void)36 static inline void receivePendingIRQ(void)
37 {
38     assert(ARCH_NODE_STATE(x86KSPendingInterrupt) == int_invalid);
39     asm volatile("sti\n"
40                  "nop\n"
41                  "cli\n"
42                  : "=m"(ARCH_NODE_STATE(x86KSPendingInterrupt)));
43 }
44 
servicePendingIRQ(void)45 static inline interrupt_t servicePendingIRQ(void)
46 {
47     assert(ARCH_NODE_STATE(x86KScurInterrupt) == int_invalid);
48     assert(ARCH_NODE_STATE(x86KSPendingInterrupt) != int_invalid);
49     interrupt_t ret = ARCH_NODE_STATE(x86KSPendingInterrupt);
50     ARCH_NODE_STATE(x86KSPendingInterrupt) = int_invalid;
51     return ret;
52 }
53 
54 /* Get the IRQ number currently working on. */
getActiveIRQ(void)55 static inline irq_t getActiveIRQ(void)
56 {
57     if (ARCH_NODE_STATE(x86KScurInterrupt) == int_invalid) {
58         /* If we tried to get the active IRQ when we don't have one then
59          * we are polling for an interrupt for some reason, in which case
60          * we should try to get a pending interrupt if there isn't already
61          * one.
62          * This logic is here and not in the main call sites in handleSyscall
63          * because this is only relevant on some interrupt controllers (notably
64          * the x86 APIC) and is cleaner to have here */
65         if (ARCH_NODE_STATE(x86KSPendingInterrupt) == int_invalid) {
66             receivePendingIRQ();
67             /* Check if there was no pending IRQ */
68             if (ARCH_NODE_STATE(x86KSPendingInterrupt) == int_invalid) {
69                 return irqInvalid;
70             }
71         }
72         /* Prepare to handle pending IRQ */
73         ARCH_NODE_STATE(x86KScurInterrupt) = servicePendingIRQ();
74     }
75     return ARCH_NODE_STATE(x86KScurInterrupt) - IRQ_INT_OFFSET;
76 }
77 
78 /* Checks for pending IRQ */
isIRQPending(void)79 static inline bool_t isIRQPending(void)
80 {
81     if (apic_is_interrupt_pending()) {
82         return true;
83     }
84 
85     if (config_set(CONFIG_IRQ_PIC) && pic_is_irq_pending()) {
86         return true;
87     }
88 
89     return false;
90 }
91 
ackInterrupt(irq_t irq)92 static inline void ackInterrupt(irq_t irq)
93 {
94     if (config_set(CONFIG_IRQ_PIC) && irq <= irq_isa_max) {
95         pic_ack_active_irq();
96     } else {
97         apic_ack_active_interrupt();
98     }
99 
100     ARCH_NODE_STATE(x86KScurInterrupt) = int_invalid;
101 }
102 
handleSpuriousIRQ(void)103 static inline void handleSpuriousIRQ(void)
104 {
105     /* do nothing */
106 }
107 
updateIRQState(irq_t irq,x86_irq_state_t state)108 static void inline updateIRQState(irq_t irq, x86_irq_state_t state)
109 {
110     assert(irq <= maxIRQ);
111     x86KSIRQState[irq] = state;
112 }
113 
maskInterrupt(bool_t disable,irq_t irq)114 static inline void maskInterrupt(bool_t disable, irq_t irq)
115 {
116     if (irq >= irq_isa_min && irq <= irq_isa_max) {
117         if (config_set(CONFIG_IRQ_PIC)) {
118             pic_mask_irq(disable, irq);
119         } else {
120             /* We shouldn't receive interrupts on the PIC range
121              * if not using the PIC, but soldier on anyway */
122         }
123     } else if (irq >= irq_user_min && irq <= irq_user_max) {
124         x86_irq_state_t state = x86KSIRQState[irq];
125         switch (x86_irq_state_get_irqType(state)) {
126         case x86_irq_state_irq_ioapic: {
127             uint32_t ioapic = x86_irq_state_irq_ioapic_get_id(state);
128             uint32_t pin = x86_irq_state_irq_ioapic_get_pin(state);
129             ioapic_mask(disable, ioapic, pin);
130             state =  x86_irq_state_irq_ioapic_set_masked(state, disable);
131             updateIRQState(irq, state);
132         }
133         break;
134         case x86_irq_state_irq_msi:
135             /* currently MSI interrupts can not be disabled */
136             break;
137         case x86_irq_state_irq_free:
138             /* A spurious interrupt, and the resulting mask here,
139              * could be from a user ripping out a vector before
140              * the interrupt reached the kernel. Silently ignore */
141             break;
142         }
143     } else {
144         /* masking some other kind of interrupt source, this probably
145          * shouldn't happen, but soldier on */
146     }
147 }
148 
149