ia64/xen-unstable

changeset 19576:ce273aa880e5

x86: Detect bogus BIOS e820 tables which are not fully covered as
cacheable (WB) by MTRRs. Fix up by truncating the memory map.

This fixes performance issues on certain systems.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Apr 24 17:51:56 2009 +0100 (2009-04-24)
parents dc5bd14a4675
children 7809e0941b38
files xen/arch/x86/e820.c
line diff
     1.1 --- a/xen/arch/x86/e820.c	Fri Apr 24 13:46:17 2009 +0100
     1.2 +++ b/xen/arch/x86/e820.c	Fri Apr 24 17:51:56 2009 +0100
     1.3 @@ -6,6 +6,9 @@
     1.4  #include <xen/dmi.h>
     1.5  #include <asm/e820.h>
     1.6  #include <asm/page.h>
     1.7 +#include <asm/processor.h>
     1.8 +#include <asm/mtrr.h>
     1.9 +#include <asm/msr.h>
    1.10  
    1.11  /* opt_mem: Limit of physical RAM. Any RAM beyond this point is ignored. */
    1.12  unsigned long long opt_mem;
    1.13 @@ -345,6 +348,55 @@ static void __init clip_to_limit(uint64_
    1.14      }
    1.15  }
    1.16  
    1.17 +/* Conservative estimate of top-of-RAM by looking for MTRR WB regions. */
    1.18 +#define MSR_MTRRphysBase(reg) (0x200 + 2 * (reg))
    1.19 +#define MSR_MTRRphysMask(reg) (0x200 + 2 * (reg) + 1)
    1.20 +static uint64_t mtrr_top_of_ram(void)
    1.21 +{
    1.22 +    uint32_t eax, ebx, ecx, edx;
    1.23 +    uint64_t mtrr_cap, mtrr_def, addr_mask, base, mask, top;
    1.24 +    unsigned int i, phys_bits = 36;
    1.25 +
    1.26 +    /* Does the CPU support architectural MTRRs? */
    1.27 +    cpuid(0x00000001, &eax, &ebx, &ecx, &edx);
    1.28 +    if ( !test_bit(X86_FEATURE_MTRR & 31, &edx) )
    1.29 +         return 0;
    1.30 +
    1.31 +    /* Find the physical address size for this CPU. */
    1.32 +    cpuid(0x80000000, &eax, &ebx, &ecx, &edx);
    1.33 +    if ( eax >= 0x80000008 )
    1.34 +    {
    1.35 +        cpuid(0x80000008, &eax, &ebx, &ecx, &edx);
    1.36 +        phys_bits = (uint8_t)eax;
    1.37 +    }
    1.38 +    addr_mask = ((1ull << phys_bits) - 1) & ~((1ull << 12) - 1);
    1.39 +
    1.40 +    rdmsrl(MSR_MTRRcap, mtrr_cap);
    1.41 +    rdmsrl(MSR_MTRRdefType, mtrr_def);
    1.42 +
    1.43 +    /* MTRRs enabled, and default memory type is not writeback? */
    1.44 +    if ( !test_bit(11, &mtrr_def) || ((uint8_t)mtrr_def == MTRR_TYPE_WRBACK) )
    1.45 +        return 0;
    1.46 +
    1.47 +    /*
    1.48 +     * Find end of highest WB-type range. This is a conservative estimate
    1.49 +     * of the highest WB address since overlapping UC/WT ranges dominate.
    1.50 +     */
    1.51 +    top = 0;
    1.52 +    for ( i = 0; i < (uint8_t)mtrr_cap; i++ )
    1.53 +    {
    1.54 +        rdmsrl(MSR_MTRRphysBase(i), base);
    1.55 +        rdmsrl(MSR_MTRRphysMask(i), mask);
    1.56 +        if ( !test_bit(11, &mask) || ((uint8_t)base != MTRR_TYPE_WRBACK) )
    1.57 +            continue;
    1.58 +        base &= addr_mask;
    1.59 +        mask &= addr_mask;
    1.60 +        top = max_t(uint64_t, top, ((base | ~mask) & addr_mask) + PAGE_SIZE);
    1.61 +    }
    1.62 +
    1.63 +    return top;
    1.64 +}
    1.65 +
    1.66  static void __init reserve_dmi_region(void)
    1.67  {
    1.68      u32 base, len;
    1.69 @@ -357,6 +409,8 @@ static void __init reserve_dmi_region(vo
    1.70  static void __init machine_specific_memory_setup(
    1.71      struct e820entry *raw, int *raw_nr)
    1.72  {
    1.73 +    uint64_t top_of_ram;
    1.74 +
    1.75      char nr = (char)*raw_nr;
    1.76      sanitize_e820_map(raw, &nr);
    1.77      *raw_nr = nr;
    1.78 @@ -389,6 +443,10 @@ static void __init machine_specific_memo
    1.79  #endif
    1.80  
    1.81      reserve_dmi_region();
    1.82 +
    1.83 +    top_of_ram = mtrr_top_of_ram();
    1.84 +    if ( top_of_ram )
    1.85 +        clip_to_limit(top_of_ram, "MTRRs do not cover all of memory.");
    1.86  }
    1.87  
    1.88  int __init e820_change_range_type(