| /*- |
| * 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 |