Some operating systems get a nasty shock if a region of the E820 map seems
authorMichael Brown <mcb30@etherboot.org>
Sat, 13 Jan 2007 23:38:33 +0000 (23:38 +0000)
committerMichael Brown <mcb30@etherboot.org>
Sat, 13 Jan 2007 23:38:33 +0000 (23:38 +0000)
to start on a non-page boundary.  Make life safer by rounding out our
edited regions.

src/arch/i386/firmware/pcbios/hidemem.c
src/include/gpxe/hidemem.h

index 3a57fcb..3396e1e 100644 (file)
  */
 
 #include <realmode.h>
+#include <bios.h>
 #include <biosint.h>
 #include <gpxe/hidemem.h>
 
-/* Linker-defined symbols */
-extern char _text[];
-extern char _end[];
+/** Alignment for hidden memory regions */
+#define ALIGN_HIDDEN 4096   /* 4kB page alignment should be enough */
 
-/** Assembly routine in e820mangler.S */
-extern void int15();
-
-/** Vector for storing original INT 15 handler */
-extern struct segoff __text16 ( int15_vector );
-#define int15_vector __use_text16 ( int15_vector )
+/**
+ * A hidden region of Etherboot
+ *
+ * This represents a region that will be edited out of the system's
+ * memory map.
+ *
+ * This structure is accessed by assembly code, so must not be
+ * changed.
+ */
+struct hidden_region {
+       /* Physical start address */
+       physaddr_t start;
+       /* Physical end address */
+       physaddr_t end;
+};
 
 /**
  * List of hidden regions
@@ -37,10 +46,64 @@ extern struct segoff __text16 ( int15_vector );
  */
 struct hidden_region __data16_array ( hidden_regions, [] ) = {
        [TEXT] = { 0, 0 },
-       [BASEMEM] = { 0, ( 640 * 1024 ) },
+       [BASEMEM] = { ( 640 * 1024 ), ( 640 * 1024 ) },
        [EXTMEM] = { 0, 0 },
        { 0, 0, } /* Terminator */
 };
+#define hidden_regions __use_data16 ( hidden_regions )
+
+/** Assembly routine in e820mangler.S */
+extern void int15();
+
+/** Vector for storing original INT 15 handler */
+extern struct segoff __text16 ( int15_vector );
+#define int15_vector __use_text16 ( int15_vector )
+
+/**
+ * Hide region of memory from system memory map
+ *
+ * @v start            Start of region
+ * @v end              End of region
+ */
+void hide_region ( unsigned int region_id, physaddr_t start, physaddr_t end ) {
+       struct hidden_region *region = &hidden_regions[region_id];
+
+       /* Some operating systems get a nasty shock if a region of the
+        * E820 map seems to start on a non-page boundary.  Make life
+        * safer by rounding out our edited region.
+        */     
+       region->start = ( start & ~( ALIGN_HIDDEN - 1 ) );
+       region->end = ( ( end + ALIGN_HIDDEN - 1 ) & ~( ALIGN_HIDDEN - 1 ) );
+       DBG ( "Hiding [%lx,%lx)\n", region->start, region->end );
+}
+
+/**
+ * Hide Etherboot text
+ *
+ */
+static void hide_text ( void ) {
+
+       /* The linker defines these symbols for us */
+       extern char _text[];
+       extern char _end[];
+
+       hide_region ( TEXT, virt_to_phys ( _text ), virt_to_phys ( _end ) );
+}
+
+/**
+ * Hide used base memory
+ *
+ */
+static void hide_basemem ( void ) {
+       uint16_t fbms;
+
+       /* Hide from the top of free base memory to 640kB.  Don't use
+        * hide_region(), because we don't want this rounded to the
+        * nearest page boundary.
+        */
+       get_real ( fbms, BDA_SEG, BDA_FBMS );
+       hidden_regions[BASEMEM].start = ( fbms * 1024 );
+}
 
 /**
  * Hide Etherboot
@@ -49,16 +112,12 @@ struct hidden_region __data16_array ( hidden_regions, [] ) = {
  * returned by the BIOS.
  */
 void hide_etherboot ( void ) {
-       hidden_regions[TEXT].start = virt_to_phys ( _text );
-       hidden_regions[TEXT].end = virt_to_phys ( _end );
-       hidden_regions[BASEMEM].start = ( rm_cs << 4 );
 
-       DBG ( "Hiding [%lx,%lx) and [%lx,%lx)\n",
-             ( unsigned long ) hidden_regions[TEXT].start,
-             ( unsigned long ) hidden_regions[TEXT].end,
-             ( unsigned long ) hidden_regions[BASEMEM].start,
-             ( unsigned long ) hidden_regions[BASEMEM].end );
+       /* Initialise the hidden regions */
+       hide_text();
+       hide_basemem();
 
+       /* Hook INT 15 */
        hook_bios_interrupt ( 0x15, ( unsigned int ) int15,
                              &int15_vector );
 }
index 8910900..547f888 100644 (file)
@@ -8,38 +8,16 @@
  *
  */
 
-/**
- * A hidden region of Etherboot
- *
- * This represents a region that will be edited out of the system's
- * memory map.
- *
- * This structure is accessed by assembly code, so must not be
- * changed.
- */
-struct hidden_region {
-       /* Physical start address */
-       physaddr_t start;
-       /* Physical end address */
-       physaddr_t end;
-};
-
 /**
  * Unique IDs for hidden regions
  */
-enum {
+enum hidemem_region_id {
        TEXT = 0,
        BASEMEM,
        EXTMEM,
 };
 
-extern struct hidden_region __data16_array ( hidden_regions, [] );
-#define hidden_regions __use_data16 ( hidden_regions )
-
-static inline void hide_region ( unsigned int region,
-                                physaddr_t start, physaddr_t end ) {
-       hidden_regions[region].start = start;
-       hidden_regions[region].end = end;
-}
+extern void hide_region ( unsigned int region_id, physaddr_t start,
+                         physaddr_t end );
 
 #endif /* _GPXE_HIDEMEM_H */