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