• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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