1/*
2 * Copyright (c) 2009 Corey Tabaka
3 * Copyright (c) 2015 Intel Corporation
4 * Copyright (c) 2016 Travis Geiselbrecht
5 *
6 * Use of this source code is governed by a MIT-style
7 * license that can be found in the LICENSE file or at
8 * https://opensource.org/licenses/MIT
9 */
10#include <lk/asm.h>
11#include <arch/x86/descriptor.h>
12
13#define NUM_INT 0x100
14#define ISR_STUB_LEN 16
15
16.text
17
18/* interrupt service routine stubs */
19
20/*
21 * pushq $i occupies 5 bytes when i >= 0x80 compare to
22 * 2 bytes when i < 0x80, use align to fill the gap
23 * to make sure isr_stub_len correct for each interrupts
24 */
25.balign ISR_STUB_LEN
26LOCAL_FUNCTION(_isr_vectors)
27_isr:
28.set i, 0
29.rept NUM_INT
30
31.balign ISR_STUB_LEN
32.if i == 8 || (i >= 10 && i <= 14) || i == 17
33    /* error code pushed by exception */
34    push $i        /* interrupt number */
35    jmp  interrupt_common
36.else
37    push $0        /* fill in error code in iframe */
38    push $i        /* interrupt number */
39    jmp  interrupt_common
40.endif
41
42.set i, i + 1
43.endr
44END_FUNCTION(_isr_vectors)
45
46.balign 16
47LOCAL_FUNCTION(interrupt_common)
48    /* clear the direction bit */
49    cld
50
51    /* save general purpose registers */
52    pushq %r15
53    pushq %r14
54    pushq %r13
55    pushq %r12
56    pushq %r11
57    pushq %r10
58    pushq %r9
59    pushq %r8
60    pushq %rax
61    pushq %rcx
62    pushq %rdx
63    pushq %rbx
64    pushq %rbp
65    pushq %rsi
66    pushq %rdi
67
68    /* TODO: deal with swapgs if coming from user space */
69
70    /* pass the  iframe using rdi */
71    movq %rsp, %rdi
72
73    call x86_exception_handler
74
75    /* restore general purpose registers */
76    popq %rdi
77    popq %rsi
78    popq %rbp
79    popq %rbx
80    popq %rdx
81    popq %rcx
82    popq %rax
83    popq %r8
84    popq %r9
85    popq %r10
86    popq %r11
87    popq %r12
88    popq %r13
89    popq %r14
90    popq %r15
91
92    /* drop vector number and error code*/
93    addq $16, %rsp
94    iretq
95END_FUNCTION(interrupt_common)
96
97FUNCTION(setup_idt)
98    /* setup isr stub descriptors in the idt */
99    mov  $_isr_vectors, %rsi
100    mov  $_idt, %rdi
101    movl $NUM_INT, %ecx
102
103.Lloop:
104    mov  %rsi, %rbx
105    movw %bx, (%rdi)        /* offset [0:15] in IDT(n).low */
106    shr  $16, %rbx
107    movw %bx, 6(%rdi)       /* offset [16:31] in IDT(n).high */
108    shr  $16, %rbx
109    movl %ebx, 8(%rdi)      /* offset [32:63] */
110
111    add  $ISR_STUB_LEN, %rsi    /* index the next ISR stub */
112    add  $16, %rdi          /* index the next IDT entry */
113
114    loop .Lloop
115
116    ret
117END_FUNCTION(setup_idt)
118
119.data
120
121.balign 8
122DATA(_idtr)
123    .short _idt_end - _idt - 1  /* IDT limit */
124    .quad _idt
125END_DATA(_idtr)
126
127.balign 16
128/* interrupt descriptor table (IDT) */
129DATA(_idt)
130
131.set i, 0
132.rept NUM_INT
133    .short 0        /* low 16 bits of ISR offset (_isr#i & 0FFFFh) */
134    .short CODE_64_SELECTOR   /* selector */
135    .byte  0
136    .byte  0x8e     /* present, ring 0, 64-bit interrupt gate */
137    .short  0       /* high 16 bits of ISR offset (_isr#i / 65536) */
138    .short  0       /* ISR offset */
139    .short  0       /* ISR offset */
140    .short  0       /* 32bits Reserved */
141    .short  0       /* 32bits Reserved */
142
143.set i, i + 1
144.endr
145
146END_DATA(_idt)
147
148DATA(_idt_end)
149
150
151