-
Notifications
You must be signed in to change notification settings - Fork 0
/
idt.h
147 lines (125 loc) · 3.04 KB
/
idt.h
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
#ifndef __IDT_H
#define __IDT_H
#include <pshpack1.h>
struct gdtr {
u16 limit;
uintptr_t base;
};
typedef union {
u64 i;
struct {
u16 lo;
u16 sel;
u8 ist : 3;
u8 zero : 5;
u8 type : 5;
u8 dpl : 2;
u8 p : 1;
u16 mid;
};
} kidt_entry_t;
struct kidt_entry64 {
kidt_entry_t e32;
u32 hi;
u32 zero;
};
#include <poppack.h>
#define LOW_U16_U64(x) ((u64)(x) & 0xFFFF)
#define MID_U16_U64(x) (((u64)(x) >> 16) & 0xFFFF)
#define HIGH_U32_U64(x) ((u64)(x) >> 32)
static inline bool idte_present(const struct kidt_entry64 *e)
{
return e->e32.p;
}
static inline u16 ide_sel(const struct kidt_entry64 *e)
{
return e->e32.sel;
}
static inline u64 idte_addr(const struct kidt_entry64 *e)
{
const kidt_entry_t *e32 = &e->e32;
return (u64)e->hi << 32 | ((u32)e32->mid << 16 | e32->lo);
}
static inline struct kidt_entry64 *idt_entry(uintptr_t base, unsigned n)
{
struct kidt_entry64 *table = (struct kidt_entry64 *)base;
return &table[n];
}
static inline void pack_entry(struct kidt_entry64 *entry, u16 selector, uintptr_t addr)
{
entry->hi = HIGH_U32_U64(addr);
entry->zero = 0;
kidt_entry_t *e = &entry->e32;
e->lo = LOW_U16_U64(addr);
e->sel = selector;
e->ist = 0;
e->zero = 0;
e->type = GATE_INTERRUPT;
e->dpl = 0;
e->p = 1;
e->mid = MID_U16_U64(addr);
}
static inline void put_entry(uintptr_t base, unsigned n, struct kidt_entry64 *entry)
{
memcpy(idt_entry(base, n), entry, sizeof(*entry));
}
static inline void __set_intr_gate(unsigned n, u16 selector, uintptr_t base, uintptr_t addr)
{
struct kidt_entry64 entry;
pack_entry(&entry, selector, addr);
put_entry(base, n, &entry);
}
static inline void set_intr_gate(unsigned n, u16 selector, uintptr_t base, void *addr)
{
NT_ASSERT(n <= 0xFF);
return __set_intr_gate(n, selector, base, (uintptr_t)addr);
}
typedef union {
u64 all;
struct {
u64 limit_low : 16;
u64 base_low : 16;
u64 base_mid : 8;
u64 type : 4;
u64 system : 1;
u64 dpl : 2;
u64 present : 1;
u64 limit_high : 4;
u64 avl : 1;
u64 l : 1;
u64 db : 1;
u64 gran : 1;
u64 base_high : 8;
};
} segmentdesc_t;
typedef struct {
segmentdesc_t d32;
u32 base_upper32;
u32 reserved;
} segmentdesc64_t;
static inline segmentdesc_t *segment_desc(uintptr_t gdt, u16 sel)
{
return (segmentdesc_t *)(gdt + (sel >> 3) * sizeof(segmentdesc_t));
}
static uintptr_t segment_desc_base(segmentdesc_t *desc)
{
uintptr_t base = (desc->base_high << 24 | desc->base_mid << 16 | desc->base_low) & MAXULONG;
if (!desc->system)
base |= (uintptr_t)(((segmentdesc64_t *)desc)->base_upper32) << 32;
return base;
}
static uintptr_t __segmentbase(uintptr_t gdt, u16 sel)
{
if (!sel)
return 0;
/* If it's an LDT segment, load the LDT, we deal with GDT mostly here,
* it's very unlikely that this will branch... See calls down below in setup_vmcs().
* in vcpu.c (Hence parameter name "gdt") */
if (sel & 4) {
segmentdesc_t *ldt = segment_desc(gdt, __sldt());
uintptr_t ldt_base = segment_desc_base(ldt);
return segment_desc_base(segment_desc(ldt_base, sel));
}
return segment_desc_base(segment_desc(gdt, sel));
}
#endif