1 #include <errno.h> 2 #include <realmode.h> 3 #include <biosint.h> 4 5 /** 6 * @file BIOS interrupts 7 * 8 */ 9 10 FILE_LICENCE ( GPL2_OR_LATER ); 11 12 /** 13 * Hook INT vector 14 * 15 * @v interrupt INT number 16 * @v handler Offset within .text16 to interrupt handler 17 * @v chain_vector Vector for chaining to previous handler 18 * 19 * Hooks in an i386 INT handler. The handler itself must reside 20 * within the .text16 segment. @c chain_vector will be filled in with 21 * the address of the previously-installed handler for this interrupt; 22 * the handler should probably exit by ljmping via this vector. 23 */ 24 void hook_bios_interrupt ( unsigned int interrupt, unsigned int handler, 25 struct segoff *chain_vector ) { 26 struct segoff vector = { 27 .segment = rm_cs, 28 .offset = handler, 29 }; 30 31 DBG ( "Hooking INT %#02x to %04x:%04x\n", 32 interrupt, rm_cs, handler ); 33 34 if ( ( chain_vector->segment != 0 ) || 35 ( chain_vector->offset != 0 ) ) { 36 /* Already hooked; do nothing */ 37 DBG ( "...already hooked\n" ); 38 return; 39 } 40 41 copy_from_real ( chain_vector, 0, ( interrupt * 4 ), 42 sizeof ( *chain_vector ) ); 43 DBG ( "...chaining to %04x:%04x\n", 44 chain_vector->segment, chain_vector->offset ); 45 if ( DBG_LOG ) { 46 char code[64]; 47 copy_from_real ( code, chain_vector->segment, 48 chain_vector->offset, sizeof ( code ) ); 49 DBG_HDA ( *chain_vector, code, sizeof ( code ) ); 50 } 51 52 copy_to_real ( 0, ( interrupt * 4 ), &vector, sizeof ( vector ) ); 53 hooked_bios_interrupts++; 54 } 55 56 /** 57 * Unhook INT vector 58 * 59 * @v interrupt INT number 60 * @v handler Offset within .text16 to interrupt handler 61 * @v chain_vector Vector containing address of previous handler 62 * 63 * Unhooks an i386 interrupt handler hooked by hook_i386_vector(). 64 * Note that this operation may fail, if some external code has hooked 65 * the vector since we hooked in our handler. If it fails, it means 66 * that it is not possible to unhook our handler, and we must leave it 67 * (and its chaining vector) resident in memory. 68 */ 69 int unhook_bios_interrupt ( unsigned int interrupt, unsigned int handler, 70 struct segoff *chain_vector ) { 71 struct segoff vector; 72 73 DBG ( "Unhooking INT %#02x from %04x:%04x\n", 74 interrupt, rm_cs, handler ); 75 76 copy_from_real ( &vector, 0, ( interrupt * 4 ), sizeof ( vector ) ); 77 if ( ( vector.segment != rm_cs ) || ( vector.offset != handler ) ) { 78 DBG ( "...cannot unhook; vector points to %04x:%04x\n", 79 vector.segment, vector.offset ); 80 return -EBUSY; 81 } 82 83 DBG ( "...restoring to %04x:%04x\n", 84 chain_vector->segment, chain_vector->offset ); 85 copy_to_real ( 0, ( interrupt * 4 ), chain_vector, 86 sizeof ( *chain_vector ) ); 87 88 chain_vector->segment = 0; 89 chain_vector->offset = 0; 90 hooked_bios_interrupts--; 91 return 0; 92 } 93