In order for Dom0 to be able to map the DMI table, it must not be in
E820 RAM; since some BIOS versions apparently fail to set the type
correctly for the page(s) containing this table, adjust it before
starting to consume memory.
Signed-off-by: Jan Beulich <jbeulich@xxxxxxxxxx>
Index: 2007-08-08/xen/arch/x86/dmi_scan.c
===================================================================
--- 2007-08-08.orig/xen/arch/x86/dmi_scan.c 2007-08-06 15:08:40.000000000
+0200
+++ 2007-08-08/xen/arch/x86/dmi_scan.c 2007-08-21 13:44:10.000000000 +0200
@@ -100,7 +100,7 @@ inline static int __init dmi_checksum(u8
return (sum==0);
}
-static int __init dmi_iterate(void (*decode)(struct dmi_header *))
+static int __init dmi_iterate(void (*decode)(struct dmi_header *), u32 *pbase)
{
u8 buf[15];
char __iomem *p, *q;
@@ -121,6 +121,11 @@ static int __init dmi_iterate(void (*dec
u16 len=buf[7]<<8|buf[6];
u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];
+ if (pbase)
+ *pbase = base;
+ if (!decode)
+ return len;
+
/*
* DMI version 0.0 means that the real version is taken
from
* the SMBIOS version, which we don't know at this
point.
@@ -433,13 +438,27 @@ static void __init dmi_decode(struct dmi
void __init dmi_scan_machine(void)
{
- int err = dmi_iterate(dmi_decode);
+ int err = dmi_iterate(dmi_decode, NULL);
if(err == 0)
dmi_check_system(dmi_blacklist);
else
printk(KERN_INFO "DMI not present.\n");
}
+int __init dmi_get_table(u32*pbase, u32*plen)
+{
+ int rc = dmi_iterate(NULL, pbase);
+
+ if (rc < 0) {
+ *pbase = *plen = 0;
+ return rc;
+ }
+
+ *plen = rc;
+
+ return 0;
+}
+
/**
* dmi_check_system - check system DMI data
Index: 2007-08-08/xen/arch/x86/setup.c
===================================================================
--- 2007-08-08.orig/xen/arch/x86/setup.c 2007-08-09 12:58:04.000000000
+0200
+++ 2007-08-08/xen/arch/x86/setup.c 2007-08-21 13:48:30.000000000 +0200
@@ -45,6 +45,7 @@
#endif
extern void dmi_scan_machine(void);
+extern int dmi_get_table(u32 *pbase, u32 *plen);
extern void generic_apic_probe(void);
extern void numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn);
@@ -425,6 +426,7 @@ void __init __start_xen(unsigned long mb
module_t *mod = (module_t *)__va(mbi->mods_addr);
unsigned long nr_pages, modules_length;
int i, e820_warn = 0, bytes = 0;
+ u32 dmi_table_start, dmi_table_len;
struct ns16550_defaults ns16550 = {
.data_bits = 8,
.parity = 'n',
@@ -554,7 +556,7 @@ void __init __start_xen(unsigned long mb
else if ( mbi->flags & MBI_MEMMAP )
{
memmap_type = "Multiboot-e820";
- while ( bytes < mbi->mmap_length )
+ while ( bytes < mbi->mmap_length && e820_raw_nr < E820MAX )
{
memory_map_t *map = __va(mbi->mmap_addr + bytes);
@@ -605,6 +607,9 @@ void __init __start_xen(unsigned long mb
EARLY_FAIL("Bootloader provided no memory information.\n");
}
+ dmi_get_table(&dmi_table_start, &dmi_table_len);
+ e820_warn = 0;
+
/* Ensure that all E820 RAM regions are page-aligned and -sized. */
for ( i = 0; i < e820_raw_nr; i++ )
{
@@ -615,6 +620,41 @@ void __init __start_xen(unsigned long mb
s = PFN_UP(e820_raw[i].addr);
e = PFN_DOWN(e820_raw[i].addr + e820_raw[i].size);
e820_raw[i].size = 0; /* discarded later */
+
+ /*
+ * Dom0 will want to map the DMI table, yet some BIOSes put it
+ * in RAM regions - forcibly cut off the portion that overlaps.
+ */
+ if ( s < e &&
+ dmi_table_len > 0 &&
+ (e << PAGE_SHIFT) > dmi_table_start &&
+ (s << PAGE_SHIFT) < (u64)dmi_table_start + dmi_table_len )
+ {
+ u64 dmi_table_end = (u64)dmi_table_start + dmi_table_len;
+
+ if ( (s << PAGE_SHIFT) >= dmi_table_start &&
+ (e << PAGE_SHIFT) <= dmi_table_end )
+ e = s;
+ else if ( (s << PAGE_SHIFT) >= dmi_table_start )
+ s = PFN_UP(dmi_table_end);
+ else if ( (e << PAGE_SHIFT) <= dmi_table_end )
+ e = PFN_DOWN(dmi_table_start);
+ else if ( e820_raw_nr < E820MAX )
+ {
+ e820_raw[e820_raw_nr].addr = dmi_table_end;
+ e820_raw[e820_raw_nr].size = (e << PAGE_SHIFT) - dmi_table_end;
+ e820_raw[e820_raw_nr].type = E820_RAM;
+ ++e820_raw_nr;
+ e = PFN_DOWN(dmi_table_start);
+ }
+ else if ( dmi_table_start - (s << PAGE_SHIFT) >=
+ (e << PAGE_SHIFT) - dmi_table_end )
+ e = PFN_DOWN(dmi_table_start);
+ else
+ s = PFN_UP(dmi_table_end);
+ e820_warn = 1;
+ }
+
if ( s < e )
{
e820_raw[i].addr = s << PAGE_SHIFT;
@@ -622,6 +662,19 @@ void __init __start_xen(unsigned long mb
}
}
+ if ( e820_warn )
+ {
+ printk("WARNING: DMI table located in E820 RAM "
+ "(fixed by shrinking/splitting RAM region).\n");
+ if ( e820_raw_nr < E820MAX )
+ {
+ e820_raw[e820_raw_nr].addr = dmi_table_start;
+ e820_raw[e820_raw_nr].size = dmi_table_len;
+ e820_raw[e820_raw_nr].type = E820_RESERVED;
+ ++e820_raw_nr;
+ }
+ }
+
/* Sanitise the raw E820 map to produce a final clean version. */
max_page = init_e820(memmap_type, e820_raw, &e820_raw_nr);
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|