source: mainline/kernel/arch/ia32/src/interrupt.c@ f6cf76f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f6cf76f was f6cf76f, checked in by Jakub Jermar <jakub@…>, 6 years ago

Move PIC spurious IRQ handling into arch code

As each architecture or even machine does IRQs differently, the genarch
i8259 driver cannot register the PIC spurious IRQ interrupt itself.

  • Property mode set to 100644
File size: 7.8 KB
Line 
1/*
2 * Copyright (c) 2001-2004 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup kernel_ia32_interrupt
30 * @{
31 */
32/** @file
33 */
34
35#include <arch/interrupt.h>
36#include <assert.h>
37#include <syscall/syscall.h>
38#include <stdio.h>
39#include <debug.h>
40#include <panic.h>
41#include <genarch/drivers/i8259/i8259.h>
42#include <halt.h>
43#include <cpu.h>
44#include <arch/asm.h>
45#include <mm/tlb.h>
46#include <mm/as.h>
47#include <arch.h>
48#include <proc/thread.h>
49#include <proc/task.h>
50#include <synch/spinlock.h>
51#include <arch/ddi/ddi.h>
52#include <ipc/sysipc.h>
53#include <interrupt.h>
54#include <ddi/irq.h>
55#include <symtab.h>
56#include <stacktrace.h>
57#include <proc/task.h>
58
59/*
60 * Interrupt and exception dispatching.
61 */
62
63void (*disable_irqs_function)(uint16_t irqmask) = NULL;
64void (*enable_irqs_function)(uint16_t irqmask) = NULL;
65void (*eoi_function)(void) = NULL;
66const char *irqs_info = NULL;
67
68void istate_decode(istate_t *istate)
69{
70 printf("cs =%0#10" PRIx32 "\teip=%0#10" PRIx32 "\t"
71 "efl=%0#10" PRIx32 "\terr=%0#10" PRIx32 "\n",
72 istate->cs, istate->eip, istate->eflags, istate->error_word);
73
74 printf("ds =%0#10" PRIx32 "\tes =%0#10" PRIx32 "\t"
75 "fs =%0#10" PRIx32 "\tgs =%0#10" PRIx32 "\n",
76 istate->ds, istate->es, istate->fs, istate->gs);
77
78 if (istate_from_uspace(istate))
79 printf("ss =%0#10" PRIx32 "\n", istate->ss);
80
81 printf("eax=%0#10" PRIx32 "\tebx=%0#10" PRIx32 "\t"
82 "ecx=%0#10" PRIx32 "\tedx=%0#10" PRIx32 "\n",
83 istate->eax, istate->ebx, istate->ecx, istate->edx);
84
85 printf("esi=%0#10" PRIx32 "\tedi=%0#10" PRIx32 "\t"
86 "ebp=%0#10" PRIx32 "\tesp=%0#10" PRIx32 "\n",
87 istate->esi, istate->edi, istate->ebp,
88 istate_from_uspace(istate) ? istate->esp :
89 (uint32_t) &istate->esp);
90}
91
92static void trap_virtual_eoi(void)
93{
94 if (eoi_function)
95 eoi_function();
96 else
97 panic("No eoi_function.");
98
99}
100
101static void null_interrupt(unsigned int n, istate_t *istate)
102{
103 fault_if_from_uspace(istate, "Unserviced interrupt: %u.", n);
104 panic_badtrap(istate, n, "Unserviced interrupt: %u.", n);
105}
106
107static void de_fault(unsigned int n, istate_t *istate)
108{
109 fault_if_from_uspace(istate, "Divide error.");
110 panic_badtrap(istate, n, "Divide error.");
111}
112
113static void db_exception(unsigned int n, istate_t *istate)
114{
115 /*
116 * We need to provide at least an empty handler that does not panic
117 * if the exception appears to come from the kernel because the
118 * userspace can inject a kernel-level #DB after e.g. the SYSENTER
119 * instruction if the EFLAGS.TF is set.
120 */
121}
122
123/** General Protection Fault. */
124static void gp_fault(unsigned int n __attribute__((unused)), istate_t *istate)
125{
126 if (TASK) {
127 irq_spinlock_lock(&TASK->lock, false);
128 size_t ver = TASK->arch.iomapver;
129 irq_spinlock_unlock(&TASK->lock, false);
130
131 if (CPU->arch.iomapver_copy != ver) {
132 /*
133 * This fault can be caused by an early access
134 * to I/O port because of an out-dated
135 * I/O Permission bitmap installed on CPU.
136 * Install the fresh copy and restart
137 * the instruction.
138 */
139 io_perm_bitmap_install();
140 return;
141 }
142 fault_if_from_uspace(istate, "General protection fault.");
143 }
144 panic_badtrap(istate, n, "General protection fault.");
145}
146
147static void ss_fault(unsigned int n __attribute__((unused)), istate_t *istate)
148{
149 fault_if_from_uspace(istate, "Stack fault.");
150 panic_badtrap(istate, n, "Stack fault.");
151}
152
153static void simd_fp_exception(unsigned int n __attribute__((unused)), istate_t *istate)
154{
155 uint32_t mxcsr;
156 asm volatile (
157 "stmxcsr %[mxcsr]\n"
158 : [mxcsr] "=m" (mxcsr)
159 );
160
161 fault_if_from_uspace(istate, "SIMD FP exception(19), MXCSR=%#0" PRIx32 ".",
162 mxcsr);
163 panic_badtrap(istate, n, "SIMD FP exception");
164}
165
166static void nm_fault(unsigned int n __attribute__((unused)),
167 istate_t *istate __attribute__((unused)))
168{
169#ifdef CONFIG_FPU_LAZY
170 scheduler_fpu_lazy_request();
171#else
172 fault_if_from_uspace(istate, "FPU fault.");
173 panic_badtrap(istate, n, "FPU fault.");
174#endif
175}
176
177#ifdef CONFIG_SMP
178static void tlb_shootdown_ipi(unsigned int n __attribute__((unused)),
179 istate_t *istate __attribute__((unused)))
180{
181 trap_virtual_eoi();
182 tlb_shootdown_ipi_recv();
183}
184#endif
185
186/** Handler of IRQ exceptions */
187static void irq_interrupt(unsigned int n, istate_t *istate __attribute__((unused)))
188{
189 assert(n >= IVT_IRQBASE);
190
191 unsigned int inum = n - IVT_IRQBASE;
192 bool ack = false;
193 assert(inum < IRQ_COUNT);
194 assert(inum != IRQ_PIC0_SPUR);
195 assert(inum != IRQ_PIC1_SPUR);
196 assert(inum != IRQ_PIC1);
197
198 irq_t *irq = irq_dispatch_and_lock(inum);
199 if (irq) {
200 /*
201 * The IRQ handler was found.
202 */
203
204 if (irq->preack) {
205 /* Send EOI before processing the interrupt */
206 trap_virtual_eoi();
207 ack = true;
208 }
209 irq->handler(irq);
210 irq_spinlock_unlock(&irq->lock, false);
211 } else {
212 /*
213 * Spurious interrupt.
214 */
215#ifdef CONFIG_DEBUG
216 printf("cpu%u: spurious interrupt (inum=%u)\n", CPU->id, inum);
217#endif
218 }
219
220 if (!ack)
221 trap_virtual_eoi();
222}
223
224static void pic_spurious(unsigned int n, istate_t *istate)
225{
226 /*
227 * XXX: Examine ISR to figure out whether this is indeed a spurious
228 * or actual IRQ.
229 */
230#ifdef CONFIG_DEBUG
231 log(LF_ARCH, LVL_DEBUG, "cpu%u: PIC spurious interrupt", CPU->id);
232#endif
233}
234
235void interrupt_init(void)
236{
237 unsigned int i;
238
239 for (i = 0; i < IVT_ITEMS; i++)
240 exc_register(i, "null", false, (iroutine_t) null_interrupt);
241
242 for (i = 0; i < IRQ_COUNT; i++) {
243 if ((i != IRQ_PIC0_SPUR) && (i != IRQ_PIC1_SPUR) &&
244 (i != IRQ_PIC1))
245 exc_register(IVT_IRQBASE + i, "irq", true,
246 (iroutine_t) irq_interrupt);
247 }
248
249 exc_register(VECTOR_DE, "de_fault", true, (iroutine_t) de_fault);
250 exc_register(VECTOR_DB, "db_exc", true, (iroutine_t) db_exception);
251 exc_register(VECTOR_NM, "nm_fault", true, (iroutine_t) nm_fault);
252 exc_register(VECTOR_SS, "ss_fault", true, (iroutine_t) ss_fault);
253 exc_register(VECTOR_GP, "gp_fault", true, (iroutine_t) gp_fault);
254 exc_register(VECTOR_XM, "simd_fp", true, (iroutine_t) simd_fp_exception);
255 exc_register(VECTOR_PIC0_SPUR, "pic0_spurious", true,
256 (iroutine_t) pic_spurious);
257 exc_register(VECTOR_PIC1_SPUR, "pic1_spurious", true,
258 (iroutine_t) pic_spurious);
259
260#ifdef CONFIG_SMP
261 exc_register(VECTOR_TLB_SHOOTDOWN_IPI, "tlb_shootdown", true,
262 (iroutine_t) tlb_shootdown_ipi);
263#endif
264}
265
266void trap_virtual_enable_irqs(uint16_t irqmask)
267{
268 if (enable_irqs_function)
269 enable_irqs_function(irqmask);
270 else
271 panic("No enable_irqs_function.");
272}
273
274void trap_virtual_disable_irqs(uint16_t irqmask)
275{
276 if (disable_irqs_function)
277 disable_irqs_function(irqmask);
278 else
279 panic("No disable_irqs_function.");
280}
281
282/** @}
283 */
Note: See TracBrowser for help on using the repository browser.