iPXE
biosint.c
Go to the documentation of this file.
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_OR_UBDL );
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 ) );
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;
91  return 0;
92 }
93 
94 /**
95  * Dump changes to interrupt vector table (for debugging)
96  *
97  */
98 void check_bios_interrupts ( void ) {
99  static struct segoff vectors[256];
100  static uint8_t initialised;
101  struct segoff vector;
102  unsigned int i;
103 
104  /* Print any changed interrupt vectors */
105  for ( i = 0; i < ( sizeof ( vectors ) / sizeof ( vectors[0] ) ); i++ ) {
106  copy_from_real ( &vector, 0, ( i * sizeof ( vector ) ),
107  sizeof ( vector ) );
108  if ( memcmp ( &vector, &vectors[i], sizeof ( vector ) ) == 0 )
109  continue;
110  if ( initialised ) {
111  dbg_printf ( "INT %02x changed %04x:%04x => "
112  "%04x:%04x\n", i, vectors[i].segment,
113  vectors[i].offset, vector.segment,
114  vector.offset );
115  }
116  memcpy ( &vectors[i], &vector, sizeof ( vectors[i] ) );
117  }
118  initialised = 1;
119 }
uint16_t segment
Definition: registers.h:193
uint16_t segment
Code segment.
Definition: librm.h:252
#define EBUSY
Device or resource busy.
Definition: errno.h:338
#define DBG_HDA(...)
Definition: compiler.h:499
void check_bios_interrupts(void)
Dump changes to interrupt vector table (for debugging)
Definition: biosint.c:98
Error codes.
uint32_t vector
MSI-X vector.
Definition: ena.h:20
void hook_bios_interrupt(unsigned int interrupt, unsigned int handler, struct segoff *chain_vector)
Hook INT vector.
Definition: biosint.c:24
int unhook_bios_interrupt(unsigned int interrupt, unsigned int handler, struct segoff *chain_vector)
Unhook INT vector.
Definition: biosint.c:69
void * memcpy(void *dest, const void *src, size_t len) __nonnull
static userptr_t size_t offset
Offset of the first segment within the content.
Definition: deflate.h:259
uint16_t offset
Definition: registers.h:192
#define hooked_bios_interrupts
Definition: biosint.h:25
#define copy_to_real
Definition: libkir.h:78
unsigned char uint8_t
Definition: stdint.h:10
#define copy_from_real
Definition: libkir.h:79
uint8_t code
Response code.
Definition: scsi.h:16
#define rm_cs
Definition: libkir.h:38
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
#define DBG_LOG
Definition: compiler.h:317
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition: string.c:98
void interrupt(int intr, struct interrupt_frame32 *frame32, struct interrupt_frame64 *frame64)
Interrupt handler.
Definition: librm_mgmt.c:246
void dbg_printf(const char *fmt,...)
Print debug message.
Definition: debug.c:38
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)