#include #include #include /** * @file BIOS interrupts * */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** * Hook INT vector * * @v interrupt INT number * @v handler Offset within .text16 to interrupt handler * @v chain_vector Vector for chaining to previous handler * * Hooks in an i386 INT handler. The handler itself must reside * within the .text16 segment. @c chain_vector will be filled in with * the address of the previously-installed handler for this interrupt; * the handler should probably exit by ljmping via this vector. */ void hook_bios_interrupt ( unsigned int interrupt, unsigned int handler, struct segoff *chain_vector ) { struct segoff vector = { .segment = rm_cs, .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++; } /** * Unhook INT vector * * @v interrupt INT number * @v handler Offset within .text16 to interrupt handler * @v chain_vector Vector containing address of previous handler * * Unhooks an i386 interrupt handler hooked by hook_i386_vector(). * Note that this operation may fail, if some external code has hooked * the vector since we hooked in our handler. If it fails, it means * that it is not possible to unhook our handler, and we must leave it * (and its chaining vector) resident in memory. */ 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 ) ) { 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; }