From 48b858ea3ab559dc2712fa3852038fd5e6ccd0db Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 30 Aug 2015 22:43:17 +0100 Subject: [PATCH] Utility for dumping the CPUID information visible to a guest Signed-off-by: Andrew Cooper --- build/common.mk | 2 +- docs/all-tests.dox | 5 ++ include/arch/x86/lib.h | 19 +++++++ tests/cpuid/Makefile | 11 ++++ tests/cpuid/main.c | 122 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 tests/cpuid/Makefile create mode 100644 tests/cpuid/main.c diff --git a/build/common.mk b/build/common.mk index f9bf0c6..a1d3eb8 100644 --- a/build/common.mk +++ b/build/common.mk @@ -3,7 +3,7 @@ DESTDIR ?= $(ROOT)/dist PREFIX ?= $(ROOT) CC = gcc -ALL_CATEGORIES := special functional xsa +ALL_CATEGORIES := special functional xsa utility ALL_ENVIRONMENTS := pv64 pv32pae hvm64 hvm32pae hvm32 diff --git a/docs/all-tests.dox b/docs/all-tests.dox index 149a467..2f73263 100644 --- a/docs/all-tests.dox +++ b/docs/all-tests.dox @@ -23,4 +23,9 @@ Coveres XSA-106 and XSA-156. @section index-xsa XSA Proof-of-Concept tests @subpage test-xsa-167 - PV superpage sanity checks. + + +@section index-utility Utilities + +@subpage test-cpuid - Print CPUID information. */ diff --git a/include/arch/x86/lib.h b/include/arch/x86/lib.h index 1bd0161..67af0dd 100644 --- a/include/arch/x86/lib.h +++ b/include/arch/x86/lib.h @@ -2,6 +2,7 @@ #define XTF_X86_LIB_H #include +#include static inline uint64_t rdmsr(uint32_t idx) { @@ -28,6 +29,15 @@ static inline void cpuid(uint32_t leaf, : "0" (leaf)); } +static inline void pv_cpuid(uint32_t leaf, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) +{ + asm volatile (_ASM_XEN_FEP "cpuid" + : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) + : "0" (leaf)); +} + static inline void cpuid_count(uint32_t leaf, uint32_t subleaf, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) @@ -37,6 +47,15 @@ static inline void cpuid_count(uint32_t leaf, uint32_t subleaf, : "0" (leaf), "2" (subleaf)); } +static inline void pv_cpuid_count(uint32_t leaf, uint32_t subleaf, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) +{ + asm volatile (_ASM_XEN_FEP "cpuid" + : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) + : "0" (leaf), "2" (subleaf)); +} + static inline uint8_t inb(uint16_t port) { uint8_t val; diff --git a/tests/cpuid/Makefile b/tests/cpuid/Makefile new file mode 100644 index 0000000..085af54 --- /dev/null +++ b/tests/cpuid/Makefile @@ -0,0 +1,11 @@ +ROOT := $(abspath $(CURDIR)/../..) + +include $(ROOT)/build/common.mk + +NAME := cpuid +CATEGORY := utility +TEST-ENVS := $(ALL_ENVIRONMENTS) + +obj-perenv += main.o + +include $(ROOT)/build/gen.mk diff --git a/tests/cpuid/main.c b/tests/cpuid/main.c new file mode 100644 index 0000000..f89ad6c --- /dev/null +++ b/tests/cpuid/main.c @@ -0,0 +1,122 @@ +/** + * @file tests/cpuid/main.c + * @ref test-cpuid + * + * @page test-cpuid CPUID + * + * Prints all CPUID information visible to the guest. PV guests dump both + * native and emulated CPUID. + * + * @sa tests/cpuid/main.c + */ +#include + +static void dump_leaves( + void (*cpuid_fn)(uint32_t leaf, uint32_t subleaf, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) + ) +{ + uint32_t leaf = 0, subleaf = ~0U; + + uint64_t valid_xstate_leaves = 0; + uint32_t max_leaf = 0, max_l7_subleaf = 0, + max_hv_leaf = 0, max_hv2_leaf = 0, max_extd_leaf = 0; + + for ( ;; ) + { + uint32_t eax, ebx, ecx, edx; + + cpuid_fn(leaf, subleaf, &eax, &ebx, &ecx, &edx); + + printk(" %08x:%08x -> %08x:%08x:%08x:%08x\n", + leaf, subleaf, eax, ebx, ecx, edx); + + switch ( leaf ) + { + case 0: + max_leaf = eax; + break; + + case 0x4: + subleaf++; + if ( (eax & 0x1f) != 0 ) + continue; + break; + + case 0x7: + if ( subleaf == 0 ) + max_l7_subleaf = eax; + subleaf++; + if ( subleaf <= max_l7_subleaf ) + continue; + break; + + case 0xd: + if ( subleaf == 0 ) + valid_xstate_leaves = ((uint64_t)edx) << 32 | eax; + do + { + subleaf++; + } while ( (subleaf < 63) && + !(valid_xstate_leaves & (1ULL << subleaf)) ); + if ( subleaf < 63 ) + continue; + break; + + case 0x40000000U: + max_hv_leaf = eax; + break; + + case 0x40000100U: + max_hv2_leaf = eax; + break; + + case 0x80000000U: + max_extd_leaf = eax; + break; + } + + leaf++; + if ( (leaf > 0) && (leaf < 0x40000000U) && (leaf > max_leaf) ) + leaf = 0x40000000U; + + if ( (leaf > 0x40000000U) && (leaf < 0x40000100U) && (leaf > max_hv_leaf) ) + leaf = 0x40000100U; + + if ( (leaf > 0x40000100U) && (leaf < 0x80000000U) && (leaf > max_hv2_leaf) ) + leaf = 0x80000000U; + + if ( (leaf > 0x80000000U) && (leaf > max_extd_leaf) ) + break; + + subleaf = ~0; + if ( leaf == 4 || leaf == 7 || leaf == 0xd ) + subleaf = 0; + } +} + +void test_main(void) +{ + printk("Guest cpuid information\n"); + + printk("Native cpuid:\n"); + dump_leaves(cpuid_count); + +#ifdef CONFIG_PV + printk("Emulated cpuid:\n"); + dump_leaves(pv_cpuid_count); +#endif + + xtf_success(NULL); +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ -- 2.39.5