@@ -1120,17 +1120,256 @@ pub enum ExceptionVector {
1120
1120
Security = 0x1E ,
1121
1121
}
1122
1122
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
+
1123
1298
#[ cfg( test) ]
1124
1299
mod test {
1125
1300
use super :: * ;
1126
1301
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
+
1127
1321
#[ test]
1128
1322
fn size_test ( ) {
1129
1323
use core:: mem:: size_of;
1130
1324
assert_eq ! ( size_of:: <Entry <HandlerFunc >>( ) , 16 ) ;
1131
1325
assert_eq ! ( size_of:: <InterruptDescriptorTable >( ) , 256 * 16 ) ;
1132
1326
}
1133
1327
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
+
1134
1373
#[ test]
1135
1374
fn entry_derive_test ( ) {
1136
1375
fn foo ( _: impl Clone + Copy + PartialEq + fmt:: Debug ) { }
0 commit comments