You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

126 lines
3.0 KiB
ArmAsm

/* Copyright (C) 2021,2022 fef <owo@fef.moe>. All rights reserved. */
#include <arch/interrupt.h>
#include <asm/common.h>
.section .text.isr
/*
* push all registers except %rsi to the stack, and store a pointer to the
* struct amd64_trap_frame in %rdi (%rsi is assumed to have already been pushed,
* right after the hardware frame).
* The pointer is stored in %rdi because that's where you put the first
* parameter for function calls as per the amd64 System V ABI.
*/
.macro prepare_trap_entry
pushq %rdi
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %r11
pushq %r10
pushq %r9
pushq %r8
pushq %rbp
pushq %rdx
pushq %rcx
pushq %rbx
pushq %rax
movq %rsp, %rdi
.endm
.macro prepare_trap_leave
popq %rax
popq %rbx
popq %rcx
popq %rdx
popq %rbp
popq %r8
popq %r9
popq %r10
popq %r11
popq %r12
popq %r13
popq %r14
popq %r15
popq %rdi
.endm
/*
* 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
ENTRY(_x86_isr_\name )
cld
pushq %rsi
prepare_trap_entry
callq x86_isr_\name
prepare_trap_leave
popq %rsi
iretq
END(_x86_isr_\name )
.endm
/*
* This is for traps that additionally push an error code to the stack before
* entering the handler. The thing with that error code is that it is *not*
* popped from the stack when leaving again, so we need to account for that
* difference ourselves.
*/
.macro gen_isr_error name
.extern x86_isr_\name
ENTRY(_x86_isr_\name )
cld
/*
* Rather than pushing %rsi, we exchange it with the error code that
* was pushed by hardware in addition to the regular stack frame.
* This produces the same stack layout as the ISRs that don't push an
* error code, and additionally moves said code into the appropriate
* register for passing it as the second argument to the handler.
*/
xchgq %rsi, (%rsp)
prepare_trap_entry
callq x86_isr_\name
prepare_trap_leave
popq %rsi
iretq
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