2 Copyright © 1995-2014, 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_bootmem.h"
18 #include "kernel_debug.h"
19 #include "kernel_globals.h"
20 #include "kernel_interrupts.h"
21 #include "kernel_intern.h"
22 #include "kernel_intr.h"
23 #include "kernel_scheduler.h"
24 #include "kernel_syscall.h"
25 #include "cpu_traps.h"
35 * Simulate SysBase access at address 8.
36 * Disabled because global SysBase is moved away from zeropage.
38 #define EMULATE_SYSBASE 8 */
43 #define IRQPROTO(x, y) \
46 #define IRQPROTO_16(x) \
47 IRQPROTO(x,0); IRQPROTO(x,1); IRQPROTO(x,2); IRQPROTO(x,3); \
48 IRQPROTO(x,4); IRQPROTO(x,5); IRQPROTO(x,6); IRQPROTO(x,7); \
49 IRQPROTO(x,8); IRQPROTO(x,9); IRQPROTO(x,a); IRQPROTO(x,b); \
50 IRQPROTO(x,c); IRQPROTO(x,d); IRQPROTO(x,e); IRQPROTO(x,f)
52 #define IRQLIST_16(x) \
53 IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \
54 IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \
55 IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
56 IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)
58 /* This generates prototypes for entry points */
64 extern void core_DefaultIRETQ(void);
66 const void *interrupt
[256] =
73 void core_SetupIDT(struct KernBootPrivate
*__KernBootPrivate
)
77 struct segment_selector IDT_sel
;
78 struct int_gate_64bit
*IGATES
;
80 if (!__KernBootPrivate
->IDT
)
82 __KernBootPrivate
->IDT
= krnAllocBootMemAligned(sizeof(struct int_gate_64bit
) * 256, 256);
84 D(bug("[Kernel] Allocated IDT at 0x%p\n", __KernBootPrivate
->IDT
));
87 D(bug("[Kernel] core_SetupIDT: Setting all interrupt handlers to default value\n"));
88 IGATES
= __KernBootPrivate
->IDT
;
90 for (i
=0; i
< 256; i
++)
93 off
= (uintptr_t)interrupt
[i
];
95 off
= (uintptr_t)IRQ0x80_intr
;
97 off
= (uintptr_t)IRQ0xfe_intr
;
99 off
= (uintptr_t)core_DefaultIRETQ
;
101 IGATES
[i
].offset_low
= off
& 0xffff;
102 IGATES
[i
].offset_mid
= (off
>> 16) & 0xffff;
103 IGATES
[i
].offset_high
= (off
>> 32) & 0xffffffff;
104 IGATES
[i
].type
= 0x0e;
107 IGATES
[i
].selector
= KERNEL_CS
;
111 D(bug("[Kernel] core_SetupIDT: Registering interrupt handlers ..\n"));
113 IDT_sel
.size
= sizeof(struct int_gate_64bit
) * 256 - 1;
114 IDT_sel
.base
= (unsigned long)__KernBootPrivate
->IDT
;
115 asm volatile ("lidt %0"::"m"(IDT_sel
));
118 /* CPU exceptions are processed here */
119 void core_IRQHandle(struct ExceptionContext
*regs
, unsigned long error_code
, unsigned long irq_number
)
121 struct KernelBase
*KernelBase
= getKernelBase();
123 #ifdef EMULATE_SYSBASE
124 if (irq_number
== 0x0e)
126 uint64_t ptr
= rdcr(cr2
);
127 unsigned char *ip
= (unsigned char *)regs
->rip
;
129 D(bug("[Kernel] Page fault exception\n"));
131 if (ptr
== EMULATE_SYSBASE
)
133 D(bug("[Kernel] ** Code at 0x%p is trying to access the SysBase at 0x%p.\n", ip
, ptr
));
135 if ((ip
[0] & 0xfb) == 0x48 &&
137 (ip
[2] & 0xc7) == 0x04 &&
140 int reg
= ((ip
[2] >> 3) & 0x07) | ((ip
[0] & 0x04) << 1);
145 regs
->rax
= (UQUAD
)SysBase
;
148 regs
->rcx
= (UQUAD
)SysBase
;
151 regs
->rdx
= (UQUAD
)SysBase
;
154 regs
->rbx
= (UQUAD
)SysBase
;
156 // case 4: /* Cannot put SysBase into rSP register */
157 // regs->rsp = (UQUAD)SysBase;
160 regs
->rbp
= (UQUAD
)SysBase
;
163 regs
->rsi
= (UQUAD
)SysBase
;
166 regs
->rdi
= (UQUAD
)SysBase
;
169 regs
->r8
= (UQUAD
)SysBase
;
172 regs
->r9
= (UQUAD
)SysBase
;
175 regs
->r10
= (UQUAD
)SysBase
;
178 regs
->r11
= (UQUAD
)SysBase
;
181 regs
->r12
= (UQUAD
)SysBase
;
184 regs
->r13
= (UQUAD
)SysBase
;
187 regs
->r14
= (UQUAD
)SysBase
;
190 regs
->r15
= (UQUAD
)SysBase
;
196 core_LeaveInterrupt(regs
);
198 else if ((ip
[0] & 0xfb) == 0x48 &&
200 (ip
[2] & 0xc7) == 0x05)
202 int reg
= ((ip
[2] >> 3) & 0x07) | ((ip
[0] & 0x04) << 1);
207 regs
->rax
= (UQUAD
)SysBase
;
210 regs
->rcx
= (UQUAD
)SysBase
;
213 regs
->rdx
= (UQUAD
)SysBase
;
216 regs
->rbx
= (UQUAD
)SysBase
;
218 // case 4: /* Cannot put SysBase into rSP register */
219 // regs->rsp = (UQUAD)SysBase;
222 regs
->rbp
= (UQUAD
)SysBase
;
225 regs
->rsi
= (UQUAD
)SysBase
;
228 regs
->rdi
= (UQUAD
)SysBase
;
231 regs
->r8
= (UQUAD
)SysBase
;
234 regs
->r9
= (UQUAD
)SysBase
;
237 regs
->r10
= (UQUAD
)SysBase
;
240 regs
->r11
= (UQUAD
)SysBase
;
243 regs
->r12
= (UQUAD
)SysBase
;
246 regs
->r13
= (UQUAD
)SysBase
;
249 regs
->r14
= (UQUAD
)SysBase
;
252 regs
->r15
= (UQUAD
)SysBase
;
258 core_LeaveInterrupt(regs
);
260 D(else bug("[Kernel] Instruction not recognized\n"));
266 bug("[Kernel] PAGE FAULT accessing 0x%p\n", ptr
);
267 bug("[Kernel] Insn: ");
268 for (i
= 0; i
< 16; i
++)
273 /* The exception will now be passed on to handling code below */
277 /* These exceptions are CPU traps */
278 if (irq_number
< 0x20)
280 cpu_Trap(regs
, error_code
, irq_number
);
282 else if (irq_number
== 0x80) /* Syscall? */
284 /* Syscall number is actually ULONG (we use only eax) */
285 ULONG sc
= regs
->rax
;
287 DSYSCALL(bug("[Kernel] Syscall %u\n", sc
));
289 /* The following syscalls can be run in both supervisor and user mode */
293 D(bug("[Kernel] Warm restart, stack 0x%p\n", AROS_GET_SP
));
296 * Restart the kernel with a double stack swap. This doesn't return.
297 * Double swap guarantees that core_Kick() is called when SP is set to a
298 * dynamically allocated emergency stack and not to boot stack.
299 * Such situation is rare but can occur in the following situation:
300 * 1. Boot task calls SuperState(). Privilege changed, but stack is manually reset
301 * back into our .bss space.
302 * 2. Boot task crashes. Privilege doesn't change this time, RSP is not changed.
303 * 3. If we call core_Kick() right now, we are dead (core_Kick() clears .bss).
305 __asm__
__volatile__(
310 ::"r"(__KernBootPrivate
->SystemStack
+ STACK_SIZE
), "r"(core_Kick
), "D"(BootMsg
), "S"(kernel_cstart
));
313 /* This doesn't return */
314 core_Supervisor(regs
);
318 * Scheduler can be called only from within user mode.
319 * Every task has ss register initialized to a valid segment descriptor.
320 * The descriptor itself isn't used by x86-64, however when a privilege
321 * level switch occurs upon an interrupt, ss is reset to zero. Old ss value
322 * is always pushed to stack as part of interrupt context.
323 * We rely on this in order to determine which CPL we are returning to.
327 DSYSCALL(bug("[Kernel] User-mode syscall\n"));
329 /* Disable interrupts for a while */
330 __asm__
__volatile__("cli; cld;");
332 core_SysCall(sc
, regs
);
335 DSYSCALL(bug("[Kernel] Returning from syscall...\n"));
337 else if (irq_number
>= 0x20) /* Hardware IRQ */
341 /* From CPU's point of view, IRQs are exceptions starting from 0x20. */
344 switch (KernelBase
->kb_Interrupts
[irq_number
].lh_Type
)
351 XTPIC_AckIntr(irq_number
, &KernelBase
->kb_PlatformData
->kb_XTPIC_Mask
);
352 krnRunIRQHandlers(KernelBase
, irq_number
);
355 * Interrupt acknowledge on XT-PIC also disables this interrupt.
356 * If we still need it, we need to re-enable it.
358 if (!IsListEmpty(&KernelBase
->kb_Interrupts
[irq_number
]))
359 XTPIC_EnableIRQ(irq_number
, &KernelBase
->kb_PlatformData
->kb_XTPIC_Mask
);
365 /* Upon exit from the lowest-level hardware IRQ we run the task scheduler */
366 if (SysBase
&& (regs
->ss
!= 0))
368 /* Disable interrupts for a while */
369 __asm__
__volatile__("cli; cld;");
371 core_ExitInterrupt(regs
);
375 core_LeaveInterrupt(regs
);
378 void ictl_enable_irq(unsigned char irq
, struct KernelBase
*KernelBase
)
380 if (KernelBase
->kb_Interrupts
[irq
].lh_Type
== KBL_XTPIC
)
381 XTPIC_EnableIRQ(irq
, &KernelBase
->kb_PlatformData
->kb_XTPIC_Mask
);
384 void ictl_Initialize(void)
386 struct KernelBase
*KernelBase
= getKernelBase();
387 struct PlatformData
*pdata
= KernelBase
->kb_PlatformData
;
391 /* No APIC was discovered by ACPI/whatever else. Do the probe. */
392 pdata
->kb_APIC
= core_APIC_Probe();
397 /* We are x86-64 and we always have APIC. */
398 krnPanic(KernelBase
, "Failed to allocate APIC descriptor\n.The system is low on memory.");
401 if (pdata
->kb_APIC
->flags
& APF_8259
)
404 * Initialize legacy 8529A PIC.
405 * TODO: We obey ACPI information about its presence, however currently we don't have
406 * IOAPIC support. Switching to IOAPIC requires full ACPI support including AML.
409 XTPIC_Init(&pdata
->kb_XTPIC_Mask
);
412 D(bug("[Kernel] kernel_cstart: Interrupts redirected. We will go back in a minute ;)\n"));