On 3/9/20 12:21 PM, Janosch Frank wrote:
The unpack facility provides the means to setup a protected guest. A
protected guest can not be introspected by the hypervisor or any
user/administrator of the machine it is running on.

Protected guests are encrypted at rest and need a special boot
mechanism via diag308 subcode 8 and 10.

Code 8 sets the PV specific IPLB which is retained seperately from
those set via code 5.

Code 10 is used to unpack the VM into protected memory, verify its
integrity and start it.

Signed-off-by: Janosch Frank <fran...@linux.ibm.com>
Signed-off-by: Christian Borntraeger <borntrae...@de.ibm.com> [Changes
to machine]
A nit: [Changes...] should go before the s-o-b.
---
  hw/s390x/Makefile.objs              |   1 +
  hw/s390x/ipl.c                      |  59 ++++++++++++-
  hw/s390x/ipl.h                      |  72 ++++++++++++++--
  hw/s390x/pv.c                       | 104 +++++++++++++++++++++++
  hw/s390x/pv.h                       |  34 ++++++++
  hw/s390x/s390-virtio-ccw.c          | 127 +++++++++++++++++++++++++++-
  include/hw/s390x/s390-virtio-ccw.h  |   1 +
  target/s390x/cpu.c                  |  17 ++++
  target/s390x/cpu.h                  |   1 +
  target/s390x/cpu_features_def.inc.h |   1 +
  target/s390x/diag.c                 |  34 +++++++-
  11 files changed, 436 insertions(+), 15 deletions(-)
  create mode 100644 hw/s390x/pv.c
  create mode 100644 hw/s390x/pv.h

diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs
index e02ed80b68..a46a1c7894 100644
--- a/hw/s390x/Makefile.objs
+++ b/hw/s390x/Makefile.objs
@@ -31,6 +31,7 @@ obj-y += tod-qemu.o
  obj-$(CONFIG_KVM) += tod-kvm.o
  obj-$(CONFIG_KVM) += s390-skeys-kvm.o
  obj-$(CONFIG_KVM) += s390-stattrib-kvm.o
+obj-$(CONFIG_KVM) += pv.o
  obj-y += s390-ccw.o
  obj-y += ap-device.o
  obj-y += ap-bridge.o
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 9c1ecd423c..ba3eac30c6 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -33,6 +33,7 @@
  #include "qemu/cutils.h"
  #include "qemu/option.h"
  #include "exec/exec-all.h"
+#include "pv.h"

  #define KERN_IMAGE_START                0x010000UL
  #define LINUX_MAGIC_ADDR                0x010008UL
@@ -542,11 +543,30 @@ void s390_ipl_update_diag308(IplParameterBlock *iplb)
  {
      S390IPLState *ipl = get_ipl_device();

-    ipl->iplb = *iplb;
-    ipl->iplb_valid = true;
+    /*
+     * The IPLB set and retrieved by subcodes 8/9 is completely
+     * separate from the one managed via subcodes 5/6.
+     */
+    if (iplb->pbt == S390_IPL_TYPE_PV) {
+        ipl->iplb_pv = *iplb;
+        ipl->iplb_valid_pv = true;
+    } else {
+        ipl->iplb = *iplb;
+        ipl->iplb_valid = true;
+    }
      ipl->netboot = is_virtio_net_device(iplb);
  }

+IplParameterBlock *s390_ipl_get_iplb_pv(void)
+{
+    S390IPLState *ipl = get_ipl_device();
+
+    if (!ipl->iplb_valid_pv) {
+        return NULL;
+    }
+    return &ipl->iplb_pv;
+}
+
  IplParameterBlock *s390_ipl_get_iplb(void)
  {
      S390IPLState *ipl = get_ipl_device();
@@ -561,7 +581,8 @@ void s390_ipl_reset_request(CPUState *cs, enum s390_reset 
reset_type)
  {
      S390IPLState *ipl = get_ipl_device();

-    if (reset_type == S390_RESET_EXTERNAL || reset_type == S390_RESET_REIPL) {
+    if (reset_type == S390_RESET_EXTERNAL || reset_type == S390_RESET_REIPL ||
+        reset_type == S390_RESET_PV) {
          /* use CPU 0 for full resets */
          ipl->reset_cpu_index = 0;
      } else {
@@ -635,6 +656,38 @@ static void s390_ipl_prepare_qipl(S390CPU *cpu)
      cpu_physical_memory_unmap(addr, len, 1, len);
  }

+int s390_ipl_prepare_pv_header(void)
+{
+    S390IPLState *ipl = get_ipl_device();
+    IPLBlockPV *ipib_pv = &ipl->iplb_pv.pv;
+    void *hdr = g_malloc(ipib_pv->pv_header_len);
+    int rc;
+
+    cpu_physical_memory_read(ipib_pv->pv_header_addr, hdr,
+                             ipib_pv->pv_header_len);
+    rc = s390_pv_set_sec_parms((uint64_t)hdr,
+                          ipib_pv->pv_header_len);
+    g_free(hdr);
+    return rc;
+}
+
+int s390_ipl_pv_unpack(void)
+{
+    int i, rc = 0;
+    S390IPLState *ipl = get_ipl_device();
+    IPLBlockPV *ipib_pv = &ipl->iplb_pv.pv;
+
+    for (i = 0; i < ipib_pv->num_comp; i++) {
+        rc = s390_pv_unpack(ipib_pv->components[i].addr,
+                            TARGET_PAGE_ALIGN(ipib_pv->components[i].size),
+                            ipib_pv->components[i].tweak_pref);
+        if (rc) {
+            break;
+        }
+    }
+    return rc;
+}
+
  void s390_ipl_prepare_cpu(S390CPU *cpu)
  {
      S390IPLState *ipl = get_ipl_device();
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index d4813105db..b2ccdd9dae 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -15,6 +15,24 @@
  #include "cpu.h"
  #include "hw/qdev-core.h"

+struct IPLBlockPVComp {
+    uint64_t tweak_pref;
+    uint64_t addr;
+    uint64_t size;
+} QEMU_PACKED;
+typedef struct IPLBlockPVComp IPLBlockPVComp;
+
+struct IPLBlockPV {
+    uint8_t  reserved18[87];    /* 0x18 */
+    uint8_t  version;           /* 0x6f */
+    uint32_t reserved70;        /* 0x70 */
+    uint32_t num_comp;          /* 0x70 */
Another nit: offset should be 0x74
+    uint64_t pv_header_addr;    /* 0x74 */
+    uint64_t pv_header_len;     /* 0x7c */
+    struct IPLBlockPVComp components[];
+} QEMU_PACKED;
+typedef struct IPLBlockPV IPLBlockPV;
+
  struct IplBlockCcw {
      uint8_t  reserved0[85];
      uint8_t  ssid;[...]
--
Kind Regards,
   Viktor


Reply via email to