summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown2008-09-29 04:55:13 +0200
committerMichael Brown2008-09-29 04:55:13 +0200
commit040f7cdf3a99ed56a4487efc8e131c84984925bf (patch)
tree9e9ae3e8d49b11d2ebdc381957889b0e3ba038e5
parent[gdb] Fix a compiler warning that shows up only when assertions are enabled (diff)
downloadipxe-040f7cdf3a99ed56a4487efc8e131c84984925bf.tar.gz
ipxe-040f7cdf3a99ed56a4487efc8e131c84984925bf.tar.xz
ipxe-040f7cdf3a99ed56a4487efc8e131c84984925bf.zip
[pcbios] Print INT 15,E820 extended attributes, if present
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.
-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++;