-
Notifications
You must be signed in to change notification settings - Fork 47
/
Copy pathidt.rs
299 lines (259 loc) · 7.48 KB
/
idt.rs
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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2022-2023 SUSE LLC
//
// Author: Joerg Roedel <[email protected]>
use super::control_regs::read_cr2;
use super::tss::IST_DF;
use super::vc::handle_vc_exception;
use super::{X86GeneralRegs, X86InterruptFrame};
use crate::address::{Address, VirtAddr};
use crate::cpu::extable::handle_exception_table;
use crate::debug::gdbstub::svsm_gdbstub::handle_bp_exception;
use crate::types::SVSM_CS;
use core::arch::{asm, global_asm};
use core::mem;
pub const _DE_VECTOR: usize = 0;
pub const _DB_VECTOR: usize = 1;
pub const _NMI_VECTOR: usize = 2;
pub const BP_VECTOR: usize = 3;
pub const _OF_VECTOR: usize = 4;
pub const _BR_VECTOR: usize = 5;
pub const _UD_VECTOR: usize = 6;
pub const _NM_VECTOR: usize = 7;
pub const DF_VECTOR: usize = 8;
pub const _CSO_VECTOR: usize = 9;
pub const _TS_VECTOR: usize = 10;
pub const _NP_VECTOR: usize = 11;
pub const _SS_VECTOR: usize = 12;
pub const GP_VECTOR: usize = 13;
pub const PF_VECTOR: usize = 14;
pub const _MF_VECTOR: usize = 16;
pub const _AC_VECTOR: usize = 17;
pub const _MCE_VECTOR: usize = 18;
pub const _XF_VECTOR: usize = 19;
pub const _CP_VECTOR: usize = 21;
pub const _HV_VECTOR: usize = 28;
pub const VC_VECTOR: usize = 29;
pub const _SX_VECTOR: usize = 30;
#[repr(C, packed)]
#[derive(Default, Debug)]
pub struct X86ExceptionContext {
pub regs: X86GeneralRegs,
pub vector: usize,
pub error_code: usize,
pub frame: X86InterruptFrame,
}
#[derive(Copy, Clone, Default, Debug)]
#[repr(C, packed)]
struct IdtEntry {
low: u64,
high: u64,
}
const IDT_TARGET_MASK_1: u64 = 0x0000_0000_0000_ffff;
const IDT_TARGET_MASK_2: u64 = 0x0000_0000_ffff_0000;
const IDT_TARGET_MASK_3: u64 = 0xffff_ffff_0000_0000;
const IDT_TARGET_MASK_1_SHIFT: u64 = 0;
const IDT_TARGET_MASK_2_SHIFT: u64 = 48 - 16;
const IDT_TARGET_MASK_3_SHIFT: u64 = 32;
const IDT_TYPE_MASK: u64 = 0xeu64 << 40; // Only interrupt gates for now
const IDT_PRESENT_MASK: u64 = 0x1u64 << 47;
const IDT_CS_SHIFT: u64 = 16;
const IDT_IST_MASK: u64 = 0x7;
const IDT_IST_SHIFT: u64 = 32;
impl IdtEntry {
fn create(target: VirtAddr, cs: u16, ist: u8) -> Self {
let vaddr = target.bits() as u64;
let cs_mask = (cs as u64) << IDT_CS_SHIFT;
let ist_mask = ((ist as u64) & IDT_IST_MASK) << IDT_IST_SHIFT;
let low = (vaddr & IDT_TARGET_MASK_1) << IDT_TARGET_MASK_1_SHIFT
| (vaddr & IDT_TARGET_MASK_2) << IDT_TARGET_MASK_2_SHIFT
| IDT_TYPE_MASK
| IDT_PRESENT_MASK
| cs_mask
| ist_mask;
let high = (vaddr & IDT_TARGET_MASK_3) >> IDT_TARGET_MASK_3_SHIFT;
IdtEntry { low, high }
}
pub fn entry(target: VirtAddr) -> Self {
IdtEntry::create(target, SVSM_CS, 0)
}
pub fn ist_entry(target: VirtAddr, ist: u8) -> Self {
IdtEntry::create(target, SVSM_CS, ist)
}
pub const fn no_handler() -> Self {
IdtEntry { low: 0, high: 0 }
}
}
const IDT_ENTRIES: usize = 256;
#[repr(C, packed)]
struct IdtDesc {
size: u16,
address: VirtAddr,
}
extern "C" {
static idt_handler_array: u8;
}
type Idt = [IdtEntry; IDT_ENTRIES];
static mut GLOBAL_IDT: Idt = [IdtEntry::no_handler(); IDT_ENTRIES];
pub fn idt_base_limit() -> (u64, u32) {
unsafe {
let base = (&GLOBAL_IDT as *const Idt) as u64;
let limit = (IDT_ENTRIES * mem::size_of::<IdtEntry>()) as u32;
(base, limit)
}
}
fn init_idt(idt: &mut Idt) {
// Set IDT handlers
let handlers = unsafe { VirtAddr::from(&idt_handler_array as *const u8) };
for (i, entry) in idt.iter_mut().enumerate() {
*entry = IdtEntry::entry(handlers + (32 * i));
}
}
unsafe fn init_ist_vectors(idt: &mut Idt) {
let handler = VirtAddr::from(&idt_handler_array as *const u8) + (32 * DF_VECTOR);
idt[DF_VECTOR] = IdtEntry::ist_entry(handler, IST_DF.try_into().unwrap());
}
fn load_idt(idt: &Idt) {
let desc: IdtDesc = IdtDesc {
size: (IDT_ENTRIES * 16) as u16,
address: VirtAddr::from(idt.as_ptr()),
};
unsafe {
asm!("lidt (%rax)", in("rax") &desc, options(att_syntax));
}
}
pub fn triple_fault() {
let desc: IdtDesc = IdtDesc {
size: 0,
address: VirtAddr::from(0u64),
};
unsafe {
asm!("lidt (%rax)
int3", in("rax") &desc, options(att_syntax));
}
}
pub fn early_idt_init() {
unsafe {
init_idt(&mut GLOBAL_IDT);
load_idt(&GLOBAL_IDT);
}
}
pub fn idt_init() {
// Set IST vectors
unsafe {
init_ist_vectors(&mut GLOBAL_IDT);
}
}
#[no_mangle]
fn generic_idt_handler(ctx: &mut X86ExceptionContext) {
if ctx.vector == DF_VECTOR {
let cr2 = read_cr2();
let rip = ctx.frame.rip;
let rsp = ctx.frame.rsp;
panic!(
"Double-Fault at RIP {:#018x} RSP: {:#018x} CR2: {:#018x}",
rip, rsp, cr2
);
} else if ctx.vector == GP_VECTOR {
let rip = ctx.frame.rip;
let err = ctx.error_code;
if !handle_exception_table(ctx) {
panic!(
"Unhandled General-Protection-Fault at RIP {:#018x} error code: {:#018x}",
rip, err
);
}
} else if ctx.vector == PF_VECTOR {
let cr2 = read_cr2();
let rip = ctx.frame.rip;
let err = ctx.error_code;
if !handle_exception_table(ctx) {
panic!(
"Unhandled Page-Fault at RIP {:#018x} CR2: {:#018x} error code: {:#018x}",
rip, cr2, err
);
}
} else if ctx.vector == VC_VECTOR {
handle_vc_exception(ctx);
} else if ctx.vector == BP_VECTOR {
handle_bp_exception(ctx);
} else {
let err = ctx.error_code;
let vec = ctx.vector;
let rip = ctx.frame.rip;
if !handle_exception_table(ctx) {
panic!(
"Unhandled exception {} RIP {:#018x} error code: {:#018x}",
vec, rip, err
);
}
}
}
#[cfg(feature = "enable-stacktrace")]
extern "C" {
static generic_idt_handler_return: u8;
}
#[cfg(feature = "enable-stacktrace")]
pub fn is_exception_handler_return_site(rip: VirtAddr) -> bool {
let addr = unsafe { VirtAddr::from(&generic_idt_handler_return as *const u8) };
addr == rip
}
// Entry Code
global_asm!(
r#"
.text
push_regs:
pushq %rax
pushq %rbx
pushq %rcx
pushq %rdx
pushq %rsi
pushq %rdi
pushq %rbp
pushq %r8
pushq %r9
pushq %r10
pushq %r11
pushq %r12
pushq %r13
pushq %r14
pushq %r15
movq %rsp, %rdi
call generic_idt_handler
/* Needed by the stack unwinder to recognize exception frames. */
.globl generic_idt_handler_return
generic_idt_handler_return:
popq %r15
popq %r14
popq %r13
popq %r12
popq %r11
popq %r10
popq %r9
popq %r8
popq %rbp
popq %rdi
popq %rsi
popq %rdx
popq %rcx
popq %rbx
popq %rax
addq $16, %rsp /* Skip vector and error code */
iretq
.align 32
.globl idt_handler_array
idt_handler_array:
i = 0
.rept 32
.align 32
.if ((0x20027d00 >> i) & 1) == 0
pushq $0
.endif
pushq $i /* Vector Number */
jmp push_regs
i = i + 1
.endr
"#,
options(att_syntax)
);