Merged in the x86_64 exception handling.
I've split the 32-bit dependent IDT setup code and ASM interrupt handlers to the 32 subdirectory, arch_int.cpp now contains only the generic hardware interrupt handling code.
This commit is contained in:
@@ -0,0 +1,774 @@
|
||||
/*
|
||||
* Copyright 2008-2011, Michael Lotz, [email protected].
|
||||
* Copyright 2010, Clemens Zeidler, [email protected].
|
||||
* Copyright 2009-2011, Ingo Weinhold, [email protected].
|
||||
* Copyright 2002-2010, Axel Dörfler, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Copyright 2001, Travis Geiselbrecht. All rights reserved.
|
||||
* Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
|
||||
|
||||
#include <cpu.h>
|
||||
#include <int.h>
|
||||
#include <kscheduler.h>
|
||||
#include <ksyscalls.h>
|
||||
#include <smp.h>
|
||||
#include <team.h>
|
||||
#include <thread.h>
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_priv.h>
|
||||
|
||||
#include <arch/cpu.h>
|
||||
#include <arch/int.h>
|
||||
#include <arch/smp.h>
|
||||
#include <arch/user_debugger.h>
|
||||
#include <arch/vm.h>
|
||||
|
||||
#include <arch/x86/apic.h>
|
||||
#include <arch/x86/descriptors.h>
|
||||
#include <arch/x86/pic.h>
|
||||
#include <arch/x86/vm86.h>
|
||||
|
||||
#include "interrupts.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
static const char *kInterruptNames[] = {
|
||||
/* 0 */ "Divide Error Exception",
|
||||
/* 1 */ "Debug Exception",
|
||||
/* 2 */ "NMI Interrupt",
|
||||
/* 3 */ "Breakpoint Exception",
|
||||
/* 4 */ "Overflow Exception",
|
||||
/* 5 */ "BOUND Range Exceeded Exception",
|
||||
/* 6 */ "Invalid Opcode Exception",
|
||||
/* 7 */ "Device Not Available Exception",
|
||||
/* 8 */ "Double Fault Exception",
|
||||
/* 9 */ "Coprocessor Segment Overrun",
|
||||
/* 10 */ "Invalid TSS Exception",
|
||||
/* 11 */ "Segment Not Present",
|
||||
/* 12 */ "Stack Fault Exception",
|
||||
/* 13 */ "General Protection Exception",
|
||||
/* 14 */ "Page-Fault Exception",
|
||||
/* 15 */ "-",
|
||||
/* 16 */ "x87 FPU Floating-Point Error",
|
||||
/* 17 */ "Alignment Check Exception",
|
||||
/* 18 */ "Machine-Check Exception",
|
||||
/* 19 */ "SIMD Floating-Point Exception",
|
||||
};
|
||||
static const int kInterruptNameCount = 20;
|
||||
|
||||
#define MAX_ARGS 16
|
||||
|
||||
typedef struct {
|
||||
uint32 a, b;
|
||||
} desc_table;
|
||||
static desc_table* sIDTs[B_MAX_CPU_COUNT];
|
||||
|
||||
// table with functions handling respective interrupts
|
||||
typedef void interrupt_handler_function(struct iframe* frame);
|
||||
|
||||
#define INTERRUPT_HANDLER_TABLE_SIZE 256
|
||||
interrupt_handler_function* gInterruptHandlerTable[
|
||||
INTERRUPT_HANDLER_TABLE_SIZE];
|
||||
|
||||
extern void hardware_interrupt(struct iframe* frame);
|
||||
|
||||
|
||||
/*! Initializes a descriptor in an IDT.
|
||||
*/
|
||||
static void
|
||||
set_gate(desc_table *gate_addr, addr_t addr, int type, int dpl)
|
||||
{
|
||||
unsigned int gate1; // first byte of gate desc
|
||||
unsigned int gate2; // second byte of gate desc
|
||||
|
||||
gate1 = (KERNEL_CODE_SEG << 16) | (0x0000ffff & addr);
|
||||
gate2 = (0xffff0000 & addr) | 0x8000 | (dpl << 13) | (type << 8);
|
||||
|
||||
gate_addr->a = gate1;
|
||||
gate_addr->b = gate2;
|
||||
}
|
||||
|
||||
|
||||
/*! Initializes the descriptor for interrupt vector \a n in the IDT of the
|
||||
specified CPU to an interrupt-gate descriptor with the given procedure
|
||||
address.
|
||||
For CPUs other than the boot CPU it must not be called before
|
||||
arch_int_init_post_vm().
|
||||
*/
|
||||
static void
|
||||
set_interrupt_gate(int32 cpu, int n, void (*addr)())
|
||||
{
|
||||
set_gate(&sIDTs[cpu][n], (addr_t)addr, 14, DPL_KERNEL);
|
||||
}
|
||||
|
||||
|
||||
/*! Initializes the descriptor for interrupt vector \a n in the IDT of the
|
||||
specified CPU to an trap-gate descriptor with the given procedure address.
|
||||
For CPUs other than the boot CPU it must not be called before
|
||||
arch_int_init_post_vm().
|
||||
*/
|
||||
static void
|
||||
set_trap_gate(int32 cpu, int n, void (*addr)())
|
||||
{
|
||||
set_gate(&sIDTs[cpu][n], (unsigned int)addr, 15, DPL_USER);
|
||||
}
|
||||
|
||||
|
||||
/*! Initializes the descriptor for interrupt vector \a n in the IDT of CPU
|
||||
\a cpu to a task-gate descripter referring to the TSS segment identified
|
||||
by TSS segment selector \a segment.
|
||||
For CPUs other than the boot CPU it must not be called before
|
||||
arch_int_init_post_vm() (arch_cpu_init_post_vm() is fine).
|
||||
*/
|
||||
void
|
||||
x86_set_task_gate(int32 cpu, int32 n, int32 segment)
|
||||
{
|
||||
sIDTs[cpu][n].a = (segment << 16);
|
||||
sIDTs[cpu][n].b = 0x8000 | (0 << 13) | (0x5 << 8); // present, dpl 0, type 5
|
||||
}
|
||||
|
||||
|
||||
/*! Returns the virtual IDT address for CPU \a cpu. */
|
||||
void*
|
||||
x86_get_idt(int32 cpu)
|
||||
{
|
||||
return sIDTs[cpu];
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
static const char *
|
||||
exception_name(int number, char *buffer, int32 bufferSize)
|
||||
{
|
||||
if (number >= 0 && number < kInterruptNameCount)
|
||||
return kInterruptNames[number];
|
||||
|
||||
snprintf(buffer, bufferSize, "exception %d", number);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
invalid_exception(struct iframe* frame)
|
||||
{
|
||||
Thread* thread = thread_get_current_thread();
|
||||
char name[32];
|
||||
panic("unhandled trap 0x%lx (%s) at ip 0x%lx, thread %ld!\n",
|
||||
frame->vector, exception_name(frame->vector, name, sizeof(name)),
|
||||
frame->eip, thread ? thread->id : -1);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fatal_exception(struct iframe *frame)
|
||||
{
|
||||
char name[32];
|
||||
panic("Fatal exception \"%s\" occurred! Error code: 0x%lx\n",
|
||||
exception_name(frame->vector, name, sizeof(name)), frame->error_code);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
unexpected_exception(struct iframe* frame)
|
||||
{
|
||||
debug_exception_type type;
|
||||
uint32 signalNumber;
|
||||
int32 signalCode;
|
||||
addr_t signalAddress = 0;
|
||||
int32 signalError = B_ERROR;
|
||||
|
||||
if (IFRAME_IS_VM86(frame)) {
|
||||
x86_vm86_return((struct vm86_iframe *)frame, (frame->vector == 13) ?
|
||||
B_OK : B_ERROR);
|
||||
// won't get here
|
||||
}
|
||||
|
||||
switch (frame->vector) {
|
||||
case 0: // Divide Error Exception (#DE)
|
||||
type = B_DIVIDE_ERROR;
|
||||
signalNumber = SIGFPE;
|
||||
signalCode = FPE_INTDIV;
|
||||
signalAddress = frame->eip;
|
||||
break;
|
||||
|
||||
case 4: // Overflow Exception (#OF)
|
||||
type = B_OVERFLOW_EXCEPTION;
|
||||
signalNumber = SIGFPE;
|
||||
signalCode = FPE_INTOVF;
|
||||
signalAddress = frame->eip;
|
||||
break;
|
||||
|
||||
case 5: // BOUND Range Exceeded Exception (#BR)
|
||||
type = B_BOUNDS_CHECK_EXCEPTION;
|
||||
signalNumber = SIGTRAP;
|
||||
signalCode = SI_USER;
|
||||
break;
|
||||
|
||||
case 6: // Invalid Opcode Exception (#UD)
|
||||
type = B_INVALID_OPCODE_EXCEPTION;
|
||||
signalNumber = SIGILL;
|
||||
signalCode = ILL_ILLOPC;
|
||||
signalAddress = frame->eip;
|
||||
break;
|
||||
|
||||
case 13: // General Protection Exception (#GP)
|
||||
type = B_GENERAL_PROTECTION_FAULT;
|
||||
signalNumber = SIGILL;
|
||||
signalCode = ILL_PRVOPC; // or ILL_PRVREG
|
||||
signalAddress = frame->eip;
|
||||
break;
|
||||
|
||||
case 16: // x87 FPU Floating-Point Error (#MF)
|
||||
type = B_FLOATING_POINT_EXCEPTION;
|
||||
signalNumber = SIGFPE;
|
||||
signalCode = FPE_FLTDIV;
|
||||
// TODO: Determine the correct cause via the FPU status
|
||||
// register!
|
||||
signalAddress = frame->eip;
|
||||
break;
|
||||
|
||||
case 17: // Alignment Check Exception (#AC)
|
||||
type = B_ALIGNMENT_EXCEPTION;
|
||||
signalNumber = SIGBUS;
|
||||
signalCode = BUS_ADRALN;
|
||||
// TODO: Also get the address (from where?). Since we don't enable
|
||||
// alignment checking this exception should never happen, though.
|
||||
signalError = EFAULT;
|
||||
break;
|
||||
|
||||
case 19: // SIMD Floating-Point Exception (#XF)
|
||||
type = B_FLOATING_POINT_EXCEPTION;
|
||||
signalNumber = SIGFPE;
|
||||
signalCode = FPE_FLTDIV;
|
||||
// TODO: Determine the correct cause via the MXCSR register!
|
||||
signalAddress = frame->eip;
|
||||
break;
|
||||
|
||||
default:
|
||||
invalid_exception(frame);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IFRAME_IS_USER(frame)) {
|
||||
struct sigaction action;
|
||||
Thread* thread = thread_get_current_thread();
|
||||
|
||||
enable_interrupts();
|
||||
|
||||
// If the thread has a signal handler for the signal, we simply send it
|
||||
// the signal. Otherwise we notify the user debugger first.
|
||||
if ((sigaction(signalNumber, NULL, &action) == 0
|
||||
&& action.sa_handler != SIG_DFL
|
||||
&& action.sa_handler != SIG_IGN)
|
||||
|| user_debug_exception_occurred(type, signalNumber)) {
|
||||
Signal signal(signalNumber, signalCode, signalError,
|
||||
thread->team->id);
|
||||
signal.SetAddress((void*)signalAddress);
|
||||
send_signal_to_thread(thread, signal, 0);
|
||||
}
|
||||
} else {
|
||||
char name[32];
|
||||
panic("Unexpected exception \"%s\" occurred in kernel mode! "
|
||||
"Error code: 0x%lx\n",
|
||||
exception_name(frame->vector, name, sizeof(name)),
|
||||
frame->error_code);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
x86_double_fault_exception(struct iframe* frame)
|
||||
{
|
||||
int cpu = x86_double_fault_get_cpu();
|
||||
|
||||
// The double fault iframe contains no useful information (as
|
||||
// per Intel's architecture spec). Thus we simply save the
|
||||
// information from the (unhandlable) exception which caused the
|
||||
// double in our iframe. This will result even in useful stack
|
||||
// traces. Only problem is that we trust that at least the
|
||||
// TSS is still accessible.
|
||||
struct tss *tss = &gCPU[cpu].arch.tss;
|
||||
|
||||
frame->cs = tss->cs;
|
||||
frame->es = tss->es;
|
||||
frame->ds = tss->ds;
|
||||
frame->fs = tss->fs;
|
||||
frame->gs = tss->gs;
|
||||
frame->eip = tss->eip;
|
||||
frame->ebp = tss->ebp;
|
||||
frame->esp = tss->esp;
|
||||
frame->eax = tss->eax;
|
||||
frame->ebx = tss->ebx;
|
||||
frame->ecx = tss->ecx;
|
||||
frame->edx = tss->edx;
|
||||
frame->esi = tss->esi;
|
||||
frame->edi = tss->edi;
|
||||
frame->flags = tss->eflags;
|
||||
|
||||
// Use a special handler for page faults which avoids the triple fault
|
||||
// pitfalls.
|
||||
set_interrupt_gate(cpu, 14, &trap14_double_fault);
|
||||
|
||||
debug_double_fault(cpu);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
x86_page_fault_exception_double_fault(struct iframe* frame)
|
||||
{
|
||||
uint32 cr2;
|
||||
asm("movl %%cr2, %0" : "=r" (cr2));
|
||||
|
||||
// Only if this CPU has a fault handler, we're allowed to be here.
|
||||
cpu_ent& cpu = gCPU[x86_double_fault_get_cpu()];
|
||||
addr_t faultHandler = cpu.fault_handler;
|
||||
if (faultHandler != 0) {
|
||||
debug_set_page_fault_info(cr2, frame->eip,
|
||||
(frame->error_code & 0x2) != 0 ? DEBUG_PAGE_FAULT_WRITE : 0);
|
||||
frame->eip = faultHandler;
|
||||
frame->ebp = cpu.fault_handler_stack_pointer;
|
||||
return;
|
||||
}
|
||||
|
||||
// No fault handler. This is bad. Since we originally came from a double
|
||||
// fault, we don't try to reenter the kernel debugger. Instead we just
|
||||
// print the info we've got and enter an infinite loop.
|
||||
kprintf("Page fault in double fault debugger without fault handler! "
|
||||
"Touching address %p from eip %p. Entering infinite loop...\n",
|
||||
(void*)cr2, (void*)frame->eip);
|
||||
|
||||
while (true);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
page_fault_exception(struct iframe* frame)
|
||||
{
|
||||
Thread *thread = thread_get_current_thread();
|
||||
uint32 cr2;
|
||||
addr_t newip;
|
||||
|
||||
asm("movl %%cr2, %0" : "=r" (cr2));
|
||||
|
||||
if (debug_debugger_running()) {
|
||||
// If this CPU or this thread has a fault handler, we're allowed to be
|
||||
// here.
|
||||
if (thread != NULL) {
|
||||
cpu_ent* cpu = &gCPU[smp_get_current_cpu()];
|
||||
if (cpu->fault_handler != 0) {
|
||||
debug_set_page_fault_info(cr2, frame->eip,
|
||||
(frame->error_code & 0x2) != 0
|
||||
? DEBUG_PAGE_FAULT_WRITE : 0);
|
||||
frame->eip = cpu->fault_handler;
|
||||
frame->ebp = cpu->fault_handler_stack_pointer;
|
||||
return;
|
||||
}
|
||||
|
||||
if (thread->fault_handler != 0) {
|
||||
kprintf("ERROR: thread::fault_handler used in kernel "
|
||||
"debugger!\n");
|
||||
debug_set_page_fault_info(cr2, frame->eip,
|
||||
(frame->error_code & 0x2) != 0
|
||||
? DEBUG_PAGE_FAULT_WRITE : 0);
|
||||
frame->eip = thread->fault_handler;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise, not really
|
||||
panic("page fault in debugger without fault handler! Touching "
|
||||
"address %p from eip %p\n", (void *)cr2, (void *)frame->eip);
|
||||
return;
|
||||
} else if ((frame->flags & 0x200) == 0) {
|
||||
// interrupts disabled
|
||||
|
||||
// If a page fault handler is installed, we're allowed to be here.
|
||||
// TODO: Now we are generally allowing user_memcpy() with interrupts
|
||||
// disabled, which in most cases is a bug. We should add some thread
|
||||
// flag allowing to explicitly indicate that this handling is desired.
|
||||
if (thread && thread->fault_handler != 0) {
|
||||
if (frame->eip != thread->fault_handler) {
|
||||
frame->eip = thread->fault_handler;
|
||||
return;
|
||||
}
|
||||
|
||||
// The fault happened at the fault handler address. This is a
|
||||
// certain infinite loop.
|
||||
panic("page fault, interrupts disabled, fault handler loop. "
|
||||
"Touching address %p from eip %p\n", (void*)cr2,
|
||||
(void*)frame->eip);
|
||||
}
|
||||
|
||||
// If we are not running the kernel startup the page fault was not
|
||||
// allowed to happen and we must panic.
|
||||
panic("page fault, but interrupts were disabled. Touching address "
|
||||
"%p from eip %p\n", (void *)cr2, (void *)frame->eip);
|
||||
return;
|
||||
} else if (thread != NULL && thread->page_faults_allowed < 1) {
|
||||
panic("page fault not allowed at this place. Touching address "
|
||||
"%p from eip %p\n", (void *)cr2, (void *)frame->eip);
|
||||
return;
|
||||
}
|
||||
|
||||
enable_interrupts();
|
||||
|
||||
vm_page_fault(cr2, frame->eip,
|
||||
(frame->error_code & 0x2) != 0, // write access
|
||||
(frame->error_code & 0x4) != 0, // userland
|
||||
&newip);
|
||||
if (newip != 0) {
|
||||
// the page fault handler wants us to modify the iframe to set the
|
||||
// IP the cpu will return to to be this ip
|
||||
frame->eip = newip;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_int_init(struct kernel_args *args)
|
||||
{
|
||||
int i;
|
||||
interrupt_handler_function** table;
|
||||
|
||||
// set the global sIDT variable
|
||||
sIDTs[0] = (desc_table *)(addr_t)args->arch_args.vir_idt;
|
||||
|
||||
// setup the standard programmable interrupt controller
|
||||
pic_init();
|
||||
|
||||
set_interrupt_gate(0, 0, &trap0);
|
||||
set_interrupt_gate(0, 1, &trap1);
|
||||
set_interrupt_gate(0, 2, &trap2);
|
||||
set_trap_gate(0, 3, &trap3);
|
||||
set_interrupt_gate(0, 4, &trap4);
|
||||
set_interrupt_gate(0, 5, &trap5);
|
||||
set_interrupt_gate(0, 6, &trap6);
|
||||
set_interrupt_gate(0, 7, &trap7);
|
||||
// trap8 (double fault) is set in arch_cpu.c
|
||||
set_interrupt_gate(0, 9, &trap9);
|
||||
set_interrupt_gate(0, 10, &trap10);
|
||||
set_interrupt_gate(0, 11, &trap11);
|
||||
set_interrupt_gate(0, 12, &trap12);
|
||||
set_interrupt_gate(0, 13, &trap13);
|
||||
set_interrupt_gate(0, 14, &trap14);
|
||||
// set_interrupt_gate(0, 15, &trap15);
|
||||
set_interrupt_gate(0, 16, &trap16);
|
||||
set_interrupt_gate(0, 17, &trap17);
|
||||
set_interrupt_gate(0, 18, &trap18);
|
||||
set_interrupt_gate(0, 19, &trap19);
|
||||
|
||||
// legacy or ioapic interrupts
|
||||
set_interrupt_gate(0, 32, &trap32);
|
||||
set_interrupt_gate(0, 33, &trap33);
|
||||
set_interrupt_gate(0, 34, &trap34);
|
||||
set_interrupt_gate(0, 35, &trap35);
|
||||
set_interrupt_gate(0, 36, &trap36);
|
||||
set_interrupt_gate(0, 37, &trap37);
|
||||
set_interrupt_gate(0, 38, &trap38);
|
||||
set_interrupt_gate(0, 39, &trap39);
|
||||
set_interrupt_gate(0, 40, &trap40);
|
||||
set_interrupt_gate(0, 41, &trap41);
|
||||
set_interrupt_gate(0, 42, &trap42);
|
||||
set_interrupt_gate(0, 43, &trap43);
|
||||
set_interrupt_gate(0, 44, &trap44);
|
||||
set_interrupt_gate(0, 45, &trap45);
|
||||
set_interrupt_gate(0, 46, &trap46);
|
||||
set_interrupt_gate(0, 47, &trap47);
|
||||
|
||||
// additional ioapic interrupts
|
||||
set_interrupt_gate(0, 48, &trap48);
|
||||
set_interrupt_gate(0, 49, &trap49);
|
||||
set_interrupt_gate(0, 50, &trap50);
|
||||
set_interrupt_gate(0, 51, &trap51);
|
||||
set_interrupt_gate(0, 52, &trap52);
|
||||
set_interrupt_gate(0, 53, &trap53);
|
||||
set_interrupt_gate(0, 54, &trap54);
|
||||
set_interrupt_gate(0, 55, &trap55);
|
||||
|
||||
// configurable msi or msi-x interrupts
|
||||
set_interrupt_gate(0, 56, &trap56);
|
||||
set_interrupt_gate(0, 57, &trap57);
|
||||
set_interrupt_gate(0, 58, &trap58);
|
||||
set_interrupt_gate(0, 59, &trap59);
|
||||
set_interrupt_gate(0, 60, &trap60);
|
||||
set_interrupt_gate(0, 61, &trap61);
|
||||
set_interrupt_gate(0, 62, &trap62);
|
||||
set_interrupt_gate(0, 63, &trap63);
|
||||
set_interrupt_gate(0, 64, &trap64);
|
||||
set_interrupt_gate(0, 65, &trap65);
|
||||
set_interrupt_gate(0, 66, &trap66);
|
||||
set_interrupt_gate(0, 67, &trap67);
|
||||
set_interrupt_gate(0, 68, &trap68);
|
||||
set_interrupt_gate(0, 69, &trap69);
|
||||
set_interrupt_gate(0, 70, &trap70);
|
||||
set_interrupt_gate(0, 71, &trap71);
|
||||
set_interrupt_gate(0, 72, &trap72);
|
||||
set_interrupt_gate(0, 73, &trap73);
|
||||
set_interrupt_gate(0, 74, &trap74);
|
||||
set_interrupt_gate(0, 75, &trap75);
|
||||
set_interrupt_gate(0, 76, &trap76);
|
||||
set_interrupt_gate(0, 77, &trap77);
|
||||
set_interrupt_gate(0, 78, &trap78);
|
||||
set_interrupt_gate(0, 79, &trap79);
|
||||
set_interrupt_gate(0, 80, &trap80);
|
||||
set_interrupt_gate(0, 81, &trap81);
|
||||
set_interrupt_gate(0, 82, &trap82);
|
||||
set_interrupt_gate(0, 83, &trap83);
|
||||
set_interrupt_gate(0, 84, &trap84);
|
||||
set_interrupt_gate(0, 85, &trap85);
|
||||
set_interrupt_gate(0, 86, &trap86);
|
||||
set_interrupt_gate(0, 87, &trap87);
|
||||
set_interrupt_gate(0, 88, &trap88);
|
||||
set_interrupt_gate(0, 89, &trap89);
|
||||
set_interrupt_gate(0, 90, &trap90);
|
||||
set_interrupt_gate(0, 91, &trap91);
|
||||
set_interrupt_gate(0, 92, &trap92);
|
||||
set_interrupt_gate(0, 93, &trap93);
|
||||
set_interrupt_gate(0, 94, &trap94);
|
||||
set_interrupt_gate(0, 95, &trap95);
|
||||
set_interrupt_gate(0, 96, &trap96);
|
||||
set_interrupt_gate(0, 97, &trap97);
|
||||
|
||||
set_trap_gate(0, 98, &trap98); // for performance testing only
|
||||
set_trap_gate(0, 99, &trap99); // syscall interrupt
|
||||
|
||||
reserve_io_interrupt_vectors(2, 98);
|
||||
|
||||
// configurable msi or msi-x interrupts
|
||||
set_interrupt_gate(0, 100, &trap100);
|
||||
set_interrupt_gate(0, 101, &trap101);
|
||||
set_interrupt_gate(0, 102, &trap102);
|
||||
set_interrupt_gate(0, 103, &trap103);
|
||||
set_interrupt_gate(0, 104, &trap104);
|
||||
set_interrupt_gate(0, 105, &trap105);
|
||||
set_interrupt_gate(0, 106, &trap106);
|
||||
set_interrupt_gate(0, 107, &trap107);
|
||||
set_interrupt_gate(0, 108, &trap108);
|
||||
set_interrupt_gate(0, 109, &trap109);
|
||||
set_interrupt_gate(0, 110, &trap110);
|
||||
set_interrupt_gate(0, 111, &trap111);
|
||||
set_interrupt_gate(0, 112, &trap112);
|
||||
set_interrupt_gate(0, 113, &trap113);
|
||||
set_interrupt_gate(0, 114, &trap114);
|
||||
set_interrupt_gate(0, 115, &trap115);
|
||||
set_interrupt_gate(0, 116, &trap116);
|
||||
set_interrupt_gate(0, 117, &trap117);
|
||||
set_interrupt_gate(0, 118, &trap118);
|
||||
set_interrupt_gate(0, 119, &trap119);
|
||||
set_interrupt_gate(0, 120, &trap120);
|
||||
set_interrupt_gate(0, 121, &trap121);
|
||||
set_interrupt_gate(0, 122, &trap122);
|
||||
set_interrupt_gate(0, 123, &trap123);
|
||||
set_interrupt_gate(0, 124, &trap124);
|
||||
set_interrupt_gate(0, 125, &trap125);
|
||||
set_interrupt_gate(0, 126, &trap126);
|
||||
set_interrupt_gate(0, 127, &trap127);
|
||||
set_interrupt_gate(0, 128, &trap128);
|
||||
set_interrupt_gate(0, 129, &trap129);
|
||||
set_interrupt_gate(0, 130, &trap130);
|
||||
set_interrupt_gate(0, 131, &trap131);
|
||||
set_interrupt_gate(0, 132, &trap132);
|
||||
set_interrupt_gate(0, 133, &trap133);
|
||||
set_interrupt_gate(0, 134, &trap134);
|
||||
set_interrupt_gate(0, 135, &trap135);
|
||||
set_interrupt_gate(0, 136, &trap136);
|
||||
set_interrupt_gate(0, 137, &trap137);
|
||||
set_interrupt_gate(0, 138, &trap138);
|
||||
set_interrupt_gate(0, 139, &trap139);
|
||||
set_interrupt_gate(0, 140, &trap140);
|
||||
set_interrupt_gate(0, 141, &trap141);
|
||||
set_interrupt_gate(0, 142, &trap142);
|
||||
set_interrupt_gate(0, 143, &trap143);
|
||||
set_interrupt_gate(0, 144, &trap144);
|
||||
set_interrupt_gate(0, 145, &trap145);
|
||||
set_interrupt_gate(0, 146, &trap146);
|
||||
set_interrupt_gate(0, 147, &trap147);
|
||||
set_interrupt_gate(0, 148, &trap148);
|
||||
set_interrupt_gate(0, 149, &trap149);
|
||||
set_interrupt_gate(0, 150, &trap150);
|
||||
set_interrupt_gate(0, 151, &trap151);
|
||||
set_interrupt_gate(0, 152, &trap152);
|
||||
set_interrupt_gate(0, 153, &trap153);
|
||||
set_interrupt_gate(0, 154, &trap154);
|
||||
set_interrupt_gate(0, 155, &trap155);
|
||||
set_interrupt_gate(0, 156, &trap156);
|
||||
set_interrupt_gate(0, 157, &trap157);
|
||||
set_interrupt_gate(0, 158, &trap158);
|
||||
set_interrupt_gate(0, 159, &trap159);
|
||||
set_interrupt_gate(0, 160, &trap160);
|
||||
set_interrupt_gate(0, 161, &trap161);
|
||||
set_interrupt_gate(0, 162, &trap162);
|
||||
set_interrupt_gate(0, 163, &trap163);
|
||||
set_interrupt_gate(0, 164, &trap164);
|
||||
set_interrupt_gate(0, 165, &trap165);
|
||||
set_interrupt_gate(0, 166, &trap166);
|
||||
set_interrupt_gate(0, 167, &trap167);
|
||||
set_interrupt_gate(0, 168, &trap168);
|
||||
set_interrupt_gate(0, 169, &trap169);
|
||||
set_interrupt_gate(0, 170, &trap170);
|
||||
set_interrupt_gate(0, 171, &trap171);
|
||||
set_interrupt_gate(0, 172, &trap172);
|
||||
set_interrupt_gate(0, 173, &trap173);
|
||||
set_interrupt_gate(0, 174, &trap174);
|
||||
set_interrupt_gate(0, 175, &trap175);
|
||||
set_interrupt_gate(0, 176, &trap176);
|
||||
set_interrupt_gate(0, 177, &trap177);
|
||||
set_interrupt_gate(0, 178, &trap178);
|
||||
set_interrupt_gate(0, 179, &trap179);
|
||||
set_interrupt_gate(0, 180, &trap180);
|
||||
set_interrupt_gate(0, 181, &trap181);
|
||||
set_interrupt_gate(0, 182, &trap182);
|
||||
set_interrupt_gate(0, 183, &trap183);
|
||||
set_interrupt_gate(0, 184, &trap184);
|
||||
set_interrupt_gate(0, 185, &trap185);
|
||||
set_interrupt_gate(0, 186, &trap186);
|
||||
set_interrupt_gate(0, 187, &trap187);
|
||||
set_interrupt_gate(0, 188, &trap188);
|
||||
set_interrupt_gate(0, 189, &trap189);
|
||||
set_interrupt_gate(0, 190, &trap190);
|
||||
set_interrupt_gate(0, 191, &trap191);
|
||||
set_interrupt_gate(0, 192, &trap192);
|
||||
set_interrupt_gate(0, 193, &trap193);
|
||||
set_interrupt_gate(0, 194, &trap194);
|
||||
set_interrupt_gate(0, 195, &trap195);
|
||||
set_interrupt_gate(0, 196, &trap196);
|
||||
set_interrupt_gate(0, 197, &trap197);
|
||||
set_interrupt_gate(0, 198, &trap198);
|
||||
set_interrupt_gate(0, 199, &trap199);
|
||||
set_interrupt_gate(0, 200, &trap200);
|
||||
set_interrupt_gate(0, 201, &trap201);
|
||||
set_interrupt_gate(0, 202, &trap202);
|
||||
set_interrupt_gate(0, 203, &trap203);
|
||||
set_interrupt_gate(0, 204, &trap204);
|
||||
set_interrupt_gate(0, 205, &trap205);
|
||||
set_interrupt_gate(0, 206, &trap206);
|
||||
set_interrupt_gate(0, 207, &trap207);
|
||||
set_interrupt_gate(0, 208, &trap208);
|
||||
set_interrupt_gate(0, 209, &trap209);
|
||||
set_interrupt_gate(0, 210, &trap210);
|
||||
set_interrupt_gate(0, 211, &trap211);
|
||||
set_interrupt_gate(0, 212, &trap212);
|
||||
set_interrupt_gate(0, 213, &trap213);
|
||||
set_interrupt_gate(0, 214, &trap214);
|
||||
set_interrupt_gate(0, 215, &trap215);
|
||||
set_interrupt_gate(0, 216, &trap216);
|
||||
set_interrupt_gate(0, 217, &trap217);
|
||||
set_interrupt_gate(0, 218, &trap218);
|
||||
set_interrupt_gate(0, 219, &trap219);
|
||||
set_interrupt_gate(0, 220, &trap220);
|
||||
set_interrupt_gate(0, 221, &trap221);
|
||||
set_interrupt_gate(0, 222, &trap222);
|
||||
set_interrupt_gate(0, 223, &trap223);
|
||||
set_interrupt_gate(0, 224, &trap224);
|
||||
set_interrupt_gate(0, 225, &trap225);
|
||||
set_interrupt_gate(0, 226, &trap226);
|
||||
set_interrupt_gate(0, 227, &trap227);
|
||||
set_interrupt_gate(0, 228, &trap228);
|
||||
set_interrupt_gate(0, 229, &trap229);
|
||||
set_interrupt_gate(0, 230, &trap230);
|
||||
set_interrupt_gate(0, 231, &trap231);
|
||||
set_interrupt_gate(0, 232, &trap232);
|
||||
set_interrupt_gate(0, 233, &trap233);
|
||||
set_interrupt_gate(0, 234, &trap234);
|
||||
set_interrupt_gate(0, 235, &trap235);
|
||||
set_interrupt_gate(0, 236, &trap236);
|
||||
set_interrupt_gate(0, 237, &trap237);
|
||||
set_interrupt_gate(0, 238, &trap238);
|
||||
set_interrupt_gate(0, 239, &trap239);
|
||||
set_interrupt_gate(0, 240, &trap240);
|
||||
set_interrupt_gate(0, 241, &trap241);
|
||||
set_interrupt_gate(0, 242, &trap242);
|
||||
set_interrupt_gate(0, 243, &trap243);
|
||||
set_interrupt_gate(0, 244, &trap244);
|
||||
set_interrupt_gate(0, 245, &trap245);
|
||||
set_interrupt_gate(0, 246, &trap246);
|
||||
set_interrupt_gate(0, 247, &trap247);
|
||||
set_interrupt_gate(0, 248, &trap248);
|
||||
set_interrupt_gate(0, 249, &trap249);
|
||||
set_interrupt_gate(0, 250, &trap250);
|
||||
|
||||
// smp / apic local interrupts
|
||||
set_interrupt_gate(0, 251, &trap251);
|
||||
set_interrupt_gate(0, 252, &trap252);
|
||||
set_interrupt_gate(0, 253, &trap253);
|
||||
set_interrupt_gate(0, 254, &trap254);
|
||||
set_interrupt_gate(0, 255, &trap255);
|
||||
|
||||
// init interrupt handler table
|
||||
table = gInterruptHandlerTable;
|
||||
|
||||
// defaults
|
||||
for (i = 0; i < ARCH_INTERRUPT_BASE; i++)
|
||||
table[i] = invalid_exception;
|
||||
for (i = ARCH_INTERRUPT_BASE; i < INTERRUPT_HANDLER_TABLE_SIZE; i++)
|
||||
table[i] = hardware_interrupt;
|
||||
|
||||
table[0] = unexpected_exception; // Divide Error Exception (#DE)
|
||||
table[1] = x86_handle_debug_exception; // Debug Exception (#DB)
|
||||
table[2] = fatal_exception; // NMI Interrupt
|
||||
table[3] = x86_handle_breakpoint_exception; // Breakpoint Exception (#BP)
|
||||
table[4] = unexpected_exception; // Overflow Exception (#OF)
|
||||
table[5] = unexpected_exception; // BOUND Range Exceeded Exception (#BR)
|
||||
table[6] = unexpected_exception; // Invalid Opcode Exception (#UD)
|
||||
table[7] = fatal_exception; // Device Not Available Exception (#NM)
|
||||
table[8] = x86_double_fault_exception; // Double Fault Exception (#DF)
|
||||
table[9] = fatal_exception; // Coprocessor Segment Overrun
|
||||
table[10] = fatal_exception; // Invalid TSS Exception (#TS)
|
||||
table[11] = fatal_exception; // Segment Not Present (#NP)
|
||||
table[12] = fatal_exception; // Stack Fault Exception (#SS)
|
||||
table[13] = unexpected_exception; // General Protection Exception (#GP)
|
||||
table[14] = page_fault_exception; // Page-Fault Exception (#PF)
|
||||
table[16] = unexpected_exception; // x87 FPU Floating-Point Error (#MF)
|
||||
table[17] = unexpected_exception; // Alignment Check Exception (#AC)
|
||||
table[18] = fatal_exception; // Machine-Check Exception (#MC)
|
||||
table[19] = unexpected_exception; // SIMD Floating-Point Exception (#XF)
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_int_init_post_vm(struct kernel_args *args)
|
||||
{
|
||||
// Always init the local apic as it can be used for timers even if we
|
||||
// don't end up using the io apic
|
||||
apic_init(args);
|
||||
|
||||
// create IDT area for the boot CPU
|
||||
area_id area = create_area("idt", (void**)&sIDTs[0], B_EXACT_ADDRESS,
|
||||
B_PAGE_SIZE, B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||
if (area < 0)
|
||||
return area;
|
||||
|
||||
// create IDTs for the off-boot CPU
|
||||
size_t idtSize = 256 * 8;
|
||||
// 256 8 bytes-sized descriptors
|
||||
int32 cpuCount = smp_get_num_cpus();
|
||||
if (cpuCount > 0) {
|
||||
size_t areaSize = ROUNDUP(cpuCount * idtSize, B_PAGE_SIZE);
|
||||
desc_table* idt;
|
||||
virtual_address_restrictions virtualRestrictions = {};
|
||||
virtualRestrictions.address_specification = B_ANY_KERNEL_ADDRESS;
|
||||
physical_address_restrictions physicalRestrictions = {};
|
||||
area = create_area_etc(B_SYSTEM_TEAM, "idt", areaSize, B_CONTIGUOUS,
|
||||
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, CREATE_AREA_DONT_WAIT,
|
||||
&virtualRestrictions, &physicalRestrictions, (void**)&idt);
|
||||
if (area < 0)
|
||||
return area;
|
||||
|
||||
for (int32 i = 1; i < cpuCount; i++) {
|
||||
sIDTs[i] = idt;
|
||||
memcpy(idt, sIDTs[0], idtSize);
|
||||
idt += 256;
|
||||
// The CPU's IDTR will be set in arch_cpu_init_percpu().
|
||||
}
|
||||
}
|
||||
|
||||
return area >= B_OK ? B_OK : area;
|
||||
}
|
||||
+17
-39
@@ -12,11 +12,14 @@
|
||||
#include <boot/kernel_args.h>
|
||||
#include <cpu.h>
|
||||
|
||||
#include <arch/x86_64/descriptors.h>
|
||||
#include <arch/x86/apic.h>
|
||||
#include <arch/x86/descriptors.h>
|
||||
#include <arch/x86/pic.h>
|
||||
|
||||
|
||||
typedef void interrupt_handler_function(iframe* frame);
|
||||
|
||||
|
||||
static const char* kInterruptNames[] = {
|
||||
/* 0 */ "Divide Error Exception",
|
||||
/* 1 */ "Debug Exception",
|
||||
@@ -46,6 +49,7 @@ static interrupt_descriptor* sIDT;
|
||||
interrupt_handler_function* gInterruptHandlerTable[kInterruptHandlerTableSize];
|
||||
|
||||
extern uint8 isr_array[kInterruptHandlerTableSize][16];
|
||||
extern void hardware_interrupt(struct iframe* frame);
|
||||
|
||||
|
||||
static const char*
|
||||
@@ -104,27 +108,6 @@ page_fault_exception(iframe* frame)
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
void
|
||||
arch_int_enable_io_interrupt(int irq)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_int_disable_io_interrupt(int irq)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_int_configure_io_interrupt(int irq, uint32 config)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_int_init(kernel_args* args)
|
||||
{
|
||||
@@ -152,8 +135,8 @@ arch_int_init(kernel_args* args)
|
||||
// Initialize the interrupt handler table.
|
||||
for (uint32 i = 0; i < ARCH_INTERRUPT_BASE; i++)
|
||||
table[i] = invalid_exception;
|
||||
//for (uint32 i = ARCH_INTERRUPT_BASE; i < INTERRUPT_HANDLER_TABLE_SIZE; i++)
|
||||
// table[i] = hardware_interrupt;
|
||||
for (uint32 i = ARCH_INTERRUPT_BASE; i < kInterruptHandlerTableSize; i++)
|
||||
table[i] = hardware_interrupt;
|
||||
|
||||
table[0] = unexpected_exception; // Divide Error Exception (#DE)
|
||||
//table[1] = x86_handle_debug_exception; // Debug Exception (#DB)
|
||||
@@ -165,7 +148,7 @@ arch_int_init(kernel_args* args)
|
||||
table[5] = unexpected_exception; // BOUND Range Exceeded Exception (#BR)
|
||||
table[6] = unexpected_exception; // Invalid Opcode Exception (#UD)
|
||||
table[7] = fatal_exception; // Device Not Available Exception (#NM)
|
||||
table[8] = fatal_exception; // Double Fault Exception (#DF)
|
||||
table[8] = fatal_exception; // Double Fault Exception (#DF)
|
||||
table[9] = fatal_exception; // Coprocessor Segment Overrun
|
||||
table[10] = fatal_exception; // Invalid TSS Exception (#TS)
|
||||
table[11] = fatal_exception; // Segment Not Present (#NP)
|
||||
@@ -184,6 +167,9 @@ arch_int_init(kernel_args* args)
|
||||
};
|
||||
asm volatile("lidt %0" :: "m"(idtr));
|
||||
|
||||
// Set up the legacy PIC.
|
||||
pic_init();
|
||||
|
||||
panic("not implemented\n");
|
||||
return B_OK;
|
||||
}
|
||||
@@ -192,19 +178,11 @@ arch_int_init(kernel_args* args)
|
||||
status_t
|
||||
arch_int_init_post_vm(kernel_args* args)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_int_init_io(kernel_args* args)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_int_init_post_device_manager(kernel_args* args)
|
||||
{
|
||||
// Always init the local apic as it can be used for timers even if we
|
||||
// don't end up using the io apic
|
||||
//apic_init(args);
|
||||
|
||||
// TODO: create area for IDT.
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
+2
-2
@@ -6,8 +6,8 @@
|
||||
|
||||
#include <asm_defs.h>
|
||||
|
||||
#include <arch/x86_64/descriptors.h>
|
||||
#include <arch/x86_64/arch_cpu.h>
|
||||
#include <arch/x86/descriptors.h>
|
||||
#include <arch/x86/arch_cpu.h>
|
||||
|
||||
#include "asm_offsets.h"
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include <debugger.h>
|
||||
#include <elf.h>
|
||||
#include <elf_priv.h>
|
||||
#include <int.h>
|
||||
#include <real_time_clock.h>
|
||||
#include <real_time_data.h>
|
||||
#include <smp.h>
|
||||
@@ -35,7 +34,6 @@
|
||||
#include <arch/system_info.h>
|
||||
#include <arch/smp.h>
|
||||
#include <arch/real_time_clock.h>
|
||||
#include <arch/int.h>
|
||||
#include <arch/elf.h>
|
||||
|
||||
|
||||
@@ -677,55 +675,6 @@ arch_vm_translation_map_is_kernel_page_accessible(addr_t virtualAddress,
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_int_enable_io_interrupt(int irq)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_int_disable_io_interrupt(int irq)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_int_configure_io_interrupt(int irq, uint32 config)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_int_init(struct kernel_args *args)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_int_init_post_vm(struct kernel_args *args)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_int_init_io(kernel_args* args)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_int_init_post_device_manager(struct kernel_args *args)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// Currently got generic elf.cpp #ifdef'd out for x86_64, define stub versions here.
|
||||
|
||||
status_t
|
||||
|
||||
@@ -20,17 +20,21 @@ if $(TARGET_ARCH) = x86_64 {
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) 64 ] ;
|
||||
|
||||
archSpecificSources =
|
||||
int.cpp
|
||||
interrupts.S
|
||||
stubs.cpp
|
||||
;
|
||||
} else {
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) 32 ] ;
|
||||
|
||||
archSpecificSources =
|
||||
int.cpp
|
||||
interrupts.S
|
||||
|
||||
arch_commpage.cpp
|
||||
arch_cpu.cpp
|
||||
arch_debug.cpp
|
||||
arch_elf.cpp
|
||||
arch_int.cpp
|
||||
arch_platform.cpp
|
||||
# arch_selector.cpp
|
||||
arch_real_time_clock.cpp
|
||||
@@ -40,7 +44,6 @@ if $(TARGET_ARCH) = x86_64 {
|
||||
arch_vm.cpp
|
||||
arch_vm_translation_map.cpp
|
||||
arch_x86.S
|
||||
arch_interrupts.S
|
||||
arch_system_info.cpp
|
||||
arch_user_debugger.cpp
|
||||
apic.cpp
|
||||
@@ -50,7 +53,6 @@ if $(TARGET_ARCH) = x86_64 {
|
||||
ioapic.cpp
|
||||
irq_routing_table.cpp
|
||||
msi.cpp
|
||||
pic.cpp
|
||||
syscall.S
|
||||
vm86.cpp
|
||||
x86_signals.cpp
|
||||
@@ -83,6 +85,8 @@ if $(TARGET_ARCH) = x86_64 {
|
||||
|
||||
local archGenericSources =
|
||||
arch_debug_console.cpp
|
||||
arch_int.cpp
|
||||
pic.cpp
|
||||
;
|
||||
|
||||
KernelMergeObject kernel_arch_x86.o :
|
||||
|
||||
@@ -13,26 +13,16 @@
|
||||
#include <cpu.h>
|
||||
#include <int.h>
|
||||
#include <kscheduler.h>
|
||||
#include <ksyscalls.h>
|
||||
#include <smp.h>
|
||||
#include <team.h>
|
||||
#include <thread.h>
|
||||
#include <util/AutoLock.h>
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_priv.h>
|
||||
|
||||
#include <arch/cpu.h>
|
||||
#include <arch/int.h>
|
||||
#include <arch/smp.h>
|
||||
#include <arch/user_debugger.h>
|
||||
#include <arch/vm.h>
|
||||
|
||||
#include <arch/x86/apic.h>
|
||||
#include <arch/x86/descriptors.h>
|
||||
#include <arch/x86/msi.h>
|
||||
#include <arch/x86/vm86.h>
|
||||
|
||||
#include "interrupts.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -49,107 +39,58 @@
|
||||
#endif
|
||||
|
||||
|
||||
static const interrupt_controller *sCurrentPIC = NULL;
|
||||
|
||||
static const char *kInterruptNames[] = {
|
||||
/* 0 */ "Divide Error Exception",
|
||||
/* 1 */ "Debug Exception",
|
||||
/* 2 */ "NMI Interrupt",
|
||||
/* 3 */ "Breakpoint Exception",
|
||||
/* 4 */ "Overflow Exception",
|
||||
/* 5 */ "BOUND Range Exceeded Exception",
|
||||
/* 6 */ "Invalid Opcode Exception",
|
||||
/* 7 */ "Device Not Available Exception",
|
||||
/* 8 */ "Double Fault Exception",
|
||||
/* 9 */ "Coprocessor Segment Overrun",
|
||||
/* 10 */ "Invalid TSS Exception",
|
||||
/* 11 */ "Segment Not Present",
|
||||
/* 12 */ "Stack Fault Exception",
|
||||
/* 13 */ "General Protection Exception",
|
||||
/* 14 */ "Page-Fault Exception",
|
||||
/* 15 */ "-",
|
||||
/* 16 */ "x87 FPU Floating-Point Error",
|
||||
/* 17 */ "Alignment Check Exception",
|
||||
/* 18 */ "Machine-Check Exception",
|
||||
/* 19 */ "SIMD Floating-Point Exception",
|
||||
};
|
||||
static const int kInterruptNameCount = 20;
|
||||
|
||||
#define MAX_ARGS 16
|
||||
|
||||
typedef struct {
|
||||
uint32 a, b;
|
||||
} desc_table;
|
||||
static desc_table* sIDTs[B_MAX_CPU_COUNT];
|
||||
|
||||
// table with functions handling respective interrupts
|
||||
typedef void interrupt_handler_function(struct iframe* frame);
|
||||
|
||||
#define INTERRUPT_HANDLER_TABLE_SIZE 256
|
||||
interrupt_handler_function* gInterruptHandlerTable[
|
||||
INTERRUPT_HANDLER_TABLE_SIZE];
|
||||
static const interrupt_controller* sCurrentPIC = NULL;
|
||||
|
||||
|
||||
/*! Initializes a descriptor in an IDT.
|
||||
*/
|
||||
static void
|
||||
set_gate(desc_table *gate_addr, addr_t addr, int type, int dpl)
|
||||
{
|
||||
unsigned int gate1; // first byte of gate desc
|
||||
unsigned int gate2; // second byte of gate desc
|
||||
|
||||
gate1 = (KERNEL_CODE_SEG << 16) | (0x0000ffff & addr);
|
||||
gate2 = (0xffff0000 & addr) | 0x8000 | (dpl << 13) | (type << 8);
|
||||
|
||||
gate_addr->a = gate1;
|
||||
gate_addr->b = gate2;
|
||||
}
|
||||
|
||||
|
||||
/*! Initializes the descriptor for interrupt vector \a n in the IDT of the
|
||||
specified CPU to an interrupt-gate descriptor with the given procedure
|
||||
address.
|
||||
For CPUs other than the boot CPU it must not be called before
|
||||
arch_int_init_post_vm().
|
||||
*/
|
||||
static void
|
||||
set_interrupt_gate(int32 cpu, int n, void (*addr)())
|
||||
{
|
||||
set_gate(&sIDTs[cpu][n], (addr_t)addr, 14, DPL_KERNEL);
|
||||
}
|
||||
|
||||
|
||||
/*! Initializes the descriptor for interrupt vector \a n in the IDT of the
|
||||
specified CPU to an trap-gate descriptor with the given procedure address.
|
||||
For CPUs other than the boot CPU it must not be called before
|
||||
arch_int_init_post_vm().
|
||||
*/
|
||||
static void
|
||||
set_trap_gate(int32 cpu, int n, void (*addr)())
|
||||
{
|
||||
set_gate(&sIDTs[cpu][n], (unsigned int)addr, 15, DPL_USER);
|
||||
}
|
||||
|
||||
|
||||
/*! Initializes the descriptor for interrupt vector \a n in the IDT of CPU
|
||||
\a cpu to a task-gate descripter referring to the TSS segment identified
|
||||
by TSS segment selector \a segment.
|
||||
For CPUs other than the boot CPU it must not be called before
|
||||
arch_int_init_post_vm() (arch_cpu_init_post_vm() is fine).
|
||||
*/
|
||||
void
|
||||
x86_set_task_gate(int32 cpu, int32 n, int32 segment)
|
||||
hardware_interrupt(struct iframe* frame)
|
||||
{
|
||||
sIDTs[cpu][n].a = (segment << 16);
|
||||
sIDTs[cpu][n].b = 0x8000 | (0 << 13) | (0x5 << 8); // present, dpl 0, type 5
|
||||
}
|
||||
#ifndef __x86_64__
|
||||
int32 vector = frame->vector - ARCH_INTERRUPT_BASE;
|
||||
bool levelTriggered = false;
|
||||
Thread* thread = thread_get_current_thread();
|
||||
|
||||
if (sCurrentPIC->is_spurious_interrupt(vector)) {
|
||||
TRACE(("got spurious interrupt at vector %ld\n", vector));
|
||||
return;
|
||||
}
|
||||
|
||||
/*! Returns the virtual IDT address for CPU \a cpu. */
|
||||
void*
|
||||
x86_get_idt(int32 cpu)
|
||||
{
|
||||
return sIDTs[cpu];
|
||||
levelTriggered = sCurrentPIC->is_level_triggered_interrupt(vector);
|
||||
|
||||
if (!levelTriggered) {
|
||||
// if it's not handled by the current pic then it's an apic generated
|
||||
// interrupt like local interrupts, msi or ipi.
|
||||
if (!sCurrentPIC->end_of_interrupt(vector))
|
||||
apic_end_of_interrupt();
|
||||
}
|
||||
|
||||
int_io_interrupt_handler(vector, levelTriggered);
|
||||
|
||||
if (levelTriggered) {
|
||||
if (!sCurrentPIC->end_of_interrupt(vector))
|
||||
apic_end_of_interrupt();
|
||||
}
|
||||
|
||||
cpu_status state = disable_interrupts();
|
||||
if (thread->cpu->invoke_scheduler) {
|
||||
SpinLocker schedulerLocker(gSchedulerLock);
|
||||
scheduler_reschedule();
|
||||
schedulerLocker.Unlock();
|
||||
restore_interrupts(state);
|
||||
} else if (thread->post_interrupt_callback != NULL) {
|
||||
void (*callback)(void*) = thread->post_interrupt_callback;
|
||||
void* data = thread->post_interrupt_data;
|
||||
|
||||
thread->post_interrupt_callback = NULL;
|
||||
thread->post_interrupt_data = NULL;
|
||||
|
||||
restore_interrupts(state);
|
||||
|
||||
callback(data);
|
||||
}
|
||||
#else
|
||||
panic("implement me");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -211,703 +152,28 @@ arch_int_are_interrupts_enabled(void)
|
||||
}
|
||||
|
||||
|
||||
static const char *
|
||||
exception_name(int number, char *buffer, int32 bufferSize)
|
||||
{
|
||||
if (number >= 0 && number < kInterruptNameCount)
|
||||
return kInterruptNames[number];
|
||||
|
||||
snprintf(buffer, bufferSize, "exception %d", number);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
invalid_exception(struct iframe* frame)
|
||||
{
|
||||
Thread* thread = thread_get_current_thread();
|
||||
char name[32];
|
||||
panic("unhandled trap 0x%lx (%s) at ip 0x%lx, thread %ld!\n",
|
||||
frame->vector, exception_name(frame->vector, name, sizeof(name)),
|
||||
frame->eip, thread ? thread->id : -1);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fatal_exception(struct iframe *frame)
|
||||
{
|
||||
char name[32];
|
||||
panic("Fatal exception \"%s\" occurred! Error code: 0x%lx\n",
|
||||
exception_name(frame->vector, name, sizeof(name)), frame->error_code);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
unexpected_exception(struct iframe* frame)
|
||||
{
|
||||
debug_exception_type type;
|
||||
uint32 signalNumber;
|
||||
int32 signalCode;
|
||||
addr_t signalAddress = 0;
|
||||
int32 signalError = B_ERROR;
|
||||
|
||||
if (IFRAME_IS_VM86(frame)) {
|
||||
x86_vm86_return((struct vm86_iframe *)frame, (frame->vector == 13) ?
|
||||
B_OK : B_ERROR);
|
||||
// won't get here
|
||||
}
|
||||
|
||||
switch (frame->vector) {
|
||||
case 0: // Divide Error Exception (#DE)
|
||||
type = B_DIVIDE_ERROR;
|
||||
signalNumber = SIGFPE;
|
||||
signalCode = FPE_INTDIV;
|
||||
signalAddress = frame->eip;
|
||||
break;
|
||||
|
||||
case 4: // Overflow Exception (#OF)
|
||||
type = B_OVERFLOW_EXCEPTION;
|
||||
signalNumber = SIGFPE;
|
||||
signalCode = FPE_INTOVF;
|
||||
signalAddress = frame->eip;
|
||||
break;
|
||||
|
||||
case 5: // BOUND Range Exceeded Exception (#BR)
|
||||
type = B_BOUNDS_CHECK_EXCEPTION;
|
||||
signalNumber = SIGTRAP;
|
||||
signalCode = SI_USER;
|
||||
break;
|
||||
|
||||
case 6: // Invalid Opcode Exception (#UD)
|
||||
type = B_INVALID_OPCODE_EXCEPTION;
|
||||
signalNumber = SIGILL;
|
||||
signalCode = ILL_ILLOPC;
|
||||
signalAddress = frame->eip;
|
||||
break;
|
||||
|
||||
case 13: // General Protection Exception (#GP)
|
||||
type = B_GENERAL_PROTECTION_FAULT;
|
||||
signalNumber = SIGILL;
|
||||
signalCode = ILL_PRVOPC; // or ILL_PRVREG
|
||||
signalAddress = frame->eip;
|
||||
break;
|
||||
|
||||
case 16: // x87 FPU Floating-Point Error (#MF)
|
||||
type = B_FLOATING_POINT_EXCEPTION;
|
||||
signalNumber = SIGFPE;
|
||||
signalCode = FPE_FLTDIV;
|
||||
// TODO: Determine the correct cause via the FPU status
|
||||
// register!
|
||||
signalAddress = frame->eip;
|
||||
break;
|
||||
|
||||
case 17: // Alignment Check Exception (#AC)
|
||||
type = B_ALIGNMENT_EXCEPTION;
|
||||
signalNumber = SIGBUS;
|
||||
signalCode = BUS_ADRALN;
|
||||
// TODO: Also get the address (from where?). Since we don't enable
|
||||
// alignment checking this exception should never happen, though.
|
||||
signalError = EFAULT;
|
||||
break;
|
||||
|
||||
case 19: // SIMD Floating-Point Exception (#XF)
|
||||
type = B_FLOATING_POINT_EXCEPTION;
|
||||
signalNumber = SIGFPE;
|
||||
signalCode = FPE_FLTDIV;
|
||||
// TODO: Determine the correct cause via the MXCSR register!
|
||||
signalAddress = frame->eip;
|
||||
break;
|
||||
|
||||
default:
|
||||
invalid_exception(frame);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IFRAME_IS_USER(frame)) {
|
||||
struct sigaction action;
|
||||
Thread* thread = thread_get_current_thread();
|
||||
|
||||
enable_interrupts();
|
||||
|
||||
// If the thread has a signal handler for the signal, we simply send it
|
||||
// the signal. Otherwise we notify the user debugger first.
|
||||
if ((sigaction(signalNumber, NULL, &action) == 0
|
||||
&& action.sa_handler != SIG_DFL
|
||||
&& action.sa_handler != SIG_IGN)
|
||||
|| user_debug_exception_occurred(type, signalNumber)) {
|
||||
Signal signal(signalNumber, signalCode, signalError,
|
||||
thread->team->id);
|
||||
signal.SetAddress((void*)signalAddress);
|
||||
send_signal_to_thread(thread, signal, 0);
|
||||
}
|
||||
} else {
|
||||
char name[32];
|
||||
panic("Unexpected exception \"%s\" occurred in kernel mode! "
|
||||
"Error code: 0x%lx\n",
|
||||
exception_name(frame->vector, name, sizeof(name)),
|
||||
frame->error_code);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
x86_double_fault_exception(struct iframe* frame)
|
||||
{
|
||||
int cpu = x86_double_fault_get_cpu();
|
||||
|
||||
// The double fault iframe contains no useful information (as
|
||||
// per Intel's architecture spec). Thus we simply save the
|
||||
// information from the (unhandlable) exception which caused the
|
||||
// double in our iframe. This will result even in useful stack
|
||||
// traces. Only problem is that we trust that at least the
|
||||
// TSS is still accessible.
|
||||
struct tss *tss = &gCPU[cpu].arch.tss;
|
||||
|
||||
frame->cs = tss->cs;
|
||||
frame->es = tss->es;
|
||||
frame->ds = tss->ds;
|
||||
frame->fs = tss->fs;
|
||||
frame->gs = tss->gs;
|
||||
frame->eip = tss->eip;
|
||||
frame->ebp = tss->ebp;
|
||||
frame->esp = tss->esp;
|
||||
frame->eax = tss->eax;
|
||||
frame->ebx = tss->ebx;
|
||||
frame->ecx = tss->ecx;
|
||||
frame->edx = tss->edx;
|
||||
frame->esi = tss->esi;
|
||||
frame->edi = tss->edi;
|
||||
frame->flags = tss->eflags;
|
||||
|
||||
// Use a special handler for page faults which avoids the triple fault
|
||||
// pitfalls.
|
||||
set_interrupt_gate(cpu, 14, &trap14_double_fault);
|
||||
|
||||
debug_double_fault(cpu);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
x86_page_fault_exception_double_fault(struct iframe* frame)
|
||||
{
|
||||
uint32 cr2;
|
||||
asm("movl %%cr2, %0" : "=r" (cr2));
|
||||
|
||||
// Only if this CPU has a fault handler, we're allowed to be here.
|
||||
cpu_ent& cpu = gCPU[x86_double_fault_get_cpu()];
|
||||
addr_t faultHandler = cpu.fault_handler;
|
||||
if (faultHandler != 0) {
|
||||
debug_set_page_fault_info(cr2, frame->eip,
|
||||
(frame->error_code & 0x2) != 0 ? DEBUG_PAGE_FAULT_WRITE : 0);
|
||||
frame->eip = faultHandler;
|
||||
frame->ebp = cpu.fault_handler_stack_pointer;
|
||||
return;
|
||||
}
|
||||
|
||||
// No fault handler. This is bad. Since we originally came from a double
|
||||
// fault, we don't try to reenter the kernel debugger. Instead we just
|
||||
// print the info we've got and enter an infinite loop.
|
||||
kprintf("Page fault in double fault debugger without fault handler! "
|
||||
"Touching address %p from eip %p. Entering infinite loop...\n",
|
||||
(void*)cr2, (void*)frame->eip);
|
||||
|
||||
while (true);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
page_fault_exception(struct iframe* frame)
|
||||
{
|
||||
Thread *thread = thread_get_current_thread();
|
||||
uint32 cr2;
|
||||
addr_t newip;
|
||||
|
||||
asm("movl %%cr2, %0" : "=r" (cr2));
|
||||
|
||||
if (debug_debugger_running()) {
|
||||
// If this CPU or this thread has a fault handler, we're allowed to be
|
||||
// here.
|
||||
if (thread != NULL) {
|
||||
cpu_ent* cpu = &gCPU[smp_get_current_cpu()];
|
||||
if (cpu->fault_handler != 0) {
|
||||
debug_set_page_fault_info(cr2, frame->eip,
|
||||
(frame->error_code & 0x2) != 0
|
||||
? DEBUG_PAGE_FAULT_WRITE : 0);
|
||||
frame->eip = cpu->fault_handler;
|
||||
frame->ebp = cpu->fault_handler_stack_pointer;
|
||||
return;
|
||||
}
|
||||
|
||||
if (thread->fault_handler != 0) {
|
||||
kprintf("ERROR: thread::fault_handler used in kernel "
|
||||
"debugger!\n");
|
||||
debug_set_page_fault_info(cr2, frame->eip,
|
||||
(frame->error_code & 0x2) != 0
|
||||
? DEBUG_PAGE_FAULT_WRITE : 0);
|
||||
frame->eip = thread->fault_handler;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise, not really
|
||||
panic("page fault in debugger without fault handler! Touching "
|
||||
"address %p from eip %p\n", (void *)cr2, (void *)frame->eip);
|
||||
return;
|
||||
} else if ((frame->flags & 0x200) == 0) {
|
||||
// interrupts disabled
|
||||
|
||||
// If a page fault handler is installed, we're allowed to be here.
|
||||
// TODO: Now we are generally allowing user_memcpy() with interrupts
|
||||
// disabled, which in most cases is a bug. We should add some thread
|
||||
// flag allowing to explicitly indicate that this handling is desired.
|
||||
if (thread && thread->fault_handler != 0) {
|
||||
if (frame->eip != thread->fault_handler) {
|
||||
frame->eip = thread->fault_handler;
|
||||
return;
|
||||
}
|
||||
|
||||
// The fault happened at the fault handler address. This is a
|
||||
// certain infinite loop.
|
||||
panic("page fault, interrupts disabled, fault handler loop. "
|
||||
"Touching address %p from eip %p\n", (void*)cr2,
|
||||
(void*)frame->eip);
|
||||
}
|
||||
|
||||
// If we are not running the kernel startup the page fault was not
|
||||
// allowed to happen and we must panic.
|
||||
panic("page fault, but interrupts were disabled. Touching address "
|
||||
"%p from eip %p\n", (void *)cr2, (void *)frame->eip);
|
||||
return;
|
||||
} else if (thread != NULL && thread->page_faults_allowed < 1) {
|
||||
panic("page fault not allowed at this place. Touching address "
|
||||
"%p from eip %p\n", (void *)cr2, (void *)frame->eip);
|
||||
return;
|
||||
}
|
||||
|
||||
enable_interrupts();
|
||||
|
||||
vm_page_fault(cr2, frame->eip,
|
||||
(frame->error_code & 0x2) != 0, // write access
|
||||
(frame->error_code & 0x4) != 0, // userland
|
||||
&newip);
|
||||
if (newip != 0) {
|
||||
// the page fault handler wants us to modify the iframe to set the
|
||||
// IP the cpu will return to to be this ip
|
||||
frame->eip = newip;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
hardware_interrupt(struct iframe* frame)
|
||||
{
|
||||
int32 vector = frame->vector - ARCH_INTERRUPT_BASE;
|
||||
bool levelTriggered = false;
|
||||
Thread* thread = thread_get_current_thread();
|
||||
|
||||
if (sCurrentPIC->is_spurious_interrupt(vector)) {
|
||||
TRACE(("got spurious interrupt at vector %ld\n", vector));
|
||||
return;
|
||||
}
|
||||
|
||||
levelTriggered = sCurrentPIC->is_level_triggered_interrupt(vector);
|
||||
|
||||
if (!levelTriggered) {
|
||||
// if it's not handled by the current pic then it's an apic generated
|
||||
// interrupt like local interrupts, msi or ipi.
|
||||
if (!sCurrentPIC->end_of_interrupt(vector))
|
||||
apic_end_of_interrupt();
|
||||
}
|
||||
|
||||
int_io_interrupt_handler(vector, levelTriggered);
|
||||
|
||||
if (levelTriggered) {
|
||||
if (!sCurrentPIC->end_of_interrupt(vector))
|
||||
apic_end_of_interrupt();
|
||||
}
|
||||
|
||||
cpu_status state = disable_interrupts();
|
||||
if (thread->cpu->invoke_scheduler) {
|
||||
SpinLocker schedulerLocker(gSchedulerLock);
|
||||
scheduler_reschedule();
|
||||
schedulerLocker.Unlock();
|
||||
restore_interrupts(state);
|
||||
} else if (thread->post_interrupt_callback != NULL) {
|
||||
void (*callback)(void*) = thread->post_interrupt_callback;
|
||||
void* data = thread->post_interrupt_data;
|
||||
|
||||
thread->post_interrupt_callback = NULL;
|
||||
thread->post_interrupt_data = NULL;
|
||||
|
||||
restore_interrupts(state);
|
||||
|
||||
callback(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_int_init(struct kernel_args *args)
|
||||
{
|
||||
int i;
|
||||
interrupt_handler_function** table;
|
||||
|
||||
// set the global sIDT variable
|
||||
sIDTs[0] = (desc_table *)(addr_t)args->arch_args.vir_idt;
|
||||
|
||||
// setup the standard programmable interrupt controller
|
||||
pic_init();
|
||||
|
||||
set_interrupt_gate(0, 0, &trap0);
|
||||
set_interrupt_gate(0, 1, &trap1);
|
||||
set_interrupt_gate(0, 2, &trap2);
|
||||
set_trap_gate(0, 3, &trap3);
|
||||
set_interrupt_gate(0, 4, &trap4);
|
||||
set_interrupt_gate(0, 5, &trap5);
|
||||
set_interrupt_gate(0, 6, &trap6);
|
||||
set_interrupt_gate(0, 7, &trap7);
|
||||
// trap8 (double fault) is set in arch_cpu.c
|
||||
set_interrupt_gate(0, 9, &trap9);
|
||||
set_interrupt_gate(0, 10, &trap10);
|
||||
set_interrupt_gate(0, 11, &trap11);
|
||||
set_interrupt_gate(0, 12, &trap12);
|
||||
set_interrupt_gate(0, 13, &trap13);
|
||||
set_interrupt_gate(0, 14, &trap14);
|
||||
// set_interrupt_gate(0, 15, &trap15);
|
||||
set_interrupt_gate(0, 16, &trap16);
|
||||
set_interrupt_gate(0, 17, &trap17);
|
||||
set_interrupt_gate(0, 18, &trap18);
|
||||
set_interrupt_gate(0, 19, &trap19);
|
||||
|
||||
// legacy or ioapic interrupts
|
||||
set_interrupt_gate(0, 32, &trap32);
|
||||
set_interrupt_gate(0, 33, &trap33);
|
||||
set_interrupt_gate(0, 34, &trap34);
|
||||
set_interrupt_gate(0, 35, &trap35);
|
||||
set_interrupt_gate(0, 36, &trap36);
|
||||
set_interrupt_gate(0, 37, &trap37);
|
||||
set_interrupt_gate(0, 38, &trap38);
|
||||
set_interrupt_gate(0, 39, &trap39);
|
||||
set_interrupt_gate(0, 40, &trap40);
|
||||
set_interrupt_gate(0, 41, &trap41);
|
||||
set_interrupt_gate(0, 42, &trap42);
|
||||
set_interrupt_gate(0, 43, &trap43);
|
||||
set_interrupt_gate(0, 44, &trap44);
|
||||
set_interrupt_gate(0, 45, &trap45);
|
||||
set_interrupt_gate(0, 46, &trap46);
|
||||
set_interrupt_gate(0, 47, &trap47);
|
||||
|
||||
// additional ioapic interrupts
|
||||
set_interrupt_gate(0, 48, &trap48);
|
||||
set_interrupt_gate(0, 49, &trap49);
|
||||
set_interrupt_gate(0, 50, &trap50);
|
||||
set_interrupt_gate(0, 51, &trap51);
|
||||
set_interrupt_gate(0, 52, &trap52);
|
||||
set_interrupt_gate(0, 53, &trap53);
|
||||
set_interrupt_gate(0, 54, &trap54);
|
||||
set_interrupt_gate(0, 55, &trap55);
|
||||
|
||||
// configurable msi or msi-x interrupts
|
||||
set_interrupt_gate(0, 56, &trap56);
|
||||
set_interrupt_gate(0, 57, &trap57);
|
||||
set_interrupt_gate(0, 58, &trap58);
|
||||
set_interrupt_gate(0, 59, &trap59);
|
||||
set_interrupt_gate(0, 60, &trap60);
|
||||
set_interrupt_gate(0, 61, &trap61);
|
||||
set_interrupt_gate(0, 62, &trap62);
|
||||
set_interrupt_gate(0, 63, &trap63);
|
||||
set_interrupt_gate(0, 64, &trap64);
|
||||
set_interrupt_gate(0, 65, &trap65);
|
||||
set_interrupt_gate(0, 66, &trap66);
|
||||
set_interrupt_gate(0, 67, &trap67);
|
||||
set_interrupt_gate(0, 68, &trap68);
|
||||
set_interrupt_gate(0, 69, &trap69);
|
||||
set_interrupt_gate(0, 70, &trap70);
|
||||
set_interrupt_gate(0, 71, &trap71);
|
||||
set_interrupt_gate(0, 72, &trap72);
|
||||
set_interrupt_gate(0, 73, &trap73);
|
||||
set_interrupt_gate(0, 74, &trap74);
|
||||
set_interrupt_gate(0, 75, &trap75);
|
||||
set_interrupt_gate(0, 76, &trap76);
|
||||
set_interrupt_gate(0, 77, &trap77);
|
||||
set_interrupt_gate(0, 78, &trap78);
|
||||
set_interrupt_gate(0, 79, &trap79);
|
||||
set_interrupt_gate(0, 80, &trap80);
|
||||
set_interrupt_gate(0, 81, &trap81);
|
||||
set_interrupt_gate(0, 82, &trap82);
|
||||
set_interrupt_gate(0, 83, &trap83);
|
||||
set_interrupt_gate(0, 84, &trap84);
|
||||
set_interrupt_gate(0, 85, &trap85);
|
||||
set_interrupt_gate(0, 86, &trap86);
|
||||
set_interrupt_gate(0, 87, &trap87);
|
||||
set_interrupt_gate(0, 88, &trap88);
|
||||
set_interrupt_gate(0, 89, &trap89);
|
||||
set_interrupt_gate(0, 90, &trap90);
|
||||
set_interrupt_gate(0, 91, &trap91);
|
||||
set_interrupt_gate(0, 92, &trap92);
|
||||
set_interrupt_gate(0, 93, &trap93);
|
||||
set_interrupt_gate(0, 94, &trap94);
|
||||
set_interrupt_gate(0, 95, &trap95);
|
||||
set_interrupt_gate(0, 96, &trap96);
|
||||
set_interrupt_gate(0, 97, &trap97);
|
||||
|
||||
set_trap_gate(0, 98, &trap98); // for performance testing only
|
||||
set_trap_gate(0, 99, &trap99); // syscall interrupt
|
||||
|
||||
reserve_io_interrupt_vectors(2, 98);
|
||||
|
||||
// configurable msi or msi-x interrupts
|
||||
set_interrupt_gate(0, 100, &trap100);
|
||||
set_interrupt_gate(0, 101, &trap101);
|
||||
set_interrupt_gate(0, 102, &trap102);
|
||||
set_interrupt_gate(0, 103, &trap103);
|
||||
set_interrupt_gate(0, 104, &trap104);
|
||||
set_interrupt_gate(0, 105, &trap105);
|
||||
set_interrupt_gate(0, 106, &trap106);
|
||||
set_interrupt_gate(0, 107, &trap107);
|
||||
set_interrupt_gate(0, 108, &trap108);
|
||||
set_interrupt_gate(0, 109, &trap109);
|
||||
set_interrupt_gate(0, 110, &trap110);
|
||||
set_interrupt_gate(0, 111, &trap111);
|
||||
set_interrupt_gate(0, 112, &trap112);
|
||||
set_interrupt_gate(0, 113, &trap113);
|
||||
set_interrupt_gate(0, 114, &trap114);
|
||||
set_interrupt_gate(0, 115, &trap115);
|
||||
set_interrupt_gate(0, 116, &trap116);
|
||||
set_interrupt_gate(0, 117, &trap117);
|
||||
set_interrupt_gate(0, 118, &trap118);
|
||||
set_interrupt_gate(0, 119, &trap119);
|
||||
set_interrupt_gate(0, 120, &trap120);
|
||||
set_interrupt_gate(0, 121, &trap121);
|
||||
set_interrupt_gate(0, 122, &trap122);
|
||||
set_interrupt_gate(0, 123, &trap123);
|
||||
set_interrupt_gate(0, 124, &trap124);
|
||||
set_interrupt_gate(0, 125, &trap125);
|
||||
set_interrupt_gate(0, 126, &trap126);
|
||||
set_interrupt_gate(0, 127, &trap127);
|
||||
set_interrupt_gate(0, 128, &trap128);
|
||||
set_interrupt_gate(0, 129, &trap129);
|
||||
set_interrupt_gate(0, 130, &trap130);
|
||||
set_interrupt_gate(0, 131, &trap131);
|
||||
set_interrupt_gate(0, 132, &trap132);
|
||||
set_interrupt_gate(0, 133, &trap133);
|
||||
set_interrupt_gate(0, 134, &trap134);
|
||||
set_interrupt_gate(0, 135, &trap135);
|
||||
set_interrupt_gate(0, 136, &trap136);
|
||||
set_interrupt_gate(0, 137, &trap137);
|
||||
set_interrupt_gate(0, 138, &trap138);
|
||||
set_interrupt_gate(0, 139, &trap139);
|
||||
set_interrupt_gate(0, 140, &trap140);
|
||||
set_interrupt_gate(0, 141, &trap141);
|
||||
set_interrupt_gate(0, 142, &trap142);
|
||||
set_interrupt_gate(0, 143, &trap143);
|
||||
set_interrupt_gate(0, 144, &trap144);
|
||||
set_interrupt_gate(0, 145, &trap145);
|
||||
set_interrupt_gate(0, 146, &trap146);
|
||||
set_interrupt_gate(0, 147, &trap147);
|
||||
set_interrupt_gate(0, 148, &trap148);
|
||||
set_interrupt_gate(0, 149, &trap149);
|
||||
set_interrupt_gate(0, 150, &trap150);
|
||||
set_interrupt_gate(0, 151, &trap151);
|
||||
set_interrupt_gate(0, 152, &trap152);
|
||||
set_interrupt_gate(0, 153, &trap153);
|
||||
set_interrupt_gate(0, 154, &trap154);
|
||||
set_interrupt_gate(0, 155, &trap155);
|
||||
set_interrupt_gate(0, 156, &trap156);
|
||||
set_interrupt_gate(0, 157, &trap157);
|
||||
set_interrupt_gate(0, 158, &trap158);
|
||||
set_interrupt_gate(0, 159, &trap159);
|
||||
set_interrupt_gate(0, 160, &trap160);
|
||||
set_interrupt_gate(0, 161, &trap161);
|
||||
set_interrupt_gate(0, 162, &trap162);
|
||||
set_interrupt_gate(0, 163, &trap163);
|
||||
set_interrupt_gate(0, 164, &trap164);
|
||||
set_interrupt_gate(0, 165, &trap165);
|
||||
set_interrupt_gate(0, 166, &trap166);
|
||||
set_interrupt_gate(0, 167, &trap167);
|
||||
set_interrupt_gate(0, 168, &trap168);
|
||||
set_interrupt_gate(0, 169, &trap169);
|
||||
set_interrupt_gate(0, 170, &trap170);
|
||||
set_interrupt_gate(0, 171, &trap171);
|
||||
set_interrupt_gate(0, 172, &trap172);
|
||||
set_interrupt_gate(0, 173, &trap173);
|
||||
set_interrupt_gate(0, 174, &trap174);
|
||||
set_interrupt_gate(0, 175, &trap175);
|
||||
set_interrupt_gate(0, 176, &trap176);
|
||||
set_interrupt_gate(0, 177, &trap177);
|
||||
set_interrupt_gate(0, 178, &trap178);
|
||||
set_interrupt_gate(0, 179, &trap179);
|
||||
set_interrupt_gate(0, 180, &trap180);
|
||||
set_interrupt_gate(0, 181, &trap181);
|
||||
set_interrupt_gate(0, 182, &trap182);
|
||||
set_interrupt_gate(0, 183, &trap183);
|
||||
set_interrupt_gate(0, 184, &trap184);
|
||||
set_interrupt_gate(0, 185, &trap185);
|
||||
set_interrupt_gate(0, 186, &trap186);
|
||||
set_interrupt_gate(0, 187, &trap187);
|
||||
set_interrupt_gate(0, 188, &trap188);
|
||||
set_interrupt_gate(0, 189, &trap189);
|
||||
set_interrupt_gate(0, 190, &trap190);
|
||||
set_interrupt_gate(0, 191, &trap191);
|
||||
set_interrupt_gate(0, 192, &trap192);
|
||||
set_interrupt_gate(0, 193, &trap193);
|
||||
set_interrupt_gate(0, 194, &trap194);
|
||||
set_interrupt_gate(0, 195, &trap195);
|
||||
set_interrupt_gate(0, 196, &trap196);
|
||||
set_interrupt_gate(0, 197, &trap197);
|
||||
set_interrupt_gate(0, 198, &trap198);
|
||||
set_interrupt_gate(0, 199, &trap199);
|
||||
set_interrupt_gate(0, 200, &trap200);
|
||||
set_interrupt_gate(0, 201, &trap201);
|
||||
set_interrupt_gate(0, 202, &trap202);
|
||||
set_interrupt_gate(0, 203, &trap203);
|
||||
set_interrupt_gate(0, 204, &trap204);
|
||||
set_interrupt_gate(0, 205, &trap205);
|
||||
set_interrupt_gate(0, 206, &trap206);
|
||||
set_interrupt_gate(0, 207, &trap207);
|
||||
set_interrupt_gate(0, 208, &trap208);
|
||||
set_interrupt_gate(0, 209, &trap209);
|
||||
set_interrupt_gate(0, 210, &trap210);
|
||||
set_interrupt_gate(0, 211, &trap211);
|
||||
set_interrupt_gate(0, 212, &trap212);
|
||||
set_interrupt_gate(0, 213, &trap213);
|
||||
set_interrupt_gate(0, 214, &trap214);
|
||||
set_interrupt_gate(0, 215, &trap215);
|
||||
set_interrupt_gate(0, 216, &trap216);
|
||||
set_interrupt_gate(0, 217, &trap217);
|
||||
set_interrupt_gate(0, 218, &trap218);
|
||||
set_interrupt_gate(0, 219, &trap219);
|
||||
set_interrupt_gate(0, 220, &trap220);
|
||||
set_interrupt_gate(0, 221, &trap221);
|
||||
set_interrupt_gate(0, 222, &trap222);
|
||||
set_interrupt_gate(0, 223, &trap223);
|
||||
set_interrupt_gate(0, 224, &trap224);
|
||||
set_interrupt_gate(0, 225, &trap225);
|
||||
set_interrupt_gate(0, 226, &trap226);
|
||||
set_interrupt_gate(0, 227, &trap227);
|
||||
set_interrupt_gate(0, 228, &trap228);
|
||||
set_interrupt_gate(0, 229, &trap229);
|
||||
set_interrupt_gate(0, 230, &trap230);
|
||||
set_interrupt_gate(0, 231, &trap231);
|
||||
set_interrupt_gate(0, 232, &trap232);
|
||||
set_interrupt_gate(0, 233, &trap233);
|
||||
set_interrupt_gate(0, 234, &trap234);
|
||||
set_interrupt_gate(0, 235, &trap235);
|
||||
set_interrupt_gate(0, 236, &trap236);
|
||||
set_interrupt_gate(0, 237, &trap237);
|
||||
set_interrupt_gate(0, 238, &trap238);
|
||||
set_interrupt_gate(0, 239, &trap239);
|
||||
set_interrupt_gate(0, 240, &trap240);
|
||||
set_interrupt_gate(0, 241, &trap241);
|
||||
set_interrupt_gate(0, 242, &trap242);
|
||||
set_interrupt_gate(0, 243, &trap243);
|
||||
set_interrupt_gate(0, 244, &trap244);
|
||||
set_interrupt_gate(0, 245, &trap245);
|
||||
set_interrupt_gate(0, 246, &trap246);
|
||||
set_interrupt_gate(0, 247, &trap247);
|
||||
set_interrupt_gate(0, 248, &trap248);
|
||||
set_interrupt_gate(0, 249, &trap249);
|
||||
set_interrupt_gate(0, 250, &trap250);
|
||||
|
||||
// smp / apic local interrupts
|
||||
set_interrupt_gate(0, 251, &trap251);
|
||||
set_interrupt_gate(0, 252, &trap252);
|
||||
set_interrupt_gate(0, 253, &trap253);
|
||||
set_interrupt_gate(0, 254, &trap254);
|
||||
set_interrupt_gate(0, 255, &trap255);
|
||||
|
||||
// init interrupt handler table
|
||||
table = gInterruptHandlerTable;
|
||||
|
||||
// defaults
|
||||
for (i = 0; i < ARCH_INTERRUPT_BASE; i++)
|
||||
table[i] = invalid_exception;
|
||||
for (i = ARCH_INTERRUPT_BASE; i < INTERRUPT_HANDLER_TABLE_SIZE; i++)
|
||||
table[i] = hardware_interrupt;
|
||||
|
||||
table[0] = unexpected_exception; // Divide Error Exception (#DE)
|
||||
table[1] = x86_handle_debug_exception; // Debug Exception (#DB)
|
||||
table[2] = fatal_exception; // NMI Interrupt
|
||||
table[3] = x86_handle_breakpoint_exception; // Breakpoint Exception (#BP)
|
||||
table[4] = unexpected_exception; // Overflow Exception (#OF)
|
||||
table[5] = unexpected_exception; // BOUND Range Exceeded Exception (#BR)
|
||||
table[6] = unexpected_exception; // Invalid Opcode Exception (#UD)
|
||||
table[7] = fatal_exception; // Device Not Available Exception (#NM)
|
||||
table[8] = x86_double_fault_exception; // Double Fault Exception (#DF)
|
||||
table[9] = fatal_exception; // Coprocessor Segment Overrun
|
||||
table[10] = fatal_exception; // Invalid TSS Exception (#TS)
|
||||
table[11] = fatal_exception; // Segment Not Present (#NP)
|
||||
table[12] = fatal_exception; // Stack Fault Exception (#SS)
|
||||
table[13] = unexpected_exception; // General Protection Exception (#GP)
|
||||
table[14] = page_fault_exception; // Page-Fault Exception (#PF)
|
||||
table[16] = unexpected_exception; // x87 FPU Floating-Point Error (#MF)
|
||||
table[17] = unexpected_exception; // Alignment Check Exception (#AC)
|
||||
table[18] = fatal_exception; // Machine-Check Exception (#MC)
|
||||
table[19] = unexpected_exception; // SIMD Floating-Point Exception (#XF)
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_int_init_post_vm(struct kernel_args *args)
|
||||
{
|
||||
// Always init the local apic as it can be used for timers even if we
|
||||
// don't end up using the io apic
|
||||
apic_init(args);
|
||||
|
||||
// create IDT area for the boot CPU
|
||||
area_id area = create_area("idt", (void**)&sIDTs[0], B_EXACT_ADDRESS,
|
||||
B_PAGE_SIZE, B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||
if (area < 0)
|
||||
return area;
|
||||
|
||||
// create IDTs for the off-boot CPU
|
||||
size_t idtSize = 256 * 8;
|
||||
// 256 8 bytes-sized descriptors
|
||||
int32 cpuCount = smp_get_num_cpus();
|
||||
if (cpuCount > 0) {
|
||||
size_t areaSize = ROUNDUP(cpuCount * idtSize, B_PAGE_SIZE);
|
||||
desc_table* idt;
|
||||
virtual_address_restrictions virtualRestrictions = {};
|
||||
virtualRestrictions.address_specification = B_ANY_KERNEL_ADDRESS;
|
||||
physical_address_restrictions physicalRestrictions = {};
|
||||
area = create_area_etc(B_SYSTEM_TEAM, "idt", areaSize, B_CONTIGUOUS,
|
||||
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, CREATE_AREA_DONT_WAIT,
|
||||
&virtualRestrictions, &physicalRestrictions, (void**)&idt);
|
||||
if (area < 0)
|
||||
return area;
|
||||
|
||||
for (int32 i = 1; i < cpuCount; i++) {
|
||||
sIDTs[i] = idt;
|
||||
memcpy(idt, sIDTs[0], idtSize);
|
||||
idt += 256;
|
||||
// The CPU's IDTR will be set in arch_cpu_init_percpu().
|
||||
}
|
||||
}
|
||||
|
||||
return area >= B_OK ? B_OK : area;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_int_init_io(kernel_args* args)
|
||||
{
|
||||
#ifndef __x86_64__
|
||||
ioapic_init(args);
|
||||
msi_init();
|
||||
#else
|
||||
panic("implement me");
|
||||
#endif
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
arch_int_init_post_device_manager(struct kernel_args *args)
|
||||
arch_int_init_post_device_manager(kernel_args* args)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
arch_int_set_interrupt_controller(const interrupt_controller &controller)
|
||||
arch_int_set_interrupt_controller(const interrupt_controller& controller)
|
||||
{
|
||||
sCurrentPIC = &controller;
|
||||
}
|
||||
|
||||
@@ -44,6 +44,11 @@ dummy()
|
||||
DEFINE_OFFSET_MACRO(THREAD, Thread, kernel_stack_top);
|
||||
DEFINE_OFFSET_MACRO(THREAD, Thread, fault_handler);
|
||||
|
||||
#ifdef __x86_64__
|
||||
// struct iframe
|
||||
DEFINE_SIZEOF_MACRO(IFRAME, iframe);
|
||||
DEFINE_OFFSET_MACRO(IFRAME, iframe, vector);
|
||||
#else
|
||||
// struct iframe
|
||||
DEFINE_SIZEOF_MACRO(IFRAME, iframe);
|
||||
DEFINE_OFFSET_MACRO(IFRAME, iframe, cs);
|
||||
@@ -58,6 +63,7 @@ dummy()
|
||||
// struct vm86_iframe
|
||||
DEFINE_SIZEOF_MACRO(VM86_IFRAME, vm86_iframe);
|
||||
DEFINE_OFFSET_MACRO(VM86_IFRAME, vm86_iframe, flags);
|
||||
#endif
|
||||
|
||||
// struct syscall_info
|
||||
DEFINE_SIZEOF_MACRO(SYSCALL_INFO, syscall_info);
|
||||
|
||||
Reference in New Issue
Block a user