This would be one variant to get the RC/RRC to userspace. Signed-off-by: Christian Borntraeger <borntraeger@xxxxxxxxxx> --- arch/s390/kvm/kvm-s390.c | 34 +++++++++++++++++++++++++--------- arch/s390/kvm/kvm-s390.h | 15 ++++++++------- arch/s390/kvm/pv.c | 30 ++++++++++++++++++++++-------- include/uapi/linux/kvm.h | 4 ++-- 4 files changed, 57 insertions(+), 26 deletions(-) diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index e1bccbb41fdd..8dae9629b47f 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -2172,6 +2172,8 @@ static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd) int r = 0; void __user *argp = (void __user *)cmd->data; + cmd->rc = 0; + cmd->rrc = 0; switch (cmd->cmd) { case KVM_PV_VM_CREATE: { r = -EINVAL; @@ -2192,7 +2194,7 @@ static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd) mutex_unlock(&kvm->lock); break; } - r = kvm_s390_pv_create_vm(kvm); + r = kvm_s390_pv_create_vm(kvm, cmd); kvm_s390_vcpu_unblock_all(kvm); mutex_unlock(&kvm->lock); break; @@ -2205,7 +2207,7 @@ static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd) /* All VCPUs have to be destroyed before this call. */ mutex_lock(&kvm->lock); kvm_s390_vcpu_block_all(kvm); - r = kvm_s390_pv_destroy_vm(kvm); + r = kvm_s390_pv_destroy_vm(kvm, cmd); if (!r) kvm_s390_pv_dealloc_vm(kvm); kvm_s390_vcpu_unblock_all(kvm); @@ -2237,7 +2239,7 @@ static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd) r = -EFAULT; if (!copy_from_user(hdr, (void __user *)parms.origin, parms.length)) - r = kvm_s390_pv_set_sec_parms(kvm, hdr, parms.length); + r = kvm_s390_pv_set_sec_parms(kvm, hdr, parms.length, cmd); vfree(hdr); break; @@ -2253,7 +2255,7 @@ static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd) if (copy_from_user(&unp, argp, sizeof(unp))) break; - r = kvm_s390_pv_unpack(kvm, unp.addr, unp.size, unp.tweak); + r = kvm_s390_pv_unpack(kvm, unp.addr, unp.size, unp.tweak, cmd); break; } case KVM_PV_VM_VERIFY: { @@ -2268,6 +2270,8 @@ static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd) &ret); VM_EVENT(kvm, 3, "PROTVIRT VERIFY: rc %x rrc %x", ret >> 16, ret & 0x0000ffff); + cmd->rc = ret >> 16; + cmd->rrc = ret & 0xffff; break; } default: @@ -2385,6 +2389,10 @@ long kvm_arch_vm_ioctl(struct file *filp, break; r = kvm_s390_handle_pv(kvm, &args); + + if (copy_to_user(argp, &args, sizeof(args))) + r = -EFAULT; + break; } default: @@ -2650,6 +2658,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) { + struct kvm_pv_cmd dummy; + VCPU_EVENT(vcpu, 3, "%s", "free cpu"); trace_kvm_s390_destroy_vcpu(vcpu->vcpu_id); kvm_s390_clear_local_irqs(vcpu); @@ -2663,7 +2673,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) if (vcpu->kvm->arch.use_cmma) kvm_s390_vcpu_unsetup_cmma(vcpu); if (kvm_s390_pv_handle_cpu(vcpu)) - kvm_s390_pv_destroy_cpu(vcpu); + kvm_s390_pv_destroy_cpu(vcpu, &dummy); free_page((unsigned long)(vcpu->arch.sie_block)); kvm_vcpu_uninit(vcpu); @@ -2688,11 +2698,13 @@ static void kvm_free_vcpus(struct kvm *kvm) void kvm_arch_destroy_vm(struct kvm *kvm) { + struct kvm_pv_cmd dummy; + kvm_free_vcpus(kvm); sca_dispose(kvm); kvm_s390_gisa_destroy(kvm); if (kvm_s390_pv_is_protected(kvm)) { - kvm_s390_pv_destroy_vm(kvm); + kvm_s390_pv_destroy_vm(kvm, &dummy); kvm_s390_pv_dealloc_vm(kvm); } debug_unregister(kvm->arch.dbf); @@ -3153,6 +3165,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, { struct kvm_vcpu *vcpu; struct sie_page *sie_page; + struct kvm_pv_cmd dummy; int rc = -EINVAL; if (!kvm_is_ucontrol(kvm) && !sca_can_add_vcpu(kvm, id)) @@ -3188,7 +3201,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, goto out_free_sie_block; if (kvm_s390_pv_is_protected(kvm)) { - rc = kvm_s390_pv_create_cpu(vcpu); + rc = kvm_s390_pv_create_cpu(vcpu, &dummy); if (rc) { kvm_vcpu_uninit(vcpu); goto out_free_sie_block; @@ -4511,19 +4524,22 @@ static int kvm_s390_handle_pv_vcpu(struct kvm_vcpu *vcpu, if (!kvm_s390_pv_is_protected(vcpu->kvm)) return -EINVAL; + cmd->rc = 0; + cmd->rrc = 0; + switch (cmd->cmd) { case KVM_PV_VCPU_CREATE: { if (kvm_s390_pv_handle_cpu(vcpu)) return -EINVAL; - r = kvm_s390_pv_create_cpu(vcpu); + r = kvm_s390_pv_create_cpu(vcpu, cmd); break; } case KVM_PV_VCPU_DESTROY: { if (!kvm_s390_pv_handle_cpu(vcpu)) return -EINVAL; - r = kvm_s390_pv_destroy_cpu(vcpu); + r = kvm_s390_pv_destroy_cpu(vcpu, cmd); break; } default: diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h index 32c0c01d5df0..b77d5f565b5c 100644 --- a/arch/s390/kvm/kvm-s390.h +++ b/arch/s390/kvm/kvm-s390.h @@ -199,14 +199,15 @@ static inline int kvm_s390_user_cpu_state_ctrl(struct kvm *kvm) /* implemented in pv.c */ void kvm_s390_pv_dealloc_vm(struct kvm *kvm); int kvm_s390_pv_alloc_vm(struct kvm *kvm); -int kvm_s390_pv_create_vm(struct kvm *kvm); -int kvm_s390_pv_create_cpu(struct kvm_vcpu *vcpu); -int kvm_s390_pv_destroy_vm(struct kvm *kvm); -int kvm_s390_pv_destroy_cpu(struct kvm_vcpu *vcpu); -int kvm_s390_pv_set_sec_parms(struct kvm *kvm, void *hdr, u64 length); +int kvm_s390_pv_create_vm(struct kvm *kvm, struct kvm_pv_cmd *cmd); +int kvm_s390_pv_create_cpu(struct kvm_vcpu *vcpu, struct kvm_pv_cmd *cmd); +int kvm_s390_pv_destroy_vm(struct kvm *kvm, struct kvm_pv_cmd *cmd); +int kvm_s390_pv_destroy_cpu(struct kvm_vcpu *vcpu, struct kvm_pv_cmd *cmd); +int kvm_s390_pv_set_sec_parms(struct kvm *kvm, void *hdr, u64 length, + struct kvm_pv_cmd *cmd); int kvm_s390_pv_unpack(struct kvm *kvm, unsigned long addr, unsigned long size, - unsigned long tweak); -int kvm_s390_pv_verify(struct kvm *kvm); + unsigned long tweak, struct kvm_pv_cmd *cmd); +int kvm_s390_pv_verify(struct kvm *kvm, struct kvm_pv_cmd *cmd); static inline bool kvm_s390_pv_is_protected(struct kvm *kvm) { diff --git a/arch/s390/kvm/pv.c b/arch/s390/kvm/pv.c index c1778cb3f8ac..381dc3fefac4 100644 --- a/arch/s390/kvm/pv.c +++ b/arch/s390/kvm/pv.c @@ -61,7 +61,7 @@ int kvm_s390_pv_alloc_vm(struct kvm *kvm) return -ENOMEM; } -int kvm_s390_pv_destroy_vm(struct kvm *kvm) +int kvm_s390_pv_destroy_vm(struct kvm *kvm, struct kvm_pv_cmd *cmd) { int rc; u32 ret; @@ -72,10 +72,12 @@ int kvm_s390_pv_destroy_vm(struct kvm *kvm) atomic_set(&kvm->mm->context.is_protected, 0); VM_EVENT(kvm, 3, "PROTVIRT DESTROY VM: rc %x rrc %x", ret >> 16, ret & 0x0000ffff); + cmd->rc = ret >> 16; + cmd->rrc = ret & 0xffff; return rc; } -int kvm_s390_pv_destroy_cpu(struct kvm_vcpu *vcpu) +int kvm_s390_pv_destroy_cpu(struct kvm_vcpu *vcpu, struct kvm_pv_cmd *cmd) { int rc = 0; u32 ret; @@ -87,6 +89,8 @@ int kvm_s390_pv_destroy_cpu(struct kvm_vcpu *vcpu) VCPU_EVENT(vcpu, 3, "PROTVIRT DESTROY VCPU: cpu %d rc %x rrc %x", vcpu->vcpu_id, ret >> 16, ret & 0x0000ffff); + cmd->rc = ret >> 16; + cmd->rrc = ret & 0xffff; } free_pages(vcpu->arch.pv.stor_base, @@ -98,7 +102,7 @@ int kvm_s390_pv_destroy_cpu(struct kvm_vcpu *vcpu) return rc; } -int kvm_s390_pv_create_cpu(struct kvm_vcpu *vcpu) +int kvm_s390_pv_create_cpu(struct kvm_vcpu *vcpu, struct kvm_pv_cmd *cmd) { int rc; struct uv_cb_csc uvcb = { @@ -124,9 +128,13 @@ int kvm_s390_pv_create_cpu(struct kvm_vcpu *vcpu) VCPU_EVENT(vcpu, 3, "PROTVIRT CREATE VCPU: cpu %d handle %llx rc %x rrc %x", vcpu->vcpu_id, uvcb.cpu_handle, uvcb.header.rc, uvcb.header.rrc); + cmd->rc = uvcb.header.rc; + cmd->rrc = uvcb.header.rrc; if (rc) { - kvm_s390_pv_destroy_cpu(vcpu); + struct kvm_pv_cmd dummy; + + kvm_s390_pv_destroy_cpu(vcpu, &dummy); return -EINVAL; } @@ -138,7 +146,7 @@ int kvm_s390_pv_create_cpu(struct kvm_vcpu *vcpu) return 0; } -int kvm_s390_pv_create_vm(struct kvm *kvm) +int kvm_s390_pv_create_vm(struct kvm *kvm, struct kvm_pv_cmd *cmd) { int rc; @@ -162,12 +170,15 @@ int kvm_s390_pv_create_vm(struct kvm *kvm) VM_EVENT(kvm, 3, "PROTVIRT CREATE VM: handle %llx len %llx rc %x rrc %x", uvcb.guest_handle, uvcb.guest_stor_len, uvcb.header.rc, uvcb.header.rrc); + cmd->rc = uvcb.header.rc; + cmd->rrc = uvcb.header.rrc; /* Outputs */ kvm->arch.pv.handle = uvcb.guest_handle; if (rc && (uvcb.header.rc & UVC_RC_NEED_DESTROY)) { - kvm_s390_pv_destroy_vm(kvm); + struct kvm_pv_cmd dummy; + kvm_s390_pv_destroy_vm(kvm, &dummy); return -EINVAL; } kvm->arch.gmap->guest_handle = uvcb.guest_handle; @@ -176,7 +187,7 @@ int kvm_s390_pv_create_vm(struct kvm *kvm) } int kvm_s390_pv_set_sec_parms(struct kvm *kvm, - void *hdr, u64 length) + void *hdr, u64 length, struct kvm_pv_cmd *cmd) { int rc; struct uv_cb_ssc uvcb = { @@ -193,6 +204,9 @@ int kvm_s390_pv_set_sec_parms(struct kvm *kvm, rc = uv_call(0, (u64)&uvcb); VM_EVENT(kvm, 3, "PROTVIRT VM SET PARMS: rc %x rrc %x", uvcb.header.rc, uvcb.header.rrc); + cmd->rc = uvcb.header.rc; + cmd->rrc = uvcb.header.rrc; + if (rc) return -EINVAL; return 0; @@ -219,7 +233,7 @@ static int unpack_one(struct kvm *kvm, unsigned long addr, u64 tweak[2]) } int kvm_s390_pv_unpack(struct kvm *kvm, unsigned long addr, unsigned long size, - unsigned long tweak) + unsigned long tweak, struct kvm_pv_cmd *cmd) { int rc = 0; u64 tw[2] = {tweak, 0}; diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index eab741bc12c3..17c1a9556eac 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1508,8 +1508,8 @@ struct kvm_pv_cmd { }; /* Available with KVM_CAP_S390_PROTECTED */ -#define KVM_S390_PV_COMMAND _IOW(KVMIO, 0xc5, struct kvm_pv_cmd) -#define KVM_S390_PV_COMMAND_VCPU _IOW(KVMIO, 0xc6, struct kvm_pv_cmd) +#define KVM_S390_PV_COMMAND _IOWR(KVMIO, 0xc5, struct kvm_pv_cmd) +#define KVM_S390_PV_COMMAND_VCPU _IOWR(KVMIO, 0xc6, struct kvm_pv_cmd) /* Secure Encrypted Virtualization command */ enum sev_cmd_id { -- 2.24.0