diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2010-03-23 19:31:19 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2010-03-23 19:31:19 +0000 |
commit | 87703a5b46f37dc37eda4c3c85f81c0ea0ecc0e6 (patch) | |
tree | d400b47b48056bfe9755ba5c9dbb3f14b7a24e51 /sys/arch/i386 | |
parent | a102e67b703d996c3298158402c016bfa9ec35f8 (diff) |
Use CPUID leaf function 0x80000008 to fetch the physical address size
supported by the processor and use it to calculate the mask used for
manipulating the MTRR registers. If CPUID leaf function 0x80000008 isn't
supported by the processor, default to the 36-bit mask we used before.
Fixes issues on machines that don't have a 36-bit physical address space
like Intel Atom and all 64-bit AMD CPUs.
ok weingart@, deraadt@
Diffstat (limited to 'sys/arch/i386')
-rw-r--r-- | sys/arch/i386/i386/i686_mem.c | 23 |
1 files changed, 20 insertions, 3 deletions
diff --git a/sys/arch/i386/i386/i686_mem.c b/sys/arch/i386/i386/i686_mem.c index 49958669c3c..8997e4b35b7 100644 --- a/sys/arch/i386/i386/i686_mem.c +++ b/sys/arch/i386/i386/i686_mem.c @@ -1,4 +1,4 @@ -/* $OpenBSD: i686_mem.c,v 1.12 2010/02/23 21:54:53 kettenis Exp $ */ +/* $OpenBSD: i686_mem.c,v 1.13 2010/03/23 19:31:18 kettenis Exp $ */ /*- * Copyright (c) 1999 Michael Smith <msmith@freebsd.org> * All rights reserved. @@ -76,6 +76,7 @@ struct mem_range_ops i686_mrops = { /* XXX for AP startup hook */ u_int64_t mtrrcap, mtrrdef; +u_int64_t mtrrmask = 0x0000000ffffff000ULL; struct mem_range_desc *mem_range_match(struct mem_range_softc *sc, struct mem_range_desc *mrd); @@ -209,13 +210,13 @@ i686_mrfetch(struct mem_range_softc *sc) msrv = rdmsr(msr); mrd->mr_flags = (mrd->mr_flags & ~MDF_ATTRMASK) | i686_mtrr2mrt(msrv & 0xff); - mrd->mr_base = msrv & 0x0000000ffffff000LL; + mrd->mr_base = msrv & mtrrmask; msrv = rdmsr(msr + 1); mrd->mr_flags = (msrv & 0x800) ? (mrd->mr_flags | MDF_ACTIVE) : (mrd->mr_flags & ~MDF_ACTIVE); /* Compute the range from the mask. Ick. */ - mrd->mr_len = (~(msrv & 0x0000000ffffff000LL) & 0x0000000fffffffffLL) + 1; + mrd->mr_len = (~(msrv & mtrrmask) & mtrrmask) + 0x1000; if (!mrvalid(mrd->mr_base, mrd->mr_len)) mrd->mr_flags |= MDF_BOGUS; /* If unclaimed and active, must be the BIOS */ @@ -534,6 +535,7 @@ void i686_mrinit(struct mem_range_softc *sc) { struct mem_range_desc *mrd; + uint32_t regs[4]; int nmdesc = 0; int i; @@ -580,6 +582,21 @@ i686_mrinit(struct mem_range_softc *sc) } /* + * Fetch maximum physical address size supported by the + * processor as supported by CPUID leaf function 0x80000008. + * If CPUID does not support leaf function 0x80000008, use the + * default a 36-bit address size. + */ + cpuid(0x80000000, regs); + if (regs[0] >= 0x80000008) { + cpuid(0x80000008, regs); + if (regs[0] & 0xff) { + mtrrmask = (1ULL << (regs[0] & 0xff)) - 1; + mtrrmask &= ~0x0000000000000fffULL; + } + } + + /* * Get current settings, anything set now is considered to have * been set by the firmware. (XXX has something already played here?) */ |