diff --git a/kernel-src/arch/x86-64/cpu.c b/kernel-src/arch/x86-64/cpu.c index 75559e75..f6951a56 100644 --- a/kernel-src/arch/x86-64/cpu.c +++ b/kernel-src/arch/x86-64/cpu.c @@ -9,6 +9,7 @@ #include #include #include +#include #define EFER_SYSCALLENABLE 1 @@ -45,6 +46,27 @@ static void x87isr(isr_t *self, context_t *ctx) { } } +void arch_nmi_isr(context_t *ctx) { + // we are in an NMI context, running on IST0 + // first load the proper gsbase to get access to cpu-local variables. + // the pointer to cpu's data is at the beggining of the stack so after the context struct. + uint64_t old_gsbase = rdmsr(MSR_GSBASE); + wrmsr(MSR_GSBASE, *(uint64_t *)(ctx + 1)); + + bool handled = false; + +#ifdef ENABLE_PROFILING + if (arch_profiling_irq(ctx)) + handled = true; +#endif + + if (!handled) + _panic("Unhandled NMI", ctx); + + // restore the old gsbase + wrmsr(MSR_GSBASE, old_gsbase); +} + #define TOPOLOGY_TYPE_THREAD 1 #define TOPOLOGY_TYPE_CORE 2 #define TOPOLOGY_TYPE_PACKAGE 0xffffffff @@ -237,6 +259,15 @@ void arch_cpu_init() { } current_cpu()->topology_node = topology_nodes[topology_depth - 1]; + + // allocate ists + uint64_t *ist1 = vmm_map(NULL, PAGE_SIZE * 4, VMM_FLAGS_ALLOCATE, ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC, NULL); + __assert(ist1); + + // the cpu automatically aligns to 16 bytes when pushing the interrupt frame, so save ourselves the trouble: + ist1 += PAGE_SIZE * 4 / sizeof(uint64_t) - 2; + *ist1 = (uint64_t)current_cpu(); + current_cpu()->ist.ist1 = (uint64_t)ist1; } INIT_ROUTINE_DEFINE(cpu, INIT_ROUTINE_FLAGS_NONE, arch_cpu_init, acpi_early); diff --git a/kernel-src/arch/x86-64/idt.c b/kernel-src/arch/x86-64/idt.c index 96451671..47f6920e 100644 --- a/kernel-src/arch/x86-64/idt.c +++ b/kernel-src/arch/x86-64/idt.c @@ -29,16 +29,18 @@ static idtr_t idtr = { .offset = (uint64_t)idt }; +void asm_nmi_handler(); extern const uint64_t isr_table[256]; void arch_idt_setup() { for (int i = 0; i < 256; ++i) { - idt[i].offset = isr_table[i] & 0xffff; + uint64_t addr = i == 2 ? (uint64_t)asm_nmi_handler : isr_table[i]; + idt[i].offset = addr & 0xffff; idt[i].segment = 0x8; - idt[i].ist = 0; + idt[i].ist = i == 2 ? 1 : 0; idt[i].flags = 0x8e; - idt[i].offset2 = (isr_table[i] >> 16) & 0xffff; - idt[i].offset3 = (isr_table[i] >> 32) & 0xffffffff; + idt[i].offset2 = (addr >> 16) & 0xffff; + idt[i].offset3 = (addr >> 32) & 0xffffffff; } } diff --git a/kernel-src/arch/x86-64/isr.asm b/kernel-src/arch/x86-64/isr.asm index 7dce6d33..b30ebc08 100644 --- a/kernel-src/arch/x86-64/isr.asm +++ b/kernel-src/arch/x86-64/isr.asm @@ -57,6 +57,9 @@ isr_common: mov rdi, rbp ; vec mov rsi, rsp ; ctx + ; set this as the end of the stack frame + xor rbp, rbp + cld extern interrupt_isr call interrupt_isr @@ -93,6 +96,78 @@ isr_common: .notneeded2: o64 iret +global asm_nmi_handler +asm_nmi_handler: + sub rsp, 8 ; error code, unused for nmi + push rbp + sub rsp, 8 ; vec number, unused for nmi + push rsi + push rdi + push r15 + push r14 + push r13 + push r12 + push r11 + push r10 + push r9 + push r8 + push rdx + push rcx + push rbx + push rax + mov rax, ds + push rax + mov rax, es + push rax + mov rax, fs + push rax + mov rax, gs + push rax + mov rdi,cr2 + push rdi + + ; set up kernel segments + mov rdi, 0x10 + mov ds, rdi + mov es, rdi + + ; save ctx pointer + mov rdi, rsp + + ; set this as the end of the stack frame + xor rbp, rbp + + cld + extern arch_nmi_isr + call arch_nmi_isr + cli + + ; pop context + add rsp, 24 ; cr2 gs and fs are not popped. + pop rax + mov es,rax + pop rax + mov ds,rax + pop rax + pop rbx + pop rcx + pop rdx + pop r8 + pop r9 + pop r10 + pop r11 + pop r12 + pop r13 + pop r14 + pop r15 + pop rdi + pop rsi + add rsp, 8 ; vector num, unused for nmi + pop rbp + add rsp, 8 ; error code, unused for nmi + + o64 iret + section .rodata global isr_table isr_table: diff --git a/kernel-src/arch/x86-64/syscall.asm b/kernel-src/arch/x86-64/syscall.asm index ab344259..d72c4875 100644 --- a/kernel-src/arch/x86-64/syscall.asm +++ b/kernel-src/arch/x86-64/syscall.asm @@ -273,6 +273,9 @@ arch_syscall_entry: mov rdx, rsi mov rsi, rdi + ; set this as the end of the stack frame + xor rbp, rbp + ; call logging function sti