Don't overwrite %dl with a (potentially) modified drive number if we
[people/sha0/gpxe.git] / src / arch / i386 / interface / pcbios / biosint.c
index 345961a..8ef2d7a 100644 (file)
@@ -7,6 +7,17 @@
  *
  */
 
+/**
+ * Hooked interrupt count
+ *
+ * At exit, after unhooking all possible interrupts, this counter
+ * should be examined.  If it is non-zero, it means that we failed to
+ * unhook at least one interrupt vector, and so must not free up the
+ * memory we are using.  (Note that this also implies that we should
+ * re-hook INT 15 in order to hide ourselves from the memory map).
+ */
+int hooked_bios_interrupts = 0;
+
 /**
  * Hook INT vector
  *
@@ -26,9 +37,29 @@ void hook_bios_interrupt ( unsigned int interrupt, unsigned int handler,
                .offset = handler,
        };
 
+       DBG ( "Hooking INT %#02x to %04x:%04x\n",
+             interrupt, rm_cs, handler );
+
+       if ( ( chain_vector->segment != 0 ) ||
+            ( chain_vector->offset != 0 ) ) {
+               /* Already hooked; do nothing */
+               DBG ( "...already hooked\n" );
+               return;
+       }
+
        copy_from_real ( chain_vector, 0, ( interrupt * 4 ),
                         sizeof ( *chain_vector ) );
+       DBG ( "...chaining to %04x:%04x\n",
+             chain_vector->segment, chain_vector->offset );
+       if ( DBG_LOG ) {
+               char code[64];
+               copy_from_real ( code, chain_vector->segment,
+                                chain_vector->offset, sizeof ( code ) );
+               DBG_HDA ( *chain_vector, code, sizeof ( code ) );
+       }
+
        copy_to_real ( 0, ( interrupt * 4 ), &vector, sizeof ( vector ) );
+       hooked_bios_interrupts++;
 }
 
 /**
@@ -48,10 +79,23 @@ int unhook_bios_interrupt ( unsigned int interrupt, unsigned int handler,
                            struct segoff *chain_vector ) {
        struct segoff vector;
 
+       DBG ( "Unhooking INT %#02x from %04x:%04x\n",
+             interrupt, rm_cs, handler );
+
        copy_from_real ( &vector, 0, ( interrupt * 4 ), sizeof ( vector ) );
-       if ( ( vector.segment != rm_cs ) || ( vector.offset != handler ) )
+       if ( ( vector.segment != rm_cs ) || ( vector.offset != handler ) ) {
+               DBG ( "...cannot unhook; vector points to %04x:%04x\n",
+                     vector.segment, vector.offset );
                return -EBUSY;
+       }
+
+       DBG ( "...restoring to %04x:%04x\n",
+             chain_vector->segment, chain_vector->offset );
        copy_to_real ( 0, ( interrupt * 4 ), chain_vector,
                       sizeof ( *chain_vector ) );
+
+       chain_vector->segment = 0;
+       chain_vector->offset = 0;
+       hooked_bios_interrupts--;
        return 0;
 }