Jan Beulich
2007-Aug-21 15:19 UTC
[Xen-devel] [PATCH] x86: force DMI table to not be in E820 RAM region
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@novell.com> 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@lists.xensource.com http://lists.xensource.com/xen-devel