You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

biosint.c 2.7KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. #include <errno.h>
  2. #include <realmode.h>
  3. #include <biosint.h>
  4. /**
  5. * @file BIOS interrupts
  6. *
  7. */
  8. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  9. /**
  10. * Hook INT vector
  11. *
  12. * @v interrupt INT number
  13. * @v handler Offset within .text16 to interrupt handler
  14. * @v chain_vector Vector for chaining to previous handler
  15. *
  16. * Hooks in an i386 INT handler. The handler itself must reside
  17. * within the .text16 segment. @c chain_vector will be filled in with
  18. * the address of the previously-installed handler for this interrupt;
  19. * the handler should probably exit by ljmping via this vector.
  20. */
  21. void hook_bios_interrupt ( unsigned int interrupt, unsigned int handler,
  22. struct segoff *chain_vector ) {
  23. struct segoff vector = {
  24. .segment = rm_cs,
  25. .offset = handler,
  26. };
  27. DBG ( "Hooking INT %#02x to %04x:%04x\n",
  28. interrupt, rm_cs, handler );
  29. if ( ( chain_vector->segment != 0 ) ||
  30. ( chain_vector->offset != 0 ) ) {
  31. /* Already hooked; do nothing */
  32. DBG ( "...already hooked\n" );
  33. return;
  34. }
  35. copy_from_real ( chain_vector, 0, ( interrupt * 4 ),
  36. sizeof ( *chain_vector ) );
  37. DBG ( "...chaining to %04x:%04x\n",
  38. chain_vector->segment, chain_vector->offset );
  39. if ( DBG_LOG ) {
  40. char code[64];
  41. copy_from_real ( code, chain_vector->segment,
  42. chain_vector->offset, sizeof ( code ) );
  43. DBG_HDA ( *chain_vector, code, sizeof ( code ) );
  44. }
  45. copy_to_real ( 0, ( interrupt * 4 ), &vector, sizeof ( vector ) );
  46. hooked_bios_interrupts++;
  47. }
  48. /**
  49. * Unhook INT vector
  50. *
  51. * @v interrupt INT number
  52. * @v handler Offset within .text16 to interrupt handler
  53. * @v chain_vector Vector containing address of previous handler
  54. *
  55. * Unhooks an i386 interrupt handler hooked by hook_i386_vector().
  56. * Note that this operation may fail, if some external code has hooked
  57. * the vector since we hooked in our handler. If it fails, it means
  58. * that it is not possible to unhook our handler, and we must leave it
  59. * (and its chaining vector) resident in memory.
  60. */
  61. int unhook_bios_interrupt ( unsigned int interrupt, unsigned int handler,
  62. struct segoff *chain_vector ) {
  63. struct segoff vector;
  64. DBG ( "Unhooking INT %#02x from %04x:%04x\n",
  65. interrupt, rm_cs, handler );
  66. copy_from_real ( &vector, 0, ( interrupt * 4 ), sizeof ( vector ) );
  67. if ( ( vector.segment != rm_cs ) || ( vector.offset != handler ) ) {
  68. DBG ( "...cannot unhook; vector points to %04x:%04x\n",
  69. vector.segment, vector.offset );
  70. return -EBUSY;
  71. }
  72. DBG ( "...restoring to %04x:%04x\n",
  73. chain_vector->segment, chain_vector->offset );
  74. copy_to_real ( 0, ( interrupt * 4 ), chain_vector,
  75. sizeof ( *chain_vector ) );
  76. chain_vector->segment = 0;
  77. chain_vector->offset = 0;
  78. hooked_bios_interrupts--;
  79. return 0;
  80. }