Home | History | Annotate | Download | only in pcbios
      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