Copyright clean-up (part 1):
[AROS.git] / arch / x86_64-pc / kernel / intr.c
blob52ca22d99354d217efbc2a911ca391403330fab9
1 /*
2 Copyright © 1995-2014, 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_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"
26 #include "apic.h"
27 #include "xtpic.h"
29 #define D(x)
30 #define DSYSCALL(x)
31 #define DTRAP(x)
32 #define DUMP_CONTEXT
35 * Simulate SysBase access at address 8.
36 * Disabled because global SysBase is moved away from zeropage.
38 #define EMULATE_SYSBASE 8 */
40 #define IRQ(x,y) \
41 IRQ##x##y##_intr
43 #define IRQPROTO(x, y) \
44 void IRQ(x, y)(void)
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 */
59 IRQPROTO_16(0x0);
60 IRQPROTO_16(0x1);
61 IRQPROTO_16(0x2);
62 IRQPROTO(0x8, 0);
63 IRQPROTO(0xf, e);
64 extern void core_DefaultIRETQ(void);
66 const void *interrupt[256] =
68 IRQLIST_16(0x0),
69 IRQLIST_16(0x1),
70 IRQLIST_16(0x2)
73 void core_SetupIDT(struct KernBootPrivate *__KernBootPrivate)
75 int i;
76 uintptr_t off;
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++)
92 if (interrupt[i])
93 off = (uintptr_t)interrupt[i];
94 else if (i == 0x80)
95 off = (uintptr_t)IRQ0x80_intr;
96 else if (i == 0xfe)
97 off = (uintptr_t)IRQ0xfe_intr;
98 else
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;
105 IGATES[i].dpl = 3;
106 IGATES[i].p = 1;
107 IGATES[i].selector = KERNEL_CS;
108 IGATES[i].ist = 0;
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 &&
136 ip[1] == 0x8b &&
137 (ip[2] & 0xc7) == 0x04 &&
138 ip[3] == 0x25)
140 int reg = ((ip[2] >> 3) & 0x07) | ((ip[0] & 0x04) << 1);
142 switch(reg)
144 case 0:
145 regs->rax = (UQUAD)SysBase;
146 break;
147 case 1:
148 regs->rcx = (UQUAD)SysBase;
149 break;
150 case 2:
151 regs->rdx = (UQUAD)SysBase;
152 break;
153 case 3:
154 regs->rbx = (UQUAD)SysBase;
155 break;
156 // case 4: /* Cannot put SysBase into rSP register */
157 // regs->rsp = (UQUAD)SysBase;
158 // break;
159 case 5:
160 regs->rbp = (UQUAD)SysBase;
161 break;
162 case 6:
163 regs->rsi = (UQUAD)SysBase;
164 break;
165 case 7:
166 regs->rdi = (UQUAD)SysBase;
167 break;
168 case 8:
169 regs->r8 = (UQUAD)SysBase;
170 break;
171 case 9:
172 regs->r9 = (UQUAD)SysBase;
173 break;
174 case 10:
175 regs->r10 = (UQUAD)SysBase;
176 break;
177 case 11:
178 regs->r11 = (UQUAD)SysBase;
179 break;
180 case 12:
181 regs->r12 = (UQUAD)SysBase;
182 break;
183 case 13:
184 regs->r13 = (UQUAD)SysBase;
185 break;
186 case 14:
187 regs->r14 = (UQUAD)SysBase;
188 break;
189 case 15:
190 regs->r15 = (UQUAD)SysBase;
191 break;
194 regs->rip += 8;
196 core_LeaveInterrupt(regs);
198 else if ((ip[0] & 0xfb) == 0x48 &&
199 ip[1] == 0x8b &&
200 (ip[2] & 0xc7) == 0x05)
202 int reg = ((ip[2] >> 3) & 0x07) | ((ip[0] & 0x04) << 1);
204 switch(reg)
206 case 0:
207 regs->rax = (UQUAD)SysBase;
208 break;
209 case 1:
210 regs->rcx = (UQUAD)SysBase;
211 break;
212 case 2:
213 regs->rdx = (UQUAD)SysBase;
214 break;
215 case 3:
216 regs->rbx = (UQUAD)SysBase;
217 break;
218 // case 4: /* Cannot put SysBase into rSP register */
219 // regs->rsp = (UQUAD)SysBase;
220 // break;
221 case 5:
222 regs->rbp = (UQUAD)SysBase;
223 break;
224 case 6:
225 regs->rsi = (UQUAD)SysBase;
226 break;
227 case 7:
228 regs->rdi = (UQUAD)SysBase;
229 break;
230 case 8:
231 regs->r8 = (UQUAD)SysBase;
232 break;
233 case 9:
234 regs->r9 = (UQUAD)SysBase;
235 break;
236 case 10:
237 regs->r10 = (UQUAD)SysBase;
238 break;
239 case 11:
240 regs->r11 = (UQUAD)SysBase;
241 break;
242 case 12:
243 regs->r12 = (UQUAD)SysBase;
244 break;
245 case 13:
246 regs->r13 = (UQUAD)SysBase;
247 break;
248 case 14:
249 regs->r14 = (UQUAD)SysBase;
250 break;
251 case 15:
252 regs->r15 = (UQUAD)SysBase;
253 break;
256 regs->rip += 7;
258 core_LeaveInterrupt(regs);
260 D(else bug("[Kernel] Instruction not recognized\n"));
263 #ifdef DUMP_CONTEXT
264 unsigned int i;
266 bug("[Kernel] PAGE FAULT accessing 0x%p\n", ptr);
267 bug("[Kernel] Insn: ");
268 for (i = 0; i < 16; i++)
269 bug("%02x ", ip[i]);
270 bug("\n");
271 #endif
273 /* The exception will now be passed on to handling code below */
275 #endif
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 */
290 switch (sc)
292 case SC_REBOOT:
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__(
306 "cli\n\t"
307 "cld\n\t"
308 "movq %0, %%rsp\n\t"
309 "jmp *%1\n"
310 ::"r"(__KernBootPrivate->SystemStack + STACK_SIZE), "r"(core_Kick), "D"(BootMsg), "S"(kernel_cstart));
312 case SC_SUPERVISOR:
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.
325 if (regs->ss != 0)
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 */
339 if (KernelBase)
341 /* From CPU's point of view, IRQs are exceptions starting from 0x20. */
342 irq_number -= 0x20;
344 switch (KernelBase->kb_Interrupts[irq_number].lh_Type)
346 case KBL_APIC:
347 core_APIC_AckIntr();
348 break;
350 case KBL_XTPIC:
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);
361 break;
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;
389 if (!pdata->kb_APIC)
391 /* No APIC was discovered by ACPI/whatever else. Do the probe. */
392 pdata->kb_APIC = core_APIC_Probe();
395 if (!pdata)
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"));