1/*
2 * Copyright (c) 2009 Corey Tabaka
3 * Copyright (c) 2015 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
28#define NUM_INT 0x31
29#define NUM_EXC 0x14
30
31.text
32
33/* interrupt service routine stubs */
34_isr:
35
36.set i, 0
37.rept NUM_INT
38
39.set isr_stub_start, .
40
41.if i == 8 || (i >= 10 && i <= 14) || i == 17
42    nop                     /* error code pushed by exception */
43    nop                     /* 2 nops are the same length as push byte */
44    pushl $i                /* interrupt number */
45    jmp interrupt_common
46.else
47    pushl $0                /* fill in error code in iframe */
48    pushl $i                /* interrupt number */
49    jmp interrupt_common
50.endif
51
52/* figure out the length of a single isr stub (usually 6 or 9 bytes) */
53.set isr_stub_len, . - isr_stub_start
54
55.set i, i + 1
56.endr
57
58/* annoying, but force AS to use the same (longer) encoding of jmp for all of the stubs */
59.fill 256
60
61FUNCTION(interrupt_common)
62    pushl %gs               /* save segment registers */
63    pushl %fs
64    pushl %es
65    pushl %ds
66    pusha                   /* save general purpose registers */
67    movl $DATA_SELECTOR, %eax /* put known good value in segment registers */
68    movl %eax, %gs
69    movl %eax, %fs
70    movl %eax, %es
71    movl %eax, %ds
72
73    movl %esp, %eax         /* store pointer to iframe */
74    pushl %eax
75
76    call x86_exception_handler
77
78    popl %eax               /* drop pointer to iframe */
79
80    popa                    /* restore general purpose registers */
81    popl %ds                /* restore segment registers */
82    popl %es
83    popl %fs
84    popl %gs
85    addl $8, %esp           /* drop exception number and error code */
86    iret
87
88FUNCTION(setup_idt)
89    /* setup isr stub descriptors in the idt */
90    movl $_isr, %esi
91    movl $_idt, %edi
92    movl $NUM_INT, %ecx
93
94.Lloop:
95    movl %esi, %ebx
96    movw %bx, (%edi)        /* low word in IDT(n).low */
97    shrl $16, %ebx
98    movw %bx, 6(%edi)       /* high word in IDT(n).high */
99
100    addl $isr_stub_len, %esi/* index the next ISR stub */
101    addl $8, %edi           /* index the next IDT entry */
102
103    loop .Lloop
104
105    lidt _idtr
106
107    ret
108
109.data
110
111.align 8
112.global _idtr
113_idtr:
114    .short _idt_end - _idt - 1  /* IDT limit */
115    .int _idt
116
117/* interrupt descriptor table (IDT) */
118.global _idt
119_idt:
120
121.set i, 0
122.rept NUM_INT-1
123    .short 0                /* low 16 bits of ISR offset (_isr#i & 0FFFFh) */
124    .short CODE_SELECTOR    /* selector */
125    .byte  0
126    .byte  0x8e             /* present, ring 0, 32-bit interrupt gate */
127    .short 0                /* high 16 bits of ISR offset (_isr#i / 65536) */
128
129.set i, i + 1
130.endr
131
132/* syscall int (ring 3) */
133_idt30:
134    .short 0                /* low 16 bits of ISR offset (_isr#i & 0FFFFh) */
135    .short CODE_SELECTOR    /* selector */
136    .byte  0
137    .byte  0xee             /* present, ring 3, 32-bit interrupt gate */
138    .short 0                /* high 16 bits of ISR offset (_isr#i / 65536) */
139
140.global _idt_end
141_idt_end:
142
143
144