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 */
hook_bios_interrupt(unsigned int interrupt,unsigned int handler,struct segoff * chain_vector)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 */
unhook_bios_interrupt(unsigned int interrupt,unsigned int handler,struct segoff * chain_vector)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