diff options
author | Michael Brown | 2005-03-08 19:53:11 +0100 |
---|---|---|
committer | Michael Brown | 2005-03-08 19:53:11 +0100 |
commit | 3d6123e69ab879c72ff489afc5bf93ef0b7a94ce (patch) | |
tree | 9f3277569153a550fa8d81ebd61bd88f266eb8da /src/arch/i386/firmware/pcbios/hidemem.c | |
download | ipxe-3d6123e69ab879c72ff489afc5bf93ef0b7a94ce.tar.gz ipxe-3d6123e69ab879c72ff489afc5bf93ef0b7a94ce.tar.xz ipxe-3d6123e69ab879c72ff489afc5bf93ef0b7a94ce.zip |
Initial revision
Diffstat (limited to 'src/arch/i386/firmware/pcbios/hidemem.c')
-rw-r--r-- | src/arch/i386/firmware/pcbios/hidemem.c | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/src/arch/i386/firmware/pcbios/hidemem.c b/src/arch/i386/firmware/pcbios/hidemem.c new file mode 100644 index 00000000..a9ae001e --- /dev/null +++ b/src/arch/i386/firmware/pcbios/hidemem.c @@ -0,0 +1,94 @@ +/* Utility functions to hide Etherboot by manipulating the E820 memory + * map. These could go in memsizes.c, but are placed here because not + * all images will need them. + */ + +#include "etherboot.h" +#include "hidemem.h" + +#ifdef CODE16 + +static int mangling = 0; +static void *mangler = NULL; + +#define INSTALLED(x) ( (typeof(&x)) ( (void*)(&x) - (void*)e820mangler \ + + mangler ) ) +#define intercept_int15 INSTALLED(_intercept_int15) +#define intercepted_int15 INSTALLED(_intercepted_int15) +#define hide_memory INSTALLED(_hide_memory) +#define INT15_VECTOR ( (segoff_t*) ( phys_to_virt( 4 * 0x15 ) ) ) + +int install_e820mangler ( void *new_mangler ) { + if ( mangling ) return 0; + memcpy ( new_mangler, &e820mangler, e820mangler_size ); + mangler = new_mangler; + return 1; +} + +/* Intercept INT15 calls and pass them through the mangler. The + * mangler must have been copied to base memory before making this + * call, and "mangler" must point to the base memory copy, which must + * be 16-byte aligned. + */ +int hide_etherboot ( void ) { + if ( mangling ) return 1; + if ( !mangler ) return 0; + + /* Hook INT15 handler */ + *intercepted_int15 = *INT15_VECTOR; + (*hide_memory)[0].start = virt_to_phys(_text); + (*hide_memory)[0].length = _end - _text; + /* IMPORTANT, possibly even FIXME: + * + * Etherboot has a tendency to claim a very large area of + * memory as possible heap; enough to make it impossible to + * load an OS if we hide all of it. We hide only the portion + * that's currently in use. This means that we MUST NOT + * perform further allocations from the heap while the mangler + * is active. + */ + (*hide_memory)[1].start = heap_ptr; + (*hide_memory)[1].length = heap_bot - heap_ptr; + INT15_VECTOR->segment = SEGMENT(mangler); + INT15_VECTOR->offset = 0; + + mangling = 1; + return 1; +} + +int unhide_etherboot ( void ) { + if ( !mangling ) return 1; + + /* Restore original INT15 handler + */ + if ( VIRTUAL(INT15_VECTOR->segment,INT15_VECTOR->offset) != mangler ) { + /* Oh dear... */ + +#ifdef WORK_AROUND_BPBATCH_BUG + /* BpBatch intercepts INT15, so can't unhook it, and + * then proceeds to ignore our PXENV_KEEP_UNDI return + * status, which means that it ends up zeroing out the + * INT15 handler routine. + * + * This rather ugly hack involves poking into + * BpBatch's code and changing it's stored value for + * the "next handler" in the INT15 chain. + */ + segoff_t *bp_chain = VIRTUAL ( 0x0060, 0x8254 ); + + if ( ( bp_chain->segment == SEGMENT(mangler) ) && + ( bp_chain->offset == 0 ) ) { + printf ( "\nBPBATCH bug workaround enabled\n" ); + *bp_chain = *intercepted_int15; + } +#endif /* WORK_AROUND_BPBATCH_BUG */ + + return 0; + } + *INT15_VECTOR = *intercepted_int15; + + mangling = 0; + return 1; +} + +#endif /* CODE16 */ |