x86_64: init local apic on boot, or legacy pic/pit as fallback
This commit is contained in:
@@ -63,6 +63,7 @@ extern void syscall_gate();
|
||||
extern uintptr_t pf_faultptr(void);
|
||||
|
||||
static int_hook isr_handlers[NR_IDT_ENTRIES];
|
||||
static queue_t irq_hooks[32];
|
||||
|
||||
static struct idt idt;
|
||||
static int idt_initialised = 0;
|
||||
@@ -86,7 +87,7 @@ static void gpf_handler(struct cpu_context *regs)
|
||||
int ext = regs->err_no & 1;
|
||||
int table = (regs->err_no >> 1) & 2;
|
||||
int index = (regs->err_no >> 3) & 13;
|
||||
|
||||
|
||||
printk("general protection fault (%08x %08x %08x %016llx)", ext, table, index, regs->rip);
|
||||
ml_halt_cpu();
|
||||
}
|
||||
@@ -103,23 +104,21 @@ static void set_syscall_gate(uintptr_t rip)
|
||||
/* sysret adds 0x10 to this to get cs, and 0x8 to get ss
|
||||
* note that the CPU should force the RPL to 3 when loading
|
||||
* the selector by using user_cs | 3. However, this doesn't happen
|
||||
* in certain scenarios (specifically, QEMU + KVM on a Ryzen 5 1600X).
|
||||
* It's probably a Magenta bug, but just in case it's not,
|
||||
* we perform the RPL OR ourselves */
|
||||
* in certain scenarios (specifically, QEMU + KVM on a Ryzen 5 1600X). */
|
||||
uint64_t user_cs = 0x13;
|
||||
uint64_t kernel_cs = 0x8;
|
||||
|
||||
|
||||
uintptr_t star_reg = 0xC0000081;
|
||||
uintptr_t lstar_reg = 0xC0000082;
|
||||
uintptr_t sfmask_reg = 0xC0000084;
|
||||
|
||||
|
||||
uint64_t selectors = 0;
|
||||
selectors |= (user_cs) << 48;
|
||||
selectors |= (kernel_cs) << 32;
|
||||
|
||||
|
||||
/* disable interrupts */
|
||||
uint64_t flag_mask = 0x200;
|
||||
|
||||
|
||||
write_msr(star_reg, selectors);
|
||||
write_msr(lstar_reg, rip);
|
||||
write_msr(sfmask_reg, flag_mask);
|
||||
@@ -139,7 +138,7 @@ static void init_pic()
|
||||
outportb(0xA1, 0x01);
|
||||
outportb(0x21, 0x0);
|
||||
outportb(0xA1, 0x0);
|
||||
|
||||
|
||||
isr_handlers[13] = gpf_handler;
|
||||
isr_handlers[14] = pf_handler;
|
||||
}
|
||||
@@ -147,7 +146,7 @@ static void init_pic()
|
||||
static void init_global_idt(void)
|
||||
{
|
||||
memset((void *)&idt.i_entries, 0, sizeof idt.i_entries);
|
||||
|
||||
|
||||
set_idt_gate(&idt, 0, (uintptr_t)_isr0, 0x08, 0x8E);
|
||||
set_idt_gate(&idt, 1, (uintptr_t)_isr1, 0x08, 0x8E);
|
||||
set_idt_gate(&idt, 2, (uintptr_t)_isr2, 0x08, 0x8E);
|
||||
@@ -180,9 +179,9 @@ static void init_global_idt(void)
|
||||
set_idt_gate(&idt, 29, (uintptr_t)_isr29, 0x08, 0x8E);
|
||||
set_idt_gate(&idt, 30, (uintptr_t)_isr30, 0x08, 0x8E);
|
||||
set_idt_gate(&idt, 31, (uintptr_t)_isr31, 0x08, 0x8E);
|
||||
|
||||
|
||||
init_pic();
|
||||
|
||||
|
||||
// Install the IRQs
|
||||
set_idt_gate(&idt, 32, (uintptr_t)_irq0, 0x08, 0x8E);
|
||||
set_idt_gate(&idt, 33, (uintptr_t)_irq1, 0x08, 0x8E);
|
||||
@@ -209,10 +208,10 @@ int idt_init(struct idt_ptr *ptr)
|
||||
if (idt_initialised == 0) {
|
||||
init_global_idt();
|
||||
}
|
||||
|
||||
|
||||
ptr->i_limit = sizeof(idt) - 1;
|
||||
ptr->i_base = (uintptr_t)&idt;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -235,8 +234,13 @@ void irq_dispatch(struct cpu_context *regs)
|
||||
if (regs->int_no >= 40) {
|
||||
outportb(0xA0, 0x20);
|
||||
}
|
||||
|
||||
|
||||
outportb(0x20, 0x20);
|
||||
|
||||
queue_t *hooks = &irq_hooks[regs->int_no - IRQ0];
|
||||
queue_foreach(irq_hook_t, hook, hooks, irq_entry) {
|
||||
hook->irq_callback();
|
||||
}
|
||||
}
|
||||
|
||||
void syscall_dispatch(struct cpu_context *regs)
|
||||
@@ -253,3 +257,9 @@ void ml_int_disable()
|
||||
{
|
||||
asm volatile("cli");
|
||||
}
|
||||
|
||||
void hook_irq(irq_vector_t vec, irq_hook_t *hook)
|
||||
{
|
||||
queue_t *hook_queue = &irq_hooks[vec - IRQ0];
|
||||
queue_push_back(hook_queue, &hook->irq_entry);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user