mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
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>
This commit is contained in:
1 parent
2156299cf0
commit
2604adda4f
5 files changed
+93
-5
No files matched your search
+49
-1
@@ -7,12 +7,12 @@
|
||||
#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 <asm/acpi.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "amd.h"
|
||||
|
||||
/*
|
||||
* Pre-canned values for overriding the CPUID features
|
||||
@@ -147,6 +147,54 @@ static void __devinit set_cpuidmask(const 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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
@@ -846,8 +847,8 @@ static void svm_init_erratum_383(struct cpuinfo_x86 *c)
|
||||
{
|
||||
uint64_t msr_content;
|
||||
|
||||
/* 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 */
|
||||
|
||||
@@ -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__ */
|
||||
@@ -252,6 +252,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
|
||||
|
||||