1/* 2 * Copyright (c) 2009 Corey Tabaka 3 * Copyright (c) 2015-2018 Intel Corporation 4 * Copyright (c) 2016 Travis Geiselbrecht 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining 7 * a copy of this software and associated documentation files 8 * (the "Software"), to deal in the Software without restriction, 9 * including without limitation the rights to use, copy, modify, merge, 10 * publish, distribute, sublicense, and/or sell copies of the Software, 11 * and to permit persons to whom the Software is furnished to do so, 12 * subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be 15 * included in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 */ 25#include <asm.h> 26#include <arch/x86/descriptor.h> 27#include <arch/x86/exceptions.h> 28 29#define NUM_INT 0x100 30#define NUM_EXC 0x14 31 32.text 33 34/* interrupt service routine stubs */ 35.align 16 36 37/* Maxium lenth is 12 */ 38.set isr_stub_len, 12 39_isr: 40.set i, 0 41.rept NUM_INT 42 43.org _isr + i * isr_stub_len 44.if i == 8 || (i >= 10 && i <= 14) || i == 17 45 pushq $i /* interrupt number */ 46 jmp interrupt_common 47.else 48 pushq $0 /* fill in error code in iframe */ 49 pushq $i /* interrupt number */ 50 jmp interrupt_common 51.endif 52 53.set i, i + 1 54.endr 55 56/* annoying, but force AS to use the same (longer) encoding of jmp for all of the stubs */ 57.fill 256 58 59interrupt_common: 60 /* Check if from user space */ 61 testb $3, 0x18(%rsp) 62 jz .Lskip_swapgs_in 63 swapgs 64 65.Lskip_swapgs_in: 66 /* save general purpose registers */ 67 pushq %r15 68 pushq %r14 69 pushq %r13 70 pushq %r12 71 pushq %r11 72 pushq %r10 73 pushq %r9 74 pushq %r8 75 pushq %rax 76 pushq %rcx 77 pushq %rdx 78 pushq %rbx 79 pushq %rbp 80 pushq %rsi 81 pushq %rdi 82 83 movq %rsp, %rdi /* pass the iframe using rdi */ 84 85 call x86_exception_handler 86 87 /* restore general purpose registers */ 88 popq %rdi 89 popq %rsi 90 popq %rbp 91 popq %rbx 92 popq %rdx 93 popq %rcx 94 popq %rax 95 popq %r8 96 popq %r9 97 popq %r10 98 popq %r11 99 popq %r12 100 popq %r13 101 popq %r14 102 popq %r15 103 104 /* check if back to user space */ 105 testb $3, 0x18(%rsp) 106 jz .Lskip_swapgs_out 107 swapgs 108 109.Lskip_swapgs_out: 110 /* drop vector number and error code*/ 111 addq $16, %rsp 112 iretq 113 114FUNCTION(setup_idt) 115 /* setup isr stub descriptors in the idt */ 116 mov $_isr, %rsi 117 mov $_idt, %rdi 118 movl $NUM_INT, %ecx 119 120.Lloop: 121 mov %rsi, %rbx 122 movw %bx, (%rdi) /* offset [0:15] in IDT(n).low */ 123 shr $16, %rbx 124 movw %bx, 6(%rdi) /* offset [16:31] in IDT(n).high */ 125 shr $16, %rbx 126 movl %ebx, 8(%rdi) /* offset [32:63] */ 127 128 add $isr_stub_len, %rsi /* index the next ISR stub */ 129 add $16, %rdi /* index the next IDT entry */ 130 131 loop .Lloop 132 133 lidt _idtr 134 135 ret 136 137.data 138 139.align 8 140DATA(_idtr) 141 .short _idt_end - _idt - 1 /* IDT limit */ 142 .quad _idt 143.fill 8 144 145.align 8 146/* interrupt descriptor table (IDT) */ 147DATA(_idt) 148 149.set i, 0 150.rept NUM_INT 151 .short 0 /* low 16 bits of ISR offset (_isr#i & 0FFFFh) */ 152 .short CODE_64_SELECTOR /* selector */ 153.if i == INT_DOUBLE_FAULT || i == INT_NMI 154 /* 155 * Use dedicated stack ist1 for Double Fault Exception and 156 * Non-Maskable-Interrupt Exception. Resetting the stack pointer for 157 * double faults allows the kernel to recover from kernel stack 158 * overflows. Resetting the stack on NMI exceptions allows the NMI 159 * exception handler to run if the NMI triggered when the stack pointer 160 * was invalid, e.g. on syscall entry. 161 */ 162 .byte 1 163.else 164 .byte 0 165.endif 166 .byte 0x8e /* present, ring 0, 64-bit interrupt gate */ 167 .short 0 /* high 16 bits of ISR offset (_isr#i / 65536) */ 168 .short 0 /* ISR offset */ 169 .short 0 /* ISR offset */ 170 .short 0 /* 32bits Reserved */ 171 .short 0 /* 32bits Reserved */ 172 173 174.set i, i + 1 175.endr 176 177.global _idt_end 178_idt_end: 179 180