/*- * Copyright (c) 2016 The FreeBSD Foundation * All rights reserved. * * This software was developed by Konstantin Belousov under sponsorship * from the FreeBSD Foundation. * * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ .macro EH N, err=1 .align 8 .globl EXC\N\()_handler EXC\N\()_handler: .if \err != 1 pushq $0 .endif pushq %rax pushq %rdx pushq %rcx movl $\N,%ecx jmp all_handlers .endm .text EH 0,0 EH 1,0 EH 2,0 EH 3,0 EH 4,0 EH 5,0 EH 6,0 EH 7,0 EH 8 EH 9,0 EH 10 EH 11 EH 12 EH 13 EH 14 EH 16,0 EH 17 EH 18,0 EH 19,0 EH 20,0 .globl exc_rsp all_handlers: cmpq %rsp,exc_rsp(%rip) je exception /* * Interrupt, not exception. * First, copy the hardware interrupt frame to the previous stack. * Our handler always has private IST stack. */ movq (6*8)(%rsp),%rax /* saved %rsp value, AKA old stack */ subq (5*8),%rax movq (3*8)(%rsp),%rdx /* copy %rip to old stack */ movq %rdx,(%rax) movq (4*8)(%rsp),%rdx /* copy %cs */ movq %rdx,(1*8)(%rax) movq (5*8)(%rsp),%rdx /* copy %rflags */ movq %rdx,(2*8)(%rax) movq (6*8)(%rsp),%rdx /* copy %rsp */ movq %rdx,(3*8)(%rax) movq (7*8)(%rsp),%rdx /* copy %ss */ movq %rdx,(4*8)(%rax) /* * Now simulate invocation of the original interrupt handler * with retq. We switch stacks and execute retq from the old * stack since there is no free registers at the last moment. */ subq $16,%rax leaq fw_intr_handlers(%rip),%rdx movq (%rdx,%rcx,8),%rdx /* push intr handler address on old stack */ movq %rdx,8(%rax) movq (2*8)(%rsp),%rcx /* saved %rax is put on top of old stack */ movq %rcx,(%rax) movq (%rsp),%rcx movq 8(%rsp),%rdx movq 32(%rsp),%rsp /* switch to old stack */ popq %rax retq exception: /* * Form the struct trapframe on our IST stack. * Skip three words, which are currently busy with temporal * saves. */ pushq %r15 pushq %r14 pushq %r13 pushq %r12 pushq %r11 pushq %r10 pushq %rbp pushq %rbx pushq $0 /* %rax */ pushq %r9 pushq %r8 pushq $0 /* %rcx */ pushq $0 /* %rdx */ pushq %rsi pushq %rdi /* * Move %rax, %rdx, %rcx values into the final location, * from the three words which were skipped above. */ movq 0x88(%rsp),%rax movq %rax,0x30(%rsp) /* tf_rax */ movq 0x78(%rsp),%rax movq %rax,0x18(%rsp) /* tf_rcx */ movq 0x80(%rsp),%rax movq %rax,0x10(%rsp) /* tf_rdx */ /* * And fill the three words themself. */ movq %cr2,%rax movq %rax,0x80(%rsp) /* tf_addr */ movl %ecx,0x78(%rsp) /* tf_trapno */ movw %ds,0x8e(%rsp) movw %es,0x8c(%rsp) movw %fs,0x7c(%rsp) movw %gs,0x7e(%rsp) movw $0,0x88(%rsp) /* tf_flags */ /* * Call dump routine. */ movq %rsp,%rdi callq report_exc /* * Hang after reporting. Interrupts are already disabled. */ 1: hlt jmp 1b