summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/arch/i386/firmware/pcbios/memmap.c46
1 files changed, 43 insertions, 3 deletions
diff --git a/src/arch/i386/firmware/pcbios/memmap.c b/src/arch/i386/firmware/pcbios/memmap.c
index e6d6428e..9de10a7a 100644
--- a/src/arch/i386/firmware/pcbios/memmap.c
+++ b/src/arch/i386/firmware/pcbios/memmap.c
@@ -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++;