// vi: ft=asm :
// 15 general-purpose registers
.set PT_REGS_SIZE, 15 * 8

.macro EXC_SAVE_STATE
    sub $PT_REGS_SIZE, %rsp
    mov %rax, 0(%rsp)
    mov %rcx, 8(%rsp)
    mov %rdx, 16(%rsp)
    mov %rbx, 24(%rsp)
    mov %rsi, 32(%rsp)
    mov %rdi, 40(%rsp)
    mov %rbp, 48(%rsp)

    mov %r8, 56(%rsp)
    mov %r9, 64(%rsp)
    mov %r10, 72(%rsp)
    mov %r11, 80(%rsp)
    mov %r12, 88(%rsp)
    mov %r13, 96(%rsp)
    mov %r14, 104(%rsp)
    mov %r15, 112(%rsp)
.endm

.macro EXC_RESTORE_STATE
    mov 0(%rsp), %rax
    mov 8(%rsp), %rcx
    mov 16(%rsp), %rdx
    mov 24(%rsp), %rbx
    mov 32(%rsp), %rsi
    mov 40(%rsp), %rdi
    mov 48(%rsp), %rbp

    mov 56(%rsp), %r8
    mov 64(%rsp), %r9
    mov 72(%rsp), %r10
    mov 80(%rsp), %r11
    mov 88(%rsp), %r12
    mov 96(%rsp), %r13
    mov 104(%rsp), %r14
    mov 112(%rsp), %r15

    addq $PT_REGS_SIZE, %rsp
.endm

.macro ISR_NERR, n
.hidden __x86_64_exc_\n
__x86_64_exc_\n:
    cli
    pushq $0
    pushq $\n
    jmp __x86_64_exc_common
.endm

.macro ISR_YERR, n
.hidden __x86_64_exc_\n
__x86_64_exc_\n:
    cli
    pushq $\n
    jmp __x86_64_exc_common
.endm

.macro EXC_SWAPGS_IF_NEEDED, cs_off
    cmpq $0x08, \cs_off(%rsp)
    je 1f
    swapgs
1:
.endm

.global __x86_64_exception_vectors
.global __kernel_start

.pushsection .text
__x86_64_exc_common:
    // %rsp + 0: error number
    // %rsp + 8: error code
    // %rsp + 16: %rip
    // %rsp + 24: %cs

    EXC_SWAPGS_IF_NEEDED 24

    EXC_SAVE_STATE

    // Save current stack into %rdi (arg 1) + %rbp
    movq %rsp, %rdi
    movq %rsp, %rbp

    // Force correct stack alignment
    orq $0xF, %rsp
    xorq $0xF, %rsp

    call {exception_handler}

    // Restore the stack
    movq %rbp, %rsp

    EXC_RESTORE_STATE

    // Remove error code and number from the stack
    addq $16, %rsp

    EXC_SWAPGS_IF_NEEDED 8

    iretq

ISR_NERR 0
ISR_NERR 1
// ISR_NERR 2
ISR_NERR 3
ISR_NERR 4
ISR_NERR 5
ISR_NERR 6
ISR_NERR 7
ISR_YERR 8
ISR_NERR 9
ISR_YERR 10
ISR_YERR 11
ISR_YERR 12
ISR_YERR 13
ISR_YERR 14
ISR_NERR 15
ISR_NERR 16
ISR_YERR 17
ISR_NERR 18
ISR_NERR 19
ISR_NERR 20
ISR_NERR 21
ISR_NERR 22
ISR_NERR 23
ISR_NERR 24
ISR_NERR 25
ISR_NERR 26
ISR_NERR 27
ISR_NERR 28
ISR_NERR 29
ISR_YERR 30
ISR_NERR 31

// Special handler for NMI
__x86_64_exc_2:
    cli
    jmp {nmi_handler}

.popsection // .text

.pushsection .data.rel
.global __x86_64_exception_vectors
.p2align 4
__x86_64_exception_vectors:
    .quad __x86_64_exc_0
    .quad __x86_64_exc_1
    .quad __x86_64_exc_2
    .quad __x86_64_exc_3
    .quad __x86_64_exc_4
    .quad __x86_64_exc_5
    .quad __x86_64_exc_6
    .quad __x86_64_exc_7
    .quad __x86_64_exc_8
    .quad __x86_64_exc_9
    .quad __x86_64_exc_10
    .quad __x86_64_exc_11
    .quad __x86_64_exc_12
    .quad __x86_64_exc_13
    .quad __x86_64_exc_14
    .quad __x86_64_exc_15
    .quad __x86_64_exc_16
    .quad __x86_64_exc_17
    .quad __x86_64_exc_18
    .quad __x86_64_exc_19
    .quad __x86_64_exc_20
    .quad __x86_64_exc_21
    .quad __x86_64_exc_22
    .quad __x86_64_exc_23
    .quad __x86_64_exc_24
    .quad __x86_64_exc_25
    .quad __x86_64_exc_26
    .quad __x86_64_exc_27
    .quad __x86_64_exc_28
    .quad __x86_64_exc_29
    .quad __x86_64_exc_30
    .quad __x86_64_exc_31
.popsection // .data.rel
