SMP and timer interrupts
This commit is contained in:
@@ -1,9 +1,13 @@
|
||||
#include <amd64/apic.h>
|
||||
#include <amd64/intr.h>
|
||||
#include <amd64/io.h>
|
||||
#include <aux/compiler.h>
|
||||
#include <irq/irq.h>
|
||||
#include <libk/std.h>
|
||||
#include <libk/string.h>
|
||||
#include <sys/debug.h>
|
||||
#include <sys/irq.h>
|
||||
#include <sys/smp.h>
|
||||
|
||||
/* 8259 PIC defs. */
|
||||
#define PIC1 0x20
|
||||
@@ -77,20 +81,23 @@ static void amd64_init_pic (void) {
|
||||
#undef IO_OP
|
||||
}
|
||||
|
||||
static void amd64_idt_set (volatile struct idt_entry* ent, uint64_t handler, uint8_t flags, uint8_t ist) {
|
||||
static void amd64_idt_set (volatile struct idt_entry* ent, uint64_t handler, uint8_t flags,
|
||||
uint8_t ist) {
|
||||
ent->intrlow = (handler & 0xFFFF);
|
||||
ent->kernel_cs = 0x08; // GDT_KCODE (init.c)
|
||||
ent->ist = 0;
|
||||
ent->ist = ist;
|
||||
ent->attrs = flags;
|
||||
ent->intrmid = ((handler >> 16) & 0xFFFF);
|
||||
ent->intrhigh = ((handler >> 32) & 0xFFFFFFFF);
|
||||
ent->resv = 0;
|
||||
}
|
||||
|
||||
void amd64_load_idt (void) { __asm__ volatile ("lidt %0" ::"m"(idt)); }
|
||||
|
||||
static void amd64_idt_init (void) {
|
||||
memset ((void*)idt_entries, 0, sizeof (idt_entries));
|
||||
|
||||
#define IDT_ENTRY(n, ist) \
|
||||
#define IDT_ENTRY(n, ist) \
|
||||
extern void amd64_intr##n (void); \
|
||||
amd64_idt_set (&idt_entries[(n)], (uint64_t)&amd64_intr##n, 0x8E, (ist))
|
||||
IDT_ENTRY (0, 0);
|
||||
@@ -146,8 +153,7 @@ static void amd64_idt_init (void) {
|
||||
idt.limit = sizeof (idt_entries) - 1;
|
||||
idt.base = (uint64_t)idt_entries;
|
||||
|
||||
__asm__ volatile ("lidt %0" ::"m"(idt));
|
||||
__asm__ volatile ("sti");
|
||||
amd64_load_idt ();
|
||||
}
|
||||
|
||||
static void amd64_intr_exception (struct saved_regs* regs) {
|
||||
@@ -179,6 +185,14 @@ void amd64_intr_handler (void* stack_ptr) {
|
||||
|
||||
if (regs->trap <= 31) {
|
||||
amd64_intr_exception (regs);
|
||||
} else if (regs->trap >= 32) {
|
||||
amd64_lapic_eoi ();
|
||||
|
||||
__asm__ volatile ("sti");
|
||||
|
||||
irq_invoke_each (regs->trap);
|
||||
|
||||
__asm__ volatile ("cli");
|
||||
} else {
|
||||
DEBUG ("unknown trap %lu\n", regs->trap);
|
||||
}
|
||||
@@ -188,3 +202,36 @@ void amd64_intr_init (void) {
|
||||
amd64_init_pic ();
|
||||
amd64_idt_init ();
|
||||
}
|
||||
|
||||
/* Aux. */
|
||||
|
||||
static uint64_t amd64_irq_save_flags (void) {
|
||||
uint64_t rflags;
|
||||
__asm__ volatile ("pushfq; cli; popq %0" : "=r"(rflags)::"memory", "cc");
|
||||
return rflags;
|
||||
}
|
||||
|
||||
static void amd64_irq_restore_flags (uint64_t rflags) {
|
||||
if (rflags & (1ULL << 9))
|
||||
__asm__ volatile ("sti");
|
||||
}
|
||||
|
||||
void irq_save (void) {
|
||||
/* before smp init. */
|
||||
if (thiscpu == NULL)
|
||||
return;
|
||||
|
||||
int prev = atomic_fetch_add_explicit (&thiscpu->irq_ctx.nesting, 1, memory_order_acq_rel);
|
||||
if (prev == 0)
|
||||
thiscpu->irq_ctx.rflags = amd64_irq_save_flags ();
|
||||
}
|
||||
|
||||
void irq_restore (void) {
|
||||
/* before smp init. */
|
||||
if (thiscpu == NULL)
|
||||
return;
|
||||
|
||||
int prev = atomic_fetch_sub_explicit (&thiscpu->irq_ctx.nesting, 1, memory_order_acq_rel);
|
||||
if (prev == 1)
|
||||
amd64_irq_restore_flags (thiscpu->irq_ctx.rflags);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user