summaryrefslogtreecommitdiffstats
path: root/src/arch/i386/firmware/pcbios/hidemem.c
diff options
context:
space:
mode:
authorMichael Brown2005-03-08 19:53:11 +0100
committerMichael Brown2005-03-08 19:53:11 +0100
commit3d6123e69ab879c72ff489afc5bf93ef0b7a94ce (patch)
tree9f3277569153a550fa8d81ebd61bd88f266eb8da /src/arch/i386/firmware/pcbios/hidemem.c
downloadipxe-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.c94
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 */