]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
KVM: PPC: Book3S HV: Support reset of secure guest
authorBharata B Rao <bharata@linux.ibm.com>
Mon, 25 Nov 2019 03:06:30 +0000 (08:36 +0530)
committerPaul Mackerras <paulus@ozlabs.org>
Thu, 28 Nov 2019 06:02:31 +0000 (17:02 +1100)
Add support for reset of secure guest via a new ioctl KVM_PPC_SVM_OFF.
This ioctl will be issued by QEMU during reset and includes the
the following steps:

- Release all device pages of the secure guest.
- Ask UV to terminate the guest via UV_SVM_TERMINATE ucall
- Unpin the VPA pages so that they can be migrated back to secure
  side when guest becomes secure again. This is required because
  pinned pages can't be migrated.
- Reinit the partition scoped page tables

After these steps, guest is ready to issue UV_ESM call once again
to switch to secure mode.

Signed-off-by: Bharata B Rao <bharata@linux.ibm.com>
Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
[Implementation of uv_svm_terminate() and its call from
guest shutdown path]
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
[Unpinning of VPA pages]
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
Documentation/virt/kvm/api.txt
arch/powerpc/include/asm/kvm_ppc.h
arch/powerpc/include/asm/ultravisor-api.h
arch/powerpc/include/asm/ultravisor.h
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/powerpc.c
include/uapi/linux/kvm.h

index 49183add44e7e073f716ccab425554418ed48ba5..9fecec6b4e86c30c8999ac79f5d5c37d6eba106e 100644 (file)
@@ -4149,6 +4149,24 @@ Valid values for 'action':
 #define KVM_PMU_EVENT_ALLOW 0
 #define KVM_PMU_EVENT_DENY 1
 
+4.121 KVM_PPC_SVM_OFF
+
+Capability: basic
+Architectures: powerpc
+Type: vm ioctl
+Parameters: none
+Returns: 0 on successful completion,
+Errors:
+  EINVAL:    if ultravisor failed to terminate the secure guest
+  ENOMEM:    if hypervisor failed to allocate new radix page tables for guest
+
+This ioctl is used to turn off the secure mode of the guest or transition
+the guest from secure mode to normal mode. This is invoked when the guest
+is reset. This has no effect if called for a normal guest.
+
+This ioctl issues an ultravisor call to terminate the secure guest,
+unpins the VPA pages and releases all the device pages that are used to
+track the secure pages by hypervisor.
 
 5. The kvm_run structure
 ------------------------
index d63f649fe713d2d24776e209e3c4f697c8899bb6..3d2f871241a8c7bfc7d4cba00f35408ccdfafbcd 100644 (file)
@@ -322,6 +322,7 @@ struct kvmppc_ops {
                               int size);
        int (*store_to_eaddr)(struct kvm_vcpu *vcpu, ulong *eaddr, void *ptr,
                              int size);
+       int (*svm_off)(struct kvm *kvm);
 };
 
 extern struct kvmppc_ops *kvmppc_hv_ops;
index 4b0d044caa2ad24e98766ef4cc04d8e6947c3959..b66f6db7be6c6830c317a1559d365796e4313ffd 100644 (file)
@@ -34,5 +34,6 @@
 #define UV_UNSHARE_PAGE                        0xF134
 #define UV_UNSHARE_ALL_PAGES           0xF140
 #define UV_PAGE_INVAL                  0xF138
+#define UV_SVM_TERMINATE               0xF13C
 
 #endif /* _ASM_POWERPC_ULTRAVISOR_API_H */
index b8e59b7b4ac84f59a4ae350f0463d7bfc0f3ebe6..790b0e63681fb21e098b9302feb2ec5eac16a5e4 100644 (file)
@@ -77,4 +77,9 @@ static inline int uv_page_inval(u64 lpid, u64 gpa, u64 page_shift)
        return ucall_norets(UV_PAGE_INVAL, lpid, gpa, page_shift);
 }
 
+static inline int uv_svm_terminate(u64 lpid)
+{
+       return ucall_norets(UV_SVM_TERMINATE, lpid);
+}
+
 #endif /* _ASM_POWERPC_ULTRAVISOR_H */
index a8e815648b0a0105683a24914f75657b4273bee5..dc53578193ee00ef0cd39b43465af4569a51f5b2 100644 (file)
@@ -4983,6 +4983,7 @@ static void kvmppc_core_destroy_vm_hv(struct kvm *kvm)
                if (nesting_enabled(kvm))
                        kvmhv_release_all_nested(kvm);
                kvm->arch.process_table = 0;
+               uv_svm_terminate(kvm->arch.lpid);
                kvmhv_set_ptbl_entry(kvm->arch.lpid, 0, 0);
        }
 
@@ -5425,6 +5426,94 @@ static int kvmhv_store_to_eaddr(struct kvm_vcpu *vcpu, ulong *eaddr, void *ptr,
        return rc;
 }
 
+static void unpin_vpa_reset(struct kvm *kvm, struct kvmppc_vpa *vpa)
+{
+       unpin_vpa(kvm, vpa);
+       vpa->gpa = 0;
+       vpa->pinned_addr = NULL;
+       vpa->dirty = false;
+       vpa->update_pending = 0;
+}
+
+/*
+ *  IOCTL handler to turn off secure mode of guest
+ *
+ * - Release all device pages
+ * - Issue ucall to terminate the guest on the UV side
+ * - Unpin the VPA pages.
+ * - Reinit the partition scoped page tables
+ */
+static int kvmhv_svm_off(struct kvm *kvm)
+{
+       struct kvm_vcpu *vcpu;
+       int mmu_was_ready;
+       int srcu_idx;
+       int ret = 0;
+       int i;
+
+       if (!(kvm->arch.secure_guest & KVMPPC_SECURE_INIT_START))
+               return ret;
+
+       mutex_lock(&kvm->arch.mmu_setup_lock);
+       mmu_was_ready = kvm->arch.mmu_ready;
+       if (kvm->arch.mmu_ready) {
+               kvm->arch.mmu_ready = 0;
+               /* order mmu_ready vs. vcpus_running */
+               smp_mb();
+               if (atomic_read(&kvm->arch.vcpus_running)) {
+                       kvm->arch.mmu_ready = 1;
+                       ret = -EBUSY;
+                       goto out;
+               }
+       }
+
+       srcu_idx = srcu_read_lock(&kvm->srcu);
+       for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) {
+               struct kvm_memory_slot *memslot;
+               struct kvm_memslots *slots = __kvm_memslots(kvm, i);
+
+               if (!slots)
+                       continue;
+
+               kvm_for_each_memslot(memslot, slots) {
+                       kvmppc_uvmem_drop_pages(memslot, kvm);
+                       uv_unregister_mem_slot(kvm->arch.lpid, memslot->id);
+               }
+       }
+       srcu_read_unlock(&kvm->srcu, srcu_idx);
+
+       ret = uv_svm_terminate(kvm->arch.lpid);
+       if (ret != U_SUCCESS) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /*
+        * When secure guest is reset, all the guest pages are sent
+        * to UV via UV_PAGE_IN before the non-boot vcpus get a
+        * chance to run and unpin their VPA pages. Unpinning of all
+        * VPA pages is done here explicitly so that VPA pages
+        * can be migrated to the secure side.
+        *
+        * This is required to for the secure SMP guest to reboot
+        * correctly.
+        */
+       kvm_for_each_vcpu(i, vcpu, kvm) {
+               spin_lock(&vcpu->arch.vpa_update_lock);
+               unpin_vpa_reset(kvm, &vcpu->arch.dtl);
+               unpin_vpa_reset(kvm, &vcpu->arch.slb_shadow);
+               unpin_vpa_reset(kvm, &vcpu->arch.vpa);
+               spin_unlock(&vcpu->arch.vpa_update_lock);
+       }
+
+       kvmppc_setup_partition_table(kvm);
+       kvm->arch.secure_guest = 0;
+       kvm->arch.mmu_ready = mmu_was_ready;
+out:
+       mutex_unlock(&kvm->arch.mmu_setup_lock);
+       return ret;
+}
+
 static struct kvmppc_ops kvm_ops_hv = {
        .get_sregs = kvm_arch_vcpu_ioctl_get_sregs_hv,
        .set_sregs = kvm_arch_vcpu_ioctl_set_sregs_hv,
@@ -5468,6 +5557,7 @@ static struct kvmppc_ops kvm_ops_hv = {
        .enable_nested = kvmhv_enable_nested,
        .load_from_eaddr = kvmhv_load_from_eaddr,
        .store_to_eaddr = kvmhv_store_to_eaddr,
+       .svm_off = kvmhv_svm_off,
 };
 
 static int kvm_init_subcore_bitmap(void)
index 9e085e931d7494cc7a31335a389c4787b72ba8b5..416fb3d2a1d0b6ec6fe1356820a5b743caf76a1f 100644 (file)
@@ -31,6 +31,8 @@
 #include <asm/hvcall.h>
 #include <asm/plpar_wrappers.h>
 #endif
+#include <asm/ultravisor.h>
+#include <asm/kvm_host.h>
 
 #include "timing.h"
 #include "irq.h"
@@ -2413,6 +2415,16 @@ long kvm_arch_vm_ioctl(struct file *filp,
                        r = -EFAULT;
                break;
        }
+       case KVM_PPC_SVM_OFF: {
+               struct kvm *kvm = filp->private_data;
+
+               r = 0;
+               if (!kvm->arch.kvm_ops->svm_off)
+                       goto out;
+
+               r = kvm->arch.kvm_ops->svm_off(kvm);
+               break;
+       }
        default: {
                struct kvm *kvm = filp->private_data;
                r = kvm->arch.kvm_ops->arch_vm_ioctl(filp, ioctl, arg);
index e6f17c8e2dbac59d03b5b81cfae289778ceaab90..f0a16b4adbbd63c421006f6ca9b0fd9a892f7a5d 100644 (file)
@@ -1348,6 +1348,7 @@ struct kvm_s390_ucas_mapping {
 #define KVM_PPC_GET_CPU_CHAR     _IOR(KVMIO,  0xb1, struct kvm_ppc_cpu_char)
 /* Available with KVM_CAP_PMU_EVENT_FILTER */
 #define KVM_SET_PMU_EVENT_FILTER  _IOW(KVMIO,  0xb2, struct kvm_pmu_event_filter)
+#define KVM_PPC_SVM_OFF                  _IO(KVMIO,  0xb3)
 
 /* ioctl for vm fd */
 #define KVM_CREATE_DEVICE        _IOWR(KVMIO,  0xe0, struct kvm_create_device)