File size: 4,681 Bytes
8df6da4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
#ifndef __IDT_TEST__
#define __IDT_TEST__

#include <setjmp.h>

void setup_idt(void);
void setup_alt_stack(void);

struct ex_regs {
    unsigned long rax, rcx, rdx, rbx;
    unsigned long dummy, rbp, rsi, rdi;
#ifdef __x86_64__
    unsigned long r8, r9, r10, r11;
    unsigned long r12, r13, r14, r15;
#endif
    unsigned long vector;
    unsigned long error_code;
    unsigned long rip;
    unsigned long cs;
    unsigned long rflags;
};

typedef void (*handler)(struct ex_regs *regs);

typedef struct {
	u16 prev;
	u16 res1;
	u32 esp0;
	u16 ss0;
	u16 res2;
	u32 esp1;
	u16 ss1;
	u16 res3;
	u32 esp2;
	u16 ss2;
	u16 res4;
	u32 cr3;
	u32 eip;
	u32 eflags;
	u32 eax, ecx, edx, ebx, esp, ebp, esi, edi;
	u16 es;
	u16 res5;
	u16 cs;
	u16 res6;
	u16 ss;
	u16 res7;
	u16 ds;
	u16 res8;
	u16 fs;
	u16 res9;
	u16 gs;
	u16 res10;
	u16 ldt;
	u16 res11;
	u16 t:1;
	u16 res12:15;
	u16 iomap_base;
} tss32_t;

typedef struct  __attribute__((packed)) {
	u32 res1;
	u64 rsp0;
	u64 rsp1;
	u64 rsp2;
	u64 res2;
	u64 ist1;
	u64 ist2;
	u64 ist3;
	u64 ist4;
	u64 ist5;
	u64 ist6;
	u64 ist7;
	u64 res3;
	u16 res4;
	u16 iomap_base;
} tss64_t;

#define ASM_TRY(catch)                                  \
    "movl $0, %%gs:4 \n\t"                              \
    ".pushsection .data.ex \n\t"                        \
    ".quad 1111f, " catch "\n\t"                        \
    ".popsection \n\t"                                  \
    "1111:"

#define DB_VECTOR   1
#define BP_VECTOR   3
#define UD_VECTOR   6
#define GP_VECTOR   13

/*
 * selector     32-bit                        64-bit
 * 0x00         NULL descriptor               NULL descriptor
 * 0x08         ring-0 code segment (32-bit)  ring-0 code segment (64-bit)
 * 0x10         ring-0 data segment (32-bit)  ring-0 data segment (32/64-bit)
 * 0x18         ring-0 code segment (P=0)     ring-0 code segment (64-bit, P=0)
 * 0x20         intr_alt_stack TSS            ring-0 code segment (32-bit)
 * 0x28         ring-0 code segment (16-bit)  same
 * 0x30         ring-0 data segment (16-bit)  same
 * 0x38 (0x3b)  ring-3 code segment (32-bit)  same
 * 0x40 (0x43)  ring-3 data segment (32-bit)  ring-3 data segment (32/64-bit)
 * 0x48 (0x4b)  **unused**                    ring-3 code segment (64-bit)
 * 0x50--0x78   free to use for test cases    same
 * 0x80         primary TSS (CPU 0)           same
 *
 * Note that the same segment can be used for 32-bit and 64-bit data segments
 * (the L bit is only defined for code segments)
 *
 * Selectors 0x08-0x10 and 0x3b-0x4b are set up for use with the SYSCALL
 * and SYSRET instructions.
 */

#define KERNEL_CS   0x08
#define KERNEL_DS   0x10
#define NP_SEL      0x18
#ifdef __x86_64__
#define KERNEL_CS32 0x20
#else
#define TSS_INTR    0x20
#endif
#define KERNEL_CS16 0x28
#define KERNEL_DS16 0x30
#define USER_CS32   0x3b
#define USER_DS     0x43
#ifdef __x86_64__
#define USER_CS64   0x4b
#endif

/* Synonyms */
#define KERNEL_DS32 KERNEL_DS
#define USER_DS32   USER_DS

#ifdef __x86_64__
#define KERNEL_CS64 KERNEL_CS
#define USER_CS     USER_CS64
#define KERNEL_DS64 KERNEL_DS
#define USER_DS64   USER_DS
#else
#define KERNEL_CS32 KERNEL_CS
#define USER_CS     USER_CS32
#endif

#define FIRST_SPARE_SEL 0x50
#define TSS_MAIN 0x80

typedef struct {
    unsigned short offset0;
    unsigned short selector;
    unsigned short ist : 3;
    unsigned short : 5;
    unsigned short type : 4;
    unsigned short : 1;
    unsigned short dpl : 2;
    unsigned short p : 1;
    unsigned short offset1;
#ifdef __x86_64__
    unsigned offset2;
    unsigned reserved;
#endif
} idt_entry_t;

typedef struct {
	u16 limit_low;
	u16 base_low;
	u8 base_middle;
	u8 access;
	u8 granularity;
	u8 base_high;
} gdt_entry_t;

extern idt_entry_t boot_idt[256];

#ifndef __x86_64__
extern gdt_entry_t gdt32[];
extern tss32_t tss;
extern tss32_t tss_intr;
void set_gdt_task_gate(u16 tss_sel, u16 sel);
void set_idt_task_gate(int vec, u16 sel);
void set_intr_task_gate(int vec, void *fn);
void setup_tss32(void);
#else
extern tss64_t tss;
#endif

unsigned exception_vector(void);
unsigned exception_error_code(void);
bool exception_rflags_rf(void);
void set_idt_entry(int vec, void *addr, int dpl);
void set_idt_sel(int vec, u16 sel);
void set_idt_dpl(int vec, u16 dpl);
void set_gdt_entry(int sel, u32 base,  u32 limit, u8 access, u8 gran);
void set_intr_alt_stack(int e, void *fn);
void print_current_tss_info(void);
handler handle_exception(u8 v, handler fn);

bool test_for_exception(unsigned int ex, void (*trigger_func)(void *data),
			void *data);
void __set_exception_jmpbuf(jmp_buf *addr);
#define set_exception_jmpbuf(jmpbuf) \
	(setjmp(jmpbuf) ? : (__set_exception_jmpbuf(&(jmpbuf)), 0))

#endif