Commit 7dd32a0d authored by Dave Martin's avatar Dave Martin Committed by Marc Zyngier

KVM: arm/arm64: Add KVM_ARM_VCPU_FINALIZE ioctl

Some aspects of vcpu configuration may be too complex to be
completed inside KVM_ARM_VCPU_INIT.  Thus, there may be a
requirement for userspace to do some additional configuration
before various other ioctls will work in a consistent way.

In particular this will be the case for SVE, where userspace will
need to negotiate the set of vector lengths to be made available to
the guest before the vcpu becomes fully usable.

In order to provide an explicit way for userspace to confirm that
it has finished setting up a particular vcpu feature, this patch
adds a new ioctl KVM_ARM_VCPU_FINALIZE.

When userspace has opted into a feature that requires finalization,
typically by means of a feature flag passed to KVM_ARM_VCPU_INIT, a
matching call to KVM_ARM_VCPU_FINALIZE is now required before
KVM_RUN or KVM_GET_REG_LIST is allowed.  Individual features may
impose additional restrictions where appropriate.

No existing vcpu features are affected by this, so current
userspace implementations will continue to work exactly as before,
with no need to issue KVM_ARM_VCPU_FINALIZE.

As implemented in this patch, KVM_ARM_VCPU_FINALIZE is currently a
placeholder: no finalizable features exist yet, so ioctl is not
required and will always yield EINVAL.  Subsequent patches will add
the finalization logic to make use of this ioctl for SVE.

No functional change for existing userspace.
Signed-off-by: default avatarDave Martin <Dave.Martin@arm.com>
Reviewed-by: default avatarJulien Thierry <julien.thierry@arm.com>
Tested-by: default avatarzhang.lei <zhang.lei@jp.fujitsu.com>
Signed-off-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
parent 0f062bfe
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#ifndef __ARM_KVM_HOST_H__ #ifndef __ARM_KVM_HOST_H__
#define __ARM_KVM_HOST_H__ #define __ARM_KVM_HOST_H__
#include <linux/errno.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/kvm_types.h> #include <linux/kvm_types.h>
#include <asm/cputype.h> #include <asm/cputype.h>
...@@ -411,4 +412,7 @@ static inline int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type) ...@@ -411,4 +412,7 @@ static inline int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type)
return 0; return 0;
} }
#define kvm_arm_vcpu_finalize(vcpu, what) (-EINVAL)
#define kvm_arm_vcpu_is_finalized(vcpu) true
#endif /* __ARM_KVM_HOST_H__ */ #endif /* __ARM_KVM_HOST_H__ */
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#define __ARM64_KVM_HOST_H__ #define __ARM64_KVM_HOST_H__
#include <linux/bitmap.h> #include <linux/bitmap.h>
#include <linux/errno.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/jump_label.h> #include <linux/jump_label.h>
#include <linux/kvm_types.h> #include <linux/kvm_types.h>
...@@ -625,4 +626,7 @@ void kvm_arch_free_vm(struct kvm *kvm); ...@@ -625,4 +626,7 @@ void kvm_arch_free_vm(struct kvm *kvm);
int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type); int kvm_arm_setup_stage2(struct kvm *kvm, unsigned long type);
#define kvm_arm_vcpu_finalize(vcpu, what) (-EINVAL)
#define kvm_arm_vcpu_is_finalized(vcpu) true
#endif /* __ARM64_KVM_HOST_H__ */ #endif /* __ARM64_KVM_HOST_H__ */
...@@ -1441,6 +1441,9 @@ struct kvm_enc_region { ...@@ -1441,6 +1441,9 @@ struct kvm_enc_region {
/* Available with KVM_CAP_HYPERV_CPUID */ /* Available with KVM_CAP_HYPERV_CPUID */
#define KVM_GET_SUPPORTED_HV_CPUID _IOWR(KVMIO, 0xc1, struct kvm_cpuid2) #define KVM_GET_SUPPORTED_HV_CPUID _IOWR(KVMIO, 0xc1, struct kvm_cpuid2)
/* Available with KVM_CAP_ARM_SVE */
#define KVM_ARM_VCPU_FINALIZE _IOW(KVMIO, 0xc2, int)
/* Secure Encrypted Virtualization command */ /* Secure Encrypted Virtualization command */
enum sev_cmd_id { enum sev_cmd_id {
/* Guest initialization commands */ /* Guest initialization commands */
......
...@@ -545,6 +545,9 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu) ...@@ -545,6 +545,9 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
if (likely(vcpu->arch.has_run_once)) if (likely(vcpu->arch.has_run_once))
return 0; return 0;
if (!kvm_arm_vcpu_is_finalized(vcpu))
return -EPERM;
vcpu->arch.has_run_once = true; vcpu->arch.has_run_once = true;
if (likely(irqchip_in_kernel(kvm))) { if (likely(irqchip_in_kernel(kvm))) {
...@@ -1116,6 +1119,10 @@ long kvm_arch_vcpu_ioctl(struct file *filp, ...@@ -1116,6 +1119,10 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
if (unlikely(!kvm_vcpu_initialized(vcpu))) if (unlikely(!kvm_vcpu_initialized(vcpu)))
break; break;
r = -EPERM;
if (!kvm_arm_vcpu_is_finalized(vcpu))
break;
r = -EFAULT; r = -EFAULT;
if (copy_from_user(&reg_list, user_list, sizeof(reg_list))) if (copy_from_user(&reg_list, user_list, sizeof(reg_list)))
break; break;
...@@ -1169,6 +1176,17 @@ long kvm_arch_vcpu_ioctl(struct file *filp, ...@@ -1169,6 +1176,17 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
return kvm_arm_vcpu_set_events(vcpu, &events); return kvm_arm_vcpu_set_events(vcpu, &events);
} }
case KVM_ARM_VCPU_FINALIZE: {
int what;
if (!kvm_vcpu_initialized(vcpu))
return -ENOEXEC;
if (get_user(what, (const int __user *)argp))
return -EFAULT;
return kvm_arm_vcpu_finalize(vcpu, what);
}
default: default:
r = -EINVAL; r = -EINVAL;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment