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