Skip to content

Commit f9b134e

Browse files
Freax13Tom Dohrmann
authored andcommitted
add set_general_handler macro
1 parent e8aee52 commit f9b134e

File tree

1 file changed

+239
-0
lines changed

1 file changed

+239
-0
lines changed

src/structures/idt.rs

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,17 +1120,256 @@ pub enum ExceptionVector {
11201120
Security = 0x1E,
11211121
}
11221122

1123+
#[macro_export]
1124+
/// Set a general handler in an [`InterruptDescriptorTable`].
1125+
/// ```
1126+
/// #![feature(abi_x86_interrupt)]
1127+
/// use x86_64::set_general_handler;
1128+
/// use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
1129+
///
1130+
/// let mut idt = InterruptDescriptorTable::new();
1131+
/// fn my_general_handler(
1132+
/// stack_frame: InterruptStackFrame,
1133+
/// index: u8,
1134+
/// error_code: Option<u64>,
1135+
/// ) {
1136+
/// todo!("handle irq {}", index)
1137+
/// }
1138+
///
1139+
/// // set only one entry
1140+
/// set_general_handler!(&mut idt, my_general_handler, 14);
1141+
///
1142+
/// // set a range of entries
1143+
/// set_general_handler!(&mut idt, my_general_handler, 32..64);
1144+
///
1145+
/// // set all entries
1146+
/// set_general_handler!(&mut idt, my_general_handler);
1147+
/// ```
1148+
macro_rules! set_general_handler {
1149+
($idt:expr, $handler:ident) => {
1150+
$crate::set_general_handler!($idt, $handler, 0..=255);
1151+
};
1152+
($idt:expr, $handler:ident, $idx:literal) => {
1153+
$crate::set_general_handler!($idt, $handler, $idx..=$idx);
1154+
};
1155+
($idt:expr, $handler:ident, $range:expr) => {{
1156+
fn set_general_handler(
1157+
idt: &mut $crate::structures::idt::InterruptDescriptorTable,
1158+
range: impl core::ops::RangeBounds<usize>,
1159+
) {
1160+
$crate::set_general_handler_recursive_bits!(idt, $handler, range);
1161+
}
1162+
set_general_handler($idt, $range);
1163+
}};
1164+
}
1165+
1166+
#[macro_export]
1167+
#[doc(hidden)]
1168+
/// We can't loop in macros, but we can use recursion.
1169+
/// This macro recursivly adds one more bit to it's arguments until we have 8 bits so that we can call set_general_handler_entry.
1170+
macro_rules! set_general_handler_recursive_bits {
1171+
// if we have 8 all bits, construct the index from the bits, check if the entry is in range and invoke the macro that sets the handler
1172+
($idt:expr, $handler:ident, $range:expr, $bit7:tt, $bit6:tt, $bit5:tt, $bit4:tt, $bit3:tt, $bit2:tt, $bit1:tt, $bit0:tt) => {{
1173+
const IDX: u8 = $bit0 | ($bit1 << 1) | ($bit2 << 2) | ($bit3 << 3) | ($bit4 << 4) | ($bit5 << 5) | ($bit6 << 6) | ($bit7 << 7);
1174+
let idx = IDX as usize;
1175+
1176+
#[allow(unreachable_code)]
1177+
if $range.contains(&idx) {
1178+
$crate::set_general_handler_entry!($idt, $handler, IDX, $bit7, $bit6, $bit5, $bit4, $bit3, $bit2, $bit1, $bit0);
1179+
}
1180+
}};
1181+
// otherwise recursivly invoke the macro adding one more bit
1182+
($idt:expr, $handler:ident, $range:expr $(, $bits:tt)*) => {
1183+
$crate::set_general_handler_recursive_bits!($idt, $handler, $range $(, $bits)*, 0);
1184+
$crate::set_general_handler_recursive_bits!($idt, $handler, $range $(, $bits)*, 1);
1185+
};
1186+
}
1187+
1188+
#[macro_export]
1189+
#[doc(hidden)]
1190+
macro_rules! set_general_handler_entry {
1191+
// special case entries that don't have the `HandlerFunc` signature
1192+
($idt:expr, $handler:ident, $idx:expr, 0, 0, 0, 0, 1, 0, 0, 0) => {{
1193+
extern "x86-interrupt" fn handler(
1194+
frame: $crate::structures::idt::InterruptStackFrame,
1195+
error_code: u64,
1196+
) -> ! {
1197+
$handler(frame, $idx.into(), Some(error_code));
1198+
panic!("General handler returned on double fault");
1199+
}
1200+
$idt.double_fault.set_handler_fn(handler);
1201+
}};
1202+
($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 0, 1, 0, 1, 0) => {{
1203+
extern "x86-interrupt" fn handler(
1204+
frame: $crate::structures::idt::InterruptStackFrame,
1205+
error_code: u64,
1206+
) {
1207+
$handler(frame, $idx.into(), Some(error_code));
1208+
}
1209+
$idt.invalid_tss.set_handler_fn(handler);
1210+
}};
1211+
($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 0, 1, 0, 1, 1) => {{
1212+
extern "x86-interrupt" fn handler(
1213+
frame: $crate::structures::idt::InterruptStackFrame,
1214+
error_code: u64,
1215+
) {
1216+
$handler(frame, $idx.into(), Some(error_code));
1217+
}
1218+
$idt.segment_not_present.set_handler_fn(handler);
1219+
}};
1220+
($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 0, 1, 1, 0, 0) => {{
1221+
extern "x86-interrupt" fn handler(
1222+
frame: $crate::structures::idt::InterruptStackFrame,
1223+
error_code: u64,
1224+
) {
1225+
$handler(frame, $idx.into(), Some(error_code));
1226+
}
1227+
$idt.stack_segment_fault.set_handler_fn(handler);
1228+
}};
1229+
($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 0, 1, 1, 0, 1) => {{
1230+
extern "x86-interrupt" fn handler(
1231+
frame: $crate::structures::idt::InterruptStackFrame,
1232+
error_code: u64,
1233+
) {
1234+
$handler(frame, $idx.into(), Some(error_code));
1235+
}
1236+
$idt.general_protection_fault.set_handler_fn(handler);
1237+
}};
1238+
($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 0, 1, 1, 1, 0) => {{
1239+
extern "x86-interrupt" fn handler(
1240+
frame: $crate::structures::idt::InterruptStackFrame,
1241+
error_code: $crate::structures::idt::PageFaultErrorCode,
1242+
) {
1243+
$handler(frame, IDX.into(), Some(error_code.bits()));
1244+
}
1245+
$idt.page_fault.set_handler_fn(handler);
1246+
}};
1247+
($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 0, 0, 0, 1) => {{
1248+
extern "x86-interrupt" fn handler(
1249+
frame: $crate::structures::idt::InterruptStackFrame,
1250+
error_code: u64,
1251+
) {
1252+
$handler(frame, $idx.into(), Some(error_code));
1253+
}
1254+
$idt.alignment_check.set_handler_fn(handler);
1255+
}};
1256+
($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 0, 0, 1, 0) => {{
1257+
extern "x86-interrupt" fn handler(
1258+
frame: $crate::structures::idt::InterruptStackFrame,
1259+
) -> ! {
1260+
$handler(frame, $idx.into(), None);
1261+
panic!("General handler returned on machine check exception");
1262+
}
1263+
$idt.machine_check.set_handler_fn(handler);
1264+
}};
1265+
($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 1, 1, 1, 0) => {{
1266+
extern "x86-interrupt" fn handler(
1267+
frame: $crate::structures::idt::InterruptStackFrame,
1268+
error_code: u64,
1269+
) {
1270+
$handler(frame, $idx.into(), Some(error_code));
1271+
}
1272+
$idt.security_exception.set_handler_fn(handler);
1273+
}};
1274+
1275+
// reserved
1276+
($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 0, 1, 1, 1, 1) => {};
1277+
($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 0, 1, 0, 1) => {};
1278+
($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 0, 1, 1, 0) => {};
1279+
($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 0, 1, 1, 1) => {};
1280+
($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 1, 0, 0, 0) => {};
1281+
($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 1, 0, 0, 1) => {};
1282+
($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 1, 0, 1, 0) => {};
1283+
($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 1, 0, 1, 1) => {};
1284+
($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 1, 1, 0, 0) => {};
1285+
($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 1, 1, 0, 1) => {};
1286+
($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 1, 1, 1, 0) => {};
1287+
($idt:expr, $handler:ident, $idx:ident, 0, 0, 0, 1, 1, 1, 1, 1) => {};
1288+
1289+
// set entries with `HandlerFunc` signature
1290+
($idt:expr, $handler:ident, $idx:ident $(, $_bits:tt)*) => {{
1291+
extern "x86-interrupt" fn handler(frame: $crate::structures::idt::InterruptStackFrame) {
1292+
$handler(frame, $idx.into(), None);
1293+
}
1294+
$idt[$idx as usize].set_handler_fn(handler);
1295+
}};
1296+
}
1297+
11231298
#[cfg(test)]
11241299
mod test {
11251300
use super::*;
11261301

1302+
fn entry_present(idt: &InterruptDescriptorTable, index: usize) -> bool {
1303+
let options = match index {
1304+
8 => &idt.double_fault.options,
1305+
10 => &idt.invalid_tss.options,
1306+
11 => &idt.segment_not_present.options,
1307+
12 => &idt.stack_segment_fault.options,
1308+
13 => &idt.general_protection_fault.options,
1309+
14 => &idt.page_fault.options,
1310+
15 => &idt.reserved_1.options,
1311+
17 => &idt.alignment_check.options,
1312+
18 => &idt.machine_check.options,
1313+
i @ 21..=29 => &idt.reserved_2[i - 21].options,
1314+
30 => &idt.security_exception.options,
1315+
31 => &idt.reserved_3.options,
1316+
other => &idt[other].options,
1317+
};
1318+
options.bits.get_bit(15)
1319+
}
1320+
11271321
#[test]
11281322
fn size_test() {
11291323
use core::mem::size_of;
11301324
assert_eq!(size_of::<Entry<HandlerFunc>>(), 16);
11311325
assert_eq!(size_of::<InterruptDescriptorTable>(), 256 * 16);
11321326
}
11331327

1328+
#[test]
1329+
fn default_handlers() {
1330+
fn general_handler(
1331+
_stack_frame: InterruptStackFrame,
1332+
_index: u8,
1333+
_error_code: Option<u64>,
1334+
) {
1335+
}
1336+
1337+
let mut idt = InterruptDescriptorTable::new();
1338+
set_general_handler!(&mut idt, general_handler, 0);
1339+
for i in 0..256 {
1340+
if i == 0 {
1341+
assert!(entry_present(&idt, i));
1342+
} else {
1343+
assert!(!entry_present(&idt, i));
1344+
}
1345+
}
1346+
set_general_handler!(&mut idt, general_handler, 14);
1347+
for i in 0..256 {
1348+
if i == 0 || i == 14 {
1349+
assert!(entry_present(&idt, i));
1350+
} else {
1351+
assert!(!entry_present(&idt, i));
1352+
}
1353+
}
1354+
set_general_handler!(&mut idt, general_handler, 32..64);
1355+
for i in 1..256 {
1356+
if i == 0 || i == 14 || (i >= 32 && i < 64) {
1357+
assert!(entry_present(&idt, i), "{}", i);
1358+
} else {
1359+
assert!(!entry_present(&idt, i));
1360+
}
1361+
}
1362+
set_general_handler!(&mut idt, general_handler);
1363+
for i in 0..256 {
1364+
if i == 15 || i == 31 || (i >= 21 && i <= 29) {
1365+
// reserved entries should not be set
1366+
assert!(!entry_present(&idt, i));
1367+
} else {
1368+
assert!(entry_present(&idt, i));
1369+
}
1370+
}
1371+
}
1372+
11341373
#[test]
11351374
fn entry_derive_test() {
11361375
fn foo(_: impl Clone + Copy + PartialEq + fmt::Debug) {}

0 commit comments

Comments
 (0)