1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
#include <errno.h>
#include <realmode.h>
#include <biosint.h>
/**
* @file BIOS interrupts
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
/**
* 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;
}
|