From: Andrew Cooper Date: Fri, 14 Oct 2016 12:32:36 +0000 (+0100) Subject: CPUID Faulting tests X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=a78dbe70cd6ea14a02a524fbe0cb8f6e11b1080e;p=xtf.git CPUID Faulting tests Signed-off-by: Andrew Cooper --- diff --git a/arch/x86/extable.c b/arch/x86/extable.c index f3bb461..3923014 100644 --- a/arch/x86/extable.c +++ b/arch/x86/extable.c @@ -26,6 +26,24 @@ bool ex_record_fault_eax(struct cpu_regs *regs, const struct extable_entry *ex) return true; } +/** + * Record the current fault in @%edi + * + * Sample usage: + *
+ *   asm volatile ("1: $INSN; 2:"
+ *                 _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_edi)
+ *                 : "=D" (fault) : "0" (0));
+ * 
+ */ +bool ex_record_fault_edi(struct cpu_regs *regs, const struct extable_entry *ex) +{ + regs->di = (uint32_t)(regs->entry_vector << 16) | regs->error_code; + regs->ip = ex->fixup; + + return true; +} + /** * Fixup from a rdmsr fault * diff --git a/docs/all-tests.dox b/docs/all-tests.dox index 79e09e7..4f86182 100644 --- a/docs/all-tests.dox +++ b/docs/all-tests.dox @@ -16,6 +16,8 @@ and functionality. @section index-functional Functional tests +@subpage test-cpuid-faulting - Guest CPUID Faulting support. + @subpage test-fpu-exception-emulation - FPU Exception Emulation. Covers XSA-190. @subpage test-invlpg - `invlpg` instruction behaviour. diff --git a/include/arch/x86/msr-index.h b/include/arch/x86/msr-index.h index 73a1e00..d479239 100644 --- a/include/arch/x86/msr-index.h +++ b/include/arch/x86/msr-index.h @@ -3,6 +3,14 @@ #include +#define MSR_INTEL_PLATFORM_INFO 0x000000ce +#define _MSR_PLATFORM_INFO_CPUID_FAULTING 31 +#define MSR_PLATFORM_INFO_CPUID_FAULTING (1ULL << _MSR_PLATFORM_INFO_CPUID_FAULTING) + +#define MSR_INTEL_MISC_FEATURES_ENABLES 0x00000140 +#define _MSR_MISC_FEATURES_CPUID_FAULTING 0 +#define MSR_MISC_FEATURES_CPUID_FAULTING (1ULL << _MSR_MISC_FEATURES_CPUID_FAULTING) + #define MSR_EFER 0xc0000080 /* Extended Feature register. */ #define _EFER_SCE 0 /* SYSCALL Enable. */ #define EFER_SCE (_AC(1, L) << _EFER_SCE) diff --git a/tests/cpuid-faulting/Makefile b/tests/cpuid-faulting/Makefile new file mode 100644 index 0000000..574408c --- /dev/null +++ b/tests/cpuid-faulting/Makefile @@ -0,0 +1,9 @@ +include $(ROOT)/build/common.mk + +NAME := cpuid-faulting +CATEGORY := functional +TEST-ENVS := $(ALL_ENVIRONMENTS) + +obj-perenv += main.o + +include $(ROOT)/build/gen.mk diff --git a/tests/cpuid-faulting/main.c b/tests/cpuid-faulting/main.c new file mode 100644 index 0000000..e30ff87 --- /dev/null +++ b/tests/cpuid-faulting/main.c @@ -0,0 +1,137 @@ +/** + * @file tests/cpuid-faulting/main.c + * @ref test-cpuid-faulting + * + * @page test-cpuid-faulting CPUID Faulting support + * + * CPUID Faulting is a feature available natively on Intel IvyBridge and newer + * processors, which allows a kernel or hypervisor to trap userspace `CPUID` + * instructions. + * + * Xen provides this support to guests, and for HVM guests is the the position + * to offer CPUID Faulting even on hardware which lacks it natively. + * + * The native definition of CPUID Faulting is that when enabled, `CPUID` + * instructions suffer @#GP[0] when executed at CPL > 0. This behaviour is + * honoured exactly for HVM guests. PV guests kernels however execute in ring + * 1 (32bit PV) or ring 3 (64bit PV). For PV guests, the implemented + * behaviour will cause a @#GP[0] fault when executed in guest userspace. + * + * @see tests/cpuid-faulting/main.c + */ +#include + +#include +#include + +bool test_wants_user_mappings = true; + +#define EXC_SYM(vec, ec) ((X86_EXC_ ## vec) << 16 | ec) + +unsigned long stub_cpuid(void) +{ + unsigned int fault = 0, tmp; + + asm volatile("1: cpuid; 2:" + _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_edi) + : "=a" (tmp), "+D" (fault) + : "a" (0) + : "ebx", "ecx", "edx"); + + return fault; +} + +unsigned long stub_fep_cpuid(void) +{ + unsigned int fault = 0, tmp; + + asm volatile(_ASM_XEN_FEP + "1: cpuid; 2:" + _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_edi) + : "=a" (tmp), "+D" (fault) + : "a" (0) + : "ebx", "ecx", "edx"); + + return fault; +} + +static void test_cpuid(bool exp_faulting) +{ + /* + * Kernel cpuids should never fault + */ + if ( stub_cpuid() ) + xtf_failure("Fail: kernel cpuid faulted\n"); + + if ( IS_DEFINED(CONFIG_PV) && stub_fep_cpuid() ) + xtf_failure("Fail: kernel pv cpuid faulted\n"); + + if ( xtf_has_fep && stub_fep_cpuid() ) + xtf_failure("Fail: kernel emulated cpuid faulted\n"); + + /* + * User cpuids should raise #GP[0] if faulting is enabled. + */ + unsigned long exp = exp_faulting ? EXC_SYM(GP, 0) : 0; + const char *exp_fail_str = exp_faulting ? "didn't fault" : "faulted"; + + if ( exec_user(stub_cpuid) != exp ) + xtf_failure("Fail: user cpuid %s\n", exp_fail_str); + + if ( IS_DEFINED(CONFIG_PV) && exec_user(stub_fep_cpuid) != exp ) + xtf_failure("Fail: user pv cpuid %s\n", exp_fail_str); + + if ( xtf_has_fep && exec_user(stub_fep_cpuid) != exp ) + xtf_failure("Fail: user emulated cpuid %s\n", exp_fail_str); +} + +void test_main(void) +{ + uint64_t platform_info, features_enable; + + printk("Guest CPUID Faulting support\n"); + + if ( IS_DEFINED(CONFIG_HVM) && !xtf_has_fep ) + xtf_skip("FEP support not detected - some tests will be skipped\n"); + + /* No faulting. CPUID should work without faulting anywhere. */ + printk("Testing CPUID without faulting enabled\n"); + test_cpuid(false); + + /* Probe for CPUID Faulting support. */ + if ( rdmsr_safe(MSR_INTEL_PLATFORM_INFO, &platform_info) || + !(platform_info & MSR_PLATFORM_INFO_CPUID_FAULTING) ) + return xtf_skip("Skip: CPUID Faulting unavailable\n"); + + if ( rdmsr_safe(MSR_INTEL_MISC_FEATURES_ENABLES, &features_enable) ) + return xtf_error("Error: Fault accessing MISC_FEATURES_ENABLES\n"); + + /* Attempt to enable CPUID Faulting. */ + if ( wrmsr_safe(MSR_INTEL_MISC_FEATURES_ENABLES, + features_enable | MSR_MISC_FEATURES_CPUID_FAULTING) ) + return xtf_failure("Fail: Unable to enable CPUID Faulting\n"); + + /* Faulting active. CPUID should fault ouside of the kernel. */ + printk("Testing CPUID with faulting enabled\n"); + test_cpuid(true); + + /* Try disabling faulting. */ + if ( wrmsr_safe(MSR_INTEL_MISC_FEATURES_ENABLES, features_enable) ) + return xtf_failure("Fail: Unable to disable CPUID Faulting\n"); + + /* Double check that CPUID no longer faults. */ + printk("Retesting CPUID without faulting enabled\n"); + test_cpuid(false); + + xtf_success(NULL); +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */