releasing the runq lock after loading page tables but before the actual context switch can leave execution in an inconsistent if the current process is descheduled from an IRQ between these two steps. this patch holds the runq lock with IRQs disabled and makes the context switch a single atomic operation.
238 lines
5.3 KiB
ArmAsm
238 lines
5.3 KiB
ArmAsm
/**
|
|
* \file interrupt.S
|
|
* License details are found in the file LICENSE.
|
|
* \brief
|
|
* Interrupt handler entries.
|
|
* \author Taku Shimosawa <shimosawa@is.s.u-tokyo.ac.jp> \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 128
|
|
#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
|
|
|
|
.globl nmi
|
|
nmi:
|
|
#define PANICED 232
|
|
#define PANIC_REGS 240
|
|
movq %rax,%gs:PANIC_REGS+0x00
|
|
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
|
|
1:
|
|
hlt
|
|
jmp 1b
|
|
|
|
.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
|
|
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
|