/** * \file interrupt.S * License details are found in the file LICENSE. * \brief * Interrupt handler entries. * \author Taku Shimosawa \par * Copyright (C) 2011 - 2012 Taku Shimosawa */ /* * HISTORY * * 2014/04 - bgerofi: save/restore rbp when entering/leaving kernel (for glibc) * 2013/?? - bgerofi + shimosawa: handle rsp correctly for nested interrupts */ #define X86_CPU_LOCAL_OFFSET_TSS 176 #define X86_TSS_OFFSET_SP0 4 #define X86_CPU_LOCAL_OFFSET_SP0 \ (X86_CPU_LOCAL_OFFSET_TSS + X86_TSS_OFFSET_SP0) #define X86_CPU_LOCAL_OFFSET_KSTACK 16 #define X86_CPU_LOCAL_OFFSET_USTACK 24 #define KERNEL_CS 32 #define KERNEL_DS 40 #define USER_CS (48 + 3) #define USER_DS (56 + 3) /* struct x86_user_context */ #define X86_SREGS_BASE (0) #define X86_SREGS_SIZE 48 #define X86_FLAGS_BASE (X86_SREGS_BASE + X86_SREGS_SIZE) #define X86_FLAGS_SIZE 8 #define X86_REGS_BASE (X86_FLAGS_BASE + X86_FLAGS_SIZE) #define RAX_OFFSET (X86_REGS_BASE + 80) #define ERROR_OFFSET (X86_REGS_BASE + 120) #define RSP_OFFSET (X86_REGS_BASE + 152) #define PUSH_ALL_REGS \ pushq %rdi; \ pushq %rsi; \ pushq %rdx; \ pushq %rcx; \ pushq %rax; \ pushq %r8; \ pushq %r9; \ pushq %r10; \ pushq %r11; \ pushq %rbx; \ pushq %rbp; \ pushq %r12; \ pushq %r13; \ pushq %r14; \ pushq %r15; \ pushq $1; /* is_gpr_valid is set, and others are cleared */ \ subq $X86_FLAGS_BASE,%rsp /* for x86_sregs, etc. */ #define POP_ALL_REGS \ movq $0,X86_FLAGS_BASE(%rsp); /* clear all flags */ \ addq $X86_REGS_BASE,%rsp; /* discard x86_sregs, flags, etc. */ \ popq %r15; \ popq %r14; \ popq %r13; \ popq %r12; \ popq %rbp; \ popq %rbx; \ popq %r11; \ popq %r10; \ popq %r9; \ popq %r8; \ popq %rax; \ popq %rcx; \ popq %rdx; \ popq %rsi; \ popq %rdi .data .globl generic_common_handlers generic_common_handlers: .text vector=0 .rept 256 1: cld pushq $vector jmp common_interrupt .previous .quad 1b .text vector=vector+1 .endr common_interrupt: PUSH_ALL_REGS movq ERROR_OFFSET(%rsp), %rdi movq %rsp, %rsi call handle_interrupt /* Enter C code */ POP_ALL_REGS addq $8, %rsp iretq .globl __page_fault_handler_address __page_fault_handler_address: .quad 0 .globl page_fault page_fault: cld PUSH_ALL_REGS movq %cr2, %rdi movq ERROR_OFFSET(%rsp),%rsi movq %rsp,%rdx movq __page_fault_handler_address(%rip), %rax andq %rax, %rax jz 1f call *%rax POP_ALL_REGS addq $8, %rsp iretq 1: jmp 1b .globl general_protection_exception general_protection_exception: cld PUSH_ALL_REGS movq %rsp, %rdi call gpe_handler POP_ALL_REGS addq $8, %rsp iretq .global __freeze __freeze: PUSH_ALL_REGS callq freeze POP_ALL_REGS iretq .globl nmi nmi: #define PANICED 232 #define PANIC_REGS 240 movq %rax,%gs:PANIC_REGS+0x00 movq %rsp,%gs:PANIC_REGS+0x08 movl nmi_mode(%rip),%eax cmp $3,%rax je 4f cmp $1,%rax je 1f cmp $2,%rax jne 3f 1: cld movq %gs:PANIC_REGS+0x00,%rax PUSH_ALL_REGS subq $40, %rsp movq %rsp,%gs:PANIC_REGS+0x10 movq %rsp, %rdi call freeze_thaw cmpq $0, %rax jnz 2f addq $40, %rsp 2: POP_ALL_REGS iretq 3: movq %rbx,%gs:PANIC_REGS+0x08 movq %rcx,%gs:PANIC_REGS+0x10 movq %rdx,%gs:PANIC_REGS+0x18 movq %rsi,%gs:PANIC_REGS+0x20 movq %rdi,%gs:PANIC_REGS+0x28 movq %rbp,%gs:PANIC_REGS+0x30 movq 0x18(%rsp),%rax /* rsp */ movq %rax,%gs:PANIC_REGS+0x38 movq %r8, %gs:PANIC_REGS+0x40 movq %r9, %gs:PANIC_REGS+0x48 movq %r10,%gs:PANIC_REGS+0x50 movq %r11,%gs:PANIC_REGS+0x58 movq %r12,%gs:PANIC_REGS+0x60 movq %r13,%gs:PANIC_REGS+0x68 movq %r14,%gs:PANIC_REGS+0x70 movq %r15,%gs:PANIC_REGS+0x78 movq 0x00(%rsp),%rax /* rip */ movq %rax,%gs:PANIC_REGS+0x80 movq 0x10(%rsp),%rax /* rflags */ movl %eax,%gs:PANIC_REGS+0x88 movq 0x08(%rsp),%rax /* cs */ movl %eax,%gs:PANIC_REGS+0x8C movq 0x20(%rsp),%rax /* ss */ movl %eax,%gs:PANIC_REGS+0x90 xorq %rax,%rax movw %ds,%ax movl %eax,%gs:PANIC_REGS+0x94 movw %es,%ax movl %eax,%gs:PANIC_REGS+0x98 movw %fs,%ax movl %eax,%gs:PANIC_REGS+0x9C movw %gs,%ax movl %eax,%gs:PANIC_REGS+0xA0 movq $1,%gs:PANICED call ihk_mc_query_mem_areas 4: hlt jmp 4b .globl x86_syscall x86_syscall: cld movq %rsp, %gs:X86_CPU_LOCAL_OFFSET_USTACK movq %gs:(X86_CPU_LOCAL_OFFSET_SP0), %rsp pushq $(USER_DS) pushq $0 pushq %r11 pushq $(USER_CS) pushq %rcx pushq %rax /* error code (= system call number) */ PUSH_ALL_REGS movq %gs:X86_CPU_LOCAL_OFFSET_USTACK, %rcx movq %rcx, RSP_OFFSET(%rsp) movq RAX_OFFSET(%rsp), %rdi movw %ss, %ax movw %ax, %ds movq %rsp, %rsi callq *__x86_syscall_handler(%rip) 1: movq %rax, RAX_OFFSET(%rsp) POP_ALL_REGS #ifdef USE_SYSRET movq 32(%rsp), %rsp sysretq #else addq $8, %rsp iretq #endif .globl enter_user_mode enter_user_mode: callq release_runq_lock movq $0, %rdi movq %rsp, %rsi call check_signal call utilthr_migrate movq $0, %rdi call set_cputime POP_ALL_REGS addq $8, %rsp iretq .globl debug_exception debug_exception: cld pushq $0 /* error */ PUSH_ALL_REGS movq %rsp, %rdi call debug_handler POP_ALL_REGS addq $8, %rsp iretq .globl int3_exception int3_exception: cld pushq $0 /* error */ PUSH_ALL_REGS movq %rsp, %rdi call int3_handler POP_ALL_REGS addq $8, %rsp iretq