aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2010-07-05 12:10:52 +0100
committerKeir Fraser <keir.fraser@citrix.com>2010-07-05 12:10:52 +0100
commit66633037f8fc6fe4168f968471cb14baf36a65f0 (patch)
tree241789dc01b6b2ba289736a217327b1f768fc9ed
parent21a50a902946ddfd90dc13d1334505902e0c1201 (diff)
downloadxen-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.c50
-rw-r--r--xen/arch/x86/hvm/svm/asid.c4
-rw-r--r--xen/arch/x86/hvm/svm/svm.c5
-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.h4
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