[pcbios] Print INT 15,E820 extended attributes, if present
authorMichael Brown <mcb30@etherboot.org>
Mon, 29 Sep 2008 02:55:13 +0000 (03:55 +0100)
committerMichael Brown <mcb30@etherboot.org>
Mon, 29 Sep 2008 02:55:13 +0000 (03:55 +0100)
The ACPI specification defines an additional 4-byte field at offset 20
for an E820 memory map entry.  This field is presumably optional,
since generally E820 gets given only a 20-byte buffer to fill.
However, the bits of this optional field are defined as:

  bit 0 : region is enabled
  bit 1 : region is non-volatile memory rather than RAM

so it seems as though callers that pass in only a 20-byte buffer may
be missing out on some rather important information.

src/arch/i386/firmware/pcbios/memmap.c

index e6d6428..9de10a7 100644 (file)
@@ -41,6 +41,8 @@ struct e820_entry {
        uint64_t len;
        /** Type of region */
        uint32_t type;
+       /** Extended attributes (optional) */
+       uint32_t attrs;
 } __attribute__ (( packed ));
 
 #define E820_TYPE_RAM          1 /**< Normal memory */
@@ -48,6 +50,12 @@ struct e820_entry {
 #define E820_TYPE_ACPI         3 /**< ACPI reclaim memory */
 #define E820_TYPE_NVS          4 /**< ACPI NVS memory */
 
+#define E820_ATTR_ENABLED      0x00000001UL
+#define E820_ATTR_NONVOLATILE  0x00000002UL
+#define E820_ATTR_UNKNOWN      0xfffffffcUL
+
+#define E820_MIN_SIZE          20
+
 /** Buffer for INT 15,e820 calls */
 static struct e820_entry __bss16 ( e820buf );
 #define e820buf __use_data16 ( e820buf )
@@ -148,8 +156,15 @@ static int meme820 ( struct memory_map *memmap ) {
        struct memory_region *region = memmap->regions;
        uint32_t next = 0;
        uint32_t smap;
+       size_t size;
        unsigned int flags;
-       unsigned int discard_c, discard_d, discard_D;
+       unsigned int discard_d, discard_D;
+
+       /* Clear the E820 buffer.  Do this once before starting,
+        * rather than on each call; some BIOSes rely on the contents
+        * being preserved between calls.
+        */
+       memset ( &e820buf, 0, sizeof ( e820buf ) );
 
        do {
                __asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
@@ -158,7 +173,7 @@ static int meme820 ( struct memory_map *memmap ) {
                                                   "popw %w0\n\t" )
                                       : "=r" ( flags ), "=a" ( smap ),
                                         "=b" ( next ), "=D" ( discard_D ),
-                                        "=c" ( discard_c ), "=d" ( discard_d )
+                                        "=c" ( size ), "=d" ( discard_d )
                                       : "a" ( 0xe820 ), "b" ( next ),
                                         "D" ( __from_data16 ( &e820buf ) ),
                                         "c" ( sizeof ( e820buf ) ),
@@ -170,17 +185,42 @@ static int meme820 ( struct memory_map *memmap ) {
                        return -ENOTSUP;
                }
 
+               if ( size < E820_MIN_SIZE ) {
+                       DBG ( "INT 15,e820 returned only %zd bytes\n", size );
+                       return -EINVAL;
+               }
+
                if ( flags & CF ) {
                        DBG ( "INT 15,e820 terminated on CF set\n" );
                        break;
                }
 
-               DBG ( "INT 15,e820 region [%llx,%llx) type %d\n",
+               DBG ( "INT 15,e820 region [%llx,%llx) type %d",
                      e820buf.start, ( e820buf.start + e820buf.len ),
                      ( int ) e820buf.type );
+               if ( size > offsetof ( typeof ( e820buf ), attrs ) ) {
+                       DBG ( " (%s", ( ( e820buf.attrs & E820_ATTR_ENABLED )
+                                       ? "enabled" : "disabled" ) );
+                       if ( e820buf.attrs & E820_ATTR_NONVOLATILE )
+                               DBG ( ", non-volatile" );
+                       if ( e820buf.attrs & E820_ATTR_UNKNOWN )
+                               DBG ( ", other [%08lx]", e820buf.attrs );
+                       DBG ( ")" );
+               }
+               DBG ( "\n" );
+
+               /* Discard non-RAM regions */
                if ( e820buf.type != E820_TYPE_RAM )
                        continue;
 
+               /* Check extended attributes, if present */
+               if ( size > offsetof ( typeof ( e820buf ), attrs ) ) {
+                       if ( ! ( e820buf.attrs & E820_ATTR_ENABLED ) )
+                               continue;
+                       if ( e820buf.attrs & E820_ATTR_NONVOLATILE )
+                               continue;
+               }
+
                region->start = e820buf.start;
                region->end = e820buf.start + e820buf.len;
                region++;