mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 00:14:32 -08:00
Previously CPU statue was passed on the stack, but the compiler is allowed to clobber values passed to it on the stack in the SysV x86 ABI. So now leave the state on the stack but pass a pointer to it into the ISR functions.
276 lines
5.7 KiB
C++
276 lines
5.7 KiB
C++
#include <stdint.h>
|
|
|
|
#include "apic.h"
|
|
#include "console.h"
|
|
#include "cpu.h"
|
|
#include "debug.h"
|
|
#include "device_manager.h"
|
|
#include "gdt.h"
|
|
#include "interrupts.h"
|
|
#include "io.h"
|
|
#include "log.h"
|
|
#include "scheduler.h"
|
|
#include "syscall.h"
|
|
|
|
static const uint16_t PIC1 = 0x20;
|
|
static const uint16_t PIC2 = 0xa0;
|
|
|
|
extern "C" {
|
|
void _halt();
|
|
|
|
uintptr_t isr_handler(uintptr_t, cpu_state*);
|
|
uintptr_t irq_handler(uintptr_t, cpu_state*);
|
|
uintptr_t syscall_handler(uintptr_t, cpu_state);
|
|
|
|
#define ISR(i, name) extern void name ();
|
|
#define EISR(i, name) extern void name ();
|
|
#define UISR(i, name) extern void name ();
|
|
#define IRQ(i, q, name) extern void name ();
|
|
#include "interrupt_isrs.inc"
|
|
#undef IRQ
|
|
#undef UISR
|
|
#undef EISR
|
|
#undef ISR
|
|
}
|
|
|
|
isr
|
|
operator+(const isr &lhs, int rhs)
|
|
{
|
|
using under_t = std::underlying_type<isr>::type;
|
|
return static_cast<isr>(static_cast<under_t>(lhs) + rhs);
|
|
}
|
|
|
|
uint8_t
|
|
get_irq(unsigned vector)
|
|
{
|
|
switch (vector) {
|
|
#define ISR(i, name)
|
|
#define EISR(i, name)
|
|
#define UISR(i, name)
|
|
#define IRQ(i, q, name) case i : return q;
|
|
#include "interrupt_isrs.inc"
|
|
#undef IRQ
|
|
#undef UISR
|
|
#undef EISR
|
|
#undef ISR
|
|
|
|
default: return 0xff;
|
|
}
|
|
}
|
|
|
|
static void
|
|
disable_legacy_pic()
|
|
{
|
|
// Mask all interrupts
|
|
outb(PIC2+1, 0xfc);
|
|
outb(PIC1+1, 0xff);
|
|
|
|
// Start initialization sequence
|
|
outb(PIC1, 0x11); io_wait();
|
|
outb(PIC2, 0x11); io_wait();
|
|
|
|
// Remap into ignore ISRs
|
|
outb(PIC1+1, static_cast<uint8_t>(isr::isrIgnore0)); io_wait();
|
|
outb(PIC2+1, static_cast<uint8_t>(isr::isrIgnore8)); io_wait();
|
|
|
|
// Tell PICs about each other
|
|
outb(PIC1+1, 0x04); io_wait();
|
|
outb(PIC2+1, 0x02); io_wait();
|
|
}
|
|
|
|
static void
|
|
enable_serial_interrupts()
|
|
{
|
|
uint8_t ier = inb(COM1+1);
|
|
outb(COM1+1, ier | 0x1);
|
|
}
|
|
|
|
void
|
|
interrupts_init()
|
|
{
|
|
#define ISR(i, name) idt_set_entry(i, reinterpret_cast<uint64_t>(& name), 0x08, 0x8e);
|
|
#define EISR(i, name) idt_set_entry(i, reinterpret_cast<uint64_t>(& name), 0x08, 0x8e);
|
|
#define UISR(i, name) idt_set_entry(i, reinterpret_cast<uint64_t>(& name), 0x08, 0xee);
|
|
#define IRQ(i, q, name) idt_set_entry(i, reinterpret_cast<uint64_t>(& name), 0x08, 0x8e);
|
|
#include "interrupt_isrs.inc"
|
|
#undef IRQ
|
|
#undef UISR
|
|
#undef EISR
|
|
#undef ISR
|
|
|
|
disable_legacy_pic();
|
|
enable_serial_interrupts();
|
|
|
|
log::info(logs::boot, "Interrupts enabled.");
|
|
}
|
|
|
|
uintptr_t
|
|
isr_handler(uintptr_t return_rsp, cpu_state *regs)
|
|
{
|
|
console *cons = console::get();
|
|
|
|
switch (static_cast<isr>(regs->interrupt & 0xff)) {
|
|
|
|
case isr::isrGPFault: {
|
|
cons->set_color(9);
|
|
cons->puts("\nGeneral Protection Fault:\n");
|
|
cons->set_color();
|
|
|
|
cons->printf(" errorcode: %lx", regs->errorcode);
|
|
if (regs->errorcode & 0x01) cons->puts(" external");
|
|
|
|
int index = (regs->errorcode & 0xffff) >> 4;
|
|
if (index) {
|
|
switch ((regs->errorcode & 0x07) >> 1) {
|
|
case 0:
|
|
cons->printf(" GDT[%x]\n", index);
|
|
gdt_dump();
|
|
break;
|
|
|
|
case 1:
|
|
case 3:
|
|
cons->printf(" IDT[%x]\n", index);
|
|
idt_dump();
|
|
break;
|
|
|
|
default:
|
|
cons->printf(" LDT[%x]??\n", index);
|
|
break;
|
|
}
|
|
} else {
|
|
cons->putc('\n');
|
|
}
|
|
print_regs(*regs);
|
|
/*
|
|
print_stacktrace(2);
|
|
print_stack(*regs);
|
|
*/
|
|
|
|
}
|
|
_halt();
|
|
break;
|
|
|
|
case isr::isrPageFault: {
|
|
cons->set_color(11);
|
|
cons->puts("\nPage Fault:\n");
|
|
cons->set_color();
|
|
|
|
cons->puts(" flags:");
|
|
if (regs->errorcode & 0x01) cons->puts(" present");
|
|
if (regs->errorcode & 0x02) cons->puts(" write");
|
|
if (regs->errorcode & 0x04) cons->puts(" user");
|
|
if (regs->errorcode & 0x08) cons->puts(" reserved");
|
|
if (regs->errorcode & 0x10) cons->puts(" ip");
|
|
cons->puts("\n");
|
|
|
|
uint64_t cr2 = 0;
|
|
__asm__ __volatile__ ("mov %%cr2, %0" : "=r"(cr2));
|
|
print_reg("cr2", cr2);
|
|
|
|
print_reg("rsp", regs->user_rsp);
|
|
print_reg("rip", regs->rip);
|
|
|
|
cons->puts("\n");
|
|
print_stacktrace(2);
|
|
}
|
|
_halt();
|
|
break;
|
|
|
|
case isr::isrTimer: {
|
|
scheduler &s = scheduler::get();
|
|
return_rsp = s.tick(return_rsp);
|
|
}
|
|
break;
|
|
|
|
case isr::isrLINT0:
|
|
cons->puts("\nLINT0\n");
|
|
break;
|
|
|
|
case isr::isrLINT1:
|
|
cons->puts("\nLINT1\n");
|
|
break;
|
|
|
|
case isr::isrAssert: {
|
|
cons->set_color();
|
|
print_regs(*regs);
|
|
print_stacktrace(2);
|
|
}
|
|
_halt();
|
|
break;
|
|
|
|
case isr::isrSyscall: {
|
|
return_rsp = syscall_dispatch(return_rsp, *regs);
|
|
}
|
|
break;
|
|
|
|
case isr::isrSpurious:
|
|
// No EOI for the spurious interrupt
|
|
return return_rsp;
|
|
|
|
case isr::isrIgnore0:
|
|
case isr::isrIgnore1:
|
|
case isr::isrIgnore2:
|
|
case isr::isrIgnore3:
|
|
case isr::isrIgnore4:
|
|
case isr::isrIgnore5:
|
|
case isr::isrIgnore6:
|
|
case isr::isrIgnore7:
|
|
//cons->printf("\nIGNORED: %02x\n", regs->interrupt);
|
|
outb(PIC1, 0x20);
|
|
break;
|
|
|
|
case isr::isrIgnore8:
|
|
case isr::isrIgnore9:
|
|
case isr::isrIgnoreA:
|
|
case isr::isrIgnoreB:
|
|
case isr::isrIgnoreC:
|
|
case isr::isrIgnoreD:
|
|
case isr::isrIgnoreE:
|
|
case isr::isrIgnoreF:
|
|
//cons->printf("\nIGNORED: %02x\n", regs->interrupt);
|
|
outb(PIC1, 0x20);
|
|
outb(PIC2, 0x20);
|
|
break;
|
|
|
|
default:
|
|
cons->set_color(9);
|
|
cons->printf("\nReceived %02x interrupt:\n",
|
|
(static_cast<isr>(regs->interrupt)));
|
|
|
|
cons->set_color();
|
|
cons->printf(" ISR: %02lx ERR: %lx\n\n",
|
|
regs->interrupt, regs->errorcode);
|
|
|
|
print_regs(*regs);
|
|
//print_stacktrace(2);
|
|
_halt();
|
|
}
|
|
*reinterpret_cast<uint32_t *>(0xffffff80fee000b0) = 0;
|
|
|
|
return return_rsp;
|
|
}
|
|
|
|
uintptr_t
|
|
irq_handler(uintptr_t return_rsp, cpu_state *regs)
|
|
{
|
|
console *cons = console::get();
|
|
uint8_t irq = get_irq(regs->interrupt);
|
|
if (! device_manager::get().dispatch_irq(irq)) {
|
|
cons->set_color(11);
|
|
cons->printf("\nReceived unknown IRQ: %d (vec %d)\n",
|
|
irq, regs->interrupt);
|
|
cons->set_color();
|
|
print_regs(*regs);
|
|
_halt();
|
|
}
|
|
|
|
*reinterpret_cast<uint32_t *>(0xffffff80fee000b0) = 0;
|
|
return return_rsp;
|
|
}
|
|
|
|
uintptr_t
|
|
syscall_handler(uintptr_t return_rsp, cpu_state regs)
|
|
{
|
|
return syscall_dispatch(return_rsp, regs);
|
|
}
|