x86: refactor traps, add register dump support

main
anna 3 years ago
parent 3e43ec5491
commit d69fd0d2aa
Signed by: fef
GPG Key ID: EC22E476DC2D3D84

@ -62,14 +62,14 @@
#include <gay/cdefs.h>
#include <gay/types.h>
__always_inline void enable_interrupts(void)
__always_inline void enable_intr(void)
{
__asm__ volatile("sti");
}
__always_inline void disable_interrupts(void)
__always_inline void disable_intr(void)
{
__asm__ volatile("cli");
__asm__ volatile("cli" ::: "memory");
}
/**
@ -95,6 +95,26 @@ struct x86_idt_entry {
/* idt.S */
extern struct x86_idt_entry x86_idt[X86_INTR_COUNT];
/**
* @brief A hardware stack frame.
* I have no idea if the x86 are calling it hardware stack frame tbh, i just
* used the (ARM) terminology i'm used to. This is what gets pushed to the
* stack automatically when entering an ISR.
*/
struct x86_hw_frame {
u32 eip;
u16 cs; u16 _pad0;
u32 eflags;
/*
* These two are only pushed when coming from another (i.e. lower)
* privilege level (wtf???). This effectively means they don't exist
* unless the CS above is equal to X86_USER_CS (arch/segment.h).
*/
u32 user_esp;
u16 user_ss; u16 _pad1;
} __packed;
/** @brief Disable the Programmable Interrupt Controller. */
void x86_disable_pic(void);

@ -15,68 +15,87 @@
* appear to be the case. Trust me, it's fine.
*/
#include <arch/interrupt.h>
#include <gay/cdefs.h>
#include <gay/types.h>
/**
* @brief x86 registers as pushed to the stack by the `pusha` instruction.
*/
struct x86_trap_frame {
/* extra pointer pushed manually, see the assembly routines */
struct x86_hw_frame *hw_frame;
u32 edi;
u32 esi;
u32 ebp;
u32 esp;
u32 ebx;
u32 edx;
u32 ecx;
u32 eax;
} __packed;
extern void _x86_isr_divide_error(void);
__asmlink void x86_isr_divide_error(void);
__asmlink void x86_isr_divide_error(struct x86_trap_frame *frame);
extern void _x86_isr_debug_exception(void);
__asmlink void x86_isr_debug_exception(void);
__asmlink void x86_isr_debug_exception(struct x86_trap_frame *frame);
extern void _x86_isr_nmi(void);
__asmlink void x86_isr_nmi(void);
__asmlink void x86_isr_nmi(struct x86_trap_frame *frame);
extern void _x86_isr_breakpoint(void);
__asmlink void x86_isr_breakpoint(void);
__asmlink void x86_isr_breakpoint(struct x86_trap_frame *frame);
extern void _x86_isr_overflow(void);
__asmlink void x86_isr_overflow(void);
__asmlink void x86_isr_overflow(struct x86_trap_frame *frame);
extern void _x86_isr_bound_range_exceeded(void);
__asmlink void x86_isr_bound_range_exceeded(void);
__asmlink void x86_isr_bound_range_exceeded(struct x86_trap_frame *frame);
extern void _x86_isr_invalid_opcode(void);
__asmlink void x86_isr_invalid_opcode(void);
__asmlink void x86_isr_invalid_opcode(struct x86_trap_frame *frame);
extern void _x86_isr_device_not_available(void);
__asmlink void x86_isr_device_not_available(void);
__asmlink void x86_isr_device_not_available(struct x86_trap_frame *frame);
extern void _x86_isr_double_fault(void);
__asmlink void x86_isr_double_fault(u32 error_code);
__asmlink void x86_isr_double_fault(struct x86_trap_frame *frame, u32 error_code);
extern void _x86_isr_invalid_tss(void);
__asmlink void x86_isr_invalid_tss(u32 error_code);
__asmlink void x86_isr_invalid_tss(struct x86_trap_frame *frame, u32 error_code);
extern void _x86_isr_segment_not_present(void);
__asmlink void x86_isr_segment_not_present(u32 error_code);
__asmlink void x86_isr_segment_not_present(struct x86_trap_frame *frame, u32 error_code);
extern void _x86_isr_stack_segment_fault(void);
__asmlink void x86_isr_stack_segment_fault(u32 error_code);
__asmlink void x86_isr_stack_segment_fault(struct x86_trap_frame *frame, u32 error_code);
extern void _x86_isr_general_protection(void);
__asmlink void x86_isr_general_protection(u32 error_code);
__asmlink void x86_isr_general_protection(struct x86_trap_frame *frame, u32 error_code);
extern void _x86_isr_page_fault(void);
__asmlink void x86_isr_page_fault(u32 error_code);
__asmlink void x86_isr_page_fault(struct x86_trap_frame *frame, u32 error_code);
extern void _x86_isr_x87_fpu_error(void);
__asmlink void x86_isr_x87_fpu_error(void);
__asmlink void x86_isr_x87_fpu_error(struct x86_trap_frame *frame);
extern void _x86_isr_alignment_check(void);
__asmlink void x86_isr_alignment_check(u32 error_code);
__asmlink void x86_isr_alignment_check(struct x86_trap_frame *frame, u32 error_code);
extern void _x86_isr_machine_check(void);
__asmlink void x86_isr_machine_check(void);
__asmlink void x86_isr_machine_check(struct x86_trap_frame *frame);
extern void _x86_isr_simd_floating_point_exception(void);
__asmlink void x86_isr_simd_floating_point_exception(void);
__asmlink void x86_isr_simd_floating_point_exception(struct x86_trap_frame *frame);
extern void _x86_isr_virtualization_exception(void);
__asmlink void x86_isr_virtualization_exception(void);
__asmlink void x86_isr_virtualization_exception(struct x86_trap_frame *frame);
extern void _x86_isr_control_protection_exception(void);
__asmlink void x86_isr_control_protection_exception(u32 error_code);
__asmlink void x86_isr_control_protection_exception(struct x86_trap_frame *frame, u32 error_code);
/*
* This file is part of GayBSD.

@ -9,6 +9,7 @@
#define ASM_ENTRY(name) \
.global name; \
.type name, @function; \
.align 4; \
name:
#define ASM_END(name) \

@ -1,11 +1,11 @@
# See the end of this file for copyright and license terms.
target_sources(gay_arch PRIVATE
entry.S
idt.S
interrupt.c
port.S
trap.c
trap.S
)
# This file is part of GayBSD.

@ -1,175 +0,0 @@
/* See the end of this file for copyright and license terms. */
#include <arch/interrupt.h>
#include <asm/common.h>
.text
/*
* low level entry points, this is what gets put into the IDT
*/
ASM_ENTRY(_x86_isr_divide_error)
cld
call x86_isr_divide_error
iret
ASM_END(_x86_isr_divide_error)
ASM_ENTRY(_x86_isr_debug_exception)
cld
call x86_isr_debug_exception
iret
ASM_END(_x86_isr_debug_exception)
ASM_ENTRY(_x86_isr_nmi)
cld
call x86_isr_nmi
iret
ASM_END(_x86_isr_nmi)
ASM_ENTRY(_x86_isr_breakpoint)
cld
call x86_isr_breakpoint
iret
ASM_END(_x86_isr_breakpoint)
ASM_ENTRY(_x86_isr_overflow)
cld
call x86_isr_overflow
iret
ASM_END(_x86_isr_overflow)
ASM_ENTRY(_x86_isr_bound_range_exceeded)
cld
call x86_isr_bound_range_exceeded
iret
ASM_END(_x86_isr_bound_range_exceeded)
ASM_ENTRY(_x86_isr_invalid_opcode)
cld
call x86_isr_invalid_opcode
iret
ASM_END(_x86_isr_invalid_opcode)
ASM_ENTRY(_x86_isr_device_not_available)
cld
call x86_isr_device_not_available
iret
ASM_END(_x86_isr_device_not_available)
ASM_ENTRY(_x86_isr_double_fault)
cld
call x86_isr_double_fault
add $4, %esp
iret
ASM_END(_x86_isr_double_fault)
ASM_ENTRY(_x86_isr_invalid_tss)
cld
call x86_isr_invalid_tss
add $4, %esp
iret
ASM_END(_x86_isr_invalid_tss)
ASM_ENTRY(_x86_isr_segment_not_present)
cld
call x86_isr_segment_not_present
add $4, %esp
iret
ASM_END(_x86_isr_segment_not_present)
ASM_ENTRY(_x86_isr_stack_segment_fault)
cld
call x86_isr_stack_segment_fault
add $4, %esp
iret
ASM_END(_x86_isr_stack_segment_fault)
ASM_ENTRY(_x86_isr_general_protection)
cld
call x86_isr_general_protection
add $4, %esp
iret
ASM_END(_x86_isr_general_protection)
ASM_ENTRY(_x86_isr_page_fault)
cld
call x86_isr_page_fault
add $4, %esp
iret
ASM_END(_x86_isr_page_fault)
ASM_ENTRY(_x86_isr_x87_fpu_error)
cld
call x86_isr_x87_fpu_error
iret
ASM_END(_x86_isr_fpu_error)
ASM_ENTRY(_x86_isr_alignment_check)
cld
call x86_isr_alignment_check
add $4, %esp
iret
ASM_END(_x86_isr_alignment_check)
ASM_ENTRY(_x86_isr_machine_check)
cld
call x86_isr_machine_check
iret
ASM_END(_x86_isr_machine_check)
ASM_ENTRY(_x86_isr_simd_floating_point_exception)
cld
call x86_isr_simd_floating_point_exception
iret
ASM_END(_x86_isr_simd_floating_point_exception)
ASM_ENTRY(_x86_isr_virtualization_exception)
cld
call x86_isr_virtualization_exception
iret
ASM_END(_x86_isr_virtualization_exception)
ASM_ENTRY(_x86_isr_control_protection_exception)
cld
call x86_isr_control_protection_exception
add $4, %esp
iret
ASM_END(_x86_isr_control_protection_exception)
/* trap.c */
.extern x86_isr_divide_error
.extern x86_isr_debug_exception
.extern x86_isr_nmi
.extern x86_isr_breakpoint
.extern x86_isr_overflow
.extern x86_isr_bound_range_exceeded
.extern x86_isr_invalid_opcode
.extern x86_isr_device_not_available
.extern x86_isr_double_fault
.extern x86_isr_invalid_tss
.extern x86_isr_segment_not_present
.extern x86_isr_stack_segment_fault
.extern x86_isr_general_protection
.extern x86_isr_page_fault
.extern x86_isr_x87_fpu_error
.extern x86_isr_alignment_check
.extern x86_isr_machine_check
.extern x86_isr_simd_floating_point_exception
.extern x86_isr_virtualization_exception
.extern x86_isr_control_protection_exception
/*
* This file is part of GayBSD.
* Copyright (c) 2021 fef <owo@fef.moe>.
*
* GayBSD is nonviolent software: you may only use, redistribute, and/or
* modify it under the terms of the Cooperative Nonviolent Public License
* (CNPL) as found in the LICENSE file in the source code root directory
* or at <https://git.pixie.town/thufie/npl-builder>; either version 7
* of the license, or (at your option) any later version.
*
* GayBSD comes with ABSOLUTELY NO WARRANTY, to the extent
* permitted by applicable law. See the CNPL for details.
*/

@ -34,7 +34,7 @@ void x86_setup_interrupts(void)
x86_set_trap_gate(X86_VECT_CP, _x86_isr_control_protection_exception);
x86_load_idt();
enable_interrupts();
enable_intr();
}
void x86_set_gate(u8 vector, void (*handler)(void), u8 flags)

@ -0,0 +1,102 @@
/* See the end of this file for copyright and license terms. */
#include <arch/interrupt.h>
#include <asm/common.h>
.text
/*
* Low level trap entry points, this is what gets put into the IDT.
*
* Hardware automatically pushes EFLAGS, CS, EIP, and (optionally) an error
* code to the stack. The rest is pushed by software using the pushal
* instruction. I wanted to use the same context save struct for both kinds
* of exceptions (the ones that push an error code and the ones that don't),
* so the pointer to the hardware context save is also pushed to the stack and
* included in struct x86_trap_frame.
*/
.macro gen_isr_noerror name
.extern x86_isr_\name
ASM_ENTRY(_x86_isr_\name )
cld
pushal
mov %esp, %eax
add $32, %eax
push %eax
call x86_isr_\name
add $4, %esp
popal
iretl
ASM_END(_x86_isr_\name )
.endm
/*
* So, instead of just adding a dedicated register for exception status, the
* Intel people apparently thought it was better to have the CPU push an error
* code to the stack. This is technically not too bad of an idea because the
* x86 ABI says all parameters are passed through the stack, so you could write
* exception handlers in C! Too bad the CPU (1) doesn't save scratch registers
* eax, ecx and edx automatically, (2) only some of the exceptions push this
* error code?? and (3) you have to pop the error code manually??????
*/
.macro gen_isr_error name
.extern x86_isr_\name
ASM_ENTRY(_x86_isr_\name )
cld
pushal
mov %esp, %eax
add $36, %eax
push %eax /* struct x86_trap_frame::hw_frame */
/*
* pushal pushes 8 registers = 32 bytes to the stack, plus 4 bytes
* for the pointer to struct x86_hw_frame, so the error code pushed
* by hardware is 36 bytes into %esp now
*/
mov 36(%esp), %ebx
mov %esp, %eax
push %ebx
push %eax
call x86_isr_\name /* x86_isr_<name>(%esp, error_code); */
add $8, %esp
popal
add $4, %esp /* "pop" the hardware error code from the stack */
iretl
ASM_END(_x86_isr_\name )
.endm
gen_isr_noerror divide_error
gen_isr_noerror debug_exception
gen_isr_noerror nmi
gen_isr_noerror breakpoint
gen_isr_noerror overflow
gen_isr_noerror bound_range_exceeded
gen_isr_noerror invalid_opcode
gen_isr_noerror device_not_available
gen_isr_error double_fault
gen_isr_error invalid_tss
gen_isr_error segment_not_present
gen_isr_error stack_segment_fault
gen_isr_error general_protection
gen_isr_error page_fault
gen_isr_noerror x87_fpu_error
gen_isr_error alignment_check
gen_isr_noerror machine_check
gen_isr_noerror simd_floating_point_exception
gen_isr_noerror virtualization_exception
gen_isr_error control_protection_exception
/*
* This file is part of GayBSD.
* Copyright (c) 2021 fef <owo@fef.moe>.
*
* GayBSD is nonviolent software: you may only use, redistribute, and/or
* modify it under the terms of the Cooperative Nonviolent Public License
* (CNPL) as found in the LICENSE file in the source code root directory
* or at <https://git.pixie.town/thufie/npl-builder>; either version 7
* of the license, or (at your option) any later version.
*
* GayBSD comes with ABSOLUTELY NO WARRANTY, to the extent
* permitted by applicable law. See the CNPL for details.
*/

@ -1,133 +1,164 @@
/* See the end of this file for copyright and license terms. */
#include <arch/segment.h>
#include <arch/trap.h>
#include <gay/kprintf.h>
/*
* NOTE: The error code is cast to a pointer for the kprintf() calls, this is
* just for looks because i haven't implemented the %x format sequence yet so
* this is the only way to print hex numbers.
*/
static void print_regs(struct x86_trap_frame *context)
{
u32 esp;
if (context->hw_frame->cs == X86_USER_CS)
esp = context->hw_frame->user_esp;
else
esp = context->esp - 3 * 4; /* eip, cs, eflags */
kprintf("EIP = 0x%08x EFLAGS = 0x%08x\n",
context->hw_frame->eip, context->hw_frame->eflags);
kprintf("EAX = 0x%08x EDI = 0x%08x\n", context->eax, context->edi);
kprintf("EBX = 0x%08x ESI = 0x%08x\n", context->ebx, context->esi);
kprintf("ECX = 0x%08x ESP = 0x%08x\n", context->ecx, esp);
kprintf("EDX = 0x%08x EBP = 0x%08x\n", context->edx, context->ebp);
}
void x86_isr_divide_error(void)
void x86_isr_divide_error(struct x86_trap_frame *frame)
{
kprintf("Divide Error\n");
print_regs(frame);
while (1);
}
void x86_isr_debug_exception(void)
void x86_isr_debug_exception(struct x86_trap_frame *frame)
{
kprintf("Debug Exception\n");
print_regs(frame);
while (1);
}
void x86_isr_nmi(void)
void x86_isr_nmi(struct x86_trap_frame *frame)
{
kprintf("Nonmaskable Interrupt\n");
print_regs(frame);
while (1);
}
void x86_isr_breakpoint(void)
void x86_isr_breakpoint(struct x86_trap_frame *frame)
{
kprintf("Breakpoint\n");
print_regs(frame);
while (1);
}
void x86_isr_overflow(void)
void x86_isr_overflow(struct x86_trap_frame *frame)
{
kprintf("Overflow\n");
print_regs(frame);
while (1);
}
void x86_isr_bound_range_exceeded(void)
void x86_isr_bound_range_exceeded(struct x86_trap_frame *frame)
{
kprintf("Bound Range Exceeded\n");
print_regs(frame);
while (1);
}
void x86_isr_invalid_opcode(void)
void x86_isr_invalid_opcode(struct x86_trap_frame *frame)
{
kprintf("Invalid Opcode\n");
print_regs(frame);
while (1);
}
void x86_isr_device_not_available(void)
void x86_isr_device_not_available(struct x86_trap_frame *frame)
{
kprintf("Device Not Available\n");
print_regs(frame);
while (1);
}
void x86_isr_double_fault(u32 error_code)
void x86_isr_double_fault(struct x86_trap_frame *frame, u32 error_code)
{
kprintf("Double Fault (error = %p)\n", (void *)error_code);
print_regs(frame);
while (1);
}
void x86_isr_invalid_tss(u32 error_code)
void x86_isr_invalid_tss(struct x86_trap_frame *frame, u32 error_code)
{
kprintf("Invalid TSS (error = %p)\n", (void *)error_code);
print_regs(frame);
while (1);
}
void x86_isr_segment_not_present(u32 error_code)
void x86_isr_segment_not_present(struct x86_trap_frame *frame, u32 error_code)
{
kprintf("Segment Not Present (error = %p)\n", (void *)error_code);
print_regs(frame);
while (1);
}
void x86_isr_stack_segment_fault(u32 error_code)
void x86_isr_stack_segment_fault(struct x86_trap_frame *frame, u32 error_code)
{
kprintf("Stack Segment Fault (error = %p)\n", (void *)error_code);
print_regs(frame);
while (1);
}
void x86_isr_general_protection(u32 error_code)
void x86_isr_general_protection(struct x86_trap_frame *frame, u32 error_code)
{
kprintf("General Protection Fault (external = %d, table = %d, index = %d)\n",
error_code & 1, (error_code >> 1) & 3, (error_code >> 3));
print_regs(frame);
while (1);
}
void x86_isr_page_fault(u32 error_code)
void x86_isr_page_fault(struct x86_trap_frame *frame, u32 error_code)
{
kprintf("Page Fault (error = %p)\n", (void *)error_code);
print_regs(frame);
while (1);
}
void x86_isr_x87_fpu_error(void)
void x86_isr_x87_fpu_error(struct x86_trap_frame *frame)
{
kprintf("x87 FPU Error\n");
print_regs(frame);
while (1);
}
void x86_isr_alignment_check(u32 error_code)
void x86_isr_alignment_check(struct x86_trap_frame *frame, u32 error_code)
{
kprintf("Alignment Check (error = %p)\n", (void *)error_code);
print_regs(frame);
while (1);
}
void x86_isr_machine_check(void)
void x86_isr_machine_check(struct x86_trap_frame *frame)
{
kprintf("Machine Check\n");
print_regs(frame);
while (1);
}
void x86_isr_simd_floating_point_exception(void)
void x86_isr_simd_floating_point_exception(struct x86_trap_frame *frame)
{
kprintf("SIMD Floating Point Exception\n");
print_regs(frame);
while (1);
}
void x86_isr_virtualization_exception(void)
void x86_isr_virtualization_exception(struct x86_trap_frame *frame)
{
kprintf("Virtualization Exception\n");
print_regs(frame);
while (1);
}
void x86_isr_control_protection_exception(u32 error_code)
void x86_isr_control_protection_exception(struct x86_trap_frame *frame, u32 error_code)
{
kprintf("Control Protection Exception (error = %p)\n", (void *)error_code);
print_regs(frame);
while (1);
}

Loading…
Cancel
Save