Confidential VMs(CVMs) need to execute hypercall instruction as per the CPU type. Normally KVM emulates the vmcall/vmmcall instruction by patching the guest code at runtime. Such a guest memory manipulation by KVM is not allowed with CVMs and is also undesirable in general.
This series adds support of executing hypercall as per the host cpu type queried using cpuid instruction. CPU vendor type is stored early during selftest setup and guest setup to be reused later.
Changes in v4: 1) Incoporated suggestions from Sean - * Added APIs to query host cpu type * Shared the host cpu type with guests to avoid querying the cpu type again * Modified kvm_hypercall to execute vmcall/vmmcall according to host cpu type. 2) Dropped the separate API for kvm_hypercall.
v3: https://lore.kernel.org/lkml/20221222230458.3828342-1-vannapurve@google.com/
Vishal Annapurve (4): KVM: selftests: x86: use this_cpu_* helpers KVM: selftests: x86: Add variables to store cpu type KVM: sefltests: x86: Replace is_*cpu with is_host_*cpu KVM: selftests: x86: Invoke kvm hypercall as per host cpu
.../selftests/kvm/include/x86_64/processor.h | 26 ++++++++++- .../selftests/kvm/lib/x86_64/processor.c | 44 ++++++++++--------- .../selftests/kvm/x86_64/fix_hypercall_test.c | 4 +- .../selftests/kvm/x86_64/mmio_warning_test.c | 2 +- .../kvm/x86_64/pmu_event_filter_test.c | 4 +- .../vmx_exception_with_invalid_guest_state.c | 2 +- 6 files changed, 54 insertions(+), 28 deletions(-)
Use this_cpu_* helpers to query the cpu vendor.
Suggested-by: Sean Christopherson seanjc@google.com Signed-off-by: Vishal Annapurve vannapurve@google.com --- .../selftests/kvm/include/x86_64/processor.h | 22 +++++++++++++++++++ .../selftests/kvm/lib/x86_64/processor.c | 16 ++------------ 2 files changed, 24 insertions(+), 14 deletions(-)
diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 2a5f47d51388..84edac133d8f 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -555,6 +555,28 @@ static inline uint32_t this_cpu_model(void) return x86_model(this_cpu_fms()); }
+static inline bool this_cpu_vendor_string_is(const char *vendor) +{ + const uint32_t *chunk = (const uint32_t *)vendor; + uint32_t eax, ebx, ecx, edx; + + cpuid(0, &eax, &ebx, &ecx, &edx); + return (ebx == chunk[0] && edx == chunk[1] && ecx == chunk[2]); +} + +static inline bool this_cpu_is_intel(void) +{ + return this_cpu_vendor_string_is("GenuineIntel"); +} + +/* + * Exclude early K5 samples with a vendor string of "AMDisbetter!" + */ +static inline bool this_cpu_is_amd(void) +{ + return this_cpu_vendor_string_is("AuthenticAMD"); +} + 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_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index acfa1d01e7df..a799af572f3f 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -1006,26 +1006,14 @@ void kvm_x86_state_cleanup(struct kvm_x86_state *state) free(state); }
-static bool cpu_vendor_string_is(const char *vendor) -{ - const uint32_t *chunk = (const uint32_t *)vendor; - uint32_t eax, ebx, ecx, edx; - - cpuid(0, &eax, &ebx, &ecx, &edx); - return (ebx == chunk[0] && edx == chunk[1] && ecx == chunk[2]); -} - bool is_intel_cpu(void) { - return cpu_vendor_string_is("GenuineIntel"); + return this_cpu_is_intel(); }
-/* - * Exclude early K5 samples with a vendor string of "AMDisbetter!" - */ bool is_amd_cpu(void) { - return cpu_vendor_string_is("AuthenticAMD"); + return this_cpu_is_amd(); }
void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bits)
On Wed, Dec 28, 2022, Vishal Annapurve wrote:
Use this_cpu_* helpers to query the cpu vendor.
Neither the changelog nor the shortlog captures what this patch actually does, or rather what I inteded it to do. Specifically, what I suggested (or intended to suggest) was:
KVM: selftests: Rename vendor string helpers to use "this_cpu" prefix
Suggested-by: Sean Christopherson seanjc@google.com Signed-off-by: Vishal Annapurve vannapurve@google.com
...
diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index acfa1d01e7df..a799af572f3f 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -1006,26 +1006,14 @@ void kvm_x86_state_cleanup(struct kvm_x86_state *state) free(state); } -static bool cpu_vendor_string_is(const char *vendor) -{
- const uint32_t *chunk = (const uint32_t *)vendor;
- uint32_t eax, ebx, ecx, edx;
- cpuid(0, &eax, &ebx, &ecx, &edx);
- return (ebx == chunk[0] && edx == chunk[1] && ecx == chunk[2]);
-}
bool is_intel_cpu(void)
Drop the is_intel_cpu() and is_amd_cpu() wrappers. The whole point of the rename was so that it's obvious at the call site that the function is checking the "current" CPU context.
That obviously means dropping the is_host_cpu_amd() and is_host_cpu_intel() wrappers too. IMO, the extra layer to jump through (more from a code reading perspective then a code generation perspective) isn't worth protecting the booleans.
It's slightly more churn (in between patches, not overall), but the benefit is that it allows squasing patches 2 and 3 into a single patch, e.g. "KVM: selftests: Cache host CPU vendor (AMD vs. Intel)"
--- tools/testing/selftests/kvm/include/x86_64/processor.h | 3 +++ tools/testing/selftests/kvm/lib/x86_64/processor.c | 8 ++++---- tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c | 4 ++-- tools/testing/selftests/kvm/x86_64/mmio_warning_test.c | 2 +- .../testing/selftests/kvm/x86_64/pmu_event_filter_test.c | 4 ++-- .../kvm/x86_64/vmx_exception_with_invalid_guest_state.c | 2 +- 6 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index fdb1af5ca611..c7885f72132a 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -19,6 +19,9 @@
#include "../kvm_util.h"
+extern bool host_cpu_is_intel; +extern bool host_cpu_is_amd; + #define NMI_VECTOR 0x02
#define X86_EFLAGS_FIXED (1u << 1) diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 0b8de34aa10e..84915bc7d689 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -19,8 +19,8 @@ #define MAX_NR_CPUID_ENTRIES 100
vm_vaddr_t exception_handlers; -static bool host_cpu_is_amd; -static bool host_cpu_is_intel; +bool host_cpu_is_amd; +bool host_cpu_is_intel;
static void regs_dump(FILE *stream, struct kvm_regs *regs, uint8_t indent) { @@ -115,7 +115,7 @@ static void sregs_dump(FILE *stream, struct kvm_sregs *sregs, uint8_t indent)
bool kvm_is_tdp_enabled(void) { - if (this_cpu_is_intel()) + if (host_cpu_is_intel) return get_kvm_intel_param_bool("ept"); else return get_kvm_amd_param_bool("npt"); @@ -1218,7 +1218,7 @@ unsigned long vm_compute_max_gfn(struct kvm_vm *vm) max_gfn = (1ULL << (vm->pa_bits - vm->page_shift)) - 1;
/* Avoid reserved HyperTransport region on AMD processors. */ - if (!this_cpu_is_amd()) + if (!host_cpu_is_amd) return max_gfn;
/* On parts with <40 physical address bits, the area is fully hidden */ diff --git a/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c b/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c index 5489c9836ec8..0f728f05ea82 100644 --- a/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c +++ b/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c @@ -48,10 +48,10 @@ static void guest_main(void) const uint8_t *other_hypercall_insn; uint64_t ret;
- if (this_cpu_is_intel()) { + if (host_cpu_is_intel) { native_hypercall_insn = vmx_vmcall; other_hypercall_insn = svm_vmmcall; - } else if (this_cpu_is_amd()) { + } else if (host_cpu_is_amd) { native_hypercall_insn = svm_vmmcall; other_hypercall_insn = vmx_vmcall; } else { diff --git a/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c b/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c index b0a2a0bae0f3..ce1ccc4c1503 100644 --- a/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c +++ b/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c @@ -93,7 +93,7 @@ int main(void) { int warnings_before, warnings_after;
- TEST_REQUIRE(this_cpu_is_intel()); + TEST_REQUIRE(host_cpu_is_intel);
TEST_REQUIRE(!vm_is_unrestricted_guest(NULL));
diff --git a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c index c728822461b2..4dbb454e1760 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c @@ -363,7 +363,7 @@ static void test_pmu_config_disable(void (*guest_code)(void)) */ static bool use_intel_pmu(void) { - return this_cpu_is_intel() && + return host_cpu_is_intel && kvm_cpu_property(X86_PROPERTY_PMU_VERSION) && kvm_cpu_property(X86_PROPERTY_PMU_NR_GP_COUNTERS) && kvm_pmu_has(X86_PMU_FEATURE_BRANCH_INSNS_RETIRED); @@ -397,7 +397,7 @@ static bool use_amd_pmu(void) uint32_t family = kvm_cpu_family(); uint32_t model = kvm_cpu_model();
- return this_cpu_is_amd() && + return host_cpu_is_amd && (is_zen1(family, model) || is_zen2(family, model) || is_zen3(family, model)); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c b/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c index 53e1ef2fc774..ccdfa5dc1a4d 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c @@ -111,7 +111,7 @@ int main(int argc, char *argv[]) struct kvm_vcpu *vcpu; struct kvm_vm *vm;
- TEST_REQUIRE(this_cpu_is_intel()); + TEST_REQUIRE(host_cpu_is_intel); TEST_REQUIRE(!vm_is_unrestricted_guest(NULL));
vm = vm_create_with_one_vcpu(&vcpu, guest_code);
base-commit: 04b420511919f7b78f17f5fa6dc92975a8b2d7c4
On Mon, Jan 9, 2023 at 10:07 AM Sean Christopherson seanjc@google.com wrote:
On Wed, Dec 28, 2022, Vishal Annapurve wrote:
Use this_cpu_* helpers to query the cpu vendor.
Neither the changelog nor the shortlog captures what this patch actually does, or rather what I inteded it to do. Specifically, what I suggested (or intended to suggest) was:
KVM: selftests: Rename vendor string helpers to use "this_cpu" prefix
Suggested-by: Sean Christopherson seanjc@google.com Signed-off-by: Vishal Annapurve vannapurve@google.com
...
diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index acfa1d01e7df..a799af572f3f 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -1006,26 +1006,14 @@ void kvm_x86_state_cleanup(struct kvm_x86_state *state) free(state); }
-static bool cpu_vendor_string_is(const char *vendor) -{
const uint32_t *chunk = (const uint32_t *)vendor;
uint32_t eax, ebx, ecx, edx;
cpuid(0, &eax, &ebx, &ecx, &edx);
return (ebx == chunk[0] && edx == chunk[1] && ecx == chunk[2]);
-}
bool is_intel_cpu(void)
Drop the is_intel_cpu() and is_amd_cpu() wrappers. The whole point of the rename was so that it's obvious at the call site that the function is checking the "current" CPU context.
That obviously means dropping the is_host_cpu_amd() and is_host_cpu_intel() wrappers too. IMO, the extra layer to jump through (more from a code reading perspective then a code generation perspective) isn't worth protecting the booleans.
It's slightly more churn (in between patches, not overall), but the benefit is that it allows squasing patches 2 and 3 into a single patch, e.g. "KVM: selftests: Cache host CPU vendor (AMD vs. Intel)"
tools/testing/selftests/kvm/include/x86_64/processor.h | 3 +++ tools/testing/selftests/kvm/lib/x86_64/processor.c | 8 ++++---- tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c | 4 ++-- tools/testing/selftests/kvm/x86_64/mmio_warning_test.c | 2 +- .../testing/selftests/kvm/x86_64/pmu_event_filter_test.c | 4 ++-- .../kvm/x86_64/vmx_exception_with_invalid_guest_state.c | 2 +- 6 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index fdb1af5ca611..c7885f72132a 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -19,6 +19,9 @@
#include "../kvm_util.h"
+extern bool host_cpu_is_intel; +extern bool host_cpu_is_amd;
#define NMI_VECTOR 0x02
#define X86_EFLAGS_FIXED (1u << 1) diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 0b8de34aa10e..84915bc7d689 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -19,8 +19,8 @@ #define MAX_NR_CPUID_ENTRIES 100
vm_vaddr_t exception_handlers; -static bool host_cpu_is_amd; -static bool host_cpu_is_intel; +bool host_cpu_is_amd; +bool host_cpu_is_intel;
static void regs_dump(FILE *stream, struct kvm_regs *regs, uint8_t indent) { @@ -115,7 +115,7 @@ static void sregs_dump(FILE *stream, struct kvm_sregs *sregs, uint8_t indent)
bool kvm_is_tdp_enabled(void) {
if (this_cpu_is_intel())
if (host_cpu_is_intel) return get_kvm_intel_param_bool("ept"); else return get_kvm_amd_param_bool("npt");
@@ -1218,7 +1218,7 @@ unsigned long vm_compute_max_gfn(struct kvm_vm *vm) max_gfn = (1ULL << (vm->pa_bits - vm->page_shift)) - 1;
/* Avoid reserved HyperTransport region on AMD processors. */
if (!this_cpu_is_amd())
if (!host_cpu_is_amd) return max_gfn; /* On parts with <40 physical address bits, the area is fully hidden */
diff --git a/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c b/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c index 5489c9836ec8..0f728f05ea82 100644 --- a/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c +++ b/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c @@ -48,10 +48,10 @@ static void guest_main(void) const uint8_t *other_hypercall_insn; uint64_t ret;
if (this_cpu_is_intel()) {
if (host_cpu_is_intel) { native_hypercall_insn = vmx_vmcall; other_hypercall_insn = svm_vmmcall;
} else if (this_cpu_is_amd()) {
} else if (host_cpu_is_amd) { native_hypercall_insn = svm_vmmcall; other_hypercall_insn = vmx_vmcall; } else {
diff --git a/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c b/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c index b0a2a0bae0f3..ce1ccc4c1503 100644 --- a/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c +++ b/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c @@ -93,7 +93,7 @@ int main(void) { int warnings_before, warnings_after;
TEST_REQUIRE(this_cpu_is_intel());
TEST_REQUIRE(host_cpu_is_intel); TEST_REQUIRE(!vm_is_unrestricted_guest(NULL));
diff --git a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c index c728822461b2..4dbb454e1760 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c @@ -363,7 +363,7 @@ static void test_pmu_config_disable(void (*guest_code)(void)) */ static bool use_intel_pmu(void) {
return this_cpu_is_intel() &&
return host_cpu_is_intel && kvm_cpu_property(X86_PROPERTY_PMU_VERSION) && kvm_cpu_property(X86_PROPERTY_PMU_NR_GP_COUNTERS) && kvm_pmu_has(X86_PMU_FEATURE_BRANCH_INSNS_RETIRED);
@@ -397,7 +397,7 @@ static bool use_amd_pmu(void) uint32_t family = kvm_cpu_family(); uint32_t model = kvm_cpu_model();
return this_cpu_is_amd() &&
return host_cpu_is_amd && (is_zen1(family, model) || is_zen2(family, model) || is_zen3(family, model));
diff --git a/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c b/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c index 53e1ef2fc774..ccdfa5dc1a4d 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c @@ -111,7 +111,7 @@ int main(int argc, char *argv[]) struct kvm_vcpu *vcpu; struct kvm_vm *vm;
TEST_REQUIRE(this_cpu_is_intel());
TEST_REQUIRE(host_cpu_is_intel); TEST_REQUIRE(!vm_is_unrestricted_guest(NULL)); vm = vm_create_with_one_vcpu(&vcpu, guest_code);
base-commit: 04b420511919f7b78f17f5fa6dc92975a8b2d7c4
Ack, that makes sense. Will include this suggestion in the next version.
Add variables to hold the cpu vendor type that are initialized early during the selftest setup and later synced to guest vm post VM creation.
These variables will be used in later patches to avoid querying CPU type multiple times.
Suggested-by: Sean Christopherson seanjc@google.com Signed-off-by: Vishal Annapurve vannapurve@google.com --- tools/testing/selftests/kvm/lib/x86_64/processor.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index a799af572f3f..b3d2a9ab5ced 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -19,6 +19,8 @@ #define MAX_NR_CPUID_ENTRIES 100
vm_vaddr_t exception_handlers; +static bool host_cpu_is_amd; +static bool host_cpu_is_intel;
static void regs_dump(FILE *stream, struct kvm_regs *regs, uint8_t indent) { @@ -555,6 +557,8 @@ static void vcpu_setup(struct kvm_vm *vm, struct kvm_vcpu *vcpu) void kvm_arch_vm_post_create(struct kvm_vm *vm) { vm_create_irqchip(vm); + sync_global_to_guest(vm, host_cpu_is_intel); + sync_global_to_guest(vm, host_cpu_is_amd); }
struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, @@ -1264,3 +1268,9 @@ bool vm_is_unrestricted_guest(struct kvm_vm *vm)
return get_kvm_intel_param_bool("unrestricted_guest"); } + +void kvm_selftest_arch_init(void) +{ + host_cpu_is_intel = this_cpu_is_intel(); + host_cpu_is_amd = this_cpu_is_amd(); +}
In shortlogs and changelogs, try to provide a synopsis of the change, not a literal description of the change. As suggested in the previous patch, this:
KVM: selftests: Cache host CPU vendor (AMD vs. Intel)
is more precise (vendor instead of "cpu type") and hints at the intent (caching the information), whereas this doesn't capture the vendor part, nor does it provide any hint whatsoever as to (a) how the variables will be used or (b) why we want to add variables to store
KVM: selftests: x86: Add variables to store cpu type
On Wed, Dec 28, 2022, Vishal Annapurve wrote:
Add variables to hold the cpu vendor type that are initialized early during the selftest setup and later synced to guest vm post VM creation.
These variables will be used in later patches to avoid querying CPU type multiple times.
Performance is a happy bonus, it is not the main reason for caching. The main reason for caching is so that the guest can select the native hypercall instruction without having to make assumptions about guest vs. host CPUID information.
On Mon, Jan 9, 2023 at 10:13 AM Sean Christopherson seanjc@google.com wrote:
In shortlogs and changelogs, try to provide a synopsis of the change, not a literal description of the change. As suggested in the previous patch, this:
KVM: selftests: Cache host CPU vendor (AMD vs. Intel)
is more precise (vendor instead of "cpu type") and hints at the intent (caching the information), whereas this doesn't capture the vendor part, nor does it provide any hint whatsoever as to (a) how the variables will be used or (b) why we want to add variables to store
KVM: selftests: x86: Add variables to store cpu type
On Wed, Dec 28, 2022, Vishal Annapurve wrote:
Add variables to hold the cpu vendor type that are initialized early during the selftest setup and later synced to guest vm post VM creation.
These variables will be used in later patches to avoid querying CPU type multiple times.
Performance is a happy bonus, it is not the main reason for caching. The main reason for caching is so that the guest can select the native hypercall instruction without having to make assumptions about guest vs. host CPUID information.
Ack, that makes sense.
Replace APIs to query cpu type with APIs always checking the host cpu type. This way there are two set of APIs to query CPU type: 1) this_cpu_is_*() 2) is_host_*cpu() that can be invoked as per the usecase.
All the current callers of is_*cpu actually care about host cpu type so they are updated to invoke is_host*cpu.
Suggested-by: Sean Christopherson seanjc@google.com Signed-off-by: Vishal Annapurve vannapurve@google.com --- .../testing/selftests/kvm/include/x86_64/processor.h | 4 ++-- tools/testing/selftests/kvm/lib/x86_64/processor.c | 12 ++++++------ .../selftests/kvm/x86_64/fix_hypercall_test.c | 4 ++-- .../testing/selftests/kvm/x86_64/mmio_warning_test.c | 2 +- .../selftests/kvm/x86_64/pmu_event_filter_test.c | 4 ++-- .../x86_64/vmx_exception_with_invalid_guest_state.c | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 84edac133d8f..8f9e066c89d9 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -713,8 +713,8 @@ static inline void cpu_relax(void) "hlt\n" \ )
-bool is_intel_cpu(void); -bool is_amd_cpu(void); +bool is_host_cpu_intel(void); +bool is_host_cpu_amd(void);
struct kvm_x86_state *vcpu_save_state(struct kvm_vcpu *vcpu); void vcpu_load_state(struct kvm_vcpu *vcpu, struct kvm_x86_state *state); diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index b3d2a9ab5ced..18f0608743d1 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -115,7 +115,7 @@ static void sregs_dump(FILE *stream, struct kvm_sregs *sregs, uint8_t indent)
bool kvm_is_tdp_enabled(void) { - if (is_intel_cpu()) + if (is_host_cpu_intel()) return get_kvm_intel_param_bool("ept"); else return get_kvm_amd_param_bool("npt"); @@ -1010,14 +1010,14 @@ void kvm_x86_state_cleanup(struct kvm_x86_state *state) free(state); }
-bool is_intel_cpu(void) +bool is_host_cpu_intel(void) { - return this_cpu_is_intel(); + return host_cpu_is_intel; }
-bool is_amd_cpu(void) +bool is_host_cpu_amd(void) { - return this_cpu_is_amd(); + return host_cpu_is_amd; }
void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bits) @@ -1228,7 +1228,7 @@ unsigned long vm_compute_max_gfn(struct kvm_vm *vm) max_gfn = (1ULL << (vm->pa_bits - vm->page_shift)) - 1;
/* Avoid reserved HyperTransport region on AMD processors. */ - if (!is_amd_cpu()) + if (!is_host_cpu_amd()) return max_gfn;
/* On parts with <40 physical address bits, the area is fully hidden */ diff --git a/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c b/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c index 32f7e09ef67c..e84c0c5a73b1 100644 --- a/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c +++ b/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c @@ -48,10 +48,10 @@ static void guest_main(void) const uint8_t *other_hypercall_insn; uint64_t ret;
- if (is_intel_cpu()) { + if (is_host_cpu_intel()) { native_hypercall_insn = vmx_vmcall; other_hypercall_insn = svm_vmmcall; - } else if (is_amd_cpu()) { + } else if (is_host_cpu_amd()) { native_hypercall_insn = svm_vmmcall; other_hypercall_insn = vmx_vmcall; } else { diff --git a/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c b/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c index fb02581953a3..d2d5dcae98e7 100644 --- a/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c +++ b/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c @@ -93,7 +93,7 @@ int main(void) { int warnings_before, warnings_after;
- TEST_REQUIRE(is_intel_cpu()); + TEST_REQUIRE(is_host_cpu_intel());
TEST_REQUIRE(!vm_is_unrestricted_guest(NULL));
diff --git a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c index 2de98fce7edd..289226117513 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c @@ -363,7 +363,7 @@ static void test_pmu_config_disable(void (*guest_code)(void)) */ static bool use_intel_pmu(void) { - return is_intel_cpu() && + return is_host_cpu_intel() && kvm_cpu_property(X86_PROPERTY_PMU_VERSION) && kvm_cpu_property(X86_PROPERTY_PMU_NR_GP_COUNTERS) && kvm_pmu_has(X86_PMU_FEATURE_BRANCH_INSNS_RETIRED); @@ -397,7 +397,7 @@ static bool use_amd_pmu(void) uint32_t family = kvm_cpu_family(); uint32_t model = kvm_cpu_model();
- return is_amd_cpu() && + return is_host_cpu_amd() && (is_zen1(family, model) || is_zen2(family, model) || is_zen3(family, model)); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c b/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c index 2641b286b4ed..d74b0d22385a 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c @@ -111,7 +111,7 @@ int main(int argc, char *argv[]) struct kvm_vcpu *vcpu; struct kvm_vm *vm;
- TEST_REQUIRE(is_intel_cpu()); + TEST_REQUIRE(is_host_cpu_intel()); TEST_REQUIRE(!vm_is_unrestricted_guest(NULL));
vm = vm_create_with_one_vcpu(&vcpu, guest_code);
Invoke vmcall/vmmcall instructions from kvm_hypercall as per host CPU type. CVMs and current kvm_hyerpcall callers need to execute hypercall as per the cpu type to avoid KVM having to emulate the instruction anyways.
CVMs need to avoid KVM emulation as the guest code is not updatable from KVM. Guest code region can be marked un-mondifiable from KVM without CVMs as well, so in general it's safer to avoid KVM emulation for vmcall/vmmcall instructions.
Suggested-by: Sean Christopherson seanjc@google.com Signed-off-by: Vishal Annapurve vannapurve@google.com --- tools/testing/selftests/kvm/lib/x86_64/processor.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 18f0608743d1..cc0b9c17fa91 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -1154,9 +1154,15 @@ uint64_t kvm_hypercall(uint64_t nr, uint64_t a0, uint64_t a1, uint64_t a2, { uint64_t r;
- asm volatile("vmcall" + asm volatile("test %[use_vmmcall], %[use_vmmcall]\n\t" + "jnz 1f\n\t" + "vmcall\n\t" + "jmp 2f\n\t" + "1: vmmcall\n\t" + "2:" : "=a"(r) - : "a"(nr), "b"(a0), "c"(a1), "d"(a2), "S"(a3)); + : "a"(nr), "b"(a0), "c"(a1), "d"(a2), "S"(a3), + [use_vmmcall] "r" (is_host_cpu_amd())); return r; }
KVM: selftests: Use host's native hypercall instruction in kvm_hypercall()
On Wed, Dec 28, 2022, Vishal Annapurve wrote:
Invoke vmcall/vmmcall instructions from kvm_hypercall as per host CPU
() for functions, i.e. kvm_hypercall().
type.
s/type/vendor, "type" is too generic.
CVMs and current kvm_hyerpcall callers need to execute hypercall
CVM isn't a not ubiquitous acronym. I would avoid it entirely because "CVM" doesn't strictly imply memory encryption, e.g. KVM could still patch the guest in a pKVM-like implementation.
Use the host CPU's native hypercall instruction, i.e. VMCALL vs. VMMCALL, in kvm_hypercall(), as relying on KVM to patch in the native hypercall on a #UD for the "wrong" hypercall requires KVM_X86_QUIRK_FIX_HYPERCALL_INSN to be enabled and flat out doesn't work if guest memory is encrypted with a private key, e.g. for SEV VMs.
On Mon, Jan 9, 2023 at 10:21 AM Sean Christopherson seanjc@google.com wrote:
KVM: selftests: Use host's native hypercall instruction in kvm_hypercall()
On Wed, Dec 28, 2022, Vishal Annapurve wrote:
Invoke vmcall/vmmcall instructions from kvm_hypercall as per host CPU
() for functions, i.e. kvm_hypercall().
type.
s/type/vendor, "type" is too generic.
CVMs and current kvm_hyerpcall callers need to execute hypercall
CVM isn't a not ubiquitous acronym. I would avoid it entirely because "CVM" doesn't strictly imply memory encryption, e.g. KVM could still patch the guest in a pKVM-like implementation.
Use the host CPU's native hypercall instruction, i.e. VMCALL vs. VMMCALL, in kvm_hypercall(), as relying on KVM to patch in the native hypercall on a #UD for the "wrong" hypercall requires KVM_X86_QUIRK_FIX_HYPERCALL_INSN to be enabled and flat out doesn't work if guest memory is encrypted with a private key, e.g. for SEV VMs.
Ack, this makes sense.
On Wed, Dec 28, 2022 at 07:24:34PM +0000, Vishal Annapurve wrote:
Confidential VMs(CVMs) need to execute hypercall instruction as per the CPU type. Normally KVM emulates the vmcall/vmmcall instruction by patching the guest code at runtime. Such a guest memory manipulation by KVM is not allowed with CVMs and is also undesirable in general.
This series adds support of executing hypercall as per the host cpu type queried using cpuid instruction. CPU vendor type is stored early during selftest setup and guest setup to be reused later.
Changes in v4:
- Incoporated suggestions from Sean -
- Added APIs to query host cpu type
- Shared the host cpu type with guests to avoid querying the cpu type again
- Modified kvm_hypercall to execute vmcall/vmmcall according to host cpu type.
- Dropped the separate API for kvm_hypercall.
v3: https://lore.kernel.org/lkml/20221222230458.3828342-1-vannapurve@google.com/
Vishal Annapurve (4): KVM: selftests: x86: use this_cpu_* helpers KVM: selftests: x86: Add variables to store cpu type KVM: sefltests: x86: Replace is_*cpu with is_host_*cpu KVM: selftests: x86: Invoke kvm hypercall as per host cpu
For the series,
Reviewed-by: David Matlack dmatlack@google.com
linux-kselftest-mirror@lists.linaro.org