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.balign ISR_STUB_LEN
20LOCAL_FUNCTION(_isr_vectors)
21.set i, 0
22.rept NUM_INT
23
24.balign ISR_STUB_LEN
25.if i == 8 || (i >= 10 && i <= 14) || i == 17
26    /* error code pushed by exception */
27    push $i                 /* interrupt number */
28    jmp interrupt_common
29.else
30    push $0                 /* fill in error code in iframe */
31    push $i                 /* interrupt number */
32    jmp interrupt_common
33.endif
34
35.set i, i + 1
36.endr
37END_FUNCTION(_isr_vectors)
38
39.balign 16
40LOCAL_FUNCTION(interrupt_common)
41    cld
42    pushl %gs               /* save segment registers */
43    pushl %fs
44    pushl %es
45    pushl %ds
46    pusha                   /* save general purpose registers */
47    movl $DATA_SELECTOR, %eax /* put known good value in segment registers */
48    // do not reset %gs, as it is used by the kernel
49    // TODO: when dealing with user space, we need to reset %gs here
50    movl %eax, %fs
51    movl %eax, %es
52    movl %eax, %ds
53
54    movl %esp, %eax         /* store pointer to iframe */
55    pushl %eax
56
57    call x86_exception_handler
58
59    popl %eax               /* drop pointer to iframe */
60
61    popa                    /* restore general purpose registers */
62    popl %ds                /* restore segment registers */
63    popl %es
64    popl %fs
65    addl $12, %esp          /* drop gs, exception number, and error code */
66    iret
67END_FUNCTION(interrupt_common)
68
69FUNCTION(setup_idt)
70    /* setup isr stub descriptors in the idt */
71    movl $_isr_vectors, %esi
72    movl $_idt, %edi
73    movl $NUM_INT, %ecx
74
75.Lloop:
76    movl %esi, %ebx
77    movw %bx, (%edi)        /* low word in IDT(n).low */
78    shrl $16, %ebx
79    movw %bx, 6(%edi)       /* high word in IDT(n).high */
80
81    addl $ISR_STUB_LEN, %esi/* index the next ISR stub */
82    addl $8, %edi           /* index the next IDT entry */
83
84    loop .Lloop
85
86    ret
87END_FUNCTION(setup_idt)
88
89.data
90
91.balign 8
92DATA(_idtr)
93    .short _idt_end - _idt - 1  /* IDT limit */
94    .int _idt
95END_DATA(_idtr)
96
97/* interrupt descriptor table (IDT) */
98.balign 8
99DATA(_idt)
100.set i, 0
101.rept NUM_INT-1
102    .short 0                /* low 16 bits of ISR offset (_isr#i & 0FFFFh) */
103    .short CODE_SELECTOR    /* selector */
104    .byte  0
105    .byte  0x8e             /* present, ring 0, 32-bit interrupt gate */
106    .short 0                /* high 16 bits of ISR offset (_isr#i / 65536) */
107
108.set i, i + 1
109.endr
110
111END_DATA(_idt)
112
113DATA(_idt_end)
114