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