]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[bios] Update to use the generic system memory map API
authorMichael Brown <mcb30@ipxe.org>
Thu, 15 May 2025 00:21:48 +0000 (01:21 +0100)
committerMichael Brown <mcb30@ipxe.org>
Fri, 16 May 2025 15:18:36 +0000 (16:18 +0100)
Provide an implementation of the system memory map API based on the
assorted BIOS INT 15 calls, and a temporary implementation of the
legacy get_memmap() function using the new API.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/arch/x86/include/bits/memmap.h [new file with mode: 0644]
src/arch/x86/include/ipxe/int15.h [new file with mode: 0644]
src/arch/x86/interface/pcbios/e820mangler.S
src/arch/x86/interface/pcbios/hidemem.c
src/arch/x86/interface/pcbios/int15.c
src/config/defaults/pcbios.h
src/core/memmap.c

diff --git a/src/arch/x86/include/bits/memmap.h b/src/arch/x86/include/bits/memmap.h
new file mode 100644 (file)
index 0000000..8f82156
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef _BITS_MEMMAP_H
+#define _BITS_MEMMAP_H
+
+/** @file
+ *
+ * x86-specific system memory map API implementations
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <ipxe/int15.h>
+
+#endif /* _BITS_MEMMAP_H */
diff --git a/src/arch/x86/include/ipxe/int15.h b/src/arch/x86/include/ipxe/int15.h
new file mode 100644 (file)
index 0000000..fbd70f8
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _IPXE_INT15_H
+#define _IPXE_INT15_H
+
+/** @file
+ *
+ * INT15-based memory map
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#ifdef MEMMAP_INT15
+#define MEMMAP_PREFIX_int15
+#else
+#define MEMMAP_PREFIX_int15 __int15_
+#endif
+
+extern void int15_intercept ( int intercept );
+
+#endif /* _IPXE_INT15_H */
index ef5dc2754efe0fcecd6d7191a064ba091fc212a3..b9e891dff35d2918671c01b18f99e752b05be3cb 100644 (file)
@@ -564,6 +564,8 @@ int15_88:
 int15:
        /* See if we want to intercept this call */
        pushfw
+       cmpb    $0, %cs:int15_intercept_flag
+       je      3f
        cmpw    $0xe820, %ax
        jne     1f
        cmpl    $SMAP, %edx
@@ -587,3 +589,9 @@ int15:
 int15_vector:
        .long 0
        .size int15_vector, . - int15_vector
+
+       .section ".text16.data", "aw", @progbits
+       .globl int15_intercept_flag
+int15_intercept_flag:
+       .byte 1
+       .size int15_intercept_flag, . - int15_intercept_flag
index 4063c055160acfe49f5c7663fcf864a4528a8ff4..f201742cf6921f0951d17512489854e5d432481e 100644 (file)
@@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 #include <fakee820.h>
 #include <ipxe/init.h>
 #include <ipxe/io.h>
+#include <ipxe/memmap.h>
 #include <ipxe/hidemem.h>
 
 /** Set to true if you want to test a fake E820 map */
@@ -73,6 +74,10 @@ extern void int15();
 extern struct segoff __text16 ( int15_vector );
 #define int15_vector __use_text16 ( int15_vector )
 
+/** INT 15 interception flag */
+extern uint8_t __text16 ( int15_intercept_flag );
+#define int15_intercept_flag __use_text16 ( int15_intercept_flag )
+
 /* The linker defines these symbols for us */
 extern char _textdata[];
 extern char _etextdata[];
@@ -131,6 +136,17 @@ void hide_textdata ( void ) {
                      virt_to_phys ( _etextdata ) );
 }
 
+/**
+ * Set INT 15 interception flag
+ *
+ * @v intercept                Intercept INT 15 calls to modify memory map
+ */
+void int15_intercept ( int intercept ) {
+
+       /* Set flag for INT 15 handler */
+       int15_intercept_flag = intercept;
+}
+
 /**
  * Hide Etherboot
  *
index 3bc1229aa517ed2895554cfb283b96e58eeb262e..ff90f551c85578bb618c520b14492b8683d8fd2a 100644 (file)
@@ -26,10 +26,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 #include <stdint.h>
 #include <string.h>
 #include <errno.h>
+#include <assert.h>
 #include <realmode.h>
 #include <bios.h>
 #include <memsizes.h>
 #include <ipxe/io.h>
+#include <ipxe/memmap.h>
 
 /**
  * @file
@@ -152,7 +154,7 @@ static unsigned int extmemsize_88 ( void ) {
  * @ret extmem         Extended memory size, in kB
  *
  * Note that this is only an approximation; for an accurate picture,
- * use the E820 memory map obtained via get_memmap();
+ * use the E820 memory map obtained via memmap_describe();
  */
 unsigned int extmemsize ( void ) {
        unsigned int extmem_e801;
@@ -167,12 +169,13 @@ unsigned int extmemsize ( void ) {
 /**
  * Get e820 memory map
  *
- * @v memmap           Memory map to fill in
+ * @v region           Memory region of interest to be updated
  * @ret rc             Return status code
  */
-static int meme820 ( struct memory_map *memmap ) {
-       struct memory_region *region = memmap->regions;
-       struct memory_region *prev_region = NULL;
+static int meme820 ( struct memmap_region *region ) {
+       unsigned int count = 0;
+       uint64_t start = 0;
+       uint64_t len = 0;
        uint32_t next = 0;
        uint32_t smap;
        uint32_t size;
@@ -226,13 +229,6 @@ static int meme820 ( struct memory_map *memmap ) {
                        break;
                }
 
-               /* If first region is not RAM, assume map is invalid */
-               if ( ( memmap->count == 0 ) &&
-                    ( e820buf.type != E820_TYPE_RAM ) ) {
-                      DBG ( "INT 15,e820 failed, first entry not RAM\n" );
-                      return -EINVAL;
-               }
-
                DBG ( "INT 15,e820 region [%llx,%llx) type %d",
                      e820buf.start, ( e820buf.start + e820buf.len ),
                      ( int ) e820buf.type );
@@ -259,27 +255,36 @@ static int meme820 ( struct memory_map *memmap ) {
                                continue;
                }
 
-               region->start = e820buf.start;
-               region->end = e820buf.start + e820buf.len;
-
                /* Check for adjacent regions and merge them */
-               if ( prev_region && ( region->start == prev_region->end ) ) {
-                       prev_region->end = region->end;
+               if ( e820buf.start == ( start + len ) ) {
+                       len += e820buf.len;
                } else {
-                       prev_region = region;
-                       region++;
-                       memmap->count++;
+                       start = e820buf.start;
+                       len = e820buf.len;
                }
 
-               if ( memmap->count >= ( sizeof ( memmap->regions ) /
-                                       sizeof ( memmap->regions[0] ) ) ) {
-                       DBG ( "INT 15,e820 too many regions returned\n" );
-                       /* Not a fatal error; what we've got so far at
-                        * least represents valid regions of memory,
-                        * even if we couldn't get them all.
-                        */
-                       break;
+               /* Sanity check: first region (base memory) should
+                * start at address zero.
+                */
+               if ( ( count == 0 ) && ( start != 0 ) ) {
+                       DBG ( "INT 15,e820 region 0 starts at %llx (expected "
+                             "0); assuming insane\n", start );
+                       return -EINVAL;
+               }
+
+               /* Sanity check: second region (extended memory)
+                * should start at address 0x100000.
+                */
+               if ( ( count == 1 ) && ( start != 0x100000 ) ) {
+                       DBG ( "INT 15,e820 region 1 starts at %llx (expected "
+                             "100000); assuming insane\n", start );
+                       return -EINVAL;
                }
+
+               /* Update region of interest */
+               memmap_update ( region, start, len, MEMMAP_FL_MEMORY, "e820" );
+               count++;
+
        } while ( next != 0 );
 
        /* Sanity checks.  Some BIOSes report complete garbage via INT
@@ -288,19 +293,9 @@ static int meme820 ( struct memory_map *memmap ) {
         * region (starting at 0) and at least one high memory region
         * (starting at 0x100000).
         */
-       if ( memmap->count < 2 ) {
+       if ( count < 2 ) {
                DBG ( "INT 15,e820 returned only %d regions; assuming "
-                     "insane\n", memmap->count );
-               return -EINVAL;
-       }
-       if ( memmap->regions[0].start != 0 ) {
-               DBG ( "INT 15,e820 region 0 starts at %llx (expected 0); "
-                     "assuming insane\n", memmap->regions[0].start );
-               return -EINVAL;
-       }
-       if ( memmap->regions[1].start != 0x100000 ) {
-               DBG ( "INT 15,e820 region 1 starts at %llx (expected 100000); "
-                     "assuming insane\n", memmap->regions[0].start );
+                     "insane\n", count );
                return -EINVAL;
        }
 
@@ -308,37 +303,52 @@ static int meme820 ( struct memory_map *memmap ) {
 }
 
 /**
- * Get memory map
+ * Describe memory region from system memory map
  *
- * @v memmap           Memory map to fill in
+ * @v addr             Address within region
+ * @v hide             Hide in-use regions from the memory map
+ * @v region           Region descriptor to fill in
  */
-void x86_get_memmap ( struct memory_map *memmap ) {
-       unsigned int basemem, extmem;
+static void int15_describe ( uint64_t addr, int hide,
+                            struct memmap_region *region ) {
+       unsigned int basemem;
+       unsigned int extmem;
+       uint64_t inaccessible;
        int rc;
 
-       DBG ( "Fetching system memory map\n" );
+       /* Initialise region */
+       memmap_init ( addr, region );
 
-       /* Clear memory map */
-       memset ( memmap, 0, sizeof ( *memmap ) );
+       /* Mark addresses above 4GB as inaccessible: we have no way to
+        * access them either in a 32-bit build or in a 64-bit build
+        * (since the 64-bit build identity-maps only the 32-bit
+        * address space).
+        */
+       inaccessible = ( 1ULL << 32 );
+       memmap_update ( region, inaccessible, -inaccessible,
+                       MEMMAP_FL_INACCESSIBLE, NULL );
 
-       /* Get base and extended memory sizes */
-       basemem = basememsize();
-       DBG ( "FBMS base memory size %d kB [0,%x)\n",
-             basemem, ( basemem * 1024 ) );
-       extmem = extmemsize();
-       
-       /* Try INT 15,e820 first */
-       if ( ( rc = meme820 ( memmap ) ) == 0 ) {
+       /* Enable/disable INT 15 interception as applicable */
+       int15_intercept ( hide );
+
+       /* Try INT 15,e820 first, falling back to constructing a map
+        * from basemem and extmem sizes
+        */
+       if ( ( rc = meme820 ( region ) ) == 0 ) {
                DBG ( "Obtained system memory map via INT 15,e820\n" );
-               return;
+       } else {
+               basemem = basememsize();
+               DBG ( "FBMS base memory size %d kB [0,%x)\n",
+                     basemem, ( basemem * 1024 ) );
+               extmem = extmemsize();
+               memmap_update ( region, 0, ( basemem * 1024 ),
+                               MEMMAP_FL_MEMORY, "basemem" );
+               memmap_update ( region, 0x100000, ( extmem * 1024 ),
+                               MEMMAP_FL_MEMORY, "extmem" );
        }
 
-       /* Fall back to constructing a map from basemem and extmem sizes */
-       DBG ( "INT 15,e820 failed; constructing map\n" );
-       memmap->regions[0].end = ( basemem * 1024 );
-       memmap->regions[1].start = 0x100000;
-       memmap->regions[1].end = 0x100000 + ( extmem * 1024 );
-       memmap->count = 2;
+       /* Restore INT 15 interception */
+       int15_intercept ( 1 );
 }
 
-PROVIDE_IOAPI ( x86, get_memmap, x86_get_memmap );
+PROVIDE_MEMMAP ( int15, memmap_describe, int15_describe );
index bdc62e8e0d313db3d8b485c2cd199da27d8fb274..0f25669e49c815c01679c15367e4dfcea65b9b8c 100644 (file)
@@ -17,7 +17,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 #define CONSOLE_PCBIOS
 #define NAP_PCBIOS
 #define UMALLOC_MEMTOP
-#define MEMMAP_NULL
+#define MEMMAP_INT15
 #define SMBIOS_PCBIOS
 #define SANBOOT_PCBIOS
 #define ENTROPY_RTC
index 5b95b6c0ae92187de63e546a5a50e8c5632d5f5d..a6ba5205e47dbc7bc7e03a182c80f66f8a75f395 100644 (file)
@@ -24,6 +24,7 @@
 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 
 #include <assert.h>
+#include <ipxe/io.h>
 #include <ipxe/memmap.h>
 
 /** @file
@@ -110,5 +111,29 @@ void memmap_update_used ( struct memmap_region *region ) {
        }
 }
 
+/**
+ * Get legacy system memory map
+ *
+ * @v memmap           Legacy memory map to fill in
+ */
+void get_memmap ( struct memory_map *memmap ) {
+       struct memmap_region region;
+       struct memory_region *usable;
+
+       /* Clear legacy memory map */
+       memmap->count = 0;
+
+       /* Populate legacy memory map */
+       for_each_memmap ( &region, 1 ) {
+               if ( memmap_is_usable ( &region ) ) {
+                       usable = &memmap->regions[memmap->count++];
+                       usable->start = region.addr;
+                       usable->end = ( region.last + 1 );
+                       if ( memmap->count == MAX_MEMORY_REGIONS )
+                               break;
+               }
+       }
+}
+
 PROVIDE_MEMMAP_INLINE ( null, memmap_describe );
 PROVIDE_MEMMAP_INLINE ( null, memmap_sync );