ia64/xen-unstable

changeset 15988:80277ff19c9c

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>
Signed-off-by: Keir Fraser <keir@xensource.com>
author Keir Fraser <keir@xensource.com>
date Wed Sep 26 14:14:16 2007 +0100 (2007-09-26)
parents 0b873d909ad3
children 69879c7bf4b5
files xen/arch/x86/dmi_scan.c xen/arch/x86/e820.c xen/arch/x86/setup.c xen/include/asm-x86/e820.h xen/include/xen/dmi.h
line diff
     1.1 --- a/xen/arch/x86/dmi_scan.c	Wed Sep 26 09:19:12 2007 +0100
     1.2 +++ b/xen/arch/x86/dmi_scan.c	Wed Sep 26 14:14:16 2007 +0100
     1.3 @@ -100,23 +100,32 @@ inline static int __init dmi_checksum(u8
     1.4  	return (sum==0);
     1.5  }
     1.6  
     1.7 +int __init dmi_get_table(u32 *base, u32 *len)
     1.8 +{
     1.9 +	u8 buf[15];
    1.10 +	char __iomem *p, *q;
    1.11 +
    1.12 +	p = maddr_to_virt(0xF0000);
    1.13 +	for (q = p; q < p + 0x10000; q += 16) {
    1.14 +		memcpy_fromio(buf, q, 15);
    1.15 +		if (memcmp(buf, "_DMI_", 5)==0 && dmi_checksum(buf)) {
    1.16 +			*base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];
    1.17 +			*len=buf[7]<<8|buf[6];
    1.18 +			return 0;
    1.19 +		}
    1.20 +	}
    1.21 +	return -1;
    1.22 +}
    1.23 +
    1.24  static int __init dmi_iterate(void (*decode)(struct dmi_header *))
    1.25  {
    1.26  	u8 buf[15];
    1.27  	char __iomem *p, *q;
    1.28  
    1.29 -	/*
    1.30 -	 * no iounmap() for that ioremap(); it would be a no-op, but it's
    1.31 -	 * so early in setup that sucker gets confused into doing what
    1.32 -	 * it shouldn't if we actually call it.
    1.33 -	 */
    1.34 -	p = ioremap(0xF0000, 0x10000);
    1.35 -	if (p == NULL)
    1.36 -		return -1;
    1.37 +	p = maddr_to_virt(0xF0000);
    1.38  	for (q = p; q < p + 0x10000; q += 16) {
    1.39  		memcpy_fromio(buf, q, 15);
    1.40 -		if(memcmp(buf, "_DMI_", 5)==0 && dmi_checksum(buf))
    1.41 -		{
    1.42 +		if (memcmp(buf, "_DMI_", 5)==0 && dmi_checksum(buf)) {
    1.43  			u16 num=buf[13]<<8|buf[12];
    1.44  			u16 len=buf[7]<<8|buf[6];
    1.45  			u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];
     2.1 --- a/xen/arch/x86/e820.c	Wed Sep 26 09:19:12 2007 +0100
     2.2 +++ b/xen/arch/x86/e820.c	Wed Sep 26 14:14:16 2007 +0100
     2.3 @@ -2,6 +2,7 @@
     2.4  #include <xen/init.h>
     2.5  #include <xen/lib.h>
     2.6  #include <xen/compat.h>
     2.7 +#include <xen/dmi.h>
     2.8  #include <asm/e820.h>
     2.9  #include <asm/page.h>
    2.10  
    2.11 @@ -343,6 +344,15 @@ static void __init clip_to_limit(uint64_
    2.12      }
    2.13  }
    2.14  
    2.15 +static void __init reserve_dmi_region(void)
    2.16 +{
    2.17 +    u32 base, len;
    2.18 +    if ( (dmi_get_table(&base, &len) == 0) && ((base + len) > base) &&
    2.19 +         reserve_e820_ram(&e820, base, base + len) )
    2.20 +        printk("WARNING: DMI table located in E820 RAM %08x-%08x. Fixed.\n",
    2.21 +               base, base+len);
    2.22 +}
    2.23 +
    2.24  static void __init machine_specific_memory_setup(
    2.25      struct e820entry *raw, int *raw_nr)
    2.26  {
    2.27 @@ -366,6 +376,61 @@ static void __init machine_specific_memo
    2.28                    "Only the first %u GB of the physical memory map "
    2.29                    "can be accessed by 32-on-64 guests.");
    2.30  #endif
    2.31 +
    2.32 +    reserve_dmi_region();
    2.33 +}
    2.34 +
    2.35 +/* Reserve RAM area (@s,@e) in the specified e820 map. */
    2.36 +int __init reserve_e820_ram(struct e820map *e820, uint64_t s, uint64_t e)
    2.37 +{
    2.38 +    uint64_t rs = 0, re = 0;
    2.39 +    int i;
    2.40 +
    2.41 +    for ( i = 0; i < e820->nr_map; i++ )
    2.42 +    {
    2.43 +        /* Have we found the e820 region that includes the specified range? */
    2.44 +        rs = e820->map[i].addr;
    2.45 +        re = rs + e820->map[i].size;
    2.46 +        if ( (s >= rs) && (e <= re) )
    2.47 +            break;
    2.48 +    }
    2.49 +
    2.50 +    if ( (i == e820->nr_map) || (e820->map[i].type != E820_RAM) )
    2.51 +        return 0;
    2.52 +
    2.53 +    if ( (s == rs) && (e == re) )
    2.54 +    {
    2.55 +        /* Complete excision. */
    2.56 +        memmove(&e820->map[i], &e820->map[i+1],
    2.57 +                (e820->nr_map-i-1) * sizeof(e820->map[0]));
    2.58 +        e820->nr_map--;
    2.59 +    }
    2.60 +    else if ( s == rs )
    2.61 +    {
    2.62 +        /* Truncate start. */
    2.63 +        e820->map[i].addr += e - s;
    2.64 +        e820->map[i].size -= e - s;
    2.65 +    }
    2.66 +    else if ( e == re )
    2.67 +    {
    2.68 +        /* Truncate end. */
    2.69 +        e820->map[i].size -= e - s;
    2.70 +    }
    2.71 +    else
    2.72 +    {
    2.73 +        /* Split in two. */
    2.74 +        if ( e820->nr_map >= ARRAY_SIZE(e820->map) )
    2.75 +            return 0;
    2.76 +        memmove(&e820->map[i+1], &e820->map[i],
    2.77 +                (e820->nr_map-i) * sizeof(e820->map[0]));
    2.78 +        e820->nr_map++;
    2.79 +        e820->map[i].size = s - rs;
    2.80 +        i++;
    2.81 +        e820->map[i].addr = e;
    2.82 +        e820->map[i].size = re - e;
    2.83 +    }
    2.84 +
    2.85 +    return 1;
    2.86  }
    2.87  
    2.88  unsigned long __init init_e820(
     3.1 --- a/xen/arch/x86/setup.c	Wed Sep 26 09:19:12 2007 +0100
     3.2 +++ b/xen/arch/x86/setup.c	Wed Sep 26 14:14:16 2007 +0100
     3.3 @@ -19,6 +19,7 @@
     3.4  #include <xen/numa.h>
     3.5  #include <xen/rcupdate.h>
     3.6  #include <xen/vga.h>
     3.7 +#include <xen/dmi.h>
     3.8  #include <public/version.h>
     3.9  #ifdef CONFIG_COMPAT
    3.10  #include <compat/platform.h>
    3.11 @@ -45,7 +46,6 @@
    3.12  #define maddr_to_bootstrap_virt(m) ((void *)(long)(m))
    3.13  #endif
    3.14  
    3.15 -extern void dmi_scan_machine(void);
    3.16  extern void generic_apic_probe(void);
    3.17  extern void numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn);
    3.18  
    3.19 @@ -281,41 +281,6 @@ static void __init move_memory(
    3.20  /* A temporary copy of the e820 map that we can mess with during bootstrap. */
    3.21  static struct e820map __initdata boot_e820;
    3.22  
    3.23 -/* Reserve area (@s,@e) in the temporary bootstrap e820 map. */
    3.24 -static int __init reserve_in_boot_e820(unsigned long s, unsigned long e)
    3.25 -{
    3.26 -    uint64_t rs, re;
    3.27 -    int i;
    3.28 -
    3.29 -    for ( i = 0; i < boot_e820.nr_map; i++ )
    3.30 -    {
    3.31 -        /* Have we found the e820 region that includes the specified range? */
    3.32 -        rs = boot_e820.map[i].addr;
    3.33 -        re = rs + boot_e820.map[i].size;
    3.34 -        if ( (s >= rs) && (e <= re) )
    3.35 -            goto found;
    3.36 -    }
    3.37 -
    3.38 -    return 0;
    3.39 -
    3.40 - found:
    3.41 -    /* Start fragment. */
    3.42 -    boot_e820.map[i].size = s - rs;
    3.43 -
    3.44 -    /* End fragment. */
    3.45 -    if ( e < re )
    3.46 -    {
    3.47 -        memmove(&boot_e820.map[i+1], &boot_e820.map[i],
    3.48 -                (boot_e820.nr_map-i) * sizeof(boot_e820.map[0]));
    3.49 -        boot_e820.nr_map++;
    3.50 -        i++;
    3.51 -        boot_e820.map[i].addr = e;
    3.52 -        boot_e820.map[i].size = re - e;
    3.53 -    }
    3.54 -
    3.55 -    return 1;
    3.56 -}
    3.57 -
    3.58  struct boot_video_info {
    3.59      u8  orig_x;             /* 0x00 */
    3.60      u8  orig_y;             /* 0x01 */
    3.61 @@ -547,7 +512,7 @@ void __init __start_xen(unsigned long mb
    3.62      else if ( mbi->flags & MBI_MEMMAP )
    3.63      {
    3.64          memmap_type = "Multiboot-e820";
    3.65 -        while ( bytes < mbi->mmap_length )
    3.66 +        while ( (bytes < mbi->mmap_length) && (e820_raw_nr < E820MAX) )
    3.67          {
    3.68              memory_map_t *map = __va(mbi->mmap_addr + bytes);
    3.69  
    3.70 @@ -597,23 +562,6 @@ void __init __start_xen(unsigned long mb
    3.71          EARLY_FAIL("Bootloader provided no memory information.\n");
    3.72      }
    3.73  
    3.74 -    /* Ensure that all E820 RAM regions are page-aligned and -sized. */
    3.75 -    for ( i = 0; i < e820_raw_nr; i++ )
    3.76 -    {
    3.77 -        uint64_t s, e;
    3.78 -
    3.79 -        if ( e820_raw[i].type != E820_RAM )
    3.80 -            continue;
    3.81 -        s = PFN_UP(e820_raw[i].addr);
    3.82 -        e = PFN_DOWN(e820_raw[i].addr + e820_raw[i].size);
    3.83 -        e820_raw[i].size = 0; /* discarded later */
    3.84 -        if ( s < e )
    3.85 -        {
    3.86 -            e820_raw[i].addr = s << PAGE_SHIFT;
    3.87 -            e820_raw[i].size = (e - s) << PAGE_SHIFT;
    3.88 -        }
    3.89 -    }
    3.90 -
    3.91      /* Sanitise the raw E820 map to produce a final clean version. */
    3.92      max_page = init_e820(memmap_type, e820_raw, &e820_raw_nr);
    3.93  
    3.94 @@ -760,7 +708,7 @@ void __init __start_xen(unsigned long mb
    3.95  
    3.96      if ( !initial_images_start )
    3.97          EARLY_FAIL("Not enough memory to relocate the dom0 kernel image.\n");
    3.98 -    reserve_in_boot_e820(initial_images_start, initial_images_end);
    3.99 +    reserve_e820_ram(&boot_e820, initial_images_start, initial_images_end);
   3.100  
   3.101      /*
   3.102       * With modules (and Xen itself, on x86/64) relocated out of the way, we
   3.103 @@ -772,8 +720,8 @@ void __init __start_xen(unsigned long mb
   3.104      if ( !xen_phys_start )
   3.105          EARLY_FAIL("Not enough memory to relocate Xen.\n");
   3.106      xenheap_phys_end += xen_phys_start;
   3.107 -    reserve_in_boot_e820(xen_phys_start,
   3.108 -                         xen_phys_start + (opt_xenheap_megabytes<<20));
   3.109 +    reserve_e820_ram(&boot_e820, xen_phys_start,
   3.110 +                     xen_phys_start + (opt_xenheap_megabytes<<20));
   3.111      init_boot_pages(1<<20, 16<<20); /* Initial seed: 15MB */
   3.112  #else
   3.113      init_boot_pages(xenheap_phys_end, 16<<20); /* Initial seed: 4MB */
   3.114 @@ -786,7 +734,7 @@ void __init __start_xen(unsigned long mb
   3.115  
   3.116          kdump_size = (kdump_size + PAGE_SIZE - 1) & PAGE_MASK;
   3.117  
   3.118 -        if ( !reserve_in_boot_e820(kdump_start, kdump_size) )
   3.119 +        if ( !reserve_e820_ram(&boot_e820, kdump_start, kdump_size) )
   3.120          {
   3.121              printk("Kdump: DISABLED (failed to reserve %luMB (%lukB) at 0x%lx)"
   3.122                     "\n", kdump_size >> 20, kdump_size >> 10, kdump_start);
     4.1 --- a/xen/include/asm-x86/e820.h	Wed Sep 26 09:19:12 2007 +0100
     4.2 +++ b/xen/include/asm-x86/e820.h	Wed Sep 26 14:14:16 2007 +0100
     4.3 @@ -23,6 +23,7 @@ struct e820map {
     4.4      struct e820entry map[E820MAX];
     4.5  };
     4.6  
     4.7 +extern int reserve_e820_ram(struct e820map *e820, uint64_t s, uint64_t e);
     4.8  extern unsigned long init_e820(const char *, struct e820entry *, int *);
     4.9  extern struct e820map e820;
    4.10  
     5.1 --- a/xen/include/xen/dmi.h	Wed Sep 26 09:19:12 2007 +0100
     5.2 +++ b/xen/include/xen/dmi.h	Wed Sep 26 14:14:16 2007 +0100
     5.3 @@ -34,5 +34,7 @@ struct dmi_system_id {
     5.4  
     5.5  extern int dmi_check_system(struct dmi_system_id *list);
     5.6  extern char * dmi_get_system_info(int field);
     5.7 +extern void dmi_scan_machine(void);
     5.8 +extern int dmi_get_table(u32 *base, u32 *len);
     5.9  
    5.10  #endif	/* __DMI_H__ */