From 51aca35fe3cf86fc9652a20a3e6ae23553f27665 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Mon, 15 Sep 2025 07:24:05 -0400 Subject: kern/amd64: Add exception handlers Signed-off-by: Ian Moffett --- src/sys/arch/amd64/cpu/cpu_conf.c | 24 ++++++ src/sys/arch/amd64/cpu/trap.S | 103 +++++++++++++++++++++++++ src/sys/arch/amd64/cpu/trap.c | 157 ++++++++++++++++++++++++++++++++++++++ src/sys/include/arch/amd64/trap.h | 68 +++++++++++++++++ 4 files changed, 352 insertions(+) create mode 100644 src/sys/arch/amd64/cpu/trap.S create mode 100644 src/sys/arch/amd64/cpu/trap.c create mode 100644 src/sys/include/arch/amd64/trap.h diff --git a/src/sys/arch/amd64/cpu/cpu_conf.c b/src/sys/arch/amd64/cpu/cpu_conf.c index 9399973..de0e9bc 100644 --- a/src/sys/arch/amd64/cpu/cpu_conf.c +++ b/src/sys/arch/amd64/cpu/cpu_conf.c @@ -30,11 +30,35 @@ #include #include #include +#include +#include + +/* + * Initialize interrupt vectors + */ +static void +init_vectors(void) +{ + idt_set_desc(0x0, IDT_TRAP_GATE, ISR(arith_err), 0); + idt_set_desc(0x2, IDT_TRAP_GATE, ISR(nmi), 0); + idt_set_desc(0x3, IDT_TRAP_GATE, ISR(breakpoint_handler), 0); + idt_set_desc(0x4, IDT_TRAP_GATE, ISR(overflow), 0); + idt_set_desc(0x5, IDT_TRAP_GATE, ISR(bound_range), 0); + idt_set_desc(0x6, IDT_TRAP_GATE, ISR(invl_op), 0); + idt_set_desc(0x8, IDT_TRAP_GATE, ISR(double_fault), 0); + idt_set_desc(0xA, IDT_TRAP_GATE, ISR(invl_tss), 0); + idt_set_desc(0xB, IDT_TRAP_GATE, ISR(segnp), 0); + idt_set_desc(0xC, IDT_TRAP_GATE, ISR(ss_fault), 0); + idt_set_desc(0xD, IDT_TRAP_GATE, ISR(general_prot), 0); + idt_set_desc(0xE, IDT_TRAP_GATE, ISR(page_fault), 0); +} void cpu_conf(struct pcore *pcore) { pcore->self = pcore; + init_vectors(); + idt_load(); platform_boot(); /* We use %GS to store the processor */ diff --git a/src/sys/arch/amd64/cpu/trap.S b/src/sys/arch/amd64/cpu/trap.S new file mode 100644 index 0000000..fb756e8 --- /dev/null +++ b/src/sys/arch/amd64/cpu/trap.S @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2025 Ian Marco Moffett and L5 engineers + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + + .globl breakpoint_handler +TRAP_ENTRY(breakpoint_handler, $TRAP_BREAKPOINT) + mov %rsp, %rdi + call trap_handler +TRAP_EXIT(breakpoint_handler) + + .globl arith_err +TRAP_ENTRY(arith_err, $TRAP_ARITH_ERR) + mov %rsp, %rdi + call trap_handler +TRAP_EXIT(arith_err) + + .globl overflow +TRAP_ENTRY(overflow, $TRAP_OVERFLOW) + mov %rsp, %rdi + call trap_handler +TRAP_EXIT(overflow) + + .globl bound_range +TRAP_ENTRY(bound_range, $TRAP_BOUND_RANGE) + mov %rsp, %rdi + call trap_handler +TRAP_EXIT(bound_range) + + .globl invl_op +TRAP_ENTRY(invl_op, $TRAP_INVLOP) + mov %rsp, %rdi + call trap_handler +TRAP_EXIT(invl_op) + + .globl double_fault +TRAP_ENTRY_EC(double_fault, $TRAP_DOUBLE_FAULT) + mov %rsp, %rdi + call trap_handler +TRAP_EXIT_EC(double_fault) + + .globl invl_tss +TRAP_ENTRY_EC(invl_tss, $TRAP_INVLTSS) + mov %rsp, %rdi + call trap_handler +TRAP_EXIT_EC(invl_tss) + + .globl segnp +TRAP_ENTRY_EC(segnp, $TRAP_SEGNP) + mov %rsp, %rdi + call trap_handler +TRAP_EXIT_EC(segnp) + + .globl general_prot +TRAP_ENTRY_EC(general_prot, $TRAP_PROTFLT) + mov %rsp, %rdi + call trap_handler +TRAP_EXIT_EC(general_prot) + + .globl page_fault +TRAP_ENTRY_EC(page_fault, $TRAP_PAGEFLT) + mov %rsp, %rdi + call trap_handler +TRAP_EXIT_EC(page_fault) + + .globl nmi +TRAP_ENTRY(nmi, $TRAP_NMI) + mov %rsp, %rdi + call trap_handler +TRAP_EXIT(nmi) + + .globl ss_fault +TRAP_ENTRY_EC(ss_fault, $TRAP_SS) + mov %rsp, %rdi + call trap_handler +TRAP_EXIT_EC(ss_fault) diff --git a/src/sys/arch/amd64/cpu/trap.c b/src/sys/arch/amd64/cpu/trap.c new file mode 100644 index 0000000..046263b --- /dev/null +++ b/src/sys/arch/amd64/cpu/trap.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2025 Ian Marco Moffett and L5 engineers + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Description: AMD64 trap handling module + * Author: Ian Marco Moffett + */ + +#include +#include +#include +#include +#include + +/* + * Trap type to type string conversion table + * Indexed by trapno field in trapframe. + */ +static const char *trapstr[] = { + [TRAP_NONE] = "bad", + [TRAP_BREAKPOINT] = "breakpoint", + [TRAP_ARITH_ERR] = "arithmetic error", + [TRAP_OVERFLOW] = "overflow", + [TRAP_BOUND_RANGE] = "bound range exceeded", + [TRAP_INVLOP] = "invalid opcode", + [TRAP_DOUBLE_FAULT] = "double fault", + [TRAP_INVLTSS] = "invalid TSS", + [TRAP_SEGNP] = "segment not present", + [TRAP_PROTFLT] = "general protection", + [TRAP_PAGEFLT] = "page fault", + [TRAP_NMI] = "non-maskable interrupt", + [TRAP_SS] = "stack-segment fault" +}; + +/* + * Page fault flags (bit relative) + */ +static const char pf_flags[] = { + 'p', /* Present */ + 'w', /* Write */ + 'u', /* User */ + 'r', /* Reserved write */ + 'x', /* Instruction fetch */ + 'k', /* Protection key violation */ + 's' /* Shadow stack access */ +}; + +/* + * Return the current value of the page fault address + * register (CR2) + */ +static inline uintptr_t +pf_faultaddr(void) +{ + uintptr_t cr2; + + __ASMV( + "mov %%cr2, %0\n" + : "=r" (cr2) + : + : "memory" + ); + return cr2; +} + +/* + * Log the error code for page faults + * + * @error_code: Page fault error code to log + */ +static void +pf_code(uint64_t error_code) +{ + char tab[8] = { + '-', '-', '-', + '-', '-', '-', + '-', '\0' + }; + + for (int i = 0; i < 7; ++i) { + if (ISSET(error_code, BIT(i))) { + tab[i] = pf_flags[i]; + } + } + + printf("code=[%s]\n", tab); +} + +/* + * Dump a trapframe + * + * @tf: Trapframe to dump + */ +static inline void +trapframe_dump(struct trapframe *tf) +{ + uintptr_t cr3, cr2 = pf_faultaddr(); + + __ASMV("mov %%cr3, %0\n" + : "=r" (cr3) + : + : "memory" + ); + + if (tf->trapno == TRAP_PAGEFLT) { + pf_code(tf->error_code); + } + + printf("got trap (%s)\n\n" + "-- DUMPING PROCESSOR STATE --\n" + "RAX=%p RCX=%p RDX=%p\n" + "RBX=%p RSI=%p RDI=%p\n" + "RFL=%p CR2=%p CR3=%p\n" + "RBP=%p RSP=%p RIP=%p\n\n", + trapstr[tf->trapno], + tf->rax, tf->rcx, tf->rdx, + tf->rbx, tf->rsi, tf->rdi, + tf->rflags, cr2, cr3, + tf->rbp, tf->rsp, tf->rip); +} + +void +trap_handler(struct trapframe *tf) +{ + trapframe_dump(tf); + if (ISSET(tf->cs, 3)) { + panic("fatal user trap\n"); + } + + panic("fatal trap\n"); +} diff --git a/src/sys/include/arch/amd64/trap.h b/src/sys/include/arch/amd64/trap.h new file mode 100644 index 0000000..53f38e8 --- /dev/null +++ b/src/sys/include/arch/amd64/trap.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2025 Ian Marco Moffett and L5 engineers + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MACHINE_TRAP_H_ +#define _MACHINE_TRAP_H_ + +#if !defined(__ASSEMBLER__) +#include +#endif + +#define TRAP_NONE 0 /* Used for general interrupts */ +#define TRAP_BREAKPOINT 1 /* Breakpoint */ +#define TRAP_ARITH_ERR 2 /* Arithmetic error (e.g division by 0) */ +#define TRAP_OVERFLOW 3 /* Overflow */ +#define TRAP_BOUND_RANGE 4 /* BOUND range exceeded */ +#define TRAP_INVLOP 5 /* Invalid opcode */ +#define TRAP_DOUBLE_FAULT 6 /* Double fault */ +#define TRAP_INVLTSS 7 /* Invalid TSS */ +#define TRAP_SEGNP 8 /* Segment not present */ +#define TRAP_PROTFLT 9 /* General protection */ +#define TRAP_PAGEFLT 10 /* Page fault */ +#define TRAP_NMI 11 /* Non-maskable interrupt */ +#define TRAP_SS 12 /* Stack-segment fault */ + +#if !defined(__ASSEMBLER__) + +void breakpoint_handler(void *sf); +void arith_err(void *sf); +void overflow(void *sf); +void bound_range(void *sf); +void invl_op(void *sf); +void double_fault(void *sf); +void invl_tss(void *sf); +void segnp(void *sf); +void general_prot(void *sf); +void page_fault(void *sf); +void nmi(void *sf); +void ss_fault(void *sf); +void trap_handler(struct trapframe *tf); + +#endif /* !__ASSEMBLER__ */ +#endif /* !_MACHINE_TRAP_H_ */ -- cgit v1.2.3