summaryrefslogtreecommitdiff
path: root/sys/arch/i386
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2010-03-23 19:31:19 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2010-03-23 19:31:19 +0000
commit87703a5b46f37dc37eda4c3c85f81c0ea0ecc0e6 (patch)
treed400b47b48056bfe9755ba5c9dbb3f14b7a24e51 /sys/arch/i386
parenta102e67b703d996c3298158402c016bfa9ec35f8 (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.c23
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?)
*/