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 );
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 }

Generated on Tue Apr 6 20:00:50 2010 for gPXE by  doxygen 1.5.7.1