iPXE
biosint.c
Go to the documentation of this file.
00001 #include <errno.h>
00002 #include <realmode.h>
00003 #include <biosint.h>
00004 
00005 /**
00006  * @file BIOS interrupts
00007  *
00008  */
00009 
00010 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00011 
00012 /**
00013  * Hook INT vector
00014  *
00015  * @v interrupt         INT number
00016  * @v handler           Offset within .text16 to interrupt handler
00017  * @v chain_vector      Vector for chaining to previous handler
00018  *
00019  * Hooks in an i386 INT handler.  The handler itself must reside
00020  * within the .text16 segment.  @c chain_vector will be filled in with
00021  * the address of the previously-installed handler for this interrupt;
00022  * the handler should probably exit by ljmping via this vector.
00023  */
00024 void hook_bios_interrupt ( unsigned int interrupt, unsigned int handler,
00025                            struct segoff *chain_vector ) {
00026         struct segoff vector = {
00027                 .segment = rm_cs,
00028                 .offset = handler,
00029         };
00030 
00031         DBG ( "Hooking INT %#02x to %04x:%04x\n",
00032               interrupt, rm_cs, handler );
00033 
00034         if ( ( chain_vector->segment != 0 ) ||
00035              ( chain_vector->offset != 0 ) ) {
00036                 /* Already hooked; do nothing */
00037                 DBG ( "...already hooked\n" );
00038                 return;
00039         }
00040 
00041         copy_from_real ( chain_vector, 0, ( interrupt * 4 ),
00042                          sizeof ( *chain_vector ) );
00043         DBG ( "...chaining to %04x:%04x\n",
00044               chain_vector->segment, chain_vector->offset );
00045         if ( DBG_LOG ) {
00046                 char code[64];
00047                 copy_from_real ( code, chain_vector->segment,
00048                                  chain_vector->offset, sizeof ( code ) );
00049                 DBG_HDA ( *chain_vector, code, sizeof ( code ) );
00050         }
00051 
00052         copy_to_real ( 0, ( interrupt * 4 ), &vector, sizeof ( vector ) );
00053         hooked_bios_interrupts++;
00054 }
00055 
00056 /**
00057  * Unhook INT vector
00058  *
00059  * @v interrupt         INT number
00060  * @v handler           Offset within .text16 to interrupt handler
00061  * @v chain_vector      Vector containing address of previous handler
00062  *
00063  * Unhooks an i386 interrupt handler hooked by hook_i386_vector().
00064  * Note that this operation may fail, if some external code has hooked
00065  * the vector since we hooked in our handler.  If it fails, it means
00066  * that it is not possible to unhook our handler, and we must leave it
00067  * (and its chaining vector) resident in memory.
00068  */
00069 int unhook_bios_interrupt ( unsigned int interrupt, unsigned int handler,
00070                             struct segoff *chain_vector ) {
00071         struct segoff vector;
00072 
00073         DBG ( "Unhooking INT %#02x from %04x:%04x\n",
00074               interrupt, rm_cs, handler );
00075 
00076         copy_from_real ( &vector, 0, ( interrupt * 4 ), sizeof ( vector ) );
00077         if ( ( vector.segment != rm_cs ) || ( vector.offset != handler ) ) {
00078                 DBG ( "...cannot unhook; vector points to %04x:%04x\n",
00079                       vector.segment, vector.offset );
00080                 return -EBUSY;
00081         }
00082 
00083         DBG ( "...restoring to %04x:%04x\n",
00084               chain_vector->segment, chain_vector->offset );
00085         copy_to_real ( 0, ( interrupt * 4 ), chain_vector,
00086                        sizeof ( *chain_vector ) );
00087 
00088         chain_vector->segment = 0;
00089         chain_vector->offset = 0;
00090         hooked_bios_interrupts--;
00091         return 0;
00092 }
00093 
00094 /**
00095  * Dump changes to interrupt vector table (for debugging)
00096  *
00097  */
00098 void check_bios_interrupts ( void ) {
00099         static struct segoff vectors[256];
00100         static uint8_t initialised;
00101         struct segoff vector;
00102         unsigned int i;
00103 
00104         /* Print any changed interrupt vectors */
00105         for ( i = 0; i < ( sizeof ( vectors ) / sizeof ( vectors[0] ) ); i++ ) {
00106                 copy_from_real ( &vector, 0, ( i * sizeof ( vector ) ),
00107                                  sizeof ( vector ) );
00108                 if ( memcmp ( &vector, &vectors[i], sizeof ( vector ) ) == 0 )
00109                         continue;
00110                 if ( initialised ) {
00111                         dbg_printf ( "INT %02x changed %04x:%04x => "
00112                                      "%04x:%04x\n", i, vectors[i].segment,
00113                                      vectors[i].offset, vector.segment,
00114                                      vector.offset );
00115                 }
00116                 memcpy ( &vectors[i], &vector, sizeof ( vectors[i] ) );
00117         }
00118         initialised = 1;
00119 }