revert between 56095 -> 55830 in arch
[AROS.git] / arch / all-pc / kernel / apic_intr.c
blobe09eeb3a20d09dcc035c269f7f6a39123c71e7b9
1 /*
2 Copyright © 1995-2018, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <asm/cpu.h>
7 #include <asm/io.h>
8 #include <aros/libcall.h>
9 #include <aros/asmcall.h>
10 #include <exec/execbase.h>
11 #include <hardware/intbits.h>
12 #include <proto/exec.h>
14 #include <inttypes.h>
16 #include "kernel_base.h"
17 #include "kernel_intern.h"
18 #include "kernel_debug.h"
19 #include "kernel_globals.h"
20 #include "kernel_interrupts.h"
21 #include "kernel_intr.h"
22 #include "kernel_scheduler.h"
23 #include "kernel_syscall.h"
24 #include "kernel_ipi.h"
25 #include "cpu_traps.h"
27 #define D(x)
28 #define DIDT(x)
29 #define DIRQ(x)
30 #define DTRAP(x)
31 #define DUMP_CONTEXT
33 //#define IRQNOSCHED_FORBID
35 /* use the correct registers depending on arch. */
36 #if (__WORDSIZE != 64)
37 #define INTR_REGA regs->eax
38 #else
39 #define INTR_REGA regs->rax
40 #endif
42 #define IRQ(x,y) \
43 IRQ##x##y##_intr
45 #define IRQPROTO(x, y) \
46 void IRQ(x, y)(void)
48 #define IRQPROTO_16(x) \
49 IRQPROTO(x,0); IRQPROTO(x,1); IRQPROTO(x,2); IRQPROTO(x,3); \
50 IRQPROTO(x,4); IRQPROTO(x,5); IRQPROTO(x,6); IRQPROTO(x,7); \
51 IRQPROTO(x,8); IRQPROTO(x,9); IRQPROTO(x,A); IRQPROTO(x,B); \
52 IRQPROTO(x,C); IRQPROTO(x,D); IRQPROTO(x,E); IRQPROTO(x,F)
54 #define IRQLIST_16(x) \
55 IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \
56 IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \
57 IRQ(x,8), IRQ(x,9), IRQ(x,A), IRQ(x,B), \
58 IRQ(x,C), IRQ(x,D), IRQ(x,E), IRQ(x,F)
60 /* This generates prototypes for entry points */
61 IRQPROTO_16(0x0);
62 IRQPROTO_16(0x1);
63 IRQPROTO_16(0x2);
64 IRQPROTO_16(0x3);
65 IRQPROTO_16(0x4);
66 IRQPROTO_16(0x5);
67 IRQPROTO_16(0x6);
68 IRQPROTO_16(0x7);
69 IRQPROTO_16(0x8);
70 IRQPROTO_16(0x9);
71 IRQPROTO_16(0xA);
72 IRQPROTO_16(0xB);
73 IRQPROTO_16(0xC);
74 IRQPROTO_16(0xD);
75 IRQPROTO_16(0xE);
76 IRQPROTO_16(0xF);
77 extern void DEF_IRQRETFUNC(void);
79 const void *IntrDefaultGates[256] =
81 IRQLIST_16(0x0),
82 IRQLIST_16(0x1),
83 IRQLIST_16(0x2),
84 IRQLIST_16(0x3),
85 IRQLIST_16(0x4),
86 IRQLIST_16(0x5),
87 IRQLIST_16(0x6),
88 IRQLIST_16(0x7),
89 IRQLIST_16(0x8),
90 IRQLIST_16(0x9),
91 IRQLIST_16(0xA),
92 IRQLIST_16(0xB),
93 IRQLIST_16(0xC),
94 IRQLIST_16(0xD),
95 IRQLIST_16(0xE),
96 IRQLIST_16(0xF)
99 /* Set the raw CPU vectors gate in the IDT */
100 BOOL core_SetIDTGate(apicidt_t *IGATES, int vect, uintptr_t gate, BOOL enable)
102 DIDT(
103 APTR gateOld;
105 bug("[Kernel] %s: Setting IDTGate #%d IDT @ 0x%p\n", __func__, vect, IGATES);
106 bug("[Kernel] %s: gate @ 0x%p\n", __func__, gate);
107 bug("[Kernel] %s: enable=%d\n", __func__, enable);
109 gateOld =
110 #if (__WORDSIZE != 64)
111 (APTR)((((IPTR)IGATES[vect].offset_high & 0xFFFF) << 16) | ((IPTR)IGATES[vect].offset_low & 0xFFFF));
112 #else
113 (APTR)((((IPTR)IGATES[vect].offset_high & 0xFFFFFFFF) << 32) | (((IPTR)IGATES[vect].offset_mid & 0xFFFF) << 16) | ((IPTR)IGATES[vect].offset_low & 0xFFFF));
114 #endif
115 if (gateOld) bug("[Kernel] %s: existing gate @ 0x%p\n", __func__, gateOld);
118 /* If the gate isn't already enabled, set it */
119 if (!IGATES[vect].p)
121 IGATES[vect].offset_low = gate & 0xFFFF;
122 #if (__WORDSIZE != 64)
123 IGATES[vect].offset_high = (gate >> 16) & 0xFFFF;
124 #else
125 IGATES[vect].offset_mid = (gate >> 16) & 0xFFFF;
126 IGATES[vect].offset_high = (gate >> 32) & 0xFFFFFFFF;
127 #endif
128 IGATES[vect].type = 0x0E;
129 IGATES[vect].dpl = 3;
130 if (enable)
131 IGATES[vect].p = 1;
132 IGATES[vect].selector = KERNEL_CS;
133 IGATES[vect].ist = 0;
135 return TRUE;
137 else
139 bug("[Kernel] %s: Vector #%d gate already enabled!\n", __func__, vect);
141 return FALSE;
144 /* Set a hardware IRQ's gate in the IDT */
145 BOOL core_SetIRQGate(void *idt, int IRQ, uintptr_t gate)
147 apicidt_t *IGATES = (apicidt_t *)idt;
148 DIDT(
149 bug("[Kernel] %s: Setting IRQGate #%d\n", __func__, IRQ);
150 bug("[Kernel] %s: gate @ 0x%p\n", __func__, gate);
153 return core_SetIDTGate(IGATES, HW_IRQ_BASE + IRQ, gate, TRUE);
156 void core_ReloadIDT()
158 struct KernelBase *KernelBase = getKernelBase();
159 struct APICData *apicData = KernelBase->kb_PlatformData->kb_APIC;
160 apicid_t cpuNo = KrnGetCPUNumber();
161 struct segment_selector IDT_sel;
163 apicidt_t *IGATES = (apicidt_t *)apicData->cores[cpuNo].cpu_IDT;
165 DIRQ(bug("[Kernel] %s()\n", __func__);)
167 IDT_sel.size = sizeof(apicidt_t) * 256 - 1;
168 IDT_sel.base = (unsigned long)IGATES;
169 DIDT(bug("[Kernel] %s[%d]: base 0x%p, size %d\n", __func__, cpuNo, IDT_sel.base, IDT_sel.size));
171 asm volatile ("lidt %0"::"m"(IDT_sel));
174 void core_SetupIDT(apicid_t _APICID, apicidt_t *IGATES)
176 int i;
177 uintptr_t off;
178 struct segment_selector IDT_sel;
180 // TODO: ASSERT IGATES is aligned
182 if (IGATES)
184 DIDT(
185 bug("[Kernel] %s[%d]: IDT @ 0x%p\n", __func__, _APICID, IGATES);
186 bug("[Kernel] %s[%d]: Setting default gates\n", __func__, _APICID);
189 // Disable ALL the default gates until something takes ownership
190 for (i=0; i < 256; i++)
192 off = (uintptr_t)DEF_IRQRETFUNC;
194 if (!core_SetIDTGate(IGATES, i, off, FALSE))
196 bug("[Kernel] %s[%d]: gate #%d failed\n", __func__, _APICID, i);
200 DIDT(bug("[Kernel] %s[%d]: Registering IDT ..\n", __func__, _APICID));
202 IDT_sel.size = sizeof(apicidt_t) * 256 - 1;
203 IDT_sel.base = (unsigned long)IGATES;
204 DIDT(bug("[Kernel] %s[%d]: base 0x%p, size %d\n", __func__, _APICID, IDT_sel.base, IDT_sel.size));
206 asm volatile ("lidt %0"::"m"(IDT_sel));
208 else
210 krnPanic(NULL, "Invalid IDT\n");
212 DIDT(bug("[Kernel] %s[%d]: IDT configured\n", __func__, _APICID));
215 /* CPU exceptions are processed here */
216 void core_IRQHandle(struct ExceptionContext *regs, unsigned long error_code, unsigned long int_number)
218 struct KernelBase *KernelBase = getKernelBase();
219 #if 0
220 // This debug works only if Local APIC exists...
221 DIRQ(
222 IPTR __APICBase = core_APIC_GetBase();
223 int cpunum = KrnGetCPUNumber();
225 bug("core_IRQHandle(%d), eflags=%08x\n", int_number, regs->rflags);
227 bug("IRR.%03x: %08x%08x%08x%08x%08x%08x%08x%08x\n", cpunum,
228 APIC_REG(__APICBase, APIC_IRR+0x70), APIC_REG(__APICBase, APIC_IRR+0x60),
229 APIC_REG(__APICBase, APIC_IRR+0x50), APIC_REG(__APICBase, APIC_IRR+0x40),
230 APIC_REG(__APICBase, APIC_IRR+0x30), APIC_REG(__APICBase, APIC_IRR+0x20),
231 APIC_REG(__APICBase, APIC_IRR+0x10), APIC_REG(__APICBase, APIC_IRR+0x00));
232 bug("ISR.%03x: %08x%08x%08x%08x%08x%08x%08x%08x\n", cpunum,
233 APIC_REG(__APICBase, APIC_ISR+0x70), APIC_REG(__APICBase, APIC_ISR + 0x60),
234 APIC_REG(__APICBase, APIC_ISR + 0x50), APIC_REG(__APICBase, APIC_ISR + 0x40),
235 APIC_REG(__APICBase, APIC_ISR + 0x30), APIC_REG(__APICBase, APIC_ISR + 0x20),
236 APIC_REG(__APICBase, APIC_ISR + 0x10), APIC_REG(__APICBase, APIC_ISR + 0x00));
238 #endif
239 // An IRQ which arrived at the CPU is *either* an exception (let it be syscall, cpu exception,
240 // LAPIC local irq) or a device IRQ.
241 if (IS_EXCEPTION(int_number))
243 unsigned long exception_number = GET_EXCEPTION_NUMBER(int_number);
245 DTRAP(bug("[Kernel] %s: CPU Exception %08x\n", __func__, int_number);)
246 DTRAP(bug("[Kernel] %s: --> CPU Trap #$%08x\n", __func__, exception_number);)
248 cpu_Trap(regs, error_code, exception_number);
250 // NOT a CPU exception, must be APIC or Syscall. If APIC, send EOI
251 if (exception_number >= X86_CPU_EXCEPT_COUNT && exception_number != APIC_EXCEPT_SYSCALL)
253 DTRAP(bug("[Kernel] %s: Sending EOI to LAPIC on CPU%03x\n", __func__, KrnGetCPUNumber());)
254 IPTR __APICBase = core_APIC_GetBase();
255 APIC_REG(__APICBase, APIC_EOI) = 0;
258 else
260 UBYTE irq_number = GET_DEVICE_IRQ(int_number);
262 DIRQ(bug("[Kernel] %s: Device IRQ #$%02X\n", __func__, irq_number);)
264 if (KernelBase)
266 struct IntrController *irqIC;
267 struct KernelInt *irqInt;
269 irqInt = &KernelBase->kb_Interrupts[irq_number];
271 if ((irqIC = krnGetInterruptController(KernelBase, irqInt->ki_List.lh_Type)) != NULL)
273 if (irqIC->ic_IntrAck)
274 irqIC->ic_IntrAck(irqIC->ic_Private, irqInt->ki_List.l_pad, irq_number);
276 if (irqInt->ki_Priv & IRQINTF_ENABLED)
278 if (!IsListEmpty(&irqInt->ki_List))
279 krnRunIRQHandlers(KernelBase, irq_number);
281 if ((irqIC->ic_Flags & ICF_ACKENABLE) &&
282 (irqIC->ic_IntrEnable))
283 irqIC->ic_IntrEnable(irqIC->ic_Private, irqInt->ki_List.l_pad, irq_number);
289 * Upon exit from the lowest-level device IRQ, if we are returning to user mode,
290 * we check if we need to call software interrupts or run the task scheduler.
292 if (SysBase != NULL && INTR_FROMUSERMODE)
294 /* Disable interrupts for a while */
295 __asm__ __volatile__("cli; cld;");
297 core_ExitInterrupt(regs);
301 core_LeaveInterrupt(regs);