/* Copyright (C) 2021,2022 fef . All rights reserved. */ #include #include .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