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