3 #include <aros/libcall.h>
4 #include <aros/asmcall.h>
5 #include <exec/execbase.h>
6 #include <hardware/intbits.h>
7 #include <proto/exec.h>
11 #include "kernel_base.h"
12 #include "kernel_bootmem.h"
13 #include "kernel_debug.h"
14 #include "kernel_globals.h"
15 #include "kernel_interrupts.h"
16 #include "kernel_intern.h"
17 #include "kernel_intr.h"
18 #include "kernel_scheduler.h"
19 #include "kernel_syscall.h"
20 #include "cpu_traps.h"
30 * Simulate SysBase access at address 8.
31 * Disabled because global SysBase is moved away from zeropage.
33 #define EMULATE_SYSBASE 8 */
38 #define IRQPROTO(x, y) \
41 #define IRQPROTO_16(x) \
42 IRQPROTO(x,0); IRQPROTO(x,1); IRQPROTO(x,2); IRQPROTO(x,3); \
43 IRQPROTO(x,4); IRQPROTO(x,5); IRQPROTO(x,6); IRQPROTO(x,7); \
44 IRQPROTO(x,8); IRQPROTO(x,9); IRQPROTO(x,a); IRQPROTO(x,b); \
45 IRQPROTO(x,c); IRQPROTO(x,d); IRQPROTO(x,e); IRQPROTO(x,f)
47 #define IRQLIST_16(x) \
48 IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \
49 IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \
50 IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
51 IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)
53 /* This generates prototypes for entry points */
59 extern void core_DefaultIRETQ(void);
61 const void *interrupt
[256] =
68 void core_SetupIDT(struct KernBootPrivate
*__KernBootPrivate
)
72 struct segment_selector IDT_sel
;
73 struct int_gate_64bit
*IGATES
;
75 if (!__KernBootPrivate
->IDT
)
77 __KernBootPrivate
->IDT
= krnAllocBootMemAligned(sizeof(struct int_gate_64bit
) * 256, 256);
79 D(bug("[Kernel] Allocated IDT at 0x%p\n", __KernBootPrivate
->IDT
));
82 D(bug("[Kernel] core_SetupIDT: Setting all interrupt handlers to default value\n"));
83 IGATES
= __KernBootPrivate
->IDT
;
85 for (i
=0; i
< 256; i
++)
88 off
= (uintptr_t)interrupt
[i
];
90 off
= (uintptr_t)IRQ0x80_intr
;
92 off
= (uintptr_t)IRQ0xfe_intr
;
94 off
= (uintptr_t)core_DefaultIRETQ
;
96 IGATES
[i
].offset_low
= off
& 0xffff;
97 IGATES
[i
].offset_mid
= (off
>> 16) & 0xffff;
98 IGATES
[i
].offset_high
= (off
>> 32) & 0xffffffff;
99 IGATES
[i
].type
= 0x0e;
102 IGATES
[i
].selector
= KERNEL_CS
;
106 D(bug("[Kernel] core_SetupIDT: Registering interrupt handlers ..\n"));
108 IDT_sel
.size
= sizeof(struct int_gate_64bit
) * 256 - 1;
109 IDT_sel
.base
= (unsigned long)__KernBootPrivate
->IDT
;
110 asm volatile ("lidt %0"::"m"(IDT_sel
));
113 /* CPU exceptions are processed here */
114 void core_IRQHandle(struct ExceptionContext
*regs
, unsigned long error_code
, unsigned long irq_number
)
116 struct KernelBase
*KernelBase
= getKernelBase();
118 #ifdef EMULATE_SYSBASE
119 if (irq_number
== 0x0e)
121 uint64_t ptr
= rdcr(cr2
);
122 unsigned char *ip
= (unsigned char *)regs
->rip
;
124 D(bug("[Kernel] Page fault exception\n"));
126 if (ptr
== EMULATE_SYSBASE
)
128 D(bug("[Kernel] ** Code at 0x%p is trying to access the SysBase at 0x%p.\n", ip
, ptr
));
130 if ((ip
[0] & 0xfb) == 0x48 &&
132 (ip
[2] & 0xc7) == 0x04 &&
135 int reg
= ((ip
[2] >> 3) & 0x07) | ((ip
[0] & 0x04) << 1);
140 regs
->rax
= (UQUAD
)SysBase
;
143 regs
->rcx
= (UQUAD
)SysBase
;
146 regs
->rdx
= (UQUAD
)SysBase
;
149 regs
->rbx
= (UQUAD
)SysBase
;
151 // case 4: /* Cannot put SysBase into rSP register */
152 // regs->rsp = (UQUAD)SysBase;
155 regs
->rbp
= (UQUAD
)SysBase
;
158 regs
->rsi
= (UQUAD
)SysBase
;
161 regs
->rdi
= (UQUAD
)SysBase
;
164 regs
->r8
= (UQUAD
)SysBase
;
167 regs
->r9
= (UQUAD
)SysBase
;
170 regs
->r10
= (UQUAD
)SysBase
;
173 regs
->r11
= (UQUAD
)SysBase
;
176 regs
->r12
= (UQUAD
)SysBase
;
179 regs
->r13
= (UQUAD
)SysBase
;
182 regs
->r14
= (UQUAD
)SysBase
;
185 regs
->r15
= (UQUAD
)SysBase
;
191 core_LeaveInterrupt(regs
);
193 else if ((ip
[0] & 0xfb) == 0x48 &&
195 (ip
[2] & 0xc7) == 0x05)
197 int reg
= ((ip
[2] >> 3) & 0x07) | ((ip
[0] & 0x04) << 1);
202 regs
->rax
= (UQUAD
)SysBase
;
205 regs
->rcx
= (UQUAD
)SysBase
;
208 regs
->rdx
= (UQUAD
)SysBase
;
211 regs
->rbx
= (UQUAD
)SysBase
;
213 // case 4: /* Cannot put SysBase into rSP register */
214 // regs->rsp = (UQUAD)SysBase;
217 regs
->rbp
= (UQUAD
)SysBase
;
220 regs
->rsi
= (UQUAD
)SysBase
;
223 regs
->rdi
= (UQUAD
)SysBase
;
226 regs
->r8
= (UQUAD
)SysBase
;
229 regs
->r9
= (UQUAD
)SysBase
;
232 regs
->r10
= (UQUAD
)SysBase
;
235 regs
->r11
= (UQUAD
)SysBase
;
238 regs
->r12
= (UQUAD
)SysBase
;
241 regs
->r13
= (UQUAD
)SysBase
;
244 regs
->r14
= (UQUAD
)SysBase
;
247 regs
->r15
= (UQUAD
)SysBase
;
253 core_LeaveInterrupt(regs
);
255 D(else bug("[Kernel] Instruction not recognized\n"));
261 bug("[Kernel] PAGE FAULT accessing 0x%p\n", ptr
);
262 bug("[Kernel] Insn: ");
263 for (i
= 0; i
< 16; i
++)
268 /* The exception will now be passed on to handling code below */
272 /* These exceptions are CPU traps */
273 if (irq_number
< 0x20)
275 cpu_Trap(regs
, error_code
, irq_number
);
277 else if (irq_number
== 0x80) /* Syscall? */
279 /* Syscall number is actually ULONG (we use only eax) */
280 ULONG sc
= regs
->rax
;
282 DSYSCALL(bug("[Kernel] Syscall %u\n", sc
));
284 /* The following syscalls can be run in both supervisor and user mode */
288 D(bug("[Kernel] Warm restart, stack 0x%p\n", AROS_GET_SP
));
291 * Restart the kernel with a double stack swap. This doesn't return.
292 * Double swap guarantees that core_Kick() is called when SP is set to a
293 * dynamically allocated emergency stack and not to boot stack.
294 * Such situation is rare but can occur in the following situation:
295 * 1. Boot task calls SuperState(). Privilege changed, but stack is manually reset
296 * back into our .bss space.
297 * 2. Boot task crashes. Privilege doesn't change this time, RSP is not changed.
298 * 3. If we call core_Kick() right now, we are dead (core_Kick() clears .bss).
300 __asm__
__volatile__(
305 ::"r"(__KernBootPrivate
->SystemStack
+ STACK_SIZE
), "r"(core_Kick
), "D"(BootMsg
), "S"(kernel_cstart
));
308 /* This doesn't return */
309 core_Supervisor(regs
);
313 * Scheduler can be called only from within user mode.
314 * Every task has ss register initialized to a valid segment descriptor.
315 * The descriptor itself isn't used by x86-64, however when a privilege
316 * level switch occurs upon an interrupt, ss is reset to zero. Old ss value
317 * is always pushed to stack as part of interrupt context.
318 * We rely on this in order to determine which CPL we are returning to.
322 DSYSCALL(bug("[Kernel] User-mode syscall\n"));
324 /* Disable interrupts for a while */
325 __asm__
__volatile__("cli; cld;");
327 core_SysCall(sc
, regs
);
330 DSYSCALL(bug("[Kernel] Returning from syscall...\n"));
332 else if (irq_number
>= 0x20) /* Hardware IRQ */
336 /* From CPU's point of view, IRQs are exceptions starting from 0x20. */
339 switch (KernelBase
->kb_Interrupts
[irq_number
].lh_Type
)
346 XTPIC_AckIntr(irq_number
, &KernelBase
->kb_PlatformData
->kb_XTPIC_Mask
);
347 krnRunIRQHandlers(KernelBase
, irq_number
);
350 * Interrupt acknowledge on XT-PIC also disables this interrupt.
351 * If we still need it, we need to re-enable it.
353 if (!IsListEmpty(&KernelBase
->kb_Interrupts
[irq_number
]))
354 XTPIC_EnableIRQ(irq_number
, &KernelBase
->kb_PlatformData
->kb_XTPIC_Mask
);
360 /* Upon exit from the lowest-level hardware IRQ we run the task scheduler */
361 if (SysBase
&& (regs
->ss
!= 0))
363 /* Disable interrupts for a while */
364 __asm__
__volatile__("cli; cld;");
366 core_ExitInterrupt(regs
);
370 core_LeaveInterrupt(regs
);
373 void ictl_enable_irq(unsigned char irq
, struct KernelBase
*KernelBase
)
375 if (KernelBase
->kb_Interrupts
[irq
].lh_Type
== KBL_XTPIC
)
376 XTPIC_EnableIRQ(irq
, &KernelBase
->kb_PlatformData
->kb_XTPIC_Mask
);
379 void ictl_Initialize(void)
381 struct KernelBase
*KernelBase
= getKernelBase();
382 struct PlatformData
*pdata
= KernelBase
->kb_PlatformData
;
386 /* No APIC was discovered by ACPI/whatever else. Do the probe. */
387 pdata
->kb_APIC
= core_APIC_Probe();
392 /* We are x86-64 and we always have APIC. */
393 krnPanic(KernelBase
, "Failed to allocate APIC descriptor\n.The system is low on memory.");
396 if (pdata
->kb_APIC
->flags
& APF_8259
)
399 * Initialize legacy 8529A PIC.
400 * TODO: We obey ACPI information about its presence, however currently we don't have
401 * IOAPIC support. Switching to IOAPIC requires full ACPI support including AML.
404 XTPIC_Init(&pdata
->kb_XTPIC_Mask
);
407 D(bug("[Kernel] kernel_cstart: Interrupts redirected. We will go back in a minute ;)\n"));