162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef ARCH_X86_KVM_CPUID_H
362306a36Sopenharmony_ci#define ARCH_X86_KVM_CPUID_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include "x86.h"
662306a36Sopenharmony_ci#include "reverse_cpuid.h"
762306a36Sopenharmony_ci#include <asm/cpu.h>
862306a36Sopenharmony_ci#include <asm/processor.h>
962306a36Sopenharmony_ci#include <uapi/asm/kvm_para.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ciextern u32 kvm_cpu_caps[NR_KVM_CPU_CAPS] __read_mostly;
1262306a36Sopenharmony_civoid kvm_set_cpu_caps(void);
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_civoid kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu);
1562306a36Sopenharmony_civoid kvm_update_pv_runtime(struct kvm_vcpu *vcpu);
1662306a36Sopenharmony_cistruct kvm_cpuid_entry2 *kvm_find_cpuid_entry_index(struct kvm_vcpu *vcpu,
1762306a36Sopenharmony_ci						    u32 function, u32 index);
1862306a36Sopenharmony_cistruct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu,
1962306a36Sopenharmony_ci					      u32 function);
2062306a36Sopenharmony_ciint kvm_dev_ioctl_get_cpuid(struct kvm_cpuid2 *cpuid,
2162306a36Sopenharmony_ci			    struct kvm_cpuid_entry2 __user *entries,
2262306a36Sopenharmony_ci			    unsigned int type);
2362306a36Sopenharmony_ciint kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
2462306a36Sopenharmony_ci			     struct kvm_cpuid *cpuid,
2562306a36Sopenharmony_ci			     struct kvm_cpuid_entry __user *entries);
2662306a36Sopenharmony_ciint kvm_vcpu_ioctl_set_cpuid2(struct kvm_vcpu *vcpu,
2762306a36Sopenharmony_ci			      struct kvm_cpuid2 *cpuid,
2862306a36Sopenharmony_ci			      struct kvm_cpuid_entry2 __user *entries);
2962306a36Sopenharmony_ciint kvm_vcpu_ioctl_get_cpuid2(struct kvm_vcpu *vcpu,
3062306a36Sopenharmony_ci			      struct kvm_cpuid2 *cpuid,
3162306a36Sopenharmony_ci			      struct kvm_cpuid_entry2 __user *entries);
3262306a36Sopenharmony_cibool kvm_cpuid(struct kvm_vcpu *vcpu, u32 *eax, u32 *ebx,
3362306a36Sopenharmony_ci	       u32 *ecx, u32 *edx, bool exact_only);
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ciu32 xstate_required_size(u64 xstate_bv, bool compacted);
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ciint cpuid_query_maxphyaddr(struct kvm_vcpu *vcpu);
3862306a36Sopenharmony_ciu64 kvm_vcpu_reserved_gpa_bits_raw(struct kvm_vcpu *vcpu);
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic inline int cpuid_maxphyaddr(struct kvm_vcpu *vcpu)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	return vcpu->arch.maxphyaddr;
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic inline bool kvm_vcpu_is_legal_gpa(struct kvm_vcpu *vcpu, gpa_t gpa)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	return !(gpa & vcpu->arch.reserved_gpa_bits);
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic inline bool kvm_vcpu_is_illegal_gpa(struct kvm_vcpu *vcpu, gpa_t gpa)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	return !kvm_vcpu_is_legal_gpa(vcpu, gpa);
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic inline bool kvm_vcpu_is_legal_aligned_gpa(struct kvm_vcpu *vcpu,
5662306a36Sopenharmony_ci						 gpa_t gpa, gpa_t alignment)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	return IS_ALIGNED(gpa, alignment) && kvm_vcpu_is_legal_gpa(vcpu, gpa);
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic inline bool page_address_valid(struct kvm_vcpu *vcpu, gpa_t gpa)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	return kvm_vcpu_is_legal_aligned_gpa(vcpu, gpa, PAGE_SIZE);
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic __always_inline void cpuid_entry_override(struct kvm_cpuid_entry2 *entry,
6762306a36Sopenharmony_ci						 unsigned int leaf)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	u32 *reg = cpuid_entry_get_reg(entry, leaf * 32);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	BUILD_BUG_ON(leaf >= ARRAY_SIZE(kvm_cpu_caps));
7262306a36Sopenharmony_ci	*reg = kvm_cpu_caps[leaf];
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic __always_inline u32 *guest_cpuid_get_register(struct kvm_vcpu *vcpu,
7662306a36Sopenharmony_ci						     unsigned int x86_feature)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	const struct cpuid_reg cpuid = x86_feature_cpuid(x86_feature);
7962306a36Sopenharmony_ci	struct kvm_cpuid_entry2 *entry;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	entry = kvm_find_cpuid_entry_index(vcpu, cpuid.function, cpuid.index);
8262306a36Sopenharmony_ci	if (!entry)
8362306a36Sopenharmony_ci		return NULL;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	return __cpuid_entry_get_reg(entry, cpuid.reg);
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic __always_inline bool guest_cpuid_has(struct kvm_vcpu *vcpu,
8962306a36Sopenharmony_ci					    unsigned int x86_feature)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	u32 *reg;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	reg = guest_cpuid_get_register(vcpu, x86_feature);
9462306a36Sopenharmony_ci	if (!reg)
9562306a36Sopenharmony_ci		return false;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	return *reg & __feature_bit(x86_feature);
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic __always_inline void guest_cpuid_clear(struct kvm_vcpu *vcpu,
10162306a36Sopenharmony_ci					      unsigned int x86_feature)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	u32 *reg;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	reg = guest_cpuid_get_register(vcpu, x86_feature);
10662306a36Sopenharmony_ci	if (reg)
10762306a36Sopenharmony_ci		*reg &= ~__feature_bit(x86_feature);
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic inline bool guest_cpuid_is_amd_or_hygon(struct kvm_vcpu *vcpu)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	struct kvm_cpuid_entry2 *best;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	best = kvm_find_cpuid_entry(vcpu, 0);
11562306a36Sopenharmony_ci	return best &&
11662306a36Sopenharmony_ci	       (is_guest_vendor_amd(best->ebx, best->ecx, best->edx) ||
11762306a36Sopenharmony_ci		is_guest_vendor_hygon(best->ebx, best->ecx, best->edx));
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic inline bool guest_cpuid_is_intel(struct kvm_vcpu *vcpu)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	struct kvm_cpuid_entry2 *best;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	best = kvm_find_cpuid_entry(vcpu, 0);
12562306a36Sopenharmony_ci	return best && is_guest_vendor_intel(best->ebx, best->ecx, best->edx);
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic inline int guest_cpuid_family(struct kvm_vcpu *vcpu)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	struct kvm_cpuid_entry2 *best;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	best = kvm_find_cpuid_entry(vcpu, 0x1);
13362306a36Sopenharmony_ci	if (!best)
13462306a36Sopenharmony_ci		return -1;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	return x86_family(best->eax);
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic inline int guest_cpuid_model(struct kvm_vcpu *vcpu)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	struct kvm_cpuid_entry2 *best;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	best = kvm_find_cpuid_entry(vcpu, 0x1);
14462306a36Sopenharmony_ci	if (!best)
14562306a36Sopenharmony_ci		return -1;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	return x86_model(best->eax);
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic inline bool cpuid_model_is_consistent(struct kvm_vcpu *vcpu)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	return boot_cpu_data.x86_model == guest_cpuid_model(vcpu);
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic inline int guest_cpuid_stepping(struct kvm_vcpu *vcpu)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	struct kvm_cpuid_entry2 *best;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	best = kvm_find_cpuid_entry(vcpu, 0x1);
16062306a36Sopenharmony_ci	if (!best)
16162306a36Sopenharmony_ci		return -1;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	return x86_stepping(best->eax);
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistatic inline bool guest_has_spec_ctrl_msr(struct kvm_vcpu *vcpu)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	return (guest_cpuid_has(vcpu, X86_FEATURE_SPEC_CTRL) ||
16962306a36Sopenharmony_ci		guest_cpuid_has(vcpu, X86_FEATURE_AMD_STIBP) ||
17062306a36Sopenharmony_ci		guest_cpuid_has(vcpu, X86_FEATURE_AMD_IBRS) ||
17162306a36Sopenharmony_ci		guest_cpuid_has(vcpu, X86_FEATURE_AMD_SSBD));
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistatic inline bool guest_has_pred_cmd_msr(struct kvm_vcpu *vcpu)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	return (guest_cpuid_has(vcpu, X86_FEATURE_SPEC_CTRL) ||
17762306a36Sopenharmony_ci		guest_cpuid_has(vcpu, X86_FEATURE_AMD_IBPB));
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic inline bool supports_cpuid_fault(struct kvm_vcpu *vcpu)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	return vcpu->arch.msr_platform_info & MSR_PLATFORM_INFO_CPUID_FAULT;
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic inline bool cpuid_fault_enabled(struct kvm_vcpu *vcpu)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	return vcpu->arch.msr_misc_features_enables &
18862306a36Sopenharmony_ci		  MSR_MISC_FEATURES_ENABLES_CPUID_FAULT;
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic __always_inline void kvm_cpu_cap_clear(unsigned int x86_feature)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	unsigned int x86_leaf = __feature_leaf(x86_feature);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	reverse_cpuid_check(x86_leaf);
19662306a36Sopenharmony_ci	kvm_cpu_caps[x86_leaf] &= ~__feature_bit(x86_feature);
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic __always_inline void kvm_cpu_cap_set(unsigned int x86_feature)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	unsigned int x86_leaf = __feature_leaf(x86_feature);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	reverse_cpuid_check(x86_leaf);
20462306a36Sopenharmony_ci	kvm_cpu_caps[x86_leaf] |= __feature_bit(x86_feature);
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic __always_inline u32 kvm_cpu_cap_get(unsigned int x86_feature)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	unsigned int x86_leaf = __feature_leaf(x86_feature);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	reverse_cpuid_check(x86_leaf);
21262306a36Sopenharmony_ci	return kvm_cpu_caps[x86_leaf] & __feature_bit(x86_feature);
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic __always_inline bool kvm_cpu_cap_has(unsigned int x86_feature)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	return !!kvm_cpu_cap_get(x86_feature);
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic __always_inline void kvm_cpu_cap_check_and_set(unsigned int x86_feature)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	if (boot_cpu_has(x86_feature))
22362306a36Sopenharmony_ci		kvm_cpu_cap_set(x86_feature);
22462306a36Sopenharmony_ci}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistatic __always_inline bool guest_pv_has(struct kvm_vcpu *vcpu,
22762306a36Sopenharmony_ci					 unsigned int kvm_feature)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	if (!vcpu->arch.pv_cpuid.enforce)
23062306a36Sopenharmony_ci		return true;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	return vcpu->arch.pv_cpuid.features & (1u << kvm_feature);
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cienum kvm_governed_features {
23662306a36Sopenharmony_ci#define KVM_GOVERNED_FEATURE(x) KVM_GOVERNED_##x,
23762306a36Sopenharmony_ci#include "governed_features.h"
23862306a36Sopenharmony_ci	KVM_NR_GOVERNED_FEATURES
23962306a36Sopenharmony_ci};
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic __always_inline int kvm_governed_feature_index(unsigned int x86_feature)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	switch (x86_feature) {
24462306a36Sopenharmony_ci#define KVM_GOVERNED_FEATURE(x) case x: return KVM_GOVERNED_##x;
24562306a36Sopenharmony_ci#include "governed_features.h"
24662306a36Sopenharmony_ci	default:
24762306a36Sopenharmony_ci		return -1;
24862306a36Sopenharmony_ci	}
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic __always_inline bool kvm_is_governed_feature(unsigned int x86_feature)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	return kvm_governed_feature_index(x86_feature) >= 0;
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic __always_inline void kvm_governed_feature_set(struct kvm_vcpu *vcpu,
25762306a36Sopenharmony_ci						     unsigned int x86_feature)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci	BUILD_BUG_ON(!kvm_is_governed_feature(x86_feature));
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	__set_bit(kvm_governed_feature_index(x86_feature),
26262306a36Sopenharmony_ci		  vcpu->arch.governed_features.enabled);
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistatic __always_inline void kvm_governed_feature_check_and_set(struct kvm_vcpu *vcpu,
26662306a36Sopenharmony_ci							       unsigned int x86_feature)
26762306a36Sopenharmony_ci{
26862306a36Sopenharmony_ci	if (kvm_cpu_cap_has(x86_feature) && guest_cpuid_has(vcpu, x86_feature))
26962306a36Sopenharmony_ci		kvm_governed_feature_set(vcpu, x86_feature);
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic __always_inline bool guest_can_use(struct kvm_vcpu *vcpu,
27362306a36Sopenharmony_ci					  unsigned int x86_feature)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	BUILD_BUG_ON(!kvm_is_governed_feature(x86_feature));
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	return test_bit(kvm_governed_feature_index(x86_feature),
27862306a36Sopenharmony_ci			vcpu->arch.governed_features.enabled);
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci#endif
282