KVM arm64 has different types of VMs with all the different modes in which the hypervisor code can be run. e.g., VHE, nVHE, PKVM etc. Then there is protected VM and normal VMs with PKVM. We might soon add other types, e.g., Arm CCA Realm. So in an effort to make the handling of these different types of VMs a bit more friendly to the eyes, add a VM flavor to the kvm_arch and we could then add handlers for different operations based on the VM type. Keep the flavor initialisation at the beginning to allow for the detection early enough and fail out on any unsupported requests. (e.g., protected on !pKVM) With that, use the vm_flavor to detect if a VM is protected VM on PKVM. A later patch would generalize the "protected" VM predicate to cater for all confidential compute VMs. Based on a patch by Marc Zyngier Suggested-by: Marc Zyngier Reviewed-by: Fuad Tabba Signed-off-by: Suzuki K Poulose --- Changes since v17: * s/PKVM/pKVM for the comments * Drop type argument for pkvm_init_host_vm and also drop protected variable. * Add helpers for checking if the VM is running on pKVM (kvm_vm_hyp_is_pkvm()) * Use kvm_vm_hyp_is_pkvm() to replace is_protected_kvm_enabled() with valid kvm instance --- arch/arm64/include/asm/kvm_host.h | 14 +++++++++++-- arch/arm64/include/asm/kvm_pkvm.h | 2 +- arch/arm64/kvm/arm.c | 35 ++++++++++++++++++++++++------- arch/arm64/kvm/hyp/nvhe/pkvm.c | 2 +- arch/arm64/kvm/pkvm.c | 6 ++---- 5 files changed, 44 insertions(+), 15 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 286489a69dff5..39d04ff702bc1 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -257,7 +257,6 @@ struct kvm_protected_vm { pkvm_handle_t handle; struct kvm_hyp_memcache teardown_mc; struct kvm_hyp_memcache stage2_teardown_mc; - bool is_protected; bool is_created; /* @@ -306,9 +305,18 @@ enum fgt_group_id { __NR_FGT_GROUP_IDS__ }; +enum kvm_arm_vm_flavor { + VM_NVHE, + VM_VHE, + VM_PKVM, /* Normal guests on pKVM */ + VM_PROTECTED_PKVM, /* Protected VM */ + VM_FLAVOR_MAX, +}; + struct kvm_arch { struct kvm_s2_mmu mmu; + enum kvm_arm_vm_flavor vm_flavor; /* * Fine-Grained UNDEF, mimicking the FGT layout defined by the * architecture. We track them globally, as we present the @@ -1504,8 +1512,10 @@ struct kvm *kvm_arch_alloc_vm(void); #define __KVM_HAVE_ARCH_FLUSH_REMOTE_TLBS_RANGE -#define kvm_vm_is_protected(kvm) (is_protected_kvm_enabled() && (kvm)->arch.pkvm.is_protected) +#define kvm_vm_is_protected(kvm) ((kvm)->arch.vm_flavor == VM_PROTECTED_PKVM) +#define kvm_vm_is_unprotected_pkvm(kvm) ((kvm)->arch.vm_flavor == VM_PKVM) +#define kvm_vm_hyp_is_pkvm(kvm) (is_protected_kvm_enabled()) #define vcpu_is_protected(vcpu) kvm_vm_is_protected((vcpu)->kvm) int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature); diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm_pkvm.h index 54a618d887fa4..a1f3e05e75dc1 100644 --- a/arch/arm64/include/asm/kvm_pkvm.h +++ b/arch/arm64/include/asm/kvm_pkvm.h @@ -17,7 +17,7 @@ #define HYP_MEMBLOCK_REGIONS 128 -int pkvm_init_host_vm(struct kvm *kvm, unsigned long type); +int pkvm_init_host_vm(struct kvm *kvm); int pkvm_create_hyp_vm(struct kvm *kvm); bool pkvm_hyp_vm_is_created(struct kvm *kvm); void pkvm_destroy_hyp_vm(struct kvm *kvm); diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 3fbdfce926475..4329c49fe49da 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -228,6 +228,26 @@ static void kvm_arch_fix_timer_offsets(struct kvm *kvm) set_bit(KVM_ARCH_FLAG_VM_COUNTER_OFFSET, &kvm->arch.flags); } +static int kvm_init_vm_flavor(struct kvm *kvm, unsigned long type) +{ + bool protected = type & KVM_VM_TYPE_ARM_PROTECTED; + + if (is_protected_kvm_enabled()) { + if (protected) + kvm->arch.vm_flavor = VM_PROTECTED_PKVM; + else + kvm->arch.vm_flavor = VM_PKVM; + } else if (protected) { + return -EINVAL; + } else if (has_vhe()) { + kvm->arch.vm_flavor = VM_VHE; + } else { + kvm->arch.vm_flavor = VM_NVHE; + } + + return 0; +} + /** * kvm_arch_init_vm - initializes a VM data structure * @kvm: pointer to the KVM struct @@ -250,6 +270,10 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) mutex_unlock(&kvm->lock); #endif + ret = kvm_init_vm_flavor(kvm, type); + if (ret) + return ret; + kvm_init_nested(kvm); ret = kvm_share_hyp(kvm, kvm + 1); @@ -266,17 +290,14 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) if (ret) goto err_free_cpumask; - if (is_protected_kvm_enabled()) { + if (kvm_vm_hyp_is_pkvm(kvm)) { /* * If any failures occur after this is successful, make sure to * call __pkvm_unreserve_vm to unreserve the VM in hyp. */ - ret = pkvm_init_host_vm(kvm, type); + ret = pkvm_init_host_vm(kvm); if (ret) goto err_uninit_mmu; - } else if (type & KVM_VM_TYPE_ARM_PROTECTED) { - ret = -EINVAL; - goto err_uninit_mmu; } kvm_vgic_early_init(kvm); @@ -341,7 +362,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm) kvm_vgic_destroy(kvm); - if (is_protected_kvm_enabled()) + if (kvm_vm_hyp_is_pkvm(kvm)) pkvm_destroy_hyp_vm(kvm); kvm_uninit_stage2_mmu(kvm); @@ -603,7 +624,7 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) { - if (!is_protected_kvm_enabled()) + if (!kvm_vm_hyp_is_pkvm(vcpu->kvm)) kvm_mmu_free_memory_cache(&vcpu->arch.mmu_page_cache); else free_hyp_memcache(&vcpu->arch.pkvm_memcache); diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c index e7b38eff63bd1..9b69228f8402c 100644 --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c @@ -432,7 +432,7 @@ static void init_pkvm_hyp_vm(struct kvm *host_kvm, struct pkvm_hyp_vm *hyp_vm, hyp_vm->host_kvm = host_kvm; hyp_vm->kvm.created_vcpus = nr_vcpus; - hyp_vm->kvm.arch.pkvm.is_protected = READ_ONCE(host_kvm->arch.pkvm.is_protected); + hyp_vm->kvm.arch.vm_flavor = READ_ONCE(host_kvm->arch.vm_flavor); hyp_vm->kvm.arch.flags = 0; pkvm_init_features_from_host(hyp_vm, host_kvm); diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c index 8e4c6e4bec123..8e9176a700926 100644 --- a/arch/arm64/kvm/pkvm.c +++ b/arch/arm64/kvm/pkvm.c @@ -229,10 +229,9 @@ void pkvm_destroy_hyp_vm(struct kvm *kvm) mutex_unlock(&kvm->arch.config_lock); } -int pkvm_init_host_vm(struct kvm *kvm, unsigned long type) +int pkvm_init_host_vm(struct kvm *kvm) { int ret; - bool protected = type & KVM_VM_TYPE_ARM_PROTECTED; /* Reserve the VM in hyp and obtain a hyp handle for the VM. */ ret = kvm_call_hyp_nvhe(__pkvm_reserve_vm); @@ -240,8 +239,7 @@ int pkvm_init_host_vm(struct kvm *kvm, unsigned long type) return ret; kvm->arch.pkvm.handle = ret; - kvm->arch.pkvm.is_protected = protected; - if (protected) { + if (kvm_vm_is_protected(kvm)) { pr_warn_once("kvm: protected VMs are experimental and for development only, tainting kernel\n"); add_taint(TAINT_USER, LOCKDEP_STILL_OK); } -- 2.43.0