a9ae001e25992ea6fef0f16ecb939c9244179529
[people/xl0/gpxe.git] / src / arch / i386 / firmware / pcbios / hidemem.c
1 /* Utility functions to hide Etherboot by manipulating the E820 memory
2  * map.  These could go in memsizes.c, but are placed here because not
3  * all images will need them.
4  */
5
6 #include "etherboot.h"
7 #include "hidemem.h"
8
9 #ifdef  CODE16
10
11 static int mangling = 0;
12 static void *mangler = NULL;
13
14 #define INSTALLED(x)    ( (typeof(&x)) ( (void*)(&x) - (void*)e820mangler \
15                                          + mangler ) )
16 #define intercept_int15         INSTALLED(_intercept_int15)
17 #define intercepted_int15       INSTALLED(_intercepted_int15)
18 #define hide_memory             INSTALLED(_hide_memory)
19 #define INT15_VECTOR ( (segoff_t*) ( phys_to_virt( 4 * 0x15 ) ) )
20
21 int install_e820mangler ( void *new_mangler ) {
22         if ( mangling ) return 0;
23         memcpy ( new_mangler, &e820mangler, e820mangler_size );
24         mangler = new_mangler;
25         return 1;
26 }
27
28 /* Intercept INT15 calls and pass them through the mangler.  The
29  * mangler must have been copied to base memory before making this
30  * call, and "mangler" must point to the base memory copy, which must
31  * be 16-byte aligned.
32  */
33 int hide_etherboot ( void ) {
34         if ( mangling ) return 1;
35         if ( !mangler ) return 0;
36
37         /* Hook INT15 handler */
38         *intercepted_int15 = *INT15_VECTOR;
39         (*hide_memory)[0].start = virt_to_phys(_text);
40         (*hide_memory)[0].length = _end - _text;
41         /* IMPORTANT, possibly even FIXME:
42          *
43          * Etherboot has a tendency to claim a very large area of
44          * memory as possible heap; enough to make it impossible to
45          * load an OS if we hide all of it.  We hide only the portion
46          * that's currently in use.  This means that we MUST NOT
47          * perform further allocations from the heap while the mangler
48          * is active.
49          */
50         (*hide_memory)[1].start = heap_ptr;
51         (*hide_memory)[1].length = heap_bot - heap_ptr;
52         INT15_VECTOR->segment = SEGMENT(mangler);
53         INT15_VECTOR->offset = 0;
54
55         mangling = 1;
56         return 1;
57 }
58
59 int unhide_etherboot ( void ) {
60         if ( !mangling ) return 1;
61
62         /* Restore original INT15 handler
63          */
64         if ( VIRTUAL(INT15_VECTOR->segment,INT15_VECTOR->offset) != mangler ) {
65                 /* Oh dear... */
66
67 #ifdef WORK_AROUND_BPBATCH_BUG
68                 /* BpBatch intercepts INT15, so can't unhook it, and
69                  * then proceeds to ignore our PXENV_KEEP_UNDI return
70                  * status, which means that it ends up zeroing out the
71                  * INT15 handler routine.
72                  *
73                  * This rather ugly hack involves poking into
74                  * BpBatch's code and changing it's stored value for
75                  * the "next handler" in the INT15 chain.
76                  */
77                 segoff_t *bp_chain = VIRTUAL ( 0x0060, 0x8254 );
78
79                 if ( ( bp_chain->segment == SEGMENT(mangler) ) &&
80                      ( bp_chain->offset == 0 ) ) {
81                         printf ( "\nBPBATCH bug workaround enabled\n" );
82                         *bp_chain = *intercepted_int15;
83                 }
84 #endif /* WORK_AROUND_BPBATCH_BUG */
85
86                 return 0;
87         }
88         *INT15_VECTOR = *intercepted_int15;
89
90         mangling = 0;
91         return 1;
92 }
93
94 #endif  /* CODE16 */