Currently some KVM selftests are failed on Hygon CPUs due to missing vendor detection and edge-case handling specific to Hygon's architecture. Add CPU vendor detection for Hygon and add a global variable "host_cpu_is_hygon" as the basic facility for the following fixes. Signed-off-by: Zhiquan Li --- tools/testing/selftests/kvm/include/x86/processor.h | 6 ++++++ tools/testing/selftests/kvm/lib/x86/processor.c | 3 +++ 2 files changed, 9 insertions(+) diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h index 57d62a425109..9ac18e0fca54 100644 --- a/tools/testing/selftests/kvm/include/x86/processor.h +++ b/tools/testing/selftests/kvm/include/x86/processor.h @@ -21,6 +21,7 @@ extern bool host_cpu_is_intel; extern bool host_cpu_is_amd; +extern bool host_cpu_is_hygon; extern uint64_t guest_tsc_khz; #ifndef MAX_NR_CPUID_ENTRIES @@ -701,6 +702,11 @@ static inline bool this_cpu_is_amd(void) return this_cpu_vendor_string_is("AuthenticAMD"); } +static inline bool this_cpu_is_hygon(void) +{ + return this_cpu_vendor_string_is("HygonGenuine"); +} + static inline uint32_t __this_cpu_has(uint32_t function, uint32_t index, uint8_t reg, uint8_t lo, uint8_t hi) { diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c index 36104d27f3d9..bbd3336f22eb 100644 --- a/tools/testing/selftests/kvm/lib/x86/processor.c +++ b/tools/testing/selftests/kvm/lib/x86/processor.c @@ -21,6 +21,7 @@ vm_vaddr_t exception_handlers; bool host_cpu_is_amd; bool host_cpu_is_intel; +bool host_cpu_is_hygon; bool is_forced_emulation_enabled; uint64_t guest_tsc_khz; @@ -671,6 +672,7 @@ void kvm_arch_vm_post_create(struct kvm_vm *vm, unsigned int nr_vcpus) sync_global_to_guest(vm, host_cpu_is_intel); sync_global_to_guest(vm, host_cpu_is_amd); + sync_global_to_guest(vm, host_cpu_is_hygon); sync_global_to_guest(vm, is_forced_emulation_enabled); sync_global_to_guest(vm, pmu_errata_mask); @@ -1303,6 +1305,7 @@ void kvm_selftest_arch_init(void) { host_cpu_is_intel = this_cpu_is_intel(); host_cpu_is_amd = this_cpu_is_amd(); + host_cpu_is_hygon = this_cpu_is_hygon(); is_forced_emulation_enabled = kvm_is_forced_emulation_enabled(); kvm_init_pmu_errata(); -- 2.43.0 Hygon architecture uses VMMCALL as guest hypercall instruction, so utilize the Hygon specific flag to avoid the test like "fix hypercall" running into the wrong branches and using VMCALL, then causing failure. Signed-off-by: Zhiquan Li --- tools/testing/selftests/kvm/lib/x86/processor.c | 3 ++- tools/testing/selftests/kvm/x86/fix_hypercall_test.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c index bbd3336f22eb..64f9ecd2387d 100644 --- a/tools/testing/selftests/kvm/lib/x86/processor.c +++ b/tools/testing/selftests/kvm/lib/x86/processor.c @@ -1229,7 +1229,8 @@ const struct kvm_cpuid_entry2 *get_cpuid_entry(const struct kvm_cpuid2 *cpuid, "1: vmmcall\n\t" \ "2:" \ : "=a"(r) \ - : [use_vmmcall] "r" (host_cpu_is_amd), inputs); \ + : [use_vmmcall] "r" \ + (host_cpu_is_amd || host_cpu_is_hygon), inputs); \ \ r; \ }) diff --git a/tools/testing/selftests/kvm/x86/fix_hypercall_test.c b/tools/testing/selftests/kvm/x86/fix_hypercall_test.c index 762628f7d4ba..0377ab5b1238 100644 --- a/tools/testing/selftests/kvm/x86/fix_hypercall_test.c +++ b/tools/testing/selftests/kvm/x86/fix_hypercall_test.c @@ -52,7 +52,7 @@ static void guest_main(void) if (host_cpu_is_intel) { native_hypercall_insn = vmx_vmcall; other_hypercall_insn = svm_vmmcall; - } else if (host_cpu_is_amd) { + } else if (host_cpu_is_amd || host_cpu_is_hygon) { native_hypercall_insn = svm_vmmcall; other_hypercall_insn = vmx_vmcall; } else { -- 2.43.0 There are similar reserved memory address regions for Hygon architecture, mapping memory into these regions and accesses to them results in a #PF. Hygon CSV also makes the "physical address space width reduction", the reduced physical address bits are reported by bits 11:6 of CPUID[0x8000001f].EBX as well, so the logic is totally applicable for Hygon processors. Following test failures are fixed by this change: - access_tracking_perf_test - demand_paging_test - dirty_log_perf_test - dirty_log_test - kvm_page_table_test - memslot_modification_stress_test - pre_fault_memory_test - x86/dirty_log_page_splitting_test Signed-off-by: Zhiquan Li --- tools/testing/selftests/kvm/lib/x86/processor.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c index 64f9ecd2387d..252b04c8e944 100644 --- a/tools/testing/selftests/kvm/lib/x86/processor.c +++ b/tools/testing/selftests/kvm/lib/x86/processor.c @@ -1270,8 +1270,8 @@ unsigned long vm_compute_max_gfn(struct kvm_vm *vm) max_gfn = (1ULL << (guest_maxphyaddr - vm->page_shift)) - 1; - /* Avoid reserved HyperTransport region on AMD processors. */ - if (!host_cpu_is_amd) + /* Avoid reserved HyperTransport region on AMD or Hygon processors. */ + if (!host_cpu_is_amd && !host_cpu_is_hygon) return max_gfn; /* On parts with <40 physical address bits, the area is fully hidden */ @@ -1285,7 +1285,7 @@ unsigned long vm_compute_max_gfn(struct kvm_vm *vm) /* * Otherwise it's at the top of the physical address space, possibly - * reduced due to SME by bits 11:6 of CPUID[0x8000001f].EBX. Use + * reduced due to SME or CSV by bits 11:6 of CPUID[0x8000001f].EBX. Use * the old conservative value if MAXPHYADDR is not enumerated. */ if (!this_cpu_has_p(X86_PROPERTY_MAX_PHY_ADDR)) -- 2.43.0 At present, the PMU event filter test is only available for Intel and AMD architecture conditionally, but it is applicable for Hygon architecture as well. Since all known Hygon processors can re-use the test cases, so it isn't necessary to create a wrapper like other architectures, using the "host_cpu_is_hygon" variable directly. Signed-off-by: Zhiquan Li --- tools/testing/selftests/kvm/x86/pmu_event_filter_test.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/x86/pmu_event_filter_test.c b/tools/testing/selftests/kvm/x86/pmu_event_filter_test.c index 1c5b7611db24..e6badd9a2a2a 100644 --- a/tools/testing/selftests/kvm/x86/pmu_event_filter_test.c +++ b/tools/testing/selftests/kvm/x86/pmu_event_filter_test.c @@ -842,14 +842,14 @@ int main(int argc, char *argv[]) TEST_REQUIRE(kvm_has_cap(KVM_CAP_PMU_EVENT_FILTER)); TEST_REQUIRE(kvm_has_cap(KVM_CAP_PMU_EVENT_MASKED_EVENTS)); - TEST_REQUIRE(use_intel_pmu() || use_amd_pmu()); + TEST_REQUIRE(use_intel_pmu() || use_amd_pmu() || host_cpu_is_hygon); guest_code = use_intel_pmu() ? intel_guest_code : amd_guest_code; vm = vm_create_with_one_vcpu(&vcpu, guest_code); TEST_REQUIRE(sanity_check_pmu(vcpu)); - if (use_amd_pmu()) + if (use_amd_pmu() || host_cpu_is_hygon) test_amd_deny_list(vcpu); test_without_filter(vcpu); @@ -862,7 +862,7 @@ int main(int argc, char *argv[]) supports_event_mem_inst_retired() && kvm_cpu_property(X86_PROPERTY_PMU_NR_GP_COUNTERS) >= 3) vcpu2 = vm_vcpu_add(vm, 2, intel_masked_events_guest_code); - else if (use_amd_pmu()) + else if (use_amd_pmu() || host_cpu_is_hygon) vcpu2 = vm_vcpu_add(vm, 2, amd_masked_events_guest_code); if (vcpu2) -- 2.43.0 On Hygon processors either RDTSCP or RDPID is supported in the host, MSR_TSC_AUX is able to be accessed. The write reserved bits test for MSR_TSC_AUX with RDPID as "feature" and RDTSCP as "feature2" is failed on Hygon CPUs which only support RDTSCP but not support RDPID. In current design, if RDPID is not supported, vCPU0 and vCPU1 write reserved bits expects #GP, however, it is not applicable for Hygon CPUs. Since on Hygon architecture whether or not RDPID is supported in the host, once RDTSCP is supported, MSR_TSC_AUX is able to be accessed, vCPU0 and vCPU1 drop bits 63:32 and write successfully. Therefore, the results of write MSR_TSC_AUX reserved bits on Hygon CPUs should be: 1) either RDTSCP or RDPID is supported case and both are supported case, expect success and a truncated value, not #GP. 2) neither RDTSCP nor RDPID is supported, expect #GP. Signed-off-by: Zhiquan Li --- tools/testing/selftests/kvm/x86/msrs_test.c | 26 +++++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/kvm/x86/msrs_test.c b/tools/testing/selftests/kvm/x86/msrs_test.c index 40d918aedce6..2f1e800fe691 100644 --- a/tools/testing/selftests/kvm/x86/msrs_test.c +++ b/tools/testing/selftests/kvm/x86/msrs_test.c @@ -77,11 +77,11 @@ static bool ignore_unsupported_msrs; static u64 fixup_rdmsr_val(u32 msr, u64 want) { /* - * AMD CPUs drop bits 63:32 on some MSRs that Intel CPUs support. KVM - * is supposed to emulate that behavior based on guest vendor model + * AMD and Hygon CPUs drop bits 63:32 on some MSRs that Intel CPUs support. + * KVM is supposed to emulate that behavior based on guest vendor model * (which is the same as the host vendor model for this test). */ - if (!host_cpu_is_amd) + if (!host_cpu_is_amd && !host_cpu_is_hygon) return want; switch (msr) { @@ -94,6 +94,17 @@ static u64 fixup_rdmsr_val(u32 msr, u64 want) } } +/* + * On Hygon processors either RDTSCP or RDPID is supported in the host, + * MSR_TSC_AUX is able to be accessed. + */ +static bool is_hygon_msr_tsc_aux_supported(const struct kvm_msr *msr) +{ + return host_cpu_is_hygon && + msr->index == MSR_TSC_AUX && + (this_cpu_has(msr->feature) || this_cpu_has(msr->feature2)); +} + static void __rdmsr(u32 msr, u64 want) { u64 val; @@ -174,9 +185,14 @@ void guest_test_reserved_val(const struct kvm_msr *msr) /* * If the CPU will truncate the written value (e.g. SYSENTER on AMD), * expect success and a truncated value, not #GP. + * + * On Hygon CPUs whether or not RDPID is supported in the host, once RDTSCP + * is supported, MSR_TSC_AUX is able to be accessed. So, for either RDTSCP + * or RDPID is supported case and both are supported case, expect + * success and a truncated value, not #GP. */ - if (!this_cpu_has(msr->feature) || - msr->rsvd_val == fixup_rdmsr_val(msr->index, msr->rsvd_val)) { + if (!is_hygon_msr_tsc_aux_supported(msr) && (!this_cpu_has(msr->feature) || + msr->rsvd_val == fixup_rdmsr_val(msr->index, msr->rsvd_val))) { u8 vec = wrmsr_safe(msr->index, msr->rsvd_val); __GUEST_ASSERT(vec == GP_VECTOR, -- 2.43.0