blob: 62a3b230d8ada54f278c324ea4c954abcda1a886 [file] [log] [blame] [edit]
/* See COPYRIGHT for copyright information.
* The two TRAP* macros (minus the .data parts) are from the JOS project.
* Everything else:
* Copyright (c) 2009, 2013 The Regents of the University of California
* Barret Rhoden <brho@cs.berkeley.edu>
* See LICENSE for details.
*/
#include <arch/mmu.h>
#include <arch/trap.h>
#include <arch/x86.h>
#include <ros/memlayout.h>
###################################################################
# exceptions/interrupts
###################################################################
/* The TRAPHANDLER macro defines a globally-visible function for handling
* a trap. It pushes a trap number onto the stack, then jumps to _alltraps.
* It also builds this traps portion of the trap_tbl.
* Use TRAPHANDLER for traps where the CPU automatically pushes an error code.
*/
#define TRAPHANDLER(name, num) \
.text; \
.globl name; /* define global symbol for 'name' */ \
.type name, @function; /* symbol type is function */ \
.align 2; /* align function definition */ \
name: /* function starts here */ \
pushq $(num); \
jmp _alltraps; \
.data; \
.quad name; \
.long num
/* Use TRAPHANDLER_NOEC for traps where the CPU doesn't push an error code.
* It pushes a 0 in place of the error code, so the trap frame has the same
* format in either case. */
#define TRAPHANDLER_NOEC(name, num) \
.text; \
.globl name; \
.type name, @function; \
.align 2; \
name: \
pushq $0; \
pushq $(num); \
jmp _alltraps; \
.data; \
.quad name; \
.long num
/* Same as NOEC, but for IRQs instead. num is the ISR number it is mapped to */
#define IRQ_HANDLER(name, num) \
.text; \
.globl name; \
.type name, @function; \
.align 2; \
name: \
pushq $0; \
pushq $(num); \
jmp _allirqs; \
.data; \
.quad name; \
.long num
/* Only used in the kernel during SMP boot. Send a LAPIC_EOI and iret. */
#define POKE_HANDLER(name, num) \
.text; \
.globl name; \
.type name, @function; \
.align 2; \
name:; \
movl $0, (LAPIC_BASE + 0x0b0); \
iretq; \
.data; \
.quad name; \
.long num
.data
.globl trap_tbl
trap_tbl:
/*
* Generate entry points for the different traps.
*/
TRAPHANDLER_NOEC(ISR_divide_error, T_DIVIDE)
TRAPHANDLER_NOEC(ISR_debug_exceptions, T_DEBUG)
TRAPHANDLER_NOEC(ISR_NMI, T_NMI)
TRAPHANDLER_NOEC(ISR_breakpoint, T_BRKPT)
TRAPHANDLER_NOEC(ISR_overflow, T_OFLOW)
TRAPHANDLER_NOEC(ISR_bounds_check, T_BOUND)
TRAPHANDLER_NOEC(ISR_invalid_opcode, T_ILLOP)
TRAPHANDLER_NOEC(ISR_device_not_available, T_DEVICE)
/* supposedly, DF generates an error code, but the one time we've had a DF so
* far, it didn't. eventually, this should probably be handled with a task gate
* it might have pushed a 0, but just the rest of the stack was corrupt
*/
TRAPHANDLER_NOEC(ISR_double_fault, T_DBLFLT)
/* 9 reserved */
TRAPHANDLER(ISR_invalid_TSS, T_TSS)
TRAPHANDLER(ISR_segment_not_present, T_SEGNP)
TRAPHANDLER(ISR_stack_exception, T_STACK)
TRAPHANDLER(ISR_general_protection_fault, T_GPFLT)
TRAPHANDLER(ISR_page_fault, T_PGFLT)
/* 15 reserved */
TRAPHANDLER_NOEC(ISR_floating_point_error, T_FPERR)
TRAPHANDLER(ISR_alignment_check, T_ALIGN)
TRAPHANDLER_NOEC(ISR_machine_check, T_MCHK)
TRAPHANDLER_NOEC(ISR_simd_error, T_SIMDERR)
/* 20 - 31 reserved */
IRQ_HANDLER(IRQ0, 32)
IRQ_HANDLER(IRQ1, 33)
IRQ_HANDLER(IRQ2, 34)
IRQ_HANDLER(IRQ3, 35)
IRQ_HANDLER(IRQ4, 36)
IRQ_HANDLER(IRQ5, 37)
IRQ_HANDLER(IRQ6, 38)
IRQ_HANDLER(IRQ7, 39)
IRQ_HANDLER(IRQ8, 40)
IRQ_HANDLER(IRQ9, 41)
IRQ_HANDLER(IRQ10, 42)
IRQ_HANDLER(IRQ11, 43)
IRQ_HANDLER(IRQ12, 44)
IRQ_HANDLER(IRQ13, 45)
IRQ_HANDLER(IRQ14, 46)
IRQ_HANDLER(IRQ15, 47)
/* 25 general purpose vectors, for use by the LAPIC. Can expand later. */
IRQ_HANDLER(IRQ198, I_TESTING) # used in testing.c
IRQ_HANDLER(IRQ199, 231)
IRQ_HANDLER(IRQ200, 232)
IRQ_HANDLER(IRQ201, 233)
IRQ_HANDLER(IRQ202, 234)
IRQ_HANDLER(IRQ203, 235)
IRQ_HANDLER(IRQ204, 236)
IRQ_HANDLER(IRQ205, 237)
IRQ_HANDLER(IRQ206, 238)
IRQ_HANDLER(IRQ207, 239)
/* 0xf0 - start of the SMP_CALL IPIS */
IRQ_HANDLER(IRQ208, I_SMP_CALL0)
IRQ_HANDLER(IRQ209, I_SMP_CALL1)
IRQ_HANDLER(IRQ210, I_SMP_CALL2)
IRQ_HANDLER(IRQ211, I_SMP_CALL3)
IRQ_HANDLER(IRQ212, I_SMP_CALL4)
IRQ_HANDLER(IRQ213, 245)
IRQ_HANDLER(IRQ214, 246)
IRQ_HANDLER(IRQ215, 247)
IRQ_HANDLER(IRQ216, 248)
IRQ_HANDLER(IRQ217, 249)
IRQ_HANDLER(IRQ218, 250)
IRQ_HANDLER(IRQ219, 251)
IRQ_HANDLER(IRQ220, 252)
IRQ_HANDLER(IRQ221, 253)
POKE_HANDLER(IRQ222, 254)
IRQ_HANDLER(IRQ223, I_KERNEL_MSG)
/* Technically, these HANDLER entries do not need to be in numeric order */
TRAPHANDLER_NOEC(ISR_syscall, T_SYSCALL)
/* But make sure default is last!! */
TRAPHANDLER_NOEC(ISR_default, T_DEFAULT)
.data
.globl trap_tbl_end
trap_tbl_end:
.text
_alltraps:
cld
swapgs # harmless if we were already in the kernel
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %r11
pushq %r10
pushq %r9
pushq %r8
pushq %rdi
pushq %rsi
pushq %rbp
pushq %rdx
pushq %rcx
pushq %rbx
pushq %rax
cmpw $GD_KT, 0x90(%rsp) # 0x90 - diff btw tf_cs and tf_rax
je trap_kernel_tf
# this is a user TF, so we need to save their fs/gsbase and load gs base for
# the kernel.
movl $MSR_FS_BASE, %ecx
rdmsr
shl $32, %rdx
orq %rax, %rdx
pushq %rdx
# because we swapped gs earlier, the user GS is now in KERN_GS_BASE
movl $MSR_KERN_GS_BASE, %ecx
rdmsr
shl $32, %rdx
orq %rax, %rdx
pushq %rdx
# make sure the kernel's gs base is loaded into the KERN slot at all times
movl $MSR_GS_BASE, %ecx
rdmsr
movl $MSR_KERN_GS_BASE, %ecx
wrmsr
jmp trap_all_tf
trap_kernel_tf:
# we don't muck with fs/gsbase, push placeholders
movq $0xdeadbeef, %rax
pushq %rax
pushq %rax
trap_all_tf:
movq $0, %rbp # so we can backtrace to this point
movq %rsp, %rdi
call trap
# the return paths are only used by the kernel
addq $0x10, %rsp # skip fs/gs base
popq %rax
popq %rbx
popq %rcx
popq %rdx
popq %rbp
popq %rsi
popq %rdi
popq %r8
popq %r9
popq %r10
popq %r11
popq %r12
popq %r13
popq %r14
popq %r15
addq $0x10, %rsp # skip trapno and err
iretq
# might merge this with _alltraps
_allirqs:
cld
swapgs # harmless if we were already in the kernel
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %r11
pushq %r10
pushq %r9
pushq %r8
pushq %rdi
pushq %rsi
pushq %rbp
pushq %rdx
pushq %rcx
pushq %rbx
pushq %rax
cmpw $GD_KT, 0x90(%rsp) # 0x90 - diff btw tf_cs and tf_rax
je irq_kernel_tf
# this is a user TF, so we need to save their fs/gsbase and load gs base for
# the kernel.
movl $MSR_FS_BASE, %ecx
rdmsr
shl $32, %rdx
orq %rax, %rdx
pushq %rdx
# because we swapped gs earlier, the user GS is now in KERN_GS_BASE
movl $MSR_KERN_GS_BASE, %ecx
rdmsr
shl $32, %rdx
orq %rax, %rdx
pushq %rdx
# make sure the kernel's gs base is loaded into the KERN slot at all times
movl $MSR_GS_BASE, %ecx
rdmsr
movl $MSR_KERN_GS_BASE, %ecx
wrmsr
jmp irq_all_tf
irq_kernel_tf:
# we don't muck with fs/gsbase, push placeholders
movq $0xdeadbeef, %rax
pushq %rax
pushq %rax
irq_all_tf:
movq $0, %rbp # so we can backtrace to this point
movq %rsp, %rdi
call handle_irq
# the return paths are only used by the kernel
addq $0x10, %rsp # skip fs/gs base
popq %rax
popq %rbx
popq %rcx
popq %rdx
popq %rbp
popq %rsi
popq %rdi
popq %r8
popq %r9
popq %r10
popq %r11
popq %r12
popq %r13
popq %r14
popq %r15
addq $0x10, %rsp # skip trapno and err
iretq
.globl sysenter_handler;
.type sysenter_handler, @function;
sysenter_handler:
#ifndef CONFIG_NOFASTCALL_FSBASE
# Do a quick TLS / FS base change, never changing stacks.
# When rdi has the magic number, rsi has the new base
movabs $FASTCALL_SETFSBASE, %rax
cmp %rax, %rdi
jne normal_syscall # could profile this and handle the jump differently
# need to check rsi, make sure it is canonical (will enfore below ULIM).
# need to either do this check, or handle the kernel GP fault on wrmsr.
movq %rsi, %rdi
shrq $47, %rdi
cmp $0, %rdi
jne fastcall_pop
# need to use cx, dx, and ax for the wrmsr. dx and ax are free.
movq %rcx, %rdi # save rcx, the retaddr
movq %rsi, %rdx
movq %rsi, %rax
shrq $32, %rdx
andl $0xffffffff, %eax
movl $MSR_FS_BASE, %ecx
wrmsr
movq %rdi, %rcx # restore retaddr
fastcall_pop:
rex.w sysret
normal_syscall:
#endif
# cld is handled by the SFMASK
swapgs
movq %gs:0, %rsp
# Saving the FPU callee-saved state for now. Might be able to have the
# preempt handler deal with it.
pushq $0 # space for mxcsr and fpucw
fnstcw 0x4(%rsp)
stmxcsr (%rsp)
pushq %rdx # rsp, saved by userspace
pushq %rcx # rip, saved by hardware
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbp
pushq %rbx
# save fs and gs base
movl $MSR_FS_BASE, %ecx
rdmsr
shl $32, %rdx
orq %rax, %rdx
pushq %rdx
# because we swapped gs earlier, the user GS is now in KERN_GS_BASE
movl $MSR_KERN_GS_BASE, %ecx
rdmsr
shl $32, %rdx
orq %rax, %rdx
pushq %rdx
# make sure the kernel's gs base is loaded into the KERN slot at all times
movl $MSR_GS_BASE, %ecx
rdmsr
movl $MSR_KERN_GS_BASE, %ecx
wrmsr
movq $0, %rbp # so we can backtrace to this point
movq %rsp, %rdx
# arg0, rdi: struct sysc*. arg1, rsi: count. arg2, rdx: sw_tf
call sysenter_callwrapper
# return via pop_tf, never this path
sysenter_spin:
jmp sysenter_spin