Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / arch / i386 / interface / pcbios / biosint.c
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  */
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  */
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 }