2 Copyright © 1995-2018, The AROS Development Team. All rights reserved.
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>
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"
33 //#define IRQNOSCHED_FORBID
35 /* use the correct registers depending on arch. */
36 #if (__WORDSIZE != 64)
37 #define INTR_REGA regs->eax
39 #define INTR_REGA regs->rax
45 #define IRQPROTO(x, y) \
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 */
77 extern void DEF_IRQRETFUNC(void);
79 const void *IntrDefaultGates
[256] =
99 /* Set the raw CPU vectors gate in the IDT */
100 BOOL
core_SetIDTGate(apicidt_t
*IGATES
, int vect
, uintptr_t gate
, BOOL enable
)
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
);
110 #if (__WORDSIZE != 64)
111 (APTR
)((((IPTR
)IGATES
[vect
].offset_high
& 0xFFFF) << 16) | ((IPTR
)IGATES
[vect
].offset_low
& 0xFFFF));
113 (APTR
)((((IPTR
)IGATES
[vect
].offset_high
& 0xFFFFFFFF) << 32) | (((IPTR
)IGATES
[vect
].offset_mid
& 0xFFFF) << 16) | ((IPTR
)IGATES
[vect
].offset_low
& 0xFFFF));
115 if (gateOld
) bug("[Kernel] %s: existing gate @ 0x%p\n", __func__
, gateOld
);
118 /* If the gate isn't already enabled, set it */
121 IGATES
[vect
].offset_low
= gate
& 0xFFFF;
122 #if (__WORDSIZE != 64)
123 IGATES
[vect
].offset_high
= (gate
>> 16) & 0xFFFF;
125 IGATES
[vect
].offset_mid
= (gate
>> 16) & 0xFFFF;
126 IGATES
[vect
].offset_high
= (gate
>> 32) & 0xFFFFFFFF;
128 IGATES
[vect
].type
= 0x0E;
129 IGATES
[vect
].dpl
= 3;
132 IGATES
[vect
].selector
= KERNEL_CS
;
133 IGATES
[vect
].ist
= 0;
139 bug("[Kernel] %s: Vector #%d gate already enabled!\n", __func__
, vect
);
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
;
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
)
178 struct segment_selector IDT_sel
;
180 // TODO: ASSERT IGATES is aligned
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
));
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();
220 // This debug works only if Local APIC exists...
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));
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;
260 UBYTE irq_number
= GET_DEVICE_IRQ(int_number
);
262 DIRQ(bug("[Kernel] %s: Device IRQ #$%02X\n", __func__
, irq_number
);)
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
);