diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2010-07-05 12:10:52 +0100 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2010-07-05 12:10:52 +0100 |
commit | 66633037f8fc6fe4168f968471cb14baf36a65f0 (patch) | |
tree | 241789dc01b6b2ba289736a217327b1f768fc9ed | |
parent | 21a50a902946ddfd90dc13d1334505902e0c1201 (diff) | |
download | xen-66633037f8fc6fe4168f968471cb14baf36a65f0.tar.gz xen-66633037f8fc6fe4168f968471cb14baf36a65f0.tar.bz2 xen-66633037f8fc6fe4168f968471cb14baf36a65f0.zip |
AMD OSVW (OS Visible Workaround) for Xen
This path enables AMD OSVW (OS Visible Workaround) feature for
Xen. New AMD errata will have a OSVW id assigned in the future. OS is
supposed to check OSVW status MSR to find out whether CPU has a
specific erratum. Legacy errata are also supported in this patch:
traditional family/model/stepping approach will be used if OSVW
feature isn't applicable. This patch is adapted from Hans Rosenfeld's
patch submitted to Linux kernel.
Signed-off-by: Wei Huang <wei.huang2@amd.com>
Signed-off-by: Hans Rosenfeld <hands.rosenfeld@amd.com>
Acked-by: Jan Beulich <jbeulich@novell.com>
xen-unstable changeset: 21712:f483b5ce7be2
xen-unstable date: Fri Jul 02 19:04:57 2010 +0100
-rw-r--r-- | xen/arch/x86/cpu/amd.c | 50 | ||||
-rw-r--r-- | xen/arch/x86/hvm/svm/asid.c | 4 | ||||
-rw-r--r-- | xen/arch/x86/hvm/svm/svm.c | 5 | ||||
-rw-r--r-- | xen/include/asm-x86/amd.h (renamed from xen/arch/x86/cpu/amd.h) | 35 | ||||
-rw-r--r-- | xen/include/asm-x86/msr-index.h | 4 |
5 files changed, 93 insertions, 5 deletions
diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c index 67a3352dbb..f7ae816b82 100644 --- a/xen/arch/x86/cpu/amd.c +++ b/xen/arch/x86/cpu/amd.c @@ -7,11 +7,11 @@ #include <asm/io.h> #include <asm/msr.h> #include <asm/processor.h> +#include <asm/amd.h> #include <asm/hvm/support.h> #include <asm/setup.h> /* amd_init_cpu */ #include "cpu.h" -#include "amd.h" void start_svm(struct cpuinfo_x86 *c); @@ -157,6 +157,54 @@ static void __devinit set_cpuidmask(struct cpuinfo_x86 *c) } /* + * Check for the presence of an AMD erratum. Arguments are defined in amd.h + * for each known erratum. Return 1 if erratum is found. + */ +int cpu_has_amd_erratum(const struct cpuinfo_x86 *cpu, int osvw, ...) +{ + va_list ap; + u32 range; + u32 ms; + + if (cpu->x86_vendor != X86_VENDOR_AMD) + return 0; + + va_start(ap, osvw); + + if (osvw) { + u16 osvw_id = va_arg(ap, int); + + if (cpu_has(cpu, X86_FEATURE_OSVW)) { + u64 osvw_len; + rdmsrl(MSR_AMD_OSVW_ID_LENGTH, osvw_len); + + if (osvw_id < osvw_len) { + u64 osvw_bits; + rdmsrl(MSR_AMD_OSVW_STATUS + (osvw_id >> 6), + osvw_bits); + + va_end(ap); + return (osvw_bits >> (osvw_id & 0x3f)) & 0x01; + } + } + } + + /* OSVW unavailable or ID unknown, match family-model-stepping range */ + ms = (cpu->x86_model << 8) | cpu->x86_mask; + while ((range = va_arg(ap, int))) { + if ((cpu->x86 == AMD_MODEL_RANGE_FAMILY(range)) && + (ms >= AMD_MODEL_RANGE_START(range)) && + (ms <= AMD_MODEL_RANGE_END(range))) { + va_end(ap); + return 1; + } + } + + va_end(ap); + return 0; +} + +/* * amd_flush_filter={on,off}. Forcibly Enable or disable the TLB flush * filter on AMD 64-bit processors. */ diff --git a/xen/arch/x86/hvm/svm/asid.c b/xen/arch/x86/hvm/svm/asid.c index 1deb2e8b4a..3a35e150ed 100644 --- a/xen/arch/x86/hvm/svm/asid.c +++ b/xen/arch/x86/hvm/svm/asid.c @@ -21,14 +21,14 @@ #include <xen/lib.h> #include <xen/perfc.h> #include <asm/hvm/svm/asid.h> +#include <asm/amd.h> void svm_asid_init(struct cpuinfo_x86 *c) { int nasids = 0; /* Check for erratum #170, and leave ASIDs disabled if it's present. */ - if ( (c->x86 == 0x10) || - ((c->x86 == 0xf) && (c->x86_model >= 0x68) && (c->x86_mask >= 1)) ) + if ( !cpu_has_amd_erratum(c, AMD_ERRATUM_170) ) nasids = cpuid_ebx(0x8000000A); hvm_asid_init(nasids); diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index d7576bc8a8..1b4be70dc7 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -34,6 +34,7 @@ #include <asm/regs.h> #include <asm/cpufeature.h> #include <asm/processor.h> +#include <asm/amd.h> #include <asm/types.h> #include <asm/debugreg.h> #include <asm/msr.h> @@ -825,8 +826,8 @@ static void svm_init_erratum_383(struct cpuinfo_x86 *c) { uint32_t l, h; - /* only family 10h is affected */ - if ( c->x86 != 0x10 ) + /* check whether CPU is affected */ + if ( !cpu_has_amd_erratum(c, AMD_ERRATUM_383) ) return; /* use safe methods to be compatible with nested virtualization */ diff --git a/xen/arch/x86/cpu/amd.h b/xen/include/asm-x86/amd.h index 4da3d64a87..c38984f553 100644 --- a/xen/arch/x86/cpu/amd.h +++ b/xen/include/asm-x86/amd.h @@ -100,4 +100,39 @@ __bit(X86_FEATURE_SKINIT)) #define AMD_EXTFEATURES_FAM11h_REV_B_EDX AMD_EXTFEATURES_K8_REV_G_EDX +/* AMD errata checking + * + * Errata are defined using the AMD_LEGACY_ERRATUM() or AMD_OSVW_ERRATUM() + * macros. The latter is intended for newer errata that have an OSVW id + * assigned, which it takes as first argument. Both take a variable number + * of family-specific model-stepping ranges created by AMD_MODEL_RANGE(). + * + * Example 1: + * #define AMD_ERRATUM_319 \ + * AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0x4, 0x2), \ + * AMD_MODEL_RANGE(0x10, 0x8, 0x0, 0x8, 0x0), \ + * AMD_MODEL_RANGE(0x10, 0x9, 0x0, 0x9, 0x0)) + * Example 2: + * #define AMD_ERRATUM_400 \ + * AMD_OSVW_ERRATUM(1, AMD_MODEL_RANGE(0xf, 0x41, 0x2, 0xff, 0xf), \ + * AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0xff, 0xf)) + * + */ + +#define AMD_LEGACY_ERRATUM(...) 0 /* legacy */, __VA_ARGS__, 0 +#define AMD_OSVW_ERRATUM(osvw_id, ...) 1 /* osvw */, osvw_id, __VA_ARGS__, 0 +#define AMD_MODEL_RANGE(f, m_start, s_start, m_end, s_end) \ + ((f << 24) | (m_start << 16) | (s_start << 12) | (m_end << 4) | (s_end)) +#define AMD_MODEL_RANGE_FAMILY(range) (((range) >> 24) & 0xff) +#define AMD_MODEL_RANGE_START(range) (((range) >> 12) & 0xfff) +#define AMD_MODEL_RANGE_END(range) ((range) & 0xfff) + +#define AMD_ERRATUM_170 \ + AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x0f, 0x0, 0x0, 0x67, 0xf)) + +#define AMD_ERRATUM_383 \ + AMD_OSVW_ERRATUM(3, AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0xff, 0xf), \ + AMD_MODEL_RANGE(0x12, 0x0, 0x0, 0x1, 0x0)) + +int cpu_has_amd_erratum(const struct cpuinfo_x86 *, int, ...); #endif /* __AMD_H__ */ diff --git a/xen/include/asm-x86/msr-index.h b/xen/include/asm-x86/msr-index.h index 99762e1b78..03fe835085 100644 --- a/xen/include/asm-x86/msr-index.h +++ b/xen/include/asm-x86/msr-index.h @@ -250,6 +250,10 @@ #define MSR_AMD_PATCHLEVEL 0x0000008b #define MSR_AMD_PATCHLOADER 0xc0010020 +/* AMD OS Visible Workaround MSRs */ +#define MSR_AMD_OSVW_ID_LENGTH 0xc0010140 +#define MSR_AMD_OSVW_STATUS 0xc0010141 + /* K6 MSRs */ #define MSR_K6_EFER 0xc0000080 #define MSR_K6_STAR 0xc0000081 |