From: Andrew Cooper Date: Wed, 28 Jun 2017 15:35:48 +0000 (+0000) Subject: Extend exinfo_t with test-available bits X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=f5936f99d3e44a9c294b1a3c7bcef80e4d2ff950;p=people%2Fandrewcoop%2Fxen-test-framework.git Extend exinfo_t with test-available bits VT-x adds two extra logical errors from executing instructions. Add two new testa-avaialble bits into the generic infrastructure. For the vvmx test, introduce XTF-wide helpers for the VMX Instruction Error ABI, and test-specific helpers for VMX Instruction Error reporting via extinfo_t, along with logic to decode the errors for printing. Signed-off-by: Andrew Cooper --- diff --git a/arch/x86/include/arch/exinfo.h b/arch/x86/include/arch/exinfo.h index 0788cea..71242ab 100644 --- a/arch/x86/include/arch/exinfo.h +++ b/arch/x86/include/arch/exinfo.h @@ -13,12 +13,16 @@ * * - Bottom 16 bits are error code * - Next 8 bits are the entry vector + * - Next 2 bits are available for tests * - Top bit it set to disambiguate @#DE from no exception */ typedef unsigned int exinfo_t; #define EXINFO_EXPECTED (1u << 31) +#define EXINFO_AVAIL1 (1u << 25) +#define EXINFO_AVAIL0 (1u << 24) + #define EXINFO(vec, ec) (EXINFO_EXPECTED | ((vec & 0xff) << 16) | (ec & 0xffff)) #define EXINFO_SYM(exc, ec) EXINFO(X86_EXC_ ## exc, ec) diff --git a/arch/x86/include/arch/vmx.h b/arch/x86/include/arch/vmx.h new file mode 100644 index 0000000..7004692 --- /dev/null +++ b/arch/x86/include/arch/vmx.h @@ -0,0 +1,26 @@ +/** + * @file arch/x86/include/arch/vmx.h + * + * Helpers for VT-x. + */ +#ifndef XTF_X86_VMX_H +#define XTF_X86_VMX_H + +#include + +/** + * Error string for VMX Instruction Errors. + */ +const char *vmx_insn_err_strerror(unsigned int err); + +#endif /* XTF_X86_VMX_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/x86/include/arch/x86-vmx.h b/arch/x86/include/arch/x86-vmx.h new file mode 100644 index 0000000..6edefbf --- /dev/null +++ b/arch/x86/include/arch/x86-vmx.h @@ -0,0 +1,49 @@ +/** + * @file arch/x86/include/arch/x86-vmx.h + * + * VT-x hardware ABI, as specified in the Intel SDM. + */ +#ifndef XTF_X86_X86_VMX_H +#define XTF_X86_X86_VMX_H + +/* VMX Instruction Error codes. */ +#define VMERR_VMCALL_IN_ROOT 1 +#define VMERR_VMCLEAR_BAD_PADDR 2 +#define VMERR_VMCLEAR_WITH_VMXON_PTR 3 +#define VMERR_VMLAUNCH_NONCLEAR_VMCS 4 +#define VMERR_VMRESUME_NONLAUNCHED_VMCS 5 +#define VMERR_VMRESUME_AFTER_VMXOFF 6 +#define VMERR_INVALID_CONTROL_STATE 7 +#define VMERR_INVALID_HOST_STATE 8 +#define VMERR_VMPTRLD_BAD_PADDR 9 +#define VMERR_VMPTRLD_WITH_VMXON_PTR 10 +#define VMERR_VMPTRLD_BAD_REVID 11 +#define VMERR_UNSUPPORTED_VMCS_FIELD 12 +#define VMERR_VMWRITE_READONLY_FIELD 13 +/* 14 not specified. */ +#define VMERR_VMXON_IN_ROOT 15 +#define VMERR_VMENTRY_BAD_EXECUTIVE 16 +#define VMERR_VMENTRY_NONLAUNCHED_EXECUTIVE 17 +#define VMERR_VMENTRY_WITHOUT_VMXON_PTR 18 +#define VMERR_VMCALL_NONCLEAR_VMCS 19 +#define VMERR_VMCALL_BAD_CONTROL_STATE 20 +/* 21 not specified. */ +#define VMERR_VMCALL_BAD_MSEG_REVID 22 +#define VMERR_VMXOFF_UNDER_DUAL 23 +#define VMERR_VMCALL_BAD_SMM_MONITOR 24 +#define VMERR_BAD_EXECUTIVE_STATE 25 +#define VMERR_VMENTRY_MOVSS 26 +/* 27 not specified. */ +#define VMERR_BAD_INV_OPERAND 28 + +#endif /* XTF_X86_X86_VMX_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/arch/x86/vmx.c b/arch/x86/vmx.c new file mode 100644 index 0000000..b14f28a --- /dev/null +++ b/arch/x86/vmx.c @@ -0,0 +1,56 @@ +/** + * @file arch/x86/vmx.c + * + * Helpers for VT-x. + */ +#include + +#include + +const char *vmx_insn_err_strerror(unsigned int err) +{ +#define ERR(x) [VMERR_ ## x] = #x + const char *const strings[] = { + ERR(VMCALL_IN_ROOT), + ERR(VMCLEAR_BAD_PADDR), + ERR(VMCLEAR_WITH_VMXON_PTR), + ERR(VMLAUNCH_NONCLEAR_VMCS), + ERR(VMRESUME_NONLAUNCHED_VMCS), + ERR(VMRESUME_AFTER_VMXOFF), + ERR(INVALID_CONTROL_STATE), + ERR(INVALID_HOST_STATE), + ERR(VMPTRLD_BAD_PADDR), + ERR(VMPTRLD_WITH_VMXON_PTR), + ERR(VMPTRLD_BAD_REVID), + ERR(UNSUPPORTED_VMCS_FIELD), + ERR(VMWRITE_READONLY_FIELD), + ERR(VMXON_IN_ROOT), + ERR(VMENTRY_BAD_EXECUTIVE), + ERR(VMENTRY_NONLAUNCHED_EXECUTIVE), + ERR(VMENTRY_WITHOUT_VMXON_PTR), + ERR(VMCALL_NONCLEAR_VMCS), + ERR(VMCALL_BAD_CONTROL_STATE), + ERR(VMCALL_BAD_MSEG_REVID), + ERR(VMXOFF_UNDER_DUAL), + ERR(VMCALL_BAD_SMM_MONITOR), + ERR(BAD_EXECUTIVE_STATE), + ERR(VMENTRY_MOVSS), + ERR(BAD_INV_OPERAND), + }; +#undef ERR + + if ( err < ARRAY_SIZE(strings) && strings[err] ) + return strings[err]; + else + return ""; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/build/files.mk b/build/files.mk index 3454aa3..8c50dd4 100644 --- a/build/files.mk +++ b/build/files.mk @@ -29,6 +29,7 @@ obj-hvm += $(ROOT)/arch/x86/hvm/pagetables.o obj-hvm += $(ROOT)/arch/x86/hvm/traps.o # Arguably common objects, but PV guests will have no interest in them. +obj-hvm += $(ROOT)/arch/x86/vmx.o obj-hvm += $(ROOT)/arch/x86/x86-tss.o $(foreach env,$(HVM_ENVIRONMENTS),$(eval obj-$(env) += $(obj-hvm))) diff --git a/common/libc/string.c b/common/libc/string.c index 5d972dd..94acc7e 100644 --- a/common/libc/string.c +++ b/common/libc/string.c @@ -20,6 +20,30 @@ size_t strnlen(const char *str, size_t max) return s - str; } +char *(strcpy)(char *dst, const char *src) +{ + char *p = dst; + + while ( *p++ == *src++ ) + ; + + return dst; +} + +char *(strncpy)(char *dst, const char *src, size_t n) +{ + char *p = dst; + size_t i; + + for ( i = 0; i < n && src[i]; ++i ) + p[i] = src[i]; + + for ( ; i < n; ++i ) + p[i] = '\0'; + + return dst; +} + int (strcmp)(const char *_s1, const char *_s2) { char s1, s2; diff --git a/include/xtf/libc.h b/include/xtf/libc.h index 18ec5f0..18b1b4a 100644 --- a/include/xtf/libc.h +++ b/include/xtf/libc.h @@ -17,6 +17,12 @@ size_t strlen(const char *str); #define strlen(s) __builtin_strlen(s) +char *strcpy(char *dst, const char *src); +#define strcpy(d, s) __builtin_strcpy(d, s) + +char *strncpy(char *dst, const char *src, size_t n); +#define strncpy(d, s, n) __builtin_strncpy(d, s, n) + int strcmp(const char *s1, const char *s2); #define strcmp(s1, s2) __builtin_strcmp(s1, s2) diff --git a/tests/vvmx/Makefile b/tests/vvmx/Makefile index 82b895e..8fe575f 100644 --- a/tests/vvmx/Makefile +++ b/tests/vvmx/Makefile @@ -6,6 +6,6 @@ TEST-ENVS := $(HVM_ENVIRONMENTS) TEST-EXTRA-CFG := extra.cfg.in -obj-perenv += main.o msr.o +obj-perenv += main.o msr.o util.o include $(ROOT)/build/gen.mk diff --git a/tests/vvmx/test.h b/tests/vvmx/test.h index 2528df2..e5a1f83 100644 --- a/tests/vvmx/test.h +++ b/tests/vvmx/test.h @@ -4,7 +4,26 @@ #include #include +#include +/* + * Extentions on top of regular EXINFO. + * + * Use EXINFO_AVAIL{0,1} for VMFail{Invalid,Valid}. (ab)use the fact that + * VMFailValid means no exception occured to stash the VMX Instruction Error + * code in the low bits, normally used for vector/error_code information. + */ +#define VMERR_SUCCESS 0 +#define VMERR_INVALID (EXINFO_EXPECTED | EXINFO_AVAIL0) +#define VMERR_VALID(x) (EXINFO_EXPECTED | EXINFO_AVAIL1 | ((x) & 0xffff)) + +/** + * Compare an expectation against what really happenend, printing + * human-readable information in case of a mismatch. + */ +void check(const char *func, exinfo_t got, exinfo_t exp); + +/* Test routines. */ void test_msr_vmx(void); #endif /* VVMX_TEST_H */ diff --git a/tests/vvmx/util.c b/tests/vvmx/util.c new file mode 100644 index 0000000..2a085c2 --- /dev/null +++ b/tests/vvmx/util.c @@ -0,0 +1,63 @@ +#include "test.h" + +#include + +static void decode_test_exinfo(char *str, size_t n, exinfo_t ex) +{ + if ( ex == VMERR_SUCCESS ) + { + strcpy(str, "VMsucceed"); + return; + } + + if ( ex == VMERR_INVALID ) + { + strcpy(str, "VMfailInvalid"); + return; + } + + unsigned int high = ex & ~0xffffff; + + if ( high == VMERR_VALID(0) ) + { + unsigned int low = ex & 0xffffff; + + snprintf(str, n, "VMfailValid(%u) %s", + low, vmx_insn_err_strerror(low)); + return; + } + + if ( high == EXINFO_EXPECTED ) + { + x86_decode_exinfo(str, n, ex); + return; + } + + strcpy(str, ""); +} + +void check(const char *func, exinfo_t got, exinfo_t exp) +{ + char gotstr[48], expstr[48]; + + if ( got == exp ) + return; + + decode_test_exinfo(gotstr, ARRAY_SIZE(gotstr), got); + decode_test_exinfo(expstr, ARRAY_SIZE(expstr), exp); + + xtf_failure("Failure in %s()\n" + " Expected 0x%08x: %s\n" + " Got 0x%08x: %s\n", + func, exp, expstr, got, gotstr); +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */