All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 00/18] s390x: Protected Virtualization support
@ 2020-03-04 11:42 Janosch Frank
  2020-03-04 11:42 ` [PATCH v6 01/18] Sync pv Janosch Frank
                   ` (18 more replies)
  0 siblings, 19 replies; 72+ messages in thread
From: Janosch Frank @ 2020-03-04 11:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck, david

Most of the QEMU changes for PV are related to the new IPL type with
subcodes 8 - 10 and the execution of the necessary Ultravisor calls to
IPL secure guests. Note that we can only boot into secure mode from
normal mode, i.e. stfle 161 is not active in secure mode.

The other changes related to data gathering for emulation and
disabling addressing checks in secure mode, as well as CPU resets.

v6:
	* diag308 rc numbers were changed by architecture
	* IPL pv block received one more reserved field by architecture
	* Officially added the bios patch to the series
	* Dropped picked constant rename patch

v5:
	* Moved docs into docs/system
	* Some more enable/disable changes
	* Moved enablement/disablement of pv in separate functions
	* Some review fixes

v4:
	* Sync with KVM changes
	* Review changes

V3:
	* Use dedicated functions to access SIDA
	* Smaller cleanups and segfault fixes
	* Error reporting for Ultravisor calls
	* Inject of RC of diag308 subcode 10 fails

V2:
	* Split out cleanups
	* Internal PV state tracking
	* Review feedback

Christian Borntraeger (1):
  s390x: Add unpack facility feature to GA1

Janosch Frank (17):
  Sync pv
  s390x: protvirt: Add diag308 subcodes 8 - 10
  s390x: protvirt: Support unpack facility
  s390x: protvirt: Add migration blocker
  s390x: protvirt: Handle diag 308 subcodes 0,1,3,4
  s390x: protvirt: Inhibit balloon when switching to protected mode
  s390x: protvirt: KVM intercept changes
  s390x: Add SIDA memory ops
  s390x: protvirt: Move STSI data over SIDAD
  s390x: protvirt: SCLP interpretation
  s390x: protvirt: Set guest IPL PSW
  s390x: protvirt: Move diag 308 data over SIDAD
  s390x: protvirt: Disable address checks for PV guest IO emulation
  s390x: protvirt: Move IO control structures over SIDA
  s390x: protvirt: Handle SIGP store status correctly
  docs: Add protvirt docs
  pc-bios: s390x: Save iplb location in lowcore

 docs/system/index.rst               |   1 +
 docs/system/protvirt.rst            |  57 +++++++++++
 hw/s390x/Makefile.objs              |   1 +
 hw/s390x/ipl.c                      |  80 ++++++++++++++-
 hw/s390x/ipl.h                      |  34 +++++++
 hw/s390x/pv.c                       | 106 ++++++++++++++++++++
 hw/s390x/pv.h                       |  34 +++++++
 hw/s390x/s390-virtio-ccw.c          | 145 +++++++++++++++++++++++++++-
 hw/s390x/sclp.c                     |  17 ++++
 include/hw/s390x/s390-virtio-ccw.h  |   1 +
 include/hw/s390x/sclp.h             |   2 +
 linux-headers/linux/kvm.h           |  45 ++++++++-
 pc-bios/s390-ccw/jump2ipl.c         |   1 +
 pc-bios/s390-ccw/main.c             |   8 +-
 pc-bios/s390-ccw/netmain.c          |   1 +
 pc-bios/s390-ccw/s390-arch.h        |  10 +-
 pc-bios/s390-ccw/s390-ccw.h         |   1 +
 target/s390x/cpu.c                  |  27 ++++--
 target/s390x/cpu.h                  |   8 +-
 target/s390x/cpu_features_def.inc.h |   1 +
 target/s390x/diag.c                 |  60 ++++++++++--
 target/s390x/gen-features.c         |   1 +
 target/s390x/helper.c               |   4 +
 target/s390x/ioinst.c               | 113 +++++++++++++++-------
 target/s390x/kvm.c                  |  54 ++++++++++-
 target/s390x/kvm_s390x.h            |   2 +
 target/s390x/mmu_helper.c           |  14 +++
 target/s390x/sigp.c                 |   1 +
 28 files changed, 762 insertions(+), 67 deletions(-)
 create mode 100644 docs/system/protvirt.rst
 create mode 100644 hw/s390x/pv.c
 create mode 100644 hw/s390x/pv.h

-- 
2.20.1



^ permalink raw reply	[flat|nested] 72+ messages in thread

* [PATCH v6 01/18] Sync pv
  2020-03-04 11:42 [PATCH v6 00/18] s390x: Protected Virtualization support Janosch Frank
@ 2020-03-04 11:42 ` Janosch Frank
  2020-03-04 11:42 ` [PATCH v6 02/18] s390x: protvirt: Add diag308 subcodes 8 - 10 Janosch Frank
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 72+ messages in thread
From: Janosch Frank @ 2020-03-04 11:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck, david

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
---
 linux-headers/linux/kvm.h | 43 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 41 insertions(+), 2 deletions(-)

diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 265099100e..e36f761194 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -474,8 +474,11 @@ struct kvm_s390_mem_op {
 	__u32 size;		/* amount of bytes */
 	__u32 op;		/* type of operation */
 	__u64 buf;		/* buffer in userspace */
-	__u8 ar;		/* the access register number */
-	__u8 reserved[31];	/* should be set to 0 */
+	union {
+		__u8 ar;	/* the access register number */
+		__u32 sida_offset; /* offset into the sida */
+		__u8 reserved[32]; /* should be set to 0 */
+	};
 };
 /* types for kvm_s390_mem_op->op */
 #define KVM_S390_MEMOP_LOGICAL_READ	0
@@ -1010,6 +1013,7 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_ARM_NISV_TO_USER 177
 #define KVM_CAP_ARM_INJECT_EXT_DABT 178
 #define KVM_CAP_S390_VCPU_RESETS 179
+#define KVM_CAP_S390_PROTECTED 180
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -1478,6 +1482,41 @@ struct kvm_enc_region {
 #define KVM_S390_NORMAL_RESET	_IO(KVMIO,   0xc3)
 #define KVM_S390_CLEAR_RESET	_IO(KVMIO,   0xc4)
 
+struct kvm_s390_pv_sec_parm {
+	__u64 origin;
+	__u64 length;
+};
+
+struct kvm_s390_pv_unp {
+	__u64 addr;
+	__u64 size;
+	__u64 tweak;
+};
+
+enum pv_cmd_id {
+	KVM_PV_ENABLE,
+	KVM_PV_DISABLE,
+	KVM_PV_VM_SET_SEC_PARMS,
+	KVM_PV_VM_UNPACK,
+	KVM_PV_VM_VERIFY,
+	KVM_PV_VM_PREP_RESET,
+	KVM_PV_VM_UNSHARE_ALL,
+	KVM_PV_VCPU_CREATE,
+	KVM_PV_VCPU_DESTROY,
+};
+
+struct kvm_pv_cmd {
+	__u32 cmd;	/* Command to be executed */
+	__u16 rc;	/* Ultravisor return code */
+	__u16 rrc;	/* Ultravisor return reason code */
+	__u64 data;	/* Data or address */
+	__u32 flags;    /* flags for future extensions. Must be 0 for now */
+	__u32 reserved[3];
+};
+
+/* Available with KVM_CAP_S390_PROTECTED */
+#define KVM_S390_PV_COMMAND		_IOWR(KVMIO, 0xc5, struct kvm_pv_cmd)
+
 /* Secure Encrypted Virtualization command */
 enum sev_cmd_id {
 	/* Guest initialization commands */
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v6 02/18] s390x: protvirt: Add diag308 subcodes 8 - 10
  2020-03-04 11:42 [PATCH v6 00/18] s390x: Protected Virtualization support Janosch Frank
  2020-03-04 11:42 ` [PATCH v6 01/18] Sync pv Janosch Frank
@ 2020-03-04 11:42 ` Janosch Frank
  2020-03-04 17:04   ` David Hildenbrand
                     ` (3 more replies)
  2020-03-04 11:42 ` [PATCH v6 03/18] s390x: protvirt: Support unpack facility Janosch Frank
                   ` (16 subsequent siblings)
  18 siblings, 4 replies; 72+ messages in thread
From: Janosch Frank @ 2020-03-04 11:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck, david

For diag308 subcodes 8 - 10 we have a new ipib of type 5. The ipib
holds the address and length of the secure execution header, as well
as a list of guest components.

Each component is a block of memory, for example kernel or initrd,
which needs to be decrypted by the Ultravisor in order to run a
protected VM. The secure execution header instructs the Ultravisor on
how to handle the protected VM and its components.

Subcodes 8 and 9 are similiar to 5 and 6 and subcode 10 will finally
start the protected guest.

Subcodes 8-10 are not valid in protected mode, we have to do a subcode
3 and then the 8 and 10 combination for a protected reboot.

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
---
 hw/s390x/ipl.c      | 47 ++++++++++++++++++++++++++++++++++++++++++---
 hw/s390x/ipl.h      | 32 ++++++++++++++++++++++++++++++
 target/s390x/diag.c | 26 ++++++++++++++++++++++---
 3 files changed, 99 insertions(+), 6 deletions(-)

diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 9c1ecd423c..80c6ab233a 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -538,15 +538,55 @@ static bool is_virtio_scsi_device(IplParameterBlock *iplb)
     return is_virtio_ccw_device_of_type(iplb, VIRTIO_ID_SCSI);
 }
 
+int s390_ipl_pv_check_components(IplParameterBlock *iplb)
+{
+    int i;
+    IPLBlockPV *ipib_pv = &iplb->pv;
+
+    if (ipib_pv->num_comp == 0) {
+        return -EINVAL;
+    }
+
+    for (i = 0; i < ipib_pv->num_comp; i++) {
+        /* Addr must be 4k aligned */
+        if (ipib_pv->components[i].addr & ~TARGET_PAGE_MASK) {
+            return -EINVAL;
+        }
+
+        /* Tweak prefix is monotonously increasing with each component */
+        if (i < ipib_pv->num_comp - 1 &&
+            ipib_pv->components[i].tweak_pref >
+            ipib_pv->components[i + 1].tweak_pref) {
+            return -EINVAL;
+        }
+    }
+    return 0;
+}
+
 void s390_ipl_update_diag308(IplParameterBlock *iplb)
 {
     S390IPLState *ipl = get_ipl_device();
 
-    ipl->iplb = *iplb;
-    ipl->iplb_valid = true;
+    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_secure(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 +601,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 {
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index d4813105db..04be63cee1 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  reserved[87];
+    uint8_t  version;
+    uint32_t reserved70;
+    uint32_t num_comp;
+    uint64_t pv_header_addr;
+    uint64_t pv_header_len;
+    struct IPLBlockPVComp components[];
+} QEMU_PACKED;
+typedef struct IPLBlockPV IPLBlockPV;
+
 struct IplBlockCcw {
     uint8_t  reserved0[85];
     uint8_t  ssid;
@@ -71,6 +89,7 @@ union IplParameterBlock {
         union {
             IplBlockCcw ccw;
             IplBlockFcp fcp;
+            IPLBlockPV pv;
             IplBlockQemuScsi scsi;
         };
     } QEMU_PACKED;
@@ -84,9 +103,11 @@ union IplParameterBlock {
 typedef union IplParameterBlock IplParameterBlock;
 
 int s390_ipl_set_loadparm(uint8_t *loadparm);
+int s390_ipl_pv_check_components(IplParameterBlock *iplb);
 void s390_ipl_update_diag308(IplParameterBlock *iplb);
 void s390_ipl_prepare_cpu(S390CPU *cpu);
 IplParameterBlock *s390_ipl_get_iplb(void);
+IplParameterBlock *s390_ipl_get_iplb_secure(void);
 
 enum s390_reset {
     /* default is a reset not triggered by a CPU e.g. issued by QMP */
@@ -94,6 +115,7 @@ enum s390_reset {
     S390_RESET_REIPL,
     S390_RESET_MODIFIED_CLEAR,
     S390_RESET_LOAD_NORMAL,
+    S390_RESET_PV,
 };
 void s390_ipl_reset_request(CPUState *cs, enum s390_reset reset_type);
 void s390_ipl_get_reset_request(CPUState **cs, enum s390_reset *reset_type);
@@ -133,6 +155,7 @@ struct S390IPLState {
     /*< private >*/
     DeviceState parent_obj;
     IplParameterBlock iplb;
+    IplParameterBlock iplb_pv;
     QemuIplParameters qipl;
     uint64_t start_addr;
     uint64_t compat_start_addr;
@@ -140,6 +163,7 @@ struct S390IPLState {
     uint64_t compat_bios_start_addr;
     bool enforce_bios;
     bool iplb_valid;
+    bool iplb_valid_pv;
     bool netboot;
     /* reset related properties don't have to be migrated or reset */
     enum s390_reset reset_type;
@@ -161,9 +185,11 @@ QEMU_BUILD_BUG_MSG(offsetof(S390IPLState, iplb) & 3, "alignment of iplb wrong");
 
 #define S390_IPL_TYPE_FCP 0x00
 #define S390_IPL_TYPE_CCW 0x02
+#define S390_IPL_TYPE_PV 0x05
 #define S390_IPL_TYPE_QEMU_SCSI 0xff
 
 #define S390_IPLB_HEADER_LEN 8
+#define S390_IPLB_MIN_PV_LEN 148
 #define S390_IPLB_MIN_CCW_LEN 200
 #define S390_IPLB_MIN_FCP_LEN 384
 #define S390_IPLB_MIN_QEMU_SCSI_LEN 200
@@ -185,4 +211,10 @@ static inline bool iplb_valid_fcp(IplParameterBlock *iplb)
            iplb->pbt == S390_IPL_TYPE_FCP;
 }
 
+static inline bool iplb_valid_pv(IplParameterBlock *iplb)
+{
+    return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_PV_LEN &&
+           iplb->pbt == S390_IPL_TYPE_PV;
+}
+
 #endif
diff --git a/target/s390x/diag.c b/target/s390x/diag.c
index b5aec06d6b..945b263f0a 100644
--- a/target/s390x/diag.c
+++ b/target/s390x/diag.c
@@ -52,6 +52,7 @@ int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
 #define DIAG_308_RC_OK              0x0001
 #define DIAG_308_RC_NO_CONF         0x0102
 #define DIAG_308_RC_INVALID         0x0402
+#define DIAG_308_RC_NO_PV_CONF      0x0902
 
 #define DIAG308_RESET_MOD_CLR       0
 #define DIAG308_RESET_LOAD_NORM     1
@@ -59,6 +60,9 @@ int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
 #define DIAG308_LOAD_NORMAL_DUMP    4
 #define DIAG308_SET                 5
 #define DIAG308_STORE               6
+#define DIAG308_PV_SET              8
+#define DIAG308_PV_STORE            9
+#define DIAG308_PV_START            10
 
 static int diag308_parm_check(CPUS390XState *env, uint64_t r1, uint64_t addr,
                               uintptr_t ra, bool write)
@@ -105,6 +109,7 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
         s390_ipl_reset_request(cs, S390_RESET_REIPL);
         break;
     case DIAG308_SET:
+    case DIAG308_PV_SET:
         if (diag308_parm_check(env, r1, addr, ra, false)) {
             return;
         }
@@ -117,7 +122,8 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
 
         cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len));
 
-        if (!iplb_valid_ccw(iplb) && !iplb_valid_fcp(iplb)) {
+        if (!iplb_valid_ccw(iplb) && !iplb_valid_fcp(iplb) &&
+            !(iplb_valid_pv(iplb) && !s390_ipl_pv_check_components(iplb))) {
             env->regs[r1 + 1] = DIAG_308_RC_INVALID;
             goto out;
         }
@@ -128,17 +134,31 @@ out:
         g_free(iplb);
         return;
     case DIAG308_STORE:
+    case DIAG308_PV_STORE:
         if (diag308_parm_check(env, r1, addr, ra, true)) {
             return;
         }
-        iplb = s390_ipl_get_iplb();
+        if (subcode == DIAG308_PV_STORE) {
+            iplb = s390_ipl_get_iplb_secure();
+        } else {
+            iplb = s390_ipl_get_iplb();
+        }
         if (iplb) {
             cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len));
             env->regs[r1 + 1] = DIAG_308_RC_OK;
         } else {
             env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;
         }
-        return;
+        break;
+    case DIAG308_PV_START:
+        iplb = s390_ipl_get_iplb_secure();
+        if (!iplb || !iplb_valid_pv(iplb)) {
+            env->regs[r1 + 1] = DIAG_308_RC_NO_PV_CONF;
+            return;
+        }
+
+        s390_ipl_reset_request(cs, S390_RESET_PV);
+        break;
     default:
         s390_program_interrupt(env, PGM_SPECIFICATION, ra);
         break;
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v6 03/18] s390x: protvirt: Support unpack facility
  2020-03-04 11:42 [PATCH v6 00/18] s390x: Protected Virtualization support Janosch Frank
  2020-03-04 11:42 ` [PATCH v6 01/18] Sync pv Janosch Frank
  2020-03-04 11:42 ` [PATCH v6 02/18] s390x: protvirt: Add diag308 subcodes 8 - 10 Janosch Frank
@ 2020-03-04 11:42 ` Janosch Frank
  2020-03-05 13:51   ` David Hildenbrand
                     ` (2 more replies)
  2020-03-04 11:42 ` [PATCH v6 04/18] s390x: protvirt: Add migration blocker Janosch Frank
                   ` (15 subsequent siblings)
  18 siblings, 3 replies; 72+ messages in thread
From: Janosch Frank @ 2020-03-04 11:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck, david

When a guest has saved a ipib of type 5 and calls diagnose308 with
subcode 10, we have to setup the protected processing environment via
Ultravisor calls. The calls are done by KVM and are exposed via an
API.

The following steps are necessary:
1. Enable protected mode for the VM (register it and its cpus with the Ultravisor)
2. Forward the secure header to the Ultravisor (has all information on
how to decrypt the image and VM information)
3. Protect image pages from the host and decrypt them
4. Verify the image integrity

Only after step 4 a protected VM is allowed to run.

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> [Changes
to machine]
---
 hw/s390x/Makefile.objs              |   1 +
 hw/s390x/ipl.c                      |  33 +++++++++
 hw/s390x/ipl.h                      |   2 +
 hw/s390x/pv.c                       | 106 ++++++++++++++++++++++++++++
 hw/s390x/pv.h                       |  34 +++++++++
 hw/s390x/s390-virtio-ccw.c          |  91 ++++++++++++++++++++++++
 include/hw/s390x/s390-virtio-ccw.h  |   1 +
 target/s390x/cpu.c                  |   4 ++
 target/s390x/cpu.h                  |   1 +
 target/s390x/cpu_features_def.inc.h |   1 +
 10 files changed, 274 insertions(+)
 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 80c6ab233a..3b241ea549 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
@@ -676,6 +677,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 04be63cee1..ad8090a02c 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -105,6 +105,8 @@ typedef union IplParameterBlock IplParameterBlock;
 int s390_ipl_set_loadparm(uint8_t *loadparm);
 int s390_ipl_pv_check_components(IplParameterBlock *iplb);
 void s390_ipl_update_diag308(IplParameterBlock *iplb);
+int s390_ipl_prepare_pv_header(void);
+int s390_ipl_pv_unpack(void);
 void s390_ipl_prepare_cpu(S390CPU *cpu);
 IplParameterBlock *s390_ipl_get_iplb(void);
 IplParameterBlock *s390_ipl_get_iplb_secure(void);
diff --git a/hw/s390x/pv.c b/hw/s390x/pv.c
new file mode 100644
index 0000000000..50b68b6c34
--- /dev/null
+++ b/hw/s390x/pv.c
@@ -0,0 +1,106 @@
+/*
+ * Secure execution functions
+ *
+ * Copyright IBM Corp. 2020
+ * Author(s):
+ *  Janosch Frank <frankja@linux.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+#include "qemu/osdep.h"
+#include <sys/ioctl.h>
+
+#include <linux/kvm.h>
+
+#include "qemu/error-report.h"
+#include "sysemu/kvm.h"
+#include "pv.h"
+
+const char *cmd_names[] = {
+    "VM_ENABLE",
+    "VM_DISABLE",
+    "VM_SET_SEC_PARAMS",
+    "VM_UNPACK",
+    "VM_VERIFY",
+    "VM_PREP_RESET",
+    "VM_UNSHARE_ALL",
+    NULL
+};
+
+static int s390_pv_cmd(uint32_t cmd, void *data)
+{
+    int rc;
+    struct kvm_pv_cmd pv_cmd = {
+        .cmd = cmd,
+        .data = (uint64_t)data,
+    };
+
+    rc = kvm_vm_ioctl(kvm_state, KVM_S390_PV_COMMAND, &pv_cmd);
+    if (rc) {
+        error_report("KVM PV command %d (%s) failed: header rc %x rrc %x "
+                     "IOCTL rc: %d", cmd, cmd_names[cmd], pv_cmd.rc, pv_cmd.rrc,
+                     rc);
+    }
+    return rc;
+}
+
+static void s390_pv_cmd_exit(uint32_t cmd, void *data)
+{
+    int rc;
+
+    rc = s390_pv_cmd(cmd, data);
+    if (rc) {
+        exit(1);
+    }
+}
+
+int s390_pv_vm_enable(void)
+{
+    return s390_pv_cmd(KVM_PV_ENABLE, NULL);
+}
+
+void s390_pv_vm_disable(void)
+{
+     s390_pv_cmd_exit(KVM_PV_DISABLE, NULL);
+}
+
+int s390_pv_set_sec_parms(uint64_t origin, uint64_t length)
+{
+    struct kvm_s390_pv_sec_parm args = {
+        .origin = origin,
+        .length = length,
+    };
+
+    return s390_pv_cmd(KVM_PV_VM_SET_SEC_PARMS, &args);
+}
+
+/*
+ * Called for each component in the SE type IPL parameter block 0.
+ */
+int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak)
+{
+    struct kvm_s390_pv_unp args = {
+        .addr = addr,
+        .size = size,
+        .tweak = tweak,
+    };
+
+    return s390_pv_cmd(KVM_PV_VM_UNPACK, &args);
+}
+
+void s390_pv_perf_clear_reset(void)
+{
+    s390_pv_cmd_exit(KVM_PV_VM_PREP_RESET, NULL);
+}
+
+int s390_pv_verify(void)
+{
+    return s390_pv_cmd(KVM_PV_VM_VERIFY, NULL);
+}
+
+void s390_pv_unshare(void)
+{
+    s390_pv_cmd_exit(KVM_PV_VM_UNSHARE_ALL, NULL);
+}
diff --git a/hw/s390x/pv.h b/hw/s390x/pv.h
new file mode 100644
index 0000000000..e58fbca96a
--- /dev/null
+++ b/hw/s390x/pv.h
@@ -0,0 +1,34 @@
+/*
+ * Protected Virtualization header
+ *
+ * Copyright IBM Corp. 2020
+ * Author(s):
+ *  Janosch Frank <frankja@linux.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#ifndef HW_S390_PV_H
+#define HW_S390_PV_H
+
+#ifdef CONFIG_KVM
+int s390_pv_vm_enable(void);
+void s390_pv_vm_disable(void);
+int s390_pv_set_sec_parms(uint64_t origin, uint64_t length);
+int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak);
+void s390_pv_perf_clear_reset(void);
+int s390_pv_verify(void);
+void s390_pv_unshare(void);
+#else
+static inline int s390_pv_vm_enable(void) { return 0; }
+static inline void s390_pv_vm_disable(void) {}
+static inline int s390_pv_set_sec_parms(uint64_t origin, uint64_t length) { return 0; }
+static inline int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak) { return 0; }
+static inline void s390_pv_perf_clear_reset(void) {}
+static inline int s390_pv_verify(void) { return 0; }
+static inline void s390_pv_unshare(void) {}
+#endif
+
+#endif /* HW_S390_PV_H */
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index a89cf4c129..dd39890f89 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -41,6 +41,8 @@
 #include "hw/qdev-properties.h"
 #include "hw/s390x/tod.h"
 #include "sysemu/sysemu.h"
+#include "hw/s390x/pv.h"
+#include <linux/kvm.h>
 
 S390CPU *s390_cpu_addr2state(uint16_t cpu_addr)
 {
@@ -238,9 +240,11 @@ static void s390_create_sclpconsole(const char *type, Chardev *chardev)
 static void ccw_init(MachineState *machine)
 {
     int ret;
+    S390CcwMachineState *ms = S390_CCW_MACHINE(machine);
     VirtualCssBus *css_bus;
     DeviceState *dev;
 
+    ms->pv = false;
     s390_sclp_init();
     /* init memory + setup max page size. Required for the CPU model */
     s390_memory_init(machine->ram);
@@ -316,10 +320,75 @@ static inline void s390_do_cpu_ipl(CPUState *cs, run_on_cpu_data arg)
     s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
 }
 
+static void s390_machine_unprotect(S390CcwMachineState *ms)
+{
+    CPUState *t;
+
+    if (!ms->pv)
+        return;
+    s390_pv_vm_disable();
+    CPU_FOREACH(t) {
+        S390_CPU(t)->env.pv = false;
+    }
+    ms->pv = false;
+}
+
+static int s390_machine_protect(S390CcwMachineState *ms)
+{
+    CPUState *t;
+    int rc;
+
+    /* Create SE VM */
+    rc = s390_pv_vm_enable();
+    if (rc) {
+        return rc;
+    }
+
+    CPU_FOREACH(t) {
+        S390_CPU(t)->env.pv = true;
+    }
+    ms->pv = true;
+
+    /* Set SE header and unpack */
+    rc = s390_ipl_prepare_pv_header();
+    if (rc) {
+        goto out_err;
+    }
+
+    /* Decrypt image */
+    rc = s390_ipl_pv_unpack();
+    if (rc) {
+        goto out_err;
+    }
+
+    /* Verify integrity */
+    rc = s390_pv_verify();
+    if (rc) {
+        goto out_err;
+    }
+    return rc;
+
+out_err:
+    s390_machine_unprotect(ms);
+    return rc;
+}
+
+#define DIAG_308_RC_INVAL_FOR_PV    0x0a02
+static void s390_machine_inject_pv_error(CPUState *cs)
+{
+    int r1 = (cs->kvm_run->s390_sieic.ipa & 0x00f0) >> 4;
+    CPUS390XState *env = &S390_CPU(cs)->env;
+
+    /* Report that we are unable to enter protected mode */
+    env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV;
+}
+
 static void s390_machine_reset(MachineState *machine)
 {
     enum s390_reset reset_type;
     CPUState *cs, *t;
+    S390CPU *cpu;
+    S390CcwMachineState *ms = S390_CCW_MACHINE(machine);
 
     /* get the reset parameters, reset them once done */
     s390_ipl_get_reset_request(&cs, &reset_type);
@@ -327,6 +396,8 @@ static void s390_machine_reset(MachineState *machine)
     /* all CPUs are paused and synchronized at this point */
     s390_cmma_reset();
 
+    cpu = S390_CPU(cs);
+
     switch (reset_type) {
     case S390_RESET_EXTERNAL:
     case S390_RESET_REIPL:
@@ -353,6 +424,26 @@ static void s390_machine_reset(MachineState *machine)
         }
         subsystem_reset();
         run_on_cpu(cs, s390_do_cpu_initial_reset, RUN_ON_CPU_NULL);
+        run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL);
+        break;
+    case S390_RESET_PV: /* Subcode 10 */
+        subsystem_reset();
+        s390_crypto_reset();
+
+        CPU_FOREACH(t) {
+            if (t == cs) {
+                continue;
+            }
+            run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
+        }
+        run_on_cpu(cs, s390_do_cpu_reset, RUN_ON_CPU_NULL);
+
+        if (s390_machine_protect(ms)) {
+            s390_machine_inject_pv_error(cs);
+            s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
+            return;
+        }
+
         run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL);
         break;
     default:
diff --git a/include/hw/s390x/s390-virtio-ccw.h b/include/hw/s390x/s390-virtio-ccw.h
index 8aa27199c9..cd1dccc6e3 100644
--- a/include/hw/s390x/s390-virtio-ccw.h
+++ b/include/hw/s390x/s390-virtio-ccw.h
@@ -28,6 +28,7 @@ typedef struct S390CcwMachineState {
     /*< public >*/
     bool aes_key_wrap;
     bool dea_key_wrap;
+    bool pv;
     uint8_t loadparm[8];
 } S390CcwMachineState;
 
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
index 3dd396e870..69b1cc5dfc 100644
--- a/target/s390x/cpu.c
+++ b/target/s390x/cpu.c
@@ -37,6 +37,8 @@
 #include "sysemu/hw_accel.h"
 #include "hw/qdev-properties.h"
 #ifndef CONFIG_USER_ONLY
+#include "hw/s390x/s390-virtio-ccw.h"
+#include "hw/s390x/pv.h"
 #include "hw/boards.h"
 #include "sysemu/arch_init.h"
 #include "sysemu/sysemu.h"
@@ -191,6 +193,7 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
 
 #if !defined(CONFIG_USER_ONLY)
     MachineState *ms = MACHINE(qdev_get_machine());
+    S390CcwMachineState *ccw = S390_CCW_MACHINE(ms);
     unsigned int max_cpus = ms->smp.max_cpus;
     if (cpu->env.core_id >= max_cpus) {
         error_setg(&err, "Unable to add CPU with core-id: %" PRIu32
@@ -205,6 +208,7 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
         goto out;
     }
 
+    cpu->env.pv = ccw->pv;
     /* sync cs->cpu_index and env->core_id. The latter is needed for TCG. */
     cs->cpu_index = cpu->env.core_id;
 #endif
diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h
index 1d17709d6e..7e4d9d267c 100644
--- a/target/s390x/cpu.h
+++ b/target/s390x/cpu.h
@@ -114,6 +114,7 @@ struct CPUS390XState {
 
     /* Fields up to this point are cleared by a CPU reset */
     struct {} end_reset_fields;
+    bool pv; /* protected virtualization */
 
 #if !defined(CONFIG_USER_ONLY)
     uint32_t core_id; /* PoP "CPU address", same as cpu_index */
diff --git a/target/s390x/cpu_features_def.inc.h b/target/s390x/cpu_features_def.inc.h
index 31dff0d84e..60db28351d 100644
--- a/target/s390x/cpu_features_def.inc.h
+++ b/target/s390x/cpu_features_def.inc.h
@@ -107,6 +107,7 @@ DEF_FEAT(DEFLATE_BASE, "deflate-base", STFL, 151, "Deflate-conversion facility (
 DEF_FEAT(VECTOR_PACKED_DECIMAL_ENH, "vxpdeh", STFL, 152, "Vector-Packed-Decimal-Enhancement Facility")
 DEF_FEAT(MSA_EXT_9, "msa9-base", STFL, 155, "Message-security-assist-extension-9 facility (excluding subfunctions)")
 DEF_FEAT(ETOKEN, "etoken", STFL, 156, "Etoken facility")
+DEF_FEAT(UNPACK, "unpack", STFL, 161, "Unpack facility")
 
 /* Features exposed via SCLP SCCB Byte 80 - 98  (bit numbers relative to byte-80) */
 DEF_FEAT(SIE_GSLS, "gsls", SCLP_CONF_CHAR, 40, "SIE: Guest-storage-limit-suppression facility")
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v6 04/18] s390x: protvirt: Add migration blocker
  2020-03-04 11:42 [PATCH v6 00/18] s390x: Protected Virtualization support Janosch Frank
                   ` (2 preceding siblings ...)
  2020-03-04 11:42 ` [PATCH v6 03/18] s390x: protvirt: Support unpack facility Janosch Frank
@ 2020-03-04 11:42 ` Janosch Frank
  2020-03-04 17:13   ` David Hildenbrand
  2020-03-04 11:42 ` [PATCH v6 05/18] s390x: protvirt: Handle diag 308 subcodes 0,1,3,4 Janosch Frank
                   ` (14 subsequent siblings)
  18 siblings, 1 reply; 72+ messages in thread
From: Janosch Frank @ 2020-03-04 11:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck, david

Migration is not yet supported.

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
---
 hw/s390x/s390-virtio-ccw.c | 33 ++++++++++++++++++++++++---------
 1 file changed, 24 insertions(+), 9 deletions(-)

diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index dd39890f89..272531a9ee 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -43,6 +43,9 @@
 #include "sysemu/sysemu.h"
 #include "hw/s390x/pv.h"
 #include <linux/kvm.h>
+#include "migration/blocker.h"
+
+static Error *pv_mig_blocker;
 
 S390CPU *s390_cpu_addr2state(uint16_t cpu_addr)
 {
@@ -324,19 +327,30 @@ static void s390_machine_unprotect(S390CcwMachineState *ms)
 {
     CPUState *t;
 
-    if (!ms->pv)
-        return;
-    s390_pv_vm_disable();
-    CPU_FOREACH(t) {
-        S390_CPU(t)->env.pv = false;
+    if (ms->pv) {
+        s390_pv_vm_disable();
+        CPU_FOREACH(t) {
+            S390_CPU(t)->env.pv = false;
+        }
+        ms->pv = false;
     }
-    ms->pv = false;
+    migrate_del_blocker(pv_mig_blocker);
 }
 
 static int s390_machine_protect(S390CcwMachineState *ms)
 {
+    static Error *local_err;
     CPUState *t;
-    int rc;
+    int rc = -1;
+
+    if (!pv_mig_blocker) {
+        error_setg(&pv_mig_blocker,
+                   "protected VMs are currently not migrateable.");
+    }
+    migrate_add_blocker(pv_mig_blocker, &local_err);
+    if (local_err) {
+        goto out_err;
+    }
 
     /* Create SE VM */
     rc = s390_pv_vm_enable();
@@ -440,11 +454,12 @@ static void s390_machine_reset(MachineState *machine)
 
         if (s390_machine_protect(ms)) {
             s390_machine_inject_pv_error(cs);
-            s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
-            return;
+            goto pv_err;
         }
 
         run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL);
+pv_err:
+        s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
         break;
     default:
         g_assert_not_reached();
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v6 05/18] s390x: protvirt: Handle diag 308 subcodes 0,1,3,4
  2020-03-04 11:42 [PATCH v6 00/18] s390x: Protected Virtualization support Janosch Frank
                   ` (3 preceding siblings ...)
  2020-03-04 11:42 ` [PATCH v6 04/18] s390x: protvirt: Add migration blocker Janosch Frank
@ 2020-03-04 11:42 ` Janosch Frank
  2020-03-04 11:42 ` [PATCH v6 06/18] s390x: protvirt: Inhibit balloon when switching to protected mode Janosch Frank
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 72+ messages in thread
From: Janosch Frank @ 2020-03-04 11:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck, david

As we now have access to the protection state of the cpus, we can
implement special handling of diag 308 subcodes for cpus in the
protected state.

For subcodes 0 and 1 we need to unshare all pages before continuing,
so the guest doesn't accidentally expose data when dumping.

For subcode 3/4 we tear down the protected VM and reboot into
unprotected mode. We do not provide a secure reboot.

Before we can do the unshare calls, we need to mark all cpus as
stopped.

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
---
 hw/s390x/s390-virtio-ccw.c | 36 +++++++++++++++++++++++++++++++++---
 target/s390x/diag.c        |  4 ++++
 2 files changed, 37 insertions(+), 3 deletions(-)

diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 272531a9ee..038bad54cd 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -397,12 +397,27 @@ static void s390_machine_inject_pv_error(CPUState *cs)
     env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV;
 }
 
+static void s390_pv_prepare_reset(CPUS390XState *env)
+{
+    CPUState *cs;
+
+    if (!env->pv) {
+        return;
+    }
+    CPU_FOREACH(cs) {
+        s390_cpu_set_state(S390_CPU_STATE_STOPPED, S390_CPU(cs));
+    }
+    s390_pv_unshare();
+    s390_pv_perf_clear_reset();
+}
+
 static void s390_machine_reset(MachineState *machine)
 {
     enum s390_reset reset_type;
     CPUState *cs, *t;
     S390CPU *cpu;
     S390CcwMachineState *ms = S390_CCW_MACHINE(machine);
+    CPUS390XState *env;
 
     /* get the reset parameters, reset them once done */
     s390_ipl_get_reset_request(&cs, &reset_type);
@@ -411,10 +426,15 @@ static void s390_machine_reset(MachineState *machine)
     s390_cmma_reset();
 
     cpu = S390_CPU(cs);
+    env = &cpu->env;
 
     switch (reset_type) {
     case S390_RESET_EXTERNAL:
     case S390_RESET_REIPL:
+        if (ms->pv) {
+            s390_machine_unprotect(ms);
+        }
+
         qemu_devices_reset();
         s390_crypto_reset();
 
@@ -422,21 +442,31 @@ static void s390_machine_reset(MachineState *machine)
         run_on_cpu(cs, s390_do_cpu_ipl, RUN_ON_CPU_NULL);
         break;
     case S390_RESET_MODIFIED_CLEAR:
+        /*
+         * Susbsystem reset needs to be done before we unshare memory
+         * and loose access to VIRTIO structures in guest memory.
+         */
+        subsystem_reset();
+        s390_crypto_reset();
+        s390_pv_prepare_reset(env);
         CPU_FOREACH(t) {
             run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
         }
-        subsystem_reset();
-        s390_crypto_reset();
         run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL);
         break;
     case S390_RESET_LOAD_NORMAL:
+        /*
+         * Susbsystem reset needs to be done before we unshare memory
+         * and loose access to VIRTIO structures in guest memory.
+         */
+        subsystem_reset();
+        s390_pv_prepare_reset(env);
         CPU_FOREACH(t) {
             if (t == cs) {
                 continue;
             }
             run_on_cpu(t, s390_do_cpu_reset, RUN_ON_CPU_NULL);
         }
-        subsystem_reset();
         run_on_cpu(cs, s390_do_cpu_initial_reset, RUN_ON_CPU_NULL);
         run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL);
         break;
diff --git a/target/s390x/diag.c b/target/s390x/diag.c
index 945b263f0a..a6cd1ea260 100644
--- a/target/s390x/diag.c
+++ b/target/s390x/diag.c
@@ -67,6 +67,10 @@ int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
 static int diag308_parm_check(CPUS390XState *env, uint64_t r1, uint64_t addr,
                               uintptr_t ra, bool write)
 {
+    /* Handled by the Ultravisor */
+    if (env->pv) {
+        return 0;
+    }
     if ((r1 & 1) || (addr & ~TARGET_PAGE_MASK)) {
         s390_program_interrupt(env, PGM_SPECIFICATION, ra);
         return -1;
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v6 06/18] s390x: protvirt: Inhibit balloon when switching to protected mode
  2020-03-04 11:42 [PATCH v6 00/18] s390x: Protected Virtualization support Janosch Frank
                   ` (4 preceding siblings ...)
  2020-03-04 11:42 ` [PATCH v6 05/18] s390x: protvirt: Handle diag 308 subcodes 0,1,3,4 Janosch Frank
@ 2020-03-04 11:42 ` Janosch Frank
  2020-03-05 12:00   ` Christian Borntraeger
  2020-03-04 11:42 ` [PATCH v6 07/18] s390x: protvirt: KVM intercept changes Janosch Frank
                   ` (12 subsequent siblings)
  18 siblings, 1 reply; 72+ messages in thread
From: Janosch Frank @ 2020-03-04 11:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck, david

Ballooning in protected VMs can only be done when the guest shares the
pages it gives to the host. If pages are not shared, the integrity
checks will fail once those pages have been altered and are given back
to the guest.

Hence, until we have a solution for this in the guest kernel, we
inhibit ballooning when switching into protected mode and reverse that
once we move out of it.

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
---
 hw/s390x/s390-virtio-ccw.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 038bad54cd..b039178004 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -41,6 +41,7 @@
 #include "hw/qdev-properties.h"
 #include "hw/s390x/tod.h"
 #include "sysemu/sysemu.h"
+#include "sysemu/balloon.h"
 #include "hw/s390x/pv.h"
 #include <linux/kvm.h>
 #include "migration/blocker.h"
@@ -335,6 +336,7 @@ static void s390_machine_unprotect(S390CcwMachineState *ms)
         ms->pv = false;
     }
     migrate_del_blocker(pv_mig_blocker);
+    qemu_balloon_inhibit(false);
 }
 
 static int s390_machine_protect(S390CcwMachineState *ms)
@@ -343,6 +345,7 @@ static int s390_machine_protect(S390CcwMachineState *ms)
     CPUState *t;
     int rc = -1;
 
+    qemu_balloon_inhibit(true);
     if (!pv_mig_blocker) {
         error_setg(&pv_mig_blocker,
                    "protected VMs are currently not migrateable.");
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v6 07/18] s390x: protvirt: KVM intercept changes
  2020-03-04 11:42 [PATCH v6 00/18] s390x: Protected Virtualization support Janosch Frank
                   ` (5 preceding siblings ...)
  2020-03-04 11:42 ` [PATCH v6 06/18] s390x: protvirt: Inhibit balloon when switching to protected mode Janosch Frank
@ 2020-03-04 11:42 ` Janosch Frank
  2020-03-04 11:42 ` [PATCH v6 08/18] s390x: Add SIDA memory ops Janosch Frank
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 72+ messages in thread
From: Janosch Frank @ 2020-03-04 11:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck, david

Secure guests no longer intercept with code 4 for an instruction
interception. Instead they have codes 104 and 108 for secure
instruction interception and secure instruction notification
respectively.

The 104 mirrors the 4 interception.

The 108 is a notification interception to let KVM and QEMU know that
something changed and we need to update tracking information or
perform specific tasks. It's currently taken for the following
instructions:

* stpx (To inform about the changed prefix location)
* sclp (On incorrect SCCB values, so we can inject a IRQ)
* sigp (All but "stop and store status")
* diag308 (Subcodes 0/1)

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
---
 target/s390x/kvm.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
index 1d6fd6a27b..eec0b92479 100644
--- a/target/s390x/kvm.c
+++ b/target/s390x/kvm.c
@@ -115,6 +115,8 @@
 #define ICPT_CPU_STOP                   0x28
 #define ICPT_OPEREXC                    0x2c
 #define ICPT_IO                         0x40
+#define ICPT_PV_INSTR                   0x68
+#define ICPT_PV_INSTR_NOTIFICATION      0x6c
 
 #define NR_LOCAL_IRQS 32
 /*
@@ -1693,6 +1695,8 @@ static int handle_intercept(S390CPU *cpu)
             (long)cs->kvm_run->psw_addr);
     switch (icpt_code) {
         case ICPT_INSTRUCTION:
+        case ICPT_PV_INSTR:
+        case ICPT_PV_INSTR_NOTIFICATION:
             r = handle_instruction(cpu, run);
             break;
         case ICPT_PROGRAM:
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v6 08/18] s390x: Add SIDA memory ops
  2020-03-04 11:42 [PATCH v6 00/18] s390x: Protected Virtualization support Janosch Frank
                   ` (6 preceding siblings ...)
  2020-03-04 11:42 ` [PATCH v6 07/18] s390x: protvirt: KVM intercept changes Janosch Frank
@ 2020-03-04 11:42 ` Janosch Frank
  2020-03-04 17:39   ` David Hildenbrand
  2020-03-04 11:42 ` [PATCH v6 09/18] s390x: protvirt: Move STSI data over SIDAD Janosch Frank
                   ` (10 subsequent siblings)
  18 siblings, 1 reply; 72+ messages in thread
From: Janosch Frank @ 2020-03-04 11:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck, david

Protected guests save the instruction control blocks in the SIDA
instead of QEMU/KVM directly accessing the guest's memory.

Let's introduce new functions to access the SIDA.

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
---
 linux-headers/linux/kvm.h |  2 ++
 target/s390x/cpu.h        |  7 ++++++-
 target/s390x/kvm.c        | 25 +++++++++++++++++++++++++
 target/s390x/kvm_s390x.h  |  2 ++
 target/s390x/mmu_helper.c | 14 ++++++++++++++
 5 files changed, 49 insertions(+), 1 deletion(-)

diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index e36f761194..c30344ab00 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -483,6 +483,8 @@ struct kvm_s390_mem_op {
 /* types for kvm_s390_mem_op->op */
 #define KVM_S390_MEMOP_LOGICAL_READ	0
 #define KVM_S390_MEMOP_LOGICAL_WRITE	1
+#define KVM_S390_MEMOP_SIDA_READ	2
+#define KVM_S390_MEMOP_SIDA_WRITE	3
 /* flags for kvm_s390_mem_op->flags */
 #define KVM_S390_MEMOP_F_CHECK_ONLY		(1ULL << 0)
 #define KVM_S390_MEMOP_F_INJECT_EXCEPTION	(1ULL << 1)
diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h
index 7e4d9d267c..2578c838f8 100644
--- a/target/s390x/cpu.h
+++ b/target/s390x/cpu.h
@@ -824,7 +824,12 @@ int s390_cpu_virt_mem_rw(S390CPU *cpu, vaddr laddr, uint8_t ar, void *hostbuf,
 #define s390_cpu_virt_mem_check_write(cpu, laddr, ar, len)   \
         s390_cpu_virt_mem_rw(cpu, laddr, ar, NULL, len, true)
 void s390_cpu_virt_mem_handle_exc(S390CPU *cpu, uintptr_t ra);
-
+int s390_cpu_pv_mem_rw(S390CPU *cpu, unsigned int offset,  void *hostbuf,
+                       int len, bool is_write);
+#define s390_cpu_pv_mem_read(cpu, offset, dest, len)    \
+        s390_cpu_pv_mem_rw(cpu, offset, dest, len, false)
+#define s390_cpu_pv_mem_write(cpu, offset, dest, len)       \
+        s390_cpu_pv_mem_rw(cpu, offset, dest, len, true)
 
 /* sigp.c */
 int s390_cpu_restart(S390CPU *cpu);
diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
index eec0b92479..cdcd538b4f 100644
--- a/target/s390x/kvm.c
+++ b/target/s390x/kvm.c
@@ -154,6 +154,7 @@ static int cap_ri;
 static int cap_gs;
 static int cap_hpage_1m;
 static int cap_vcpu_resets;
+static int cap_protected;
 
 static int active_cmma;
 
@@ -346,6 +347,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
     cap_mem_op = kvm_check_extension(s, KVM_CAP_S390_MEM_OP);
     cap_s390_irq = kvm_check_extension(s, KVM_CAP_S390_INJECT_IRQ);
     cap_vcpu_resets = kvm_check_extension(s, KVM_CAP_S390_VCPU_RESETS);
+    cap_protected = kvm_check_extension(s, KVM_CAP_S390_PROTECTED);
 
     if (!kvm_check_extension(s, KVM_CAP_S390_GMAP)
         || !kvm_check_extension(s, KVM_CAP_S390_COW)) {
@@ -846,6 +848,29 @@ int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf,
     return ret;
 }
 
+int kvm_s390_mem_op_pv(S390CPU *cpu, uint64_t offset, void *hostbuf,
+                       int len, bool is_write)
+{
+    struct kvm_s390_mem_op mem_op = {
+        .sida_offset = offset,
+        .size = len,
+        .op = is_write ? KVM_S390_MEMOP_SIDA_WRITE
+                       : KVM_S390_MEMOP_SIDA_READ,
+        .buf = (uint64_t)hostbuf,
+    };
+    int ret;
+
+    if (!cap_mem_op || !cap_protected) {
+        return -ENOSYS;
+    }
+
+    ret = kvm_vcpu_ioctl(CPU(cpu), KVM_S390_MEM_OP, &mem_op);
+    if (ret < 0) {
+        error_report("KVM_S390_MEM_OP failed: %s", strerror(-ret));
+    }
+    return ret;
+}
+
 /*
  * Legacy layout for s390:
  * Older S390 KVM requires the topmost vma of the RAM to be
diff --git a/target/s390x/kvm_s390x.h b/target/s390x/kvm_s390x.h
index 0b21789796..9c38f6ccce 100644
--- a/target/s390x/kvm_s390x.h
+++ b/target/s390x/kvm_s390x.h
@@ -19,6 +19,8 @@ void kvm_s390_vcpu_interrupt(S390CPU *cpu, struct kvm_s390_irq *irq);
 void kvm_s390_access_exception(S390CPU *cpu, uint16_t code, uint64_t te_code);
 int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf,
                     int len, bool is_write);
+int kvm_s390_mem_op_pv(S390CPU *cpu, vaddr addr, void *hostbuf, int len,
+                       bool is_write);
 void kvm_s390_program_interrupt(S390CPU *cpu, uint16_t code);
 int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state);
 void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu);
diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c
index 0be2f300bb..7d9f3059cd 100644
--- a/target/s390x/mmu_helper.c
+++ b/target/s390x/mmu_helper.c
@@ -474,6 +474,20 @@ static int translate_pages(S390CPU *cpu, vaddr addr, int nr_pages,
     return 0;
 }
 
+int s390_cpu_pv_mem_rw(S390CPU *cpu, unsigned int offset, void *hostbuf,
+                       int len, bool is_write)
+{
+    int ret;
+
+    if (kvm_enabled()) {
+        ret = kvm_s390_mem_op_pv(cpu, offset, hostbuf, len, is_write);
+    } else {
+        /* Protected Virtualization is a KVM/Hardware only feature */
+        g_assert_not_reached();
+    }
+    return ret;
+}
+
 /**
  * s390_cpu_virt_mem_rw:
  * @laddr:     the logical start address
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v6 09/18] s390x: protvirt: Move STSI data over SIDAD
  2020-03-04 11:42 [PATCH v6 00/18] s390x: Protected Virtualization support Janosch Frank
                   ` (7 preceding siblings ...)
  2020-03-04 11:42 ` [PATCH v6 08/18] s390x: Add SIDA memory ops Janosch Frank
@ 2020-03-04 11:42 ` Janosch Frank
  2020-03-04 17:43   ` David Hildenbrand
  2020-03-04 11:42 ` [PATCH v6 10/18] s390x: protvirt: SCLP interpretation Janosch Frank
                   ` (9 subsequent siblings)
  18 siblings, 1 reply; 72+ messages in thread
From: Janosch Frank @ 2020-03-04 11:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck, david

For protected guests, we need to put the STSI emulation results into
the SIDA, so SIE will write them into the guest at the next entry.

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
Acked-by: David Hildenbrand <david@redhat.com>
---
 target/s390x/kvm.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
index cdcd538b4f..43fc0c088b 100644
--- a/target/s390x/kvm.c
+++ b/target/s390x/kvm.c
@@ -1797,11 +1797,16 @@ static int handle_tsch(S390CPU *cpu)
 
 static void insert_stsi_3_2_2(S390CPU *cpu, __u64 addr, uint8_t ar)
 {
+    CPUS390XState *env = &cpu->env;
     SysIB_322 sysib;
     int del;
 
-    if (s390_cpu_virt_mem_read(cpu, addr, ar, &sysib, sizeof(sysib))) {
-        return;
+    if (env->pv) {
+        s390_cpu_pv_mem_read(cpu, 0, &sysib, sizeof(sysib));
+    } else {
+        if (s390_cpu_virt_mem_read(cpu, addr, ar, &sysib, sizeof(sysib))) {
+            return;
+        }
     }
     /* Shift the stack of Extended Names to prepare for our own data */
     memmove(&sysib.ext_names[1], &sysib.ext_names[0],
@@ -1840,7 +1845,11 @@ static void insert_stsi_3_2_2(S390CPU *cpu, __u64 addr, uint8_t ar)
     /* Insert UUID */
     memcpy(sysib.vm[0].uuid, &qemu_uuid, sizeof(sysib.vm[0].uuid));
 
-    s390_cpu_virt_mem_write(cpu, addr, ar, &sysib, sizeof(sysib));
+    if (env->pv) {
+        s390_cpu_pv_mem_write(cpu, 0, &sysib, sizeof(sysib));
+    } else {
+        s390_cpu_virt_mem_write(cpu, addr, ar, &sysib, sizeof(sysib));
+    }
 }
 
 static int handle_stsi(S390CPU *cpu)
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v6 10/18] s390x: protvirt: SCLP interpretation
  2020-03-04 11:42 [PATCH v6 00/18] s390x: Protected Virtualization support Janosch Frank
                   ` (8 preceding siblings ...)
  2020-03-04 11:42 ` [PATCH v6 09/18] s390x: protvirt: Move STSI data over SIDAD Janosch Frank
@ 2020-03-04 11:42 ` Janosch Frank
  2020-03-04 17:48   ` David Hildenbrand
  2020-03-04 11:42 ` [PATCH v6 11/18] s390x: protvirt: Set guest IPL PSW Janosch Frank
                   ` (8 subsequent siblings)
  18 siblings, 1 reply; 72+ messages in thread
From: Janosch Frank @ 2020-03-04 11:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck, david

SCLP for a protected guest is done over the SIDAD, so we need to use
the s390_cpu_virt_mem_* functions to access the SIDAD instead of guest
memory when reading/writing SCBs.

To not confuse the sclp emulation, we set 0x4000 as the SCCB address,
since the function that injects the sclp external interrupt would
reject a zero sccb address.

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
---
 hw/s390x/sclp.c         | 17 +++++++++++++++++
 include/hw/s390x/sclp.h |  2 ++
 target/s390x/kvm.c      |  5 +++++
 3 files changed, 24 insertions(+)

diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
index af0bfbc2ec..5136f5fcbe 100644
--- a/hw/s390x/sclp.c
+++ b/hw/s390x/sclp.c
@@ -193,6 +193,23 @@ static void sclp_execute(SCLPDevice *sclp, SCCB *sccb, uint32_t code)
     }
 }
 
+#define SCLP_PV_DUMMY_ADDR 0x4000
+int sclp_service_call_protected(CPUS390XState *env, uint64_t sccb,
+                                uint32_t code)
+{
+    SCLPDevice *sclp = get_sclp_device();
+    SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp);
+    SCCB work_sccb;
+    hwaddr sccb_len = sizeof(SCCB);
+
+    s390_cpu_pv_mem_read(env_archcpu(env), 0, &work_sccb, sccb_len);
+    sclp_c->execute(sclp, &work_sccb, code);
+    s390_cpu_pv_mem_write(env_archcpu(env), 0, &work_sccb,
+                          be16_to_cpu(work_sccb.h.length));
+    sclp_c->service_interrupt(sclp, SCLP_PV_DUMMY_ADDR);
+    return 0;
+}
+
 int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code)
 {
     SCLPDevice *sclp = get_sclp_device();
diff --git a/include/hw/s390x/sclp.h b/include/hw/s390x/sclp.h
index c54413b78c..c0a3faa37d 100644
--- a/include/hw/s390x/sclp.h
+++ b/include/hw/s390x/sclp.h
@@ -217,5 +217,7 @@ void s390_sclp_init(void);
 void sclp_service_interrupt(uint32_t sccb);
 void raise_irq_cpu_hotplug(void);
 int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code);
+int sclp_service_call_protected(CPUS390XState *env, uint64_t sccb,
+                                uint32_t code);
 
 #endif
diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
index 43fc0c088b..a4cbdc5fc6 100644
--- a/target/s390x/kvm.c
+++ b/target/s390x/kvm.c
@@ -1226,6 +1226,11 @@ static void kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run,
     sccb = env->regs[ipbh0 & 0xf];
     code = env->regs[(ipbh0 & 0xf0) >> 4];
 
+    if (run->s390_sieic.icptcode == ICPT_PV_INSTR) {
+        sclp_service_call_protected(env, sccb, code);
+        return;
+    }
+
     r = sclp_service_call(env, sccb, code);
     if (r < 0) {
         kvm_s390_program_interrupt(cpu, -r);
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v6 11/18] s390x: protvirt: Set guest IPL PSW
  2020-03-04 11:42 [PATCH v6 00/18] s390x: Protected Virtualization support Janosch Frank
                   ` (9 preceding siblings ...)
  2020-03-04 11:42 ` [PATCH v6 10/18] s390x: protvirt: SCLP interpretation Janosch Frank
@ 2020-03-04 11:42 ` Janosch Frank
  2020-03-04 17:51   ` David Hildenbrand
  2020-03-04 11:42 ` [PATCH v6 12/18] s390x: protvirt: Move diag 308 data over SIDAD Janosch Frank
                   ` (7 subsequent siblings)
  18 siblings, 1 reply; 72+ messages in thread
From: Janosch Frank @ 2020-03-04 11:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck, david

Handling of CPU reset and setting of the IPL psw from guest storage at
offset 0 is done by a Ultravisor call. Let's only fetch it if
necessary.

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
---
 target/s390x/cpu.c | 23 ++++++++++++++---------
 1 file changed, 14 insertions(+), 9 deletions(-)

diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
index 69b1cc5dfc..7840e784f1 100644
--- a/target/s390x/cpu.c
+++ b/target/s390x/cpu.c
@@ -78,16 +78,21 @@ static bool s390_cpu_has_work(CPUState *cs)
 static void s390_cpu_load_normal(CPUState *s)
 {
     S390CPU *cpu = S390_CPU(s);
-    uint64_t spsw = ldq_phys(s->as, 0);
-
-    cpu->env.psw.mask = spsw & PSW_MASK_SHORT_CTRL;
-    /*
-     * Invert short psw indication, so SIE will report a specification
-     * exception if it was not set.
-     */
-    cpu->env.psw.mask ^= PSW_MASK_SHORTPSW;
-    cpu->env.psw.addr = spsw & PSW_MASK_SHORT_ADDR;
+    CPUS390XState *env = &cpu->env;
+    uint64_t spsw;
 
+    if (!env->pv) {
+        spsw = ldq_phys(s->as, 0);
+        cpu->env.psw.mask = spsw & PSW_MASK_SHORT_CTRL;
+        /*
+         * Invert short psw indication, so SIE will report a specification
+         * exception if it was not set.
+         */
+        cpu->env.psw.mask ^= PSW_MASK_SHORTPSW;
+        cpu->env.psw.addr = spsw & PSW_MASK_SHORT_ADDR;
+    } else {
+        s390_cpu_set_state(S390_CPU_STATE_LOAD, cpu);
+    }
     s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
 }
 #endif
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v6 12/18] s390x: protvirt: Move diag 308 data over SIDAD
  2020-03-04 11:42 [PATCH v6 00/18] s390x: Protected Virtualization support Janosch Frank
                   ` (10 preceding siblings ...)
  2020-03-04 11:42 ` [PATCH v6 11/18] s390x: protvirt: Set guest IPL PSW Janosch Frank
@ 2020-03-04 11:42 ` Janosch Frank
  2020-03-04 17:54   ` David Hildenbrand
  2020-03-04 11:42 ` [PATCH v6 13/18] s390x: protvirt: Disable address checks for PV guest IO emulation Janosch Frank
                   ` (6 subsequent siblings)
  18 siblings, 1 reply; 72+ messages in thread
From: Janosch Frank @ 2020-03-04 11:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck, david

For protected guests the IPIB is written/read to/from the satellite
block, so we need those accesses to go through
s390_cpu_pv_mem_read/write().

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
---
 target/s390x/diag.c | 30 +++++++++++++++++++++++-------
 1 file changed, 23 insertions(+), 7 deletions(-)

diff --git a/target/s390x/diag.c b/target/s390x/diag.c
index a6cd1ea260..444c88ef15 100644
--- a/target/s390x/diag.c
+++ b/target/s390x/diag.c
@@ -87,6 +87,7 @@ static int diag308_parm_check(CPUS390XState *env, uint64_t r1, uint64_t addr,
 void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
 {
     CPUState *cs = env_cpu(env);
+    S390CPU *cpu = S390_CPU(cs);
     uint64_t addr =  env->regs[r1];
     uint64_t subcode = env->regs[r3];
     IplParameterBlock *iplb;
@@ -118,13 +119,22 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
             return;
         }
         iplb = g_new0(IplParameterBlock, 1);
-        cpu_physical_memory_read(addr, iplb, sizeof(iplb->len));
+        if (!env->pv) {
+            cpu_physical_memory_read(addr, iplb, sizeof(iplb->len));
+        } else {
+            s390_cpu_pv_mem_read(cpu, 0, iplb, sizeof(iplb->len));
+        }
+
         if (!iplb_valid_len(iplb)) {
             env->regs[r1 + 1] = DIAG_308_RC_INVALID;
             goto out;
         }
 
-        cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len));
+        if (!env->pv) {
+            cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len));
+        } else {
+            s390_cpu_pv_mem_read(cpu, 0, iplb, be32_to_cpu(iplb->len));
+        }
 
         if (!iplb_valid_ccw(iplb) && !iplb_valid_fcp(iplb) &&
             !(iplb_valid_pv(iplb) && !s390_ipl_pv_check_components(iplb))) {
@@ -136,7 +146,7 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
         env->regs[r1 + 1] = DIAG_308_RC_OK;
 out:
         g_free(iplb);
-        return;
+        break;
     case DIAG308_STORE:
     case DIAG308_PV_STORE:
         if (diag308_parm_check(env, r1, addr, ra, true)) {
@@ -147,12 +157,18 @@ out:
         } else {
             iplb = s390_ipl_get_iplb();
         }
-        if (iplb) {
-            cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len));
-            env->regs[r1 + 1] = DIAG_308_RC_OK;
-        } else {
+        if (!iplb) {
             env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;
+            return;
         }
+
+        if (!env->pv) {
+            cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len));
+        } else {
+            s390_cpu_pv_mem_write(cpu, 0, iplb, be32_to_cpu(iplb->len));
+        }
+
+        env->regs[r1 + 1] = DIAG_308_RC_OK;
         break;
     case DIAG308_PV_START:
         iplb = s390_ipl_get_iplb_secure();
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v6 13/18] s390x: protvirt: Disable address checks for PV guest IO emulation
  2020-03-04 11:42 [PATCH v6 00/18] s390x: Protected Virtualization support Janosch Frank
                   ` (11 preceding siblings ...)
  2020-03-04 11:42 ` [PATCH v6 12/18] s390x: protvirt: Move diag 308 data over SIDAD Janosch Frank
@ 2020-03-04 11:42 ` Janosch Frank
  2020-03-04 17:55   ` David Hildenbrand
  2020-03-04 11:42 ` [PATCH v6 14/18] s390x: protvirt: Move IO control structures over SIDA Janosch Frank
                   ` (5 subsequent siblings)
  18 siblings, 1 reply; 72+ messages in thread
From: Janosch Frank @ 2020-03-04 11:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck, david

IO instruction data is routed through SIDAD for protected guests, so
adresses do not need to be checked, as this is kernel memory.

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
---
 target/s390x/ioinst.c | 26 +++++++++++++++++++-------
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c
index c437a1d8c6..e4102430aa 100644
--- a/target/s390x/ioinst.c
+++ b/target/s390x/ioinst.c
@@ -17,6 +17,16 @@
 #include "trace.h"
 #include "hw/s390x/s390-pci-bus.h"
 
+static uint64_t get_address_from_regs(CPUS390XState *env, uint32_t ipb,
+                                      uint8_t *ar)
+{
+    if (env->pv) {
+        *ar = 0;
+        return 0;
+    }
+    return decode_basedisp_s(env, ipb, ar);
+}
+
 int ioinst_disassemble_sch_ident(uint32_t value, int *m, int *cssid, int *ssid,
                                  int *schid)
 {
@@ -114,7 +124,7 @@ void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra)
     CPUS390XState *env = &cpu->env;
     uint8_t ar;
 
-    addr = decode_basedisp_s(env, ipb, &ar);
+    addr = get_address_from_regs(env, ipb, &ar);
     if (addr & 3) {
         s390_program_interrupt(env, PGM_SPECIFICATION, ra);
         return;
@@ -171,7 +181,7 @@ void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra)
     CPUS390XState *env = &cpu->env;
     uint8_t ar;
 
-    addr = decode_basedisp_s(env, ipb, &ar);
+    addr = get_address_from_regs(env, ipb, &ar);
     if (addr & 3) {
         s390_program_interrupt(env, PGM_SPECIFICATION, ra);
         return;
@@ -203,7 +213,7 @@ void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb, uintptr_t ra)
     CPUS390XState *env = &cpu->env;
     uint8_t ar;
 
-    addr = decode_basedisp_s(env, ipb, &ar);
+    addr = get_address_from_regs(env, ipb, &ar);
     if (addr & 3) {
         s390_program_interrupt(env, PGM_SPECIFICATION, ra);
         return;
@@ -234,7 +244,7 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb,
     CPUS390XState *env = &cpu->env;
     uint8_t ar;
 
-    addr = decode_basedisp_s(env, ipb, &ar);
+    addr = get_address_from_regs(env, ipb, &ar);
     if (addr & 3) {
         s390_program_interrupt(env, PGM_SPECIFICATION, ra);
         return;
@@ -303,7 +313,7 @@ int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra)
         return -EIO;
     }
     trace_ioinst_sch_id("tsch", cssid, ssid, schid);
-    addr = decode_basedisp_s(env, ipb, &ar);
+    addr = get_address_from_regs(env, ipb, &ar);
     if (addr & 3) {
         s390_program_interrupt(env, PGM_SPECIFICATION, ra);
         return -EIO;
@@ -601,7 +611,7 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra)
 {
     ChscReq *req;
     ChscResp *res;
-    uint64_t addr;
+    uint64_t addr = 0;
     int reg;
     uint16_t len;
     uint16_t command;
@@ -610,7 +620,9 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra)
 
     trace_ioinst("chsc");
     reg = (ipb >> 20) & 0x00f;
-    addr = env->regs[reg];
+    if (!env->pv) {
+        addr = env->regs[reg];
+    }
     /* Page boundary? */
     if (addr & 0xfff) {
         s390_program_interrupt(env, PGM_SPECIFICATION, ra);
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v6 14/18] s390x: protvirt: Move IO control structures over SIDA
  2020-03-04 11:42 [PATCH v6 00/18] s390x: Protected Virtualization support Janosch Frank
                   ` (12 preceding siblings ...)
  2020-03-04 11:42 ` [PATCH v6 13/18] s390x: protvirt: Disable address checks for PV guest IO emulation Janosch Frank
@ 2020-03-04 11:42 ` Janosch Frank
  2020-03-04 18:56   ` David Hildenbrand
  2020-03-04 11:42 ` [PATCH v6 15/18] s390x: protvirt: Handle SIGP store status correctly Janosch Frank
                   ` (4 subsequent siblings)
  18 siblings, 1 reply; 72+ messages in thread
From: Janosch Frank @ 2020-03-04 11:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck, david

For protected guests, we need to put the IO emulation results into the
SIDA, so SIE will write them into the guest at the next entry.

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
---
 target/s390x/ioinst.c | 87 ++++++++++++++++++++++++++++++-------------
 1 file changed, 61 insertions(+), 26 deletions(-)

diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c
index e4102430aa..330b04d79a 100644
--- a/target/s390x/ioinst.c
+++ b/target/s390x/ioinst.c
@@ -129,9 +129,13 @@ void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra)
         s390_program_interrupt(env, PGM_SPECIFICATION, ra);
         return;
     }
-    if (s390_cpu_virt_mem_read(cpu, addr, ar, &schib, sizeof(schib))) {
-        s390_cpu_virt_mem_handle_exc(cpu, ra);
-        return;
+    if (env->pv) {
+        s390_cpu_pv_mem_read(cpu, addr, &schib, sizeof(schib));
+    } else {
+        if (s390_cpu_virt_mem_read(cpu, addr, ar, &schib, sizeof(schib))) {
+            s390_cpu_virt_mem_handle_exc(cpu, ra);
+            return;
+        }
     }
     if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) ||
         !ioinst_schib_valid(&schib)) {
@@ -186,9 +190,13 @@ void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra)
         s390_program_interrupt(env, PGM_SPECIFICATION, ra);
         return;
     }
-    if (s390_cpu_virt_mem_read(cpu, addr, ar, &orig_orb, sizeof(orb))) {
-        s390_cpu_virt_mem_handle_exc(cpu, ra);
-        return;
+    if (env->pv) {
+        s390_cpu_pv_mem_read(cpu, addr, &orig_orb, sizeof(orb));
+    } else {
+        if (s390_cpu_virt_mem_read(cpu, addr, ar, &orig_orb, sizeof(orb))) {
+            s390_cpu_virt_mem_handle_exc(cpu, ra);
+            return;
+        }
     }
     copy_orb_from_guest(&orb, &orig_orb);
     if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) ||
@@ -222,14 +230,19 @@ void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb, uintptr_t ra)
     cc = css_do_stcrw(&crw);
     /* 0 - crw stored, 1 - zeroes stored */
 
-    if (s390_cpu_virt_mem_write(cpu, addr, ar, &crw, sizeof(crw)) == 0) {
+    if (env->pv) {
+        s390_cpu_pv_mem_write(cpu, addr, &crw, sizeof(crw));
         setcc(cpu, cc);
     } else {
-        if (cc == 0) {
-            /* Write failed: requeue CRW since STCRW is suppressing */
-            css_undo_stcrw(&crw);
+        if (s390_cpu_virt_mem_write(cpu, addr, ar, &crw, sizeof(crw)) == 0) {
+            setcc(cpu, cc);
+        } else {
+            if (cc == 0) {
+                /* Write failed: requeue CRW since STCRW is suppressing */
+                css_undo_stcrw(&crw);
+            }
+            s390_cpu_virt_mem_handle_exc(cpu, ra);
         }
-        s390_cpu_virt_mem_handle_exc(cpu, ra);
     }
 }
 
@@ -251,6 +264,9 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb,
     }
 
     if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
+        if (env->pv) {
+            return;
+        }
         /*
          * As operand exceptions have a lower priority than access exceptions,
          * we check whether the memory area is writeable (injecting the
@@ -283,14 +299,19 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb,
         }
     }
     if (cc != 3) {
-        if (s390_cpu_virt_mem_write(cpu, addr, ar, &schib,
-                                    sizeof(schib)) != 0) {
-            s390_cpu_virt_mem_handle_exc(cpu, ra);
-            return;
+        if (env->pv) {
+            s390_cpu_pv_mem_write(cpu, addr, &schib, sizeof(schib));
+        } else {
+            if (s390_cpu_virt_mem_write(cpu, addr, ar, &schib,
+                                        sizeof(schib)) != 0) {
+                s390_cpu_virt_mem_handle_exc(cpu, ra);
+                return;
+            }
         }
     } else {
         /* Access exceptions have a higher priority than cc3 */
-        if (s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib)) != 0) {
+        if (!env->pv &&
+            s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib)) != 0) {
             s390_cpu_virt_mem_handle_exc(cpu, ra);
             return;
         }
@@ -327,15 +348,20 @@ int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra)
     }
     /* 0 - status pending, 1 - not status pending, 3 - not operational */
     if (cc != 3) {
-        if (s390_cpu_virt_mem_write(cpu, addr, ar, &irb, irb_len) != 0) {
-            s390_cpu_virt_mem_handle_exc(cpu, ra);
-            return -EFAULT;
+        if (env->pv) {
+            s390_cpu_pv_mem_write(cpu, addr, &irb, irb_len);
+        } else {
+            if (s390_cpu_virt_mem_write(cpu, addr, ar, &irb, irb_len) != 0) {
+                s390_cpu_virt_mem_handle_exc(cpu, ra);
+                return -EFAULT;
+            }
         }
         css_do_tsch_update_subch(sch);
     } else {
         irb_len = sizeof(irb) - sizeof(irb.emw);
         /* Access exceptions have a higher priority than cc3 */
-        if (s390_cpu_virt_mem_check_write(cpu, addr, ar, irb_len) != 0) {
+        if (!env->pv &&
+            s390_cpu_virt_mem_check_write(cpu, addr, ar, irb_len) != 0) {
             s390_cpu_virt_mem_handle_exc(cpu, ra);
             return -EFAULT;
         }
@@ -633,9 +659,13 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra)
      * present CHSC sub-handlers ... if we ever need more, we should take
      * care of req->len here first.
      */
-    if (s390_cpu_virt_mem_read(cpu, addr, reg, buf, sizeof(ChscReq))) {
-        s390_cpu_virt_mem_handle_exc(cpu, ra);
-        return;
+    if (env->pv) {
+        s390_cpu_pv_mem_read(cpu, addr, buf, sizeof(ChscReq));
+    } else {
+        if (s390_cpu_virt_mem_read(cpu, addr, reg, buf, sizeof(ChscReq))) {
+            s390_cpu_virt_mem_handle_exc(cpu, ra);
+            return;
+        }
     }
     req = (ChscReq *)buf;
     len = be16_to_cpu(req->len);
@@ -666,11 +696,16 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra)
         break;
     }
 
-    if (!s390_cpu_virt_mem_write(cpu, addr + len, reg, res,
-                                 be16_to_cpu(res->len))) {
+    if (env->pv) {
+        s390_cpu_pv_mem_write(cpu, addr + len, res, be16_to_cpu(res->len));
         setcc(cpu, 0);    /* Command execution complete */
     } else {
-        s390_cpu_virt_mem_handle_exc(cpu, ra);
+        if (!s390_cpu_virt_mem_write(cpu, addr + len, reg, res,
+                                     be16_to_cpu(res->len))) {
+            setcc(cpu, 0);    /* Command execution complete */
+        } else {
+            s390_cpu_virt_mem_handle_exc(cpu, ra);
+        }
     }
 }
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v6 15/18] s390x: protvirt: Handle SIGP store status correctly
  2020-03-04 11:42 [PATCH v6 00/18] s390x: Protected Virtualization support Janosch Frank
                   ` (13 preceding siblings ...)
  2020-03-04 11:42 ` [PATCH v6 14/18] s390x: protvirt: Move IO control structures over SIDA Janosch Frank
@ 2020-03-04 11:42 ` Janosch Frank
  2020-03-04 18:41   ` David Hildenbrand
  2020-03-04 11:42 ` [PATCH v6 16/18] s390x: Add unpack facility feature to GA1 Janosch Frank
                   ` (3 subsequent siblings)
  18 siblings, 1 reply; 72+ messages in thread
From: Janosch Frank @ 2020-03-04 11:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck, david

Status storing is not done by QEMU anymore, but is handled by SIE.

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
---
 target/s390x/helper.c | 4 ++++
 target/s390x/sigp.c   | 1 +
 2 files changed, 5 insertions(+)

diff --git a/target/s390x/helper.c b/target/s390x/helper.c
index ed72684911..8b91ed68f0 100644
--- a/target/s390x/helper.c
+++ b/target/s390x/helper.c
@@ -246,6 +246,10 @@ int s390_store_status(S390CPU *cpu, hwaddr addr, bool store_arch)
     hwaddr len = sizeof(*sa);
     int i;
 
+    if (cpu->env.pv) {
+        return 0;
+    }
+
     sa = cpu_physical_memory_map(addr, &len, true);
     if (!sa) {
         return -EFAULT;
diff --git a/target/s390x/sigp.c b/target/s390x/sigp.c
index c604f17710..e1c8071464 100644
--- a/target/s390x/sigp.c
+++ b/target/s390x/sigp.c
@@ -497,6 +497,7 @@ void do_stop_interrupt(CPUS390XState *env)
     if (s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu) == 0) {
         qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
     }
+    /* Storing will occur on next SIE entry for protected VMs */
     if (cpu->env.sigp_order == SIGP_STOP_STORE_STATUS) {
         s390_store_status(cpu, S390_STORE_STATUS_DEF_ADDR, true);
     }
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v6 16/18] s390x: Add unpack facility feature to GA1
  2020-03-04 11:42 [PATCH v6 00/18] s390x: Protected Virtualization support Janosch Frank
                   ` (14 preceding siblings ...)
  2020-03-04 11:42 ` [PATCH v6 15/18] s390x: protvirt: Handle SIGP store status correctly Janosch Frank
@ 2020-03-04 11:42 ` Janosch Frank
  2020-03-04 18:42   ` David Hildenbrand
  2020-03-06 10:14   ` Janosch Frank
  2020-03-04 11:42 ` [PATCH v6 17/18] docs: Add protvirt docs Janosch Frank
                   ` (2 subsequent siblings)
  18 siblings, 2 replies; 72+ messages in thread
From: Janosch Frank @ 2020-03-04 11:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck, david

From: Christian Borntraeger <borntraeger@de.ibm.com>

The unpack facility is an indication that diagnose 308 subcodes 8-10
are available to the guest. That means, that the guest can put itself
into protected mode.

Once it is in protected mode, the hardware stops any attempt of VM
introspection by the hypervisor.

Some features are currently not supported in protected mode:
     * Passthrough devices
     * Migration
     * Huge page backings

Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
 target/s390x/gen-features.c | 1 +
 target/s390x/kvm.c          | 5 +++++
 2 files changed, 6 insertions(+)

diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
index 6278845b12..8ddeebc544 100644
--- a/target/s390x/gen-features.c
+++ b/target/s390x/gen-features.c
@@ -562,6 +562,7 @@ static uint16_t full_GEN15_GA1[] = {
     S390_FEAT_GROUP_MSA_EXT_9,
     S390_FEAT_GROUP_MSA_EXT_9_PCKMO,
     S390_FEAT_ETOKEN,
+    S390_FEAT_UNPACK,
 };
 
 /* Default features (in order of release)
diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
index a4cbdc5fc6..bf807793bc 100644
--- a/target/s390x/kvm.c
+++ b/target/s390x/kvm.c
@@ -2396,6 +2396,11 @@ void kvm_s390_get_host_cpu_model(S390CPUModel *model, Error **errp)
         clear_bit(S390_FEAT_BPB, model->features);
     }
 
+    /* we do have the IPL enhancements */
+    if (cap_protected) {
+        set_bit(S390_FEAT_UNPACK, model->features);
+    }
+
     /* We emulate a zPCI bus and AEN, therefore we don't need HW support */
     set_bit(S390_FEAT_ZPCI, model->features);
     set_bit(S390_FEAT_ADAPTER_EVENT_NOTIFICATION, model->features);
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v6 17/18] docs: Add protvirt docs
  2020-03-04 11:42 [PATCH v6 00/18] s390x: Protected Virtualization support Janosch Frank
                   ` (15 preceding siblings ...)
  2020-03-04 11:42 ` [PATCH v6 16/18] s390x: Add unpack facility feature to GA1 Janosch Frank
@ 2020-03-04 11:42 ` Janosch Frank
  2020-03-04 19:09   ` David Hildenbrand
  2020-03-04 11:42 ` [PATCH v6 18/18] pc-bios: s390x: Save iplb location in lowcore Janosch Frank
  2020-03-04 17:15 ` [PATCH v6 00/18] s390x: Protected Virtualization support David Hildenbrand
  18 siblings, 1 reply; 72+ messages in thread
From: Janosch Frank @ 2020-03-04 11:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck, david

Lets add some documentation for the Protected VM functionality.

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
---
 docs/system/index.rst    |  1 +
 docs/system/protvirt.rst | 57 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 58 insertions(+)
 create mode 100644 docs/system/protvirt.rst

diff --git a/docs/system/index.rst b/docs/system/index.rst
index 1a4b2c82ac..d2dc63b973 100644
--- a/docs/system/index.rst
+++ b/docs/system/index.rst
@@ -16,3 +16,4 @@ Contents:
 
    qemu-block-drivers
    vfio-ap
+   protvirt
diff --git a/docs/system/protvirt.rst b/docs/system/protvirt.rst
new file mode 100644
index 0000000000..a1902cc47c
--- /dev/null
+++ b/docs/system/protvirt.rst
@@ -0,0 +1,57 @@
+Protected Virtualization on s390x
+=================================
+
+The memory and most of the register contents of Protected Virtual
+Machines (PVMs) are inaccessible to the hypervisor, effectively
+prohibiting VM introspection when the VM is running. At rest, PVMs are
+encrypted and can only be decrypted by the firmware of specific IBM Z
+machines.
+
+
+Prerequisites
+-------------
+
+To run PVMs, you need to have a machine with the Protected
+Virtualization feature, which is indicated by the Ultravisor Call
+facility (stfle bit 158). This is a KVM only feature, therefore you
+need a KVM which is able to support PVMs and activate the Ultravisor
+initialization by setting `prot_virt=1` on the kernel command line.
+
+If those requirements are met, the capability `KVM_CAP_S390_PROTECTED`
+will indicate that KVM can support PVMs on that LPAR.
+
+
+QEMU Settings
+-------------
+
+To indicate to the VM that it can move into protected mode, the
+`Unpack facility` (stfle bit 161) needs to be part of the cpu model of
+the VM.
+
+All I/O devices need to use the IOMMU.
+Passthrough (vfio) devices are currently not supported.
+
+Host huge page backings are not supported. The guest however can use
+huge pages as indicated by its facilities.
+
+
+Boot Process
+------------
+
+A secure guest image can be both booted from disk and using the QEMU
+command line. Booting from disk is done by the unmodified s390-ccw
+BIOS. I.e., the bootmap is interpreted and a number of components is
+read into memory and control is transferred to one of the components
+(zipl stage3), which does some fixups and then transfers control to
+some program residing in guest memory, which is normally the OS
+kernel. The secure image has another component prepended (stage3a)
+which uses the new diag308 subcodes 8 and 10 to trigger the transition
+into secure mode.
+
+Booting from the command line requires that the file passed
+via -kernel has the same memory layout as would result from the disk
+boot. This memory layout includes the encrypted components (kernel,
+initrd, cmdline), the stage3a loader and metadata. In case this boot
+method is used, the command line options -initrd and -cmdline are
+ineffective.  The preparation of secure guest image is done by a
+program (name tbd) of the s390-tools package.
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 72+ messages in thread

* [PATCH v6 18/18] pc-bios: s390x: Save iplb location in lowcore
  2020-03-04 11:42 [PATCH v6 00/18] s390x: Protected Virtualization support Janosch Frank
                   ` (16 preceding siblings ...)
  2020-03-04 11:42 ` [PATCH v6 17/18] docs: Add protvirt docs Janosch Frank
@ 2020-03-04 11:42 ` Janosch Frank
  2020-03-04 12:40   ` David Hildenbrand
                     ` (2 more replies)
  2020-03-04 17:15 ` [PATCH v6 00/18] s390x: Protected Virtualization support David Hildenbrand
  18 siblings, 3 replies; 72+ messages in thread
From: Janosch Frank @ 2020-03-04 11:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck, david

The POP states that for a list directed IPL the IPLB is stored into
memory by the machine loader and its address is stored at offset 0x14
of the lowcore.

ZIPL currently uses the address in offset 0x14 to access the IPLB and
acquire flags about secure boot. If the IPLB address points into
memory which has an unsupported mix of flags set, ZIPL will panic
instead of booting the OS.

As the lowcore can have quite a high entropy for a guest that did drop
out of protected mode (i.e. rebooted) we encountered the ZIPL panic
quite often.

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
Tested-by: Marc Hartmayer <mhartmay@linux.ibm.com>
---
 pc-bios/s390-ccw/jump2ipl.c  |  1 +
 pc-bios/s390-ccw/main.c      |  8 +++++++-
 pc-bios/s390-ccw/netmain.c   |  1 +
 pc-bios/s390-ccw/s390-arch.h | 10 ++++++++--
 pc-bios/s390-ccw/s390-ccw.h  |  1 +
 5 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
index da13c43cc0..4eba2510b0 100644
--- a/pc-bios/s390-ccw/jump2ipl.c
+++ b/pc-bios/s390-ccw/jump2ipl.c
@@ -35,6 +35,7 @@ void jump_to_IPL_code(uint64_t address)
 {
     /* store the subsystem information _after_ the bootmap was loaded */
     write_subsystem_identification();
+    write_iplb_location();
 
     /* prevent unknown IPL types in the guest */
     if (iplb.pbt == S390_IPL_TYPE_QEMU_SCSI) {
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index a21b386280..4e65b411e1 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -9,6 +9,7 @@
  */
 
 #include "libc.h"
+#include "helper.h"
 #include "s390-arch.h"
 #include "s390-ccw.h"
 #include "cio.h"
@@ -22,7 +23,7 @@ QemuIplParameters qipl;
 IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
 static bool have_iplb;
 static uint16_t cutype;
-LowCore const *lowcore; /* Yes, this *is* a pointer to address 0 */
+LowCore *lowcore; /* Yes, this *is* a pointer to address 0 */
 
 #define LOADPARM_PROMPT "PROMPT  "
 #define LOADPARM_EMPTY  "        "
@@ -42,6 +43,11 @@ void write_subsystem_identification(void)
     *zeroes = 0;
 }
 
+void write_iplb_location(void)
+{
+    lowcore->ptr_iplb = ptr2u32(&iplb);
+}
+
 void panic(const char *string)
 {
     sclp_print(string);
diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c
index f2dcc01e27..309ffa30d9 100644
--- a/pc-bios/s390-ccw/netmain.c
+++ b/pc-bios/s390-ccw/netmain.c
@@ -40,6 +40,7 @@
 #define DEFAULT_TFTP_RETRIES 20
 
 extern char _start[];
+void write_iplb_location(void) {}
 
 #define KERNEL_ADDR             ((void *)0L)
 #define KERNEL_MAX_SIZE         ((long)_start)
diff --git a/pc-bios/s390-ccw/s390-arch.h b/pc-bios/s390-ccw/s390-arch.h
index 504fc7c2f0..5f36361c02 100644
--- a/pc-bios/s390-ccw/s390-arch.h
+++ b/pc-bios/s390-ccw/s390-arch.h
@@ -36,7 +36,13 @@ typedef struct LowCore {
     /* prefix area: defined by architecture */
     PSWLegacy       ipl_psw;                  /* 0x000 */
     uint32_t        ccw1[2];                  /* 0x008 */
-    uint32_t        ccw2[2];                  /* 0x010 */
+    union {
+        uint32_t        ccw2[2];                  /* 0x010 */
+        struct {
+            uint32_t reserved10;
+            uint32_t ptr_iplb;
+        };
+    };
     uint8_t         pad1[0x80 - 0x18];        /* 0x018 */
     uint32_t        ext_params;               /* 0x080 */
     uint16_t        cpu_addr;                 /* 0x084 */
@@ -85,7 +91,7 @@ typedef struct LowCore {
     PSW             io_new_psw;               /* 0x1f0 */
 } __attribute__((packed, aligned(8192))) LowCore;
 
-extern LowCore const *lowcore;
+extern LowCore *lowcore;
 
 static inline void set_prefix(uint32_t address)
 {
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index 11bce7d73c..21f27e7990 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -57,6 +57,7 @@ void consume_io_int(void);
 /* main.c */
 void panic(const char *string);
 void write_subsystem_identification(void);
+void write_iplb_location(void);
 extern char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
 unsigned int get_loadparm_index(void);
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 18/18] pc-bios: s390x: Save iplb location in lowcore
  2020-03-04 11:42 ` [PATCH v6 18/18] pc-bios: s390x: Save iplb location in lowcore Janosch Frank
@ 2020-03-04 12:40   ` David Hildenbrand
  2020-03-04 13:25   ` Christian Borntraeger
  2020-03-05 17:04   ` Christian Borntraeger
  2 siblings, 0 replies; 72+ messages in thread
From: David Hildenbrand @ 2020-03-04 12:40 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

On 04.03.20 12:42, Janosch Frank wrote:
> The POP states that for a list directed IPL the IPLB is stored into
> memory by the machine loader and its address is stored at offset 0x14
> of the lowcore.
> 
> ZIPL currently uses the address in offset 0x14 to access the IPLB and
> acquire flags about secure boot. If the IPLB address points into
> memory which has an unsupported mix of flags set, ZIPL will panic
> instead of booting the OS.
> 
> As the lowcore can have quite a high entropy for a guest that did drop
> out of protected mode (i.e. rebooted) we encountered the ZIPL panic
> quite often.
> 
> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
> Tested-by: Marc Hartmayer <mhartmay@linux.ibm.com>
> ---
>  pc-bios/s390-ccw/jump2ipl.c  |  1 +
>  pc-bios/s390-ccw/main.c      |  8 +++++++-
>  pc-bios/s390-ccw/netmain.c   |  1 +
>  pc-bios/s390-ccw/s390-arch.h | 10 ++++++++--
>  pc-bios/s390-ccw/s390-ccw.h  |  1 +
>  5 files changed, 18 insertions(+), 3 deletions(-)
> 
> diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
> index da13c43cc0..4eba2510b0 100644
> --- a/pc-bios/s390-ccw/jump2ipl.c
> +++ b/pc-bios/s390-ccw/jump2ipl.c
> @@ -35,6 +35,7 @@ void jump_to_IPL_code(uint64_t address)
>  {
>      /* store the subsystem information _after_ the bootmap was loaded */
>      write_subsystem_identification();
> +    write_iplb_location();
>  
>      /* prevent unknown IPL types in the guest */
>      if (iplb.pbt == S390_IPL_TYPE_QEMU_SCSI) {
> diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
> index a21b386280..4e65b411e1 100644
> --- a/pc-bios/s390-ccw/main.c
> +++ b/pc-bios/s390-ccw/main.c
> @@ -9,6 +9,7 @@
>   */
>  
>  #include "libc.h"
> +#include "helper.h"
>  #include "s390-arch.h"
>  #include "s390-ccw.h"
>  #include "cio.h"
> @@ -22,7 +23,7 @@ QemuIplParameters qipl;
>  IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
>  static bool have_iplb;
>  static uint16_t cutype;
> -LowCore const *lowcore; /* Yes, this *is* a pointer to address 0 */
> +LowCore *lowcore; /* Yes, this *is* a pointer to address 0 */
>  
>  #define LOADPARM_PROMPT "PROMPT  "
>  #define LOADPARM_EMPTY  "        "
> @@ -42,6 +43,11 @@ void write_subsystem_identification(void)
>      *zeroes = 0;
>  }
>  
> +void write_iplb_location(void)
> +{
> +    lowcore->ptr_iplb = ptr2u32(&iplb);
> +}
> +
>  void panic(const char *string)
>  {
>      sclp_print(string);
> diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c
> index f2dcc01e27..309ffa30d9 100644
> --- a/pc-bios/s390-ccw/netmain.c
> +++ b/pc-bios/s390-ccw/netmain.c
> @@ -40,6 +40,7 @@
>  #define DEFAULT_TFTP_RETRIES 20
>  
>  extern char _start[];
> +void write_iplb_location(void) {}
>  
>  #define KERNEL_ADDR             ((void *)0L)
>  #define KERNEL_MAX_SIZE         ((long)_start)
> diff --git a/pc-bios/s390-ccw/s390-arch.h b/pc-bios/s390-ccw/s390-arch.h
> index 504fc7c2f0..5f36361c02 100644
> --- a/pc-bios/s390-ccw/s390-arch.h
> +++ b/pc-bios/s390-ccw/s390-arch.h
> @@ -36,7 +36,13 @@ typedef struct LowCore {
>      /* prefix area: defined by architecture */
>      PSWLegacy       ipl_psw;                  /* 0x000 */
>      uint32_t        ccw1[2];                  /* 0x008 */
> -    uint32_t        ccw2[2];                  /* 0x010 */
> +    union {
> +        uint32_t        ccw2[2];                  /* 0x010 */
> +        struct {
> +            uint32_t reserved10;
> +            uint32_t ptr_iplb;
> +        };
> +    };
>      uint8_t         pad1[0x80 - 0x18];        /* 0x018 */
>      uint32_t        ext_params;               /* 0x080 */
>      uint16_t        cpu_addr;                 /* 0x084 */
> @@ -85,7 +91,7 @@ typedef struct LowCore {
>      PSW             io_new_psw;               /* 0x1f0 */
>  } __attribute__((packed, aligned(8192))) LowCore;
>  
> -extern LowCore const *lowcore;
> +extern LowCore *lowcore;
>  
>  static inline void set_prefix(uint32_t address)
>  {
> diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
> index 11bce7d73c..21f27e7990 100644
> --- a/pc-bios/s390-ccw/s390-ccw.h
> +++ b/pc-bios/s390-ccw/s390-ccw.h
> @@ -57,6 +57,7 @@ void consume_io_int(void);
>  /* main.c */
>  void panic(const char *string);
>  void write_subsystem_identification(void);
> +void write_iplb_location(void);
>  extern char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
>  unsigned int get_loadparm_index(void);
>  
> 

Reviewed-by: David Hildenbrand <david@redhat.com>

-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 18/18] pc-bios: s390x: Save iplb location in lowcore
  2020-03-04 11:42 ` [PATCH v6 18/18] pc-bios: s390x: Save iplb location in lowcore Janosch Frank
  2020-03-04 12:40   ` David Hildenbrand
@ 2020-03-04 13:25   ` Christian Borntraeger
  2020-03-04 13:37     ` David Hildenbrand
  2020-03-05 17:04   ` Christian Borntraeger
  2 siblings, 1 reply; 72+ messages in thread
From: Christian Borntraeger @ 2020-03-04 13:25 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: qemu-s390x, cohuck, david

On 04.03.20 12:42, Janosch Frank wrote:
> The POP states that for a list directed IPL the IPLB is stored into
> memory by the machine loader and its address is stored at offset 0x14
> of the lowcore.
> 
> ZIPL currently uses the address in offset 0x14 to access the IPLB and
> acquire flags about secure boot. If the IPLB address points into
> memory which has an unsupported mix of flags set, ZIPL will panic
> instead of booting the OS.
> 
> As the lowcore can have quite a high entropy for a guest that did drop
> out of protected mode (i.e. rebooted) we encountered the ZIPL panic
> quite often.
> 
> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
> Tested-by: Marc Hartmayer <mhartmay@linux.ibm.com>

I think this makes sense even without protected virtualization, no?
Unless somebody complains, I think I will pick this up while Conny is
on vacation.



> ---
>  pc-bios/s390-ccw/jump2ipl.c  |  1 +
>  pc-bios/s390-ccw/main.c      |  8 +++++++-
>  pc-bios/s390-ccw/netmain.c   |  1 +
>  pc-bios/s390-ccw/s390-arch.h | 10 ++++++++--
>  pc-bios/s390-ccw/s390-ccw.h  |  1 +
>  5 files changed, 18 insertions(+), 3 deletions(-)
> 
> diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
> index da13c43cc0..4eba2510b0 100644
> --- a/pc-bios/s390-ccw/jump2ipl.c
> +++ b/pc-bios/s390-ccw/jump2ipl.c
> @@ -35,6 +35,7 @@ void jump_to_IPL_code(uint64_t address)
>  {
>      /* store the subsystem information _after_ the bootmap was loaded */
>      write_subsystem_identification();
> +    write_iplb_location();
>  
>      /* prevent unknown IPL types in the guest */
>      if (iplb.pbt == S390_IPL_TYPE_QEMU_SCSI) {
> diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
> index a21b386280..4e65b411e1 100644
> --- a/pc-bios/s390-ccw/main.c
> +++ b/pc-bios/s390-ccw/main.c
> @@ -9,6 +9,7 @@
>   */
>  
>  #include "libc.h"
> +#include "helper.h"
>  #include "s390-arch.h"
>  #include "s390-ccw.h"
>  #include "cio.h"
> @@ -22,7 +23,7 @@ QemuIplParameters qipl;
>  IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
>  static bool have_iplb;
>  static uint16_t cutype;
> -LowCore const *lowcore; /* Yes, this *is* a pointer to address 0 */
> +LowCore *lowcore; /* Yes, this *is* a pointer to address 0 */
>  
>  #define LOADPARM_PROMPT "PROMPT  "
>  #define LOADPARM_EMPTY  "        "
> @@ -42,6 +43,11 @@ void write_subsystem_identification(void)
>      *zeroes = 0;
>  }
>  
> +void write_iplb_location(void)
> +{
> +    lowcore->ptr_iplb = ptr2u32(&iplb);
> +}
> +
>  void panic(const char *string)
>  {
>      sclp_print(string);
> diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c
> index f2dcc01e27..309ffa30d9 100644
> --- a/pc-bios/s390-ccw/netmain.c
> +++ b/pc-bios/s390-ccw/netmain.c
> @@ -40,6 +40,7 @@
>  #define DEFAULT_TFTP_RETRIES 20
>  
>  extern char _start[];
> +void write_iplb_location(void) {}
>  
>  #define KERNEL_ADDR             ((void *)0L)
>  #define KERNEL_MAX_SIZE         ((long)_start)
> diff --git a/pc-bios/s390-ccw/s390-arch.h b/pc-bios/s390-ccw/s390-arch.h
> index 504fc7c2f0..5f36361c02 100644
> --- a/pc-bios/s390-ccw/s390-arch.h
> +++ b/pc-bios/s390-ccw/s390-arch.h
> @@ -36,7 +36,13 @@ typedef struct LowCore {
>      /* prefix area: defined by architecture */
>      PSWLegacy       ipl_psw;                  /* 0x000 */
>      uint32_t        ccw1[2];                  /* 0x008 */
> -    uint32_t        ccw2[2];                  /* 0x010 */
> +    union {
> +        uint32_t        ccw2[2];                  /* 0x010 */
> +        struct {
> +            uint32_t reserved10;
> +            uint32_t ptr_iplb;
> +        };
> +    };
>      uint8_t         pad1[0x80 - 0x18];        /* 0x018 */
>      uint32_t        ext_params;               /* 0x080 */
>      uint16_t        cpu_addr;                 /* 0x084 */
> @@ -85,7 +91,7 @@ typedef struct LowCore {
>      PSW             io_new_psw;               /* 0x1f0 */
>  } __attribute__((packed, aligned(8192))) LowCore;
>  
> -extern LowCore const *lowcore;
> +extern LowCore *lowcore;
>  
>  static inline void set_prefix(uint32_t address)
>  {
> diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
> index 11bce7d73c..21f27e7990 100644
> --- a/pc-bios/s390-ccw/s390-ccw.h
> +++ b/pc-bios/s390-ccw/s390-ccw.h
> @@ -57,6 +57,7 @@ void consume_io_int(void);
>  /* main.c */
>  void panic(const char *string);
>  void write_subsystem_identification(void);
> +void write_iplb_location(void);
>  extern char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
>  unsigned int get_loadparm_index(void);
>  
> 



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 18/18] pc-bios: s390x: Save iplb location in lowcore
  2020-03-04 13:25   ` Christian Borntraeger
@ 2020-03-04 13:37     ` David Hildenbrand
  0 siblings, 0 replies; 72+ messages in thread
From: David Hildenbrand @ 2020-03-04 13:37 UTC (permalink / raw)
  To: Christian Borntraeger, Janosch Frank, qemu-devel; +Cc: qemu-s390x, cohuck

On 04.03.20 14:25, Christian Borntraeger wrote:
> On 04.03.20 12:42, Janosch Frank wrote:
>> The POP states that for a list directed IPL the IPLB is stored into
>> memory by the machine loader and its address is stored at offset 0x14
>> of the lowcore.
>>
>> ZIPL currently uses the address in offset 0x14 to access the IPLB and
>> acquire flags about secure boot. If the IPLB address points into
>> memory which has an unsupported mix of flags set, ZIPL will panic
>> instead of booting the OS.
>>
>> As the lowcore can have quite a high entropy for a guest that did drop
>> out of protected mode (i.e. rebooted) we encountered the ZIPL panic
>> quite often.
>>
>> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
>> Tested-by: Marc Hartmayer <mhartmay@linux.ibm.com>
> 
> I think this makes sense even without protected virtualization, no?
> Unless somebody complains, I think I will pick this up while Conny is
> on vacation.

Yes, makes sense!


-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 02/18] s390x: protvirt: Add diag308 subcodes 8 - 10
  2020-03-04 11:42 ` [PATCH v6 02/18] s390x: protvirt: Add diag308 subcodes 8 - 10 Janosch Frank
@ 2020-03-04 17:04   ` David Hildenbrand
  2020-03-05 12:04     ` Janosch Frank
  2020-03-04 17:04   ` David Hildenbrand
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 72+ messages in thread
From: David Hildenbrand @ 2020-03-04 17:04 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

On 04.03.20 12:42, Janosch Frank wrote:
> For diag308 subcodes 8 - 10 we have a new ipib of type 5. The ipib
> holds the address and length of the secure execution header, as well
> as a list of guest components.
> 
> Each component is a block of memory, for example kernel or initrd,
> which needs to be decrypted by the Ultravisor in order to run a
> protected VM. The secure execution header instructs the Ultravisor on
> how to handle the protected VM and its components.
> 
> Subcodes 8 and 9 are similiar to 5 and 6 and subcode 10 will finally
> start the protected guest.
> 
> Subcodes 8-10 are not valid in protected mode, we have to do a subcode
> 3 and then the 8 and 10 combination for a protected reboot.
> 
> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
> ---
>  hw/s390x/ipl.c      | 47 ++++++++++++++++++++++++++++++++++++++++++---
>  hw/s390x/ipl.h      | 32 ++++++++++++++++++++++++++++++
>  target/s390x/diag.c | 26 ++++++++++++++++++++++---
>  3 files changed, 99 insertions(+), 6 deletions(-)
> 
> diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
> index 9c1ecd423c..80c6ab233a 100644
> --- a/hw/s390x/ipl.c
> +++ b/hw/s390x/ipl.c
> @@ -538,15 +538,55 @@ static bool is_virtio_scsi_device(IplParameterBlock *iplb)
>      return is_virtio_ccw_device_of_type(iplb, VIRTIO_ID_SCSI);
>  }
>  
> +int s390_ipl_pv_check_components(IplParameterBlock *iplb)

What about making this

bool s390_ipl_pv_valid(IplParameterBlock *iplb)

and return true/false?

> +{
> +    int i;
> +    IPLBlockPV *ipib_pv = &iplb->pv;

nit: place "int i;" down here

> +
> +    if (ipib_pv->num_comp == 0) {
> +        return -EINVAL;
> +    }
> +
> +    for (i = 0; i < ipib_pv->num_comp; i++) {
> +        /* Addr must be 4k aligned */
> +        if (ipib_pv->components[i].addr & ~TARGET_PAGE_MASK) {
> +            return -EINVAL;
> +        }
> +
> +        /* Tweak prefix is monotonously increasing with each component */

should that be "monotonically increasing" ?

> +        if (i < ipib_pv->num_comp - 1 &&
> +            ipib_pv->components[i].tweak_pref >
> +            ipib_pv->components[i + 1].tweak_pref) {

and I assume "==" is valid then.

> +            return -EINVAL;
> +        }
> +    }
> +    return 0;
> +}
> +
>  void s390_ipl_update_diag308(IplParameterBlock *iplb)
>  {
>      S390IPLState *ipl = get_ipl_device();
>  
> -    ipl->iplb = *iplb;
> -    ipl->iplb_valid = true;
> +    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_secure(void)

Why suddenly the "secure" ? s390_ipl_get_iplb_pv?

> +{
> +    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 +601,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) {

What about a switch-case now instead?

>          /* use CPU 0 for full resets */
>          ipl->reset_cpu_index = 0;
>      } else {
> diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
> index d4813105db..04be63cee1 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;

Do we need the packed here? All members are naturally aligned.

> +typedef struct IPLBlockPVComp IPLBlockPVComp;
> +
> +struct IPLBlockPV {
> +    uint8_t  reserved[87];
> +    uint8_t  version;
> +    uint32_t reserved70;
> +    uint32_t num_comp;
> +    uint64_t pv_header_addr;
> +    uint64_t pv_header_len;
> +    struct IPLBlockPVComp components[];
> +} QEMU_PACKED;

Dito.

[...]

>      uint64_t compat_bios_start_addr;
>      bool enforce_bios;
>      bool iplb_valid;
> +    bool iplb_valid_pv;

I'd name this "iplb_pv_valid" to match "iplb_pv".

>      bool netboot;
>      /* reset related properties don't have to be migrated or reset */
>      enum s390_reset reset_type;
> @@ -161,9 +185,11 @@ QEMU_BUILD_BUG_MSG(offsetof(S390IPLState, iplb) & 3, "alignment of iplb wrong");
>  
>  #define S390_IPL_TYPE_FCP 0x00
>  #define S390_IPL_TYPE_CCW 0x02
> +#define S390_IPL_TYPE_PV 0x05
>  #define S390_IPL_TYPE_QEMU_SCSI 0xff
>  
>  #define S390_IPLB_HEADER_LEN 8
> +#define S390_IPLB_MIN_PV_LEN 148
>  #define S390_IPLB_MIN_CCW_LEN 200
>  #define S390_IPLB_MIN_FCP_LEN 384
>  #define S390_IPLB_MIN_QEMU_SCSI_LEN 200
> @@ -185,4 +211,10 @@ static inline bool iplb_valid_fcp(IplParameterBlock *iplb)
>             iplb->pbt == S390_IPL_TYPE_FCP;
>  }
>  
> +static inline bool iplb_valid_pv(IplParameterBlock *iplb)
> +{
> +    return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_PV_LEN &&
> +           iplb->pbt == S390_IPL_TYPE_PV;
> +}
> +
>  #endif
> diff --git a/target/s390x/diag.c b/target/s390x/diag.c
> index b5aec06d6b..945b263f0a 100644
> --- a/target/s390x/diag.c
> +++ b/target/s390x/diag.c
> @@ -52,6 +52,7 @@ int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
>  #define DIAG_308_RC_OK              0x0001
>  #define DIAG_308_RC_NO_CONF         0x0102
>  #define DIAG_308_RC_INVALID         0x0402
> +#define DIAG_308_RC_NO_PV_CONF      0x0902
>  
>  #define DIAG308_RESET_MOD_CLR       0
>  #define DIAG308_RESET_LOAD_NORM     1
> @@ -59,6 +60,9 @@ int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
>  #define DIAG308_LOAD_NORMAL_DUMP    4
>  #define DIAG308_SET                 5
>  #define DIAG308_STORE               6
> +#define DIAG308_PV_SET              8
> +#define DIAG308_PV_STORE            9
> +#define DIAG308_PV_START            10
>  
>  static int diag308_parm_check(CPUS390XState *env, uint64_t r1, uint64_t addr,
>                                uintptr_t ra, bool write)
> @@ -105,6 +109,7 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
>          s390_ipl_reset_request(cs, S390_RESET_REIPL);
>          break;
>      case DIAG308_SET:
> +    case DIAG308_PV_SET:
>          if (diag308_parm_check(env, r1, addr, ra, false)) {
>              return;
>          }
> @@ -117,7 +122,8 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
>  
>          cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len));
>  
> -        if (!iplb_valid_ccw(iplb) && !iplb_valid_fcp(iplb)) {
> +        if (!iplb_valid_ccw(iplb) && !iplb_valid_fcp(iplb) &&
> +            !(iplb_valid_pv(iplb) && !s390_ipl_pv_check_components(iplb))) {

I really think we should make this s390_ipl_pv_valid(), we're mixing
functions that return true on success with functions that return 0 on
success. Also, can't we simply move that check into iplb_valid_pv(iplb)
to make this here easier to read?

>              env->regs[r1 + 1] = DIAG_308_RC_INVALID;
>              goto out;
>          }
> @@ -128,17 +134,31 @@ out:
>          g_free(iplb);
>          return;
>      case DIAG308_STORE:
> +    case DIAG308_PV_STORE:
>          if (diag308_parm_check(env, r1, addr, ra, true)) {
>              return;
>          }
> -        iplb = s390_ipl_get_iplb();
> +        if (subcode == DIAG308_PV_STORE) {
> +            iplb = s390_ipl_get_iplb_secure();
> +        } else {
> +            iplb = s390_ipl_get_iplb();
> +        }
>          if (iplb) {
>              cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len));
>              env->regs[r1 + 1] = DIAG_308_RC_OK;
>          } else {
>              env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;
>          }
> -        return;
> +        break;
> +    case DIAG308_PV_START:
> +        iplb = s390_ipl_get_iplb_secure();
> +        if (!iplb || !iplb_valid_pv(iplb)) {

Why do we need another iplb_valid_pv() check? I thought we would verify
this when setting and marking valid.

> +            env->regs[r1 + 1] = DIAG_308_RC_NO_PV_CONF;
> +            return;
> +        }
> +


-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 02/18] s390x: protvirt: Add diag308 subcodes 8 - 10
  2020-03-04 11:42 ` [PATCH v6 02/18] s390x: protvirt: Add diag308 subcodes 8 - 10 Janosch Frank
  2020-03-04 17:04   ` David Hildenbrand
@ 2020-03-04 17:04   ` David Hildenbrand
  2020-03-04 17:06   ` David Hildenbrand
  2020-03-04 18:59   ` Christian Borntraeger
  3 siblings, 0 replies; 72+ messages in thread
From: David Hildenbrand @ 2020-03-04 17:04 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

On 04.03.20 12:42, Janosch Frank wrote:
> For diag308 subcodes 8 - 10 we have a new ipib of type 5. The ipib
> holds the address and length of the secure execution header, as well
> as a list of guest components.
> 
> Each component is a block of memory, for example kernel or initrd,
> which needs to be decrypted by the Ultravisor in order to run a
> protected VM. The secure execution header instructs the Ultravisor on
> how to handle the protected VM and its components.
> 
> Subcodes 8 and 9 are similiar to 5 and 6 and subcode 10 will finally
> start the protected guest.

s/similiar/similar/


-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 02/18] s390x: protvirt: Add diag308 subcodes 8 - 10
  2020-03-04 11:42 ` [PATCH v6 02/18] s390x: protvirt: Add diag308 subcodes 8 - 10 Janosch Frank
  2020-03-04 17:04   ` David Hildenbrand
  2020-03-04 17:04   ` David Hildenbrand
@ 2020-03-04 17:06   ` David Hildenbrand
  2020-03-06  9:59     ` Janosch Frank
  2020-03-04 18:59   ` Christian Borntraeger
  3 siblings, 1 reply; 72+ messages in thread
From: David Hildenbrand @ 2020-03-04 17:06 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

On 04.03.20 12:42, Janosch Frank wrote:
> For diag308 subcodes 8 - 10 we have a new ipib of type 5. The ipib
> holds the address and length of the secure execution header, as well
> as a list of guest components.
> 
> Each component is a block of memory, for example kernel or initrd,
> which needs to be decrypted by the Ultravisor in order to run a
> protected VM. The secure execution header instructs the Ultravisor on
> how to handle the protected VM and its components.
> 
> Subcodes 8 and 9 are similiar to 5 and 6 and subcode 10 will finally
> start the protected guest.
> 
> Subcodes 8-10 are not valid in protected mode, we have to do a subcode
> 3 and then the 8 and 10 combination for a protected reboot.
> 
> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
> ---
>  hw/s390x/ipl.c      | 47 ++++++++++++++++++++++++++++++++++++++++++---
>  hw/s390x/ipl.h      | 32 ++++++++++++++++++++++++++++++
>  target/s390x/diag.c | 26 ++++++++++++++++++++++---
>  3 files changed, 99 insertions(+), 6 deletions(-)
> 
> diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
> index 9c1ecd423c..80c6ab233a 100644
> --- a/hw/s390x/ipl.c
> +++ b/hw/s390x/ipl.c
> @@ -538,15 +538,55 @@ static bool is_virtio_scsi_device(IplParameterBlock *iplb)
>      return is_virtio_ccw_device_of_type(iplb, VIRTIO_ID_SCSI);
>  }
>  
> +int s390_ipl_pv_check_components(IplParameterBlock *iplb)
> +{
> +    int i;
> +    IPLBlockPV *ipib_pv = &iplb->pv;
> +
> +    if (ipib_pv->num_comp == 0) {
> +        return -EINVAL;
> +    }
> +
> +    for (i = 0; i < ipib_pv->num_comp; i++) {
> +        /* Addr must be 4k aligned */
> +        if (ipib_pv->components[i].addr & ~TARGET_PAGE_MASK) {
> +            return -EINVAL;
> +        }
> +
> +        /* Tweak prefix is monotonously increasing with each component */
> +        if (i < ipib_pv->num_comp - 1 &&
> +            ipib_pv->components[i].tweak_pref >
> +            ipib_pv->components[i + 1].tweak_pref) {
> +            return -EINVAL;
> +        }
> +    }
> +    return 0;
> +}
> +
>  void s390_ipl_update_diag308(IplParameterBlock *iplb)
>  {
>      S390IPLState *ipl = get_ipl_device();
>  
> -    ipl->iplb = *iplb;
> -    ipl->iplb_valid = true;
> +    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_secure(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 +601,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 {
> diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
> index d4813105db..04be63cee1 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  reserved[87];
> +    uint8_t  version;
> +    uint32_t reserved70;
> +    uint32_t num_comp;
> +    uint64_t pv_header_addr;
> +    uint64_t pv_header_len;
> +    struct IPLBlockPVComp components[];
> +} QEMU_PACKED;
> +typedef struct IPLBlockPV IPLBlockPV;
> +
>  struct IplBlockCcw {
>      uint8_t  reserved0[85];
>      uint8_t  ssid;
> @@ -71,6 +89,7 @@ union IplParameterBlock {
>          union {
>              IplBlockCcw ccw;
>              IplBlockFcp fcp;
> +            IPLBlockPV pv;
>              IplBlockQemuScsi scsi;
>          };
>      } QEMU_PACKED;
> @@ -84,9 +103,11 @@ union IplParameterBlock {
>  typedef union IplParameterBlock IplParameterBlock;
>  
>  int s390_ipl_set_loadparm(uint8_t *loadparm);
> +int s390_ipl_pv_check_components(IplParameterBlock *iplb);
>  void s390_ipl_update_diag308(IplParameterBlock *iplb);
>  void s390_ipl_prepare_cpu(S390CPU *cpu);
>  IplParameterBlock *s390_ipl_get_iplb(void);
> +IplParameterBlock *s390_ipl_get_iplb_secure(void);
>  
>  enum s390_reset {
>      /* default is a reset not triggered by a CPU e.g. issued by QMP */
> @@ -94,6 +115,7 @@ enum s390_reset {
>      S390_RESET_REIPL,
>      S390_RESET_MODIFIED_CLEAR,
>      S390_RESET_LOAD_NORMAL,
> +    S390_RESET_PV,
>  };
>  void s390_ipl_reset_request(CPUState *cs, enum s390_reset reset_type);
>  void s390_ipl_get_reset_request(CPUState **cs, enum s390_reset *reset_type);
> @@ -133,6 +155,7 @@ struct S390IPLState {
>      /*< private >*/
>      DeviceState parent_obj;
>      IplParameterBlock iplb;
> +    IplParameterBlock iplb_pv;
>      QemuIplParameters qipl;
>      uint64_t start_addr;
>      uint64_t compat_start_addr;
> @@ -140,6 +163,7 @@ struct S390IPLState {
>      uint64_t compat_bios_start_addr;
>      bool enforce_bios;
>      bool iplb_valid;
> +    bool iplb_valid_pv;
>      bool netboot;
>      /* reset related properties don't have to be migrated or reset */
>      enum s390_reset reset_type;
> @@ -161,9 +185,11 @@ QEMU_BUILD_BUG_MSG(offsetof(S390IPLState, iplb) & 3, "alignment of iplb wrong");
>  
>  #define S390_IPL_TYPE_FCP 0x00
>  #define S390_IPL_TYPE_CCW 0x02
> +#define S390_IPL_TYPE_PV 0x05
>  #define S390_IPL_TYPE_QEMU_SCSI 0xff
>  
>  #define S390_IPLB_HEADER_LEN 8
> +#define S390_IPLB_MIN_PV_LEN 148
>  #define S390_IPLB_MIN_CCW_LEN 200
>  #define S390_IPLB_MIN_FCP_LEN 384
>  #define S390_IPLB_MIN_QEMU_SCSI_LEN 200
> @@ -185,4 +211,10 @@ static inline bool iplb_valid_fcp(IplParameterBlock *iplb)
>             iplb->pbt == S390_IPL_TYPE_FCP;
>  }
>  
> +static inline bool iplb_valid_pv(IplParameterBlock *iplb)
> +{
> +    return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_PV_LEN &&
> +           iplb->pbt == S390_IPL_TYPE_PV;
> +}
> +
>  #endif
> diff --git a/target/s390x/diag.c b/target/s390x/diag.c
> index b5aec06d6b..945b263f0a 100644
> --- a/target/s390x/diag.c
> +++ b/target/s390x/diag.c
> @@ -52,6 +52,7 @@ int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
>  #define DIAG_308_RC_OK              0x0001
>  #define DIAG_308_RC_NO_CONF         0x0102
>  #define DIAG_308_RC_INVALID         0x0402
> +#define DIAG_308_RC_NO_PV_CONF      0x0902
>  
>  #define DIAG308_RESET_MOD_CLR       0
>  #define DIAG308_RESET_LOAD_NORM     1
> @@ -59,6 +60,9 @@ int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
>  #define DIAG308_LOAD_NORMAL_DUMP    4
>  #define DIAG308_SET                 5
>  #define DIAG308_STORE               6
> +#define DIAG308_PV_SET              8
> +#define DIAG308_PV_STORE            9
> +#define DIAG308_PV_START            10
>  
>  static int diag308_parm_check(CPUS390XState *env, uint64_t r1, uint64_t addr,
>                                uintptr_t ra, bool write)
> @@ -105,6 +109,7 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
>          s390_ipl_reset_request(cs, S390_RESET_REIPL);
>          break;
>      case DIAG308_SET:
> +    case DIAG308_PV_SET:
>          if (diag308_parm_check(env, r1, addr, ra, false)) {
>              return;
>          }
> @@ -117,7 +122,8 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
>  
>          cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len));
>  
> -        if (!iplb_valid_ccw(iplb) && !iplb_valid_fcp(iplb)) {
> +        if (!iplb_valid_ccw(iplb) && !iplb_valid_fcp(iplb) &&
> +            !(iplb_valid_pv(iplb) && !s390_ipl_pv_check_components(iplb))) {
>              env->regs[r1 + 1] = DIAG_308_RC_INVALID;
>              goto out;
>          }
> @@ -128,17 +134,31 @@ out:
>          g_free(iplb);
>          return;
>      case DIAG308_STORE:
> +    case DIAG308_PV_STORE:
>          if (diag308_parm_check(env, r1, addr, ra, true)) {
>              return;
>          }
> -        iplb = s390_ipl_get_iplb();
> +        if (subcode == DIAG308_PV_STORE) {
> +            iplb = s390_ipl_get_iplb_secure();
> +        } else {
> +            iplb = s390_ipl_get_iplb();
> +        }
>          if (iplb) {
>              cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len));
>              env->regs[r1 + 1] = DIAG_308_RC_OK;
>          } else {
>              env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;
>          }
> -        return;
> +        break;
> +    case DIAG308_PV_START:
> +        iplb = s390_ipl_get_iplb_secure();
> +        if (!iplb || !iplb_valid_pv(iplb)) {
> +            env->regs[r1 + 1] = DIAG_308_RC_NO_PV_CONF;
> +            return;
> +        }
> +
> +        s390_ipl_reset_request(cs, S390_RESET_PV);
> +        break;
>      default:
>          s390_program_interrupt(env, PGM_SPECIFICATION, ra);
>          break;
> 

Sorry, another comment. The new subcodes should be fenced via the cpu
model or similar. Applying this patch and triggering one of these
subcodes will end in a questionable state.

-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 04/18] s390x: protvirt: Add migration blocker
  2020-03-04 11:42 ` [PATCH v6 04/18] s390x: protvirt: Add migration blocker Janosch Frank
@ 2020-03-04 17:13   ` David Hildenbrand
  2020-03-05  9:16     ` Janosch Frank
  0 siblings, 1 reply; 72+ messages in thread
From: David Hildenbrand @ 2020-03-04 17:13 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

On 04.03.20 12:42, Janosch Frank wrote:
> Migration is not yet supported.
> 
> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
> ---
>  hw/s390x/s390-virtio-ccw.c | 33 ++++++++++++++++++++++++---------
>  1 file changed, 24 insertions(+), 9 deletions(-)
> 
> diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
> index dd39890f89..272531a9ee 100644
> --- a/hw/s390x/s390-virtio-ccw.c
> +++ b/hw/s390x/s390-virtio-ccw.c
> @@ -43,6 +43,9 @@
>  #include "sysemu/sysemu.h"
>  #include "hw/s390x/pv.h"
>  #include <linux/kvm.h>
> +#include "migration/blocker.h"
> +
> +static Error *pv_mig_blocker;
>  
>  S390CPU *s390_cpu_addr2state(uint16_t cpu_addr)
>  {
> @@ -324,19 +327,30 @@ static void s390_machine_unprotect(S390CcwMachineState *ms)
>  {
>      CPUState *t;
>  
> -    if (!ms->pv)
> -        return;
> -    s390_pv_vm_disable();
> -    CPU_FOREACH(t) {
> -        S390_CPU(t)->env.pv = false;
> +    if (ms->pv) {
> +        s390_pv_vm_disable();
> +        CPU_FOREACH(t) {
> +            S390_CPU(t)->env.pv = false;
> +        }
> +        ms->pv = false;
>      }
> -    ms->pv = false;
> +    migrate_del_blocker(pv_mig_blocker);

Is it just me or is this unnecessary code churn that wants to challenge
my reviewing capabilities? ;) Please perform that rework in the previous
patch already.

Also, I do wonder why the blocker is always removed (IOW, how we could
end up unprotecting, although there is nothing to unprotect).

This needs a comment in the patch description.


>  }
>  
>  static int s390_machine_protect(S390CcwMachineState *ms)
>  {
> +    static Error *local_err;
>      CPUState *t;
> -    int rc;
> +    int rc = -1;
> +
> +    if (!pv_mig_blocker) {

I think we should instead error_free() when unprotecting ...

> +        error_setg(&pv_mig_blocker,
> +                   "protected VMs are currently not migrateable.");
> +    }
> +    migrate_add_blocker(pv_mig_blocker, &local_err);
> +    if (local_err) {
> +        goto out_err;

... and on the error path.

> +    }
>  
>      /* Create SE VM */
>      rc = s390_pv_vm_enable();
> @@ -440,11 +454,12 @@ static void s390_machine_reset(MachineState *machine)
>  
>          if (s390_machine_protect(ms)) {
>              s390_machine_inject_pv_error(cs);

ew, injecting an exception during a reset. (I know this belongs into the
previous patch)

> -            s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
> -            return;
> +            goto pv_err;

I have no idea why this hunk is in this patch. What am I missing?

>          }
>  
>          run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL);
> +pv_err:
> +        s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
>          break;
>      default:
>          g_assert_not_reached();
> 


-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 00/18] s390x: Protected Virtualization support
  2020-03-04 11:42 [PATCH v6 00/18] s390x: Protected Virtualization support Janosch Frank
                   ` (17 preceding siblings ...)
  2020-03-04 11:42 ` [PATCH v6 18/18] pc-bios: s390x: Save iplb location in lowcore Janosch Frank
@ 2020-03-04 17:15 ` David Hildenbrand
  2020-03-04 17:45   ` Christian Borntraeger
  18 siblings, 1 reply; 72+ messages in thread
From: David Hildenbrand @ 2020-03-04 17:15 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

On 04.03.20 12:42, Janosch Frank wrote:
> Most of the QEMU changes for PV are related to the new IPL type with
> subcodes 8 - 10 and the execution of the necessary Ultravisor calls to
> IPL secure guests. Note that we can only boot into secure mode from
> normal mode, i.e. stfle 161 is not active in secure mode.
> 
> The other changes related to data gathering for emulation and
> disabling addressing checks in secure mode, as well as CPU resets.
> 

BTW, I can't find any RBs from IBM folks. Similar to the kernel part, I
think it would be a good idea if some of your peers could review this as
well (either upstream or before you send out). Would make my life most
probably a little easier ...


-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 08/18] s390x: Add SIDA memory ops
  2020-03-04 11:42 ` [PATCH v6 08/18] s390x: Add SIDA memory ops Janosch Frank
@ 2020-03-04 17:39   ` David Hildenbrand
  2020-03-05  9:23     ` Janosch Frank
  0 siblings, 1 reply; 72+ messages in thread
From: David Hildenbrand @ 2020-03-04 17:39 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

On 04.03.20 12:42, Janosch Frank wrote:
> Protected guests save the instruction control blocks in the SIDA
> instead of QEMU/KVM directly accessing the guest's memory.
> 
> Let's introduce new functions to access the SIDA.

"The new memops are available with KVM_CAP_S390_PROTECTED, so let's
check for that."

> 
> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
> ---
>  linux-headers/linux/kvm.h |  2 ++
>  target/s390x/cpu.h        |  7 ++++++-
>  target/s390x/kvm.c        | 25 +++++++++++++++++++++++++
>  target/s390x/kvm_s390x.h  |  2 ++
>  target/s390x/mmu_helper.c | 14 ++++++++++++++
>  5 files changed, 49 insertions(+), 1 deletion(-)
> 
> diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
> index e36f761194..c30344ab00 100644
> --- a/linux-headers/linux/kvm.h
> +++ b/linux-headers/linux/kvm.h
> @@ -483,6 +483,8 @@ struct kvm_s390_mem_op {
>  /* types for kvm_s390_mem_op->op */
>  #define KVM_S390_MEMOP_LOGICAL_READ	0
>  #define KVM_S390_MEMOP_LOGICAL_WRITE	1
> +#define KVM_S390_MEMOP_SIDA_READ	2
> +#define KVM_S390_MEMOP_SIDA_WRITE	3
>  /* flags for kvm_s390_mem_op->flags */
>  #define KVM_S390_MEMOP_F_CHECK_ONLY		(1ULL << 0)
>  #define KVM_S390_MEMOP_F_INJECT_EXCEPTION	(1ULL << 1)

This should go into the header sync.

[...]

> index 7e4d9d267c..2578c838f8 100644
> --- a/target/s390x/cpu.h
> +++ b/target/s390x/cpu.h
> @@ -824,7 +824,12 @@ int s390_cpu_virt_mem_rw(S390CPU *cpu, vaddr laddr, uint8_t ar, void *hostbuf,
>  #define s390_cpu_virt_mem_check_write(cpu, laddr, ar, len)   \
>          s390_cpu_virt_mem_rw(cpu, laddr, ar, NULL, len, true)
>  void s390_cpu_virt_mem_handle_exc(S390CPU *cpu, uintptr_t ra);
> -
> +int s390_cpu_pv_mem_rw(S390CPU *cpu, unsigned int offset,  void *hostbuf,

double space after "offset,"

[...]

>  
> +int s390_cpu_pv_mem_rw(S390CPU *cpu, unsigned int offset, void *hostbuf,
> +                       int len, bool is_write)
> +{
> +    int ret;
> +
> +    if (kvm_enabled()) {
> +        ret = kvm_s390_mem_op_pv(cpu, offset, hostbuf, len, is_write);
> +    } else {
> +        /* Protected Virtualization is a KVM/Hardware only feature */
> +        g_assert_not_reached();
> +    }
> +    return ret;
> +}


I suspect nobody will ever check the return value, correct?

With the things changed

Reviewed-by: David Hildenbrand <david@redhat.com>

-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 09/18] s390x: protvirt: Move STSI data over SIDAD
  2020-03-04 11:42 ` [PATCH v6 09/18] s390x: protvirt: Move STSI data over SIDAD Janosch Frank
@ 2020-03-04 17:43   ` David Hildenbrand
  2020-03-05  9:27     ` Janosch Frank
  0 siblings, 1 reply; 72+ messages in thread
From: David Hildenbrand @ 2020-03-04 17:43 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

On 04.03.20 12:42, Janosch Frank wrote:
> For protected guests, we need to put the STSI emulation results into
> the SIDA, so SIE will write them into the guest at the next entry.
> 
> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
> Acked-by: David Hildenbrand <david@redhat.com>
> ---
>  target/s390x/kvm.c | 15 ++++++++++++---
>  1 file changed, 12 insertions(+), 3 deletions(-)
> 
> diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
> index cdcd538b4f..43fc0c088b 100644
> --- a/target/s390x/kvm.c
> +++ b/target/s390x/kvm.c
> @@ -1797,11 +1797,16 @@ static int handle_tsch(S390CPU *cpu)
>  
>  static void insert_stsi_3_2_2(S390CPU *cpu, __u64 addr, uint8_t ar)
>  {
> +    CPUS390XState *env = &cpu->env;
>      SysIB_322 sysib;
>      int del;
>  
> -    if (s390_cpu_virt_mem_read(cpu, addr, ar, &sysib, sizeof(sysib))) {
> -        return;
> +    if (env->pv) {
> +        s390_cpu_pv_mem_read(cpu, 0, &sysib, sizeof(sysib));
> +    } else {

else if please (not sure if I mentioned that already)

> +        if (s390_cpu_virt_mem_read(cpu, addr, ar, &sysib, sizeof(sysib))) {
> +            return;

With that, you can convert the ack to a

Reviewed-by: David Hildenbrand <david@redhat.com>


-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 00/18] s390x: Protected Virtualization support
  2020-03-04 17:15 ` [PATCH v6 00/18] s390x: Protected Virtualization support David Hildenbrand
@ 2020-03-04 17:45   ` Christian Borntraeger
  0 siblings, 0 replies; 72+ messages in thread
From: Christian Borntraeger @ 2020-03-04 17:45 UTC (permalink / raw)
  To: David Hildenbrand, Janosch Frank, qemu-devel; +Cc: qemu-s390x, cohuck



On 04.03.20 18:15, David Hildenbrand wrote:
> On 04.03.20 12:42, Janosch Frank wrote:
>> Most of the QEMU changes for PV are related to the new IPL type with
>> subcodes 8 - 10 and the execution of the necessary Ultravisor calls to
>> IPL secure guests. Note that we can only boot into secure mode from
>> normal mode, i.e. stfle 161 is not active in secure mode.
>>
>> The other changes related to data gathering for emulation and
>> disabling addressing checks in secure mode, as well as CPU resets.
>>
> 
> BTW, I can't find any RBs from IBM folks. Similar to the kernel part, I
> think it would be a good idea if some of your peers could review this as
> well (either upstream or before you send out). Would make my life most
> probably a little easier ...

Yes, its on my list of things todo. Regarding the kernel I found it odd
to send around Janoschs Patches reworked and then give a RB myself. I certainly
did a lot of review for them.



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 10/18] s390x: protvirt: SCLP interpretation
  2020-03-04 11:42 ` [PATCH v6 10/18] s390x: protvirt: SCLP interpretation Janosch Frank
@ 2020-03-04 17:48   ` David Hildenbrand
  2020-03-05  9:34     ` Janosch Frank
  0 siblings, 1 reply; 72+ messages in thread
From: David Hildenbrand @ 2020-03-04 17:48 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

On 04.03.20 12:42, Janosch Frank wrote:
> SCLP for a protected guest is done over the SIDAD, so we need to use
> the s390_cpu_virt_mem_* functions to access the SIDAD instead of guest

nope :)

s390_cpu_pv_mem_*

> memory when reading/writing SCBs.
> 
> To not confuse the sclp emulation, we set 0x4000 as the SCCB address,
> since the function that injects the sclp external interrupt would
> reject a zero sccb address.

Please add that as a comment to SCLP_PV_DUMMY_ADDR.

> 
> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
> ---
>  hw/s390x/sclp.c         | 17 +++++++++++++++++
>  include/hw/s390x/sclp.h |  2 ++
>  target/s390x/kvm.c      |  5 +++++
>  3 files changed, 24 insertions(+)
> 
> diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
> index af0bfbc2ec..5136f5fcbe 100644
> --- a/hw/s390x/sclp.c
> +++ b/hw/s390x/sclp.c
> @@ -193,6 +193,23 @@ static void sclp_execute(SCLPDevice *sclp, SCCB *sccb, uint32_t code)
>      }
>  }
>  
> +#define SCLP_PV_DUMMY_ADDR 0x4000

Should we move that to sclp_c->service_interrupt instead and document it
properly?

Or what about providing a

sclp_c->service_interrupt_pv(sclp) that handles this internally?

> +int sclp_service_call_protected(CPUS390XState *env, uint64_t sccb,
> +                                uint32_t code)
> +{
> +    SCLPDevice *sclp = get_sclp_device();
> +    SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp);
> +    SCCB work_sccb;
> +    hwaddr sccb_len = sizeof(SCCB);
> +
> +    s390_cpu_pv_mem_read(env_archcpu(env), 0, &work_sccb, sccb_len);

I assume it's valid to always read the full SCCB length?

> +    sclp_c->execute(sclp, &work_sccb, code);
> +    s390_cpu_pv_mem_write(env_archcpu(env), 0, &work_sccb,
> +                          be16_to_cpu(work_sccb.h.length));
> +    sclp_c->service_interrupt(sclp, SCLP_PV_DUMMY_ADDR);
> +    return 0;
> +}
> +
>  int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code)
>  {
>      SCLPDevice *sclp = get_sclp_device();
> diff --git a/include/hw/s390x/sclp.h b/include/hw/s390x/sclp.h
> index c54413b78c..c0a3faa37d 100644
> --- a/include/hw/s390x/sclp.h
> +++ b/include/hw/s390x/sclp.h
> @@ -217,5 +217,7 @@ void s390_sclp_init(void);
>  void sclp_service_interrupt(uint32_t sccb);
>  void raise_irq_cpu_hotplug(void);
>  int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code);
> +int sclp_service_call_protected(CPUS390XState *env, uint64_t sccb,
> +                                uint32_t code);
>  
>  #endif
> diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
> index 43fc0c088b..a4cbdc5fc6 100644
> --- a/target/s390x/kvm.c
> +++ b/target/s390x/kvm.c
> @@ -1226,6 +1226,11 @@ static void kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run,
>      sccb = env->regs[ipbh0 & 0xf];
>      code = env->regs[(ipbh0 & 0xf0) >> 4];
>  
> +    if (run->s390_sieic.icptcode == ICPT_PV_INSTR) {

I still somewhat prefer checking for env->pv instead - similar to patch #9.


-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 11/18] s390x: protvirt: Set guest IPL PSW
  2020-03-04 11:42 ` [PATCH v6 11/18] s390x: protvirt: Set guest IPL PSW Janosch Frank
@ 2020-03-04 17:51   ` David Hildenbrand
  0 siblings, 0 replies; 72+ messages in thread
From: David Hildenbrand @ 2020-03-04 17:51 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

On 04.03.20 12:42, Janosch Frank wrote:
> Handling of CPU reset and setting of the IPL psw from guest storage at
> offset 0 is done by a Ultravisor call. Let's only fetch it if
> necessary.
> 
> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
> Reviewed-by: Thomas Huth <thuth@redhat.com>
> ---
>  target/s390x/cpu.c | 23 ++++++++++++++---------
>  1 file changed, 14 insertions(+), 9 deletions(-)
> 
> diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
> index 69b1cc5dfc..7840e784f1 100644
> --- a/target/s390x/cpu.c
> +++ b/target/s390x/cpu.c
> @@ -78,16 +78,21 @@ static bool s390_cpu_has_work(CPUState *cs)
>  static void s390_cpu_load_normal(CPUState *s)
>  {
>      S390CPU *cpu = S390_CPU(s);
> -    uint64_t spsw = ldq_phys(s->as, 0);
> -
> -    cpu->env.psw.mask = spsw & PSW_MASK_SHORT_CTRL;
> -    /*
> -     * Invert short psw indication, so SIE will report a specification
> -     * exception if it was not set.
> -     */
> -    cpu->env.psw.mask ^= PSW_MASK_SHORTPSW;
> -    cpu->env.psw.addr = spsw & PSW_MASK_SHORT_ADDR;
> +    CPUS390XState *env = &cpu->env;
> +    uint64_t spsw;
>  
> +    if (!env->pv) {
> +        spsw = ldq_phys(s->as, 0);
> +        cpu->env.psw.mask = spsw & PSW_MASK_SHORT_CTRL;
> +        /*
> +         * Invert short psw indication, so SIE will report a specification
> +         * exception if it was not set.
> +         */
> +        cpu->env.psw.mask ^= PSW_MASK_SHORTPSW;
> +        cpu->env.psw.addr = spsw & PSW_MASK_SHORT_ADDR;
> +    } else {
> +        s390_cpu_set_state(S390_CPU_STATE_LOAD, cpu);
> +    }
>      s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
>  }
>  #endif
> 

Reviewed-by: David Hildenbrand <david@redhat.com>

-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 12/18] s390x: protvirt: Move diag 308 data over SIDAD
  2020-03-04 11:42 ` [PATCH v6 12/18] s390x: protvirt: Move diag 308 data over SIDAD Janosch Frank
@ 2020-03-04 17:54   ` David Hildenbrand
  0 siblings, 0 replies; 72+ messages in thread
From: David Hildenbrand @ 2020-03-04 17:54 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

On 04.03.20 12:42, Janosch Frank wrote:
> For protected guests the IPIB is written/read to/from the satellite
> block, so we need those accesses to go through
> s390_cpu_pv_mem_read/write().

Maybe mention SIDAD instead if "satellite block", similar to the other
patch descriptions.

[...]

> -        cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len));
> +        if (!env->pv) {
> +            cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len));
> +        } else {
> +            s390_cpu_pv_mem_read(cpu, 0, iplb, be32_to_cpu(iplb->len));
> +        }
>  
>          if (!iplb_valid_ccw(iplb) && !iplb_valid_fcp(iplb) &&
>              !(iplb_valid_pv(iplb) && !s390_ipl_pv_check_components(iplb))) {
> @@ -136,7 +146,7 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
>          env->regs[r1 + 1] = DIAG_308_RC_OK;
>  out:
>          g_free(iplb);
> -        return;
> +        break;

Why that change? Unrelated?

>      case DIAG308_STORE:
>      case DIAG308_PV_STORE:
>          if (diag308_parm_check(env, r1, addr, ra, true)) {
> @@ -147,12 +157,18 @@ out:
>          } else {
>              iplb = s390_ipl_get_iplb();
>          }
> -        if (iplb) {
> -            cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len));
> -            env->regs[r1 + 1] = DIAG_308_RC_OK;
> -        } else {
> +        if (!iplb) {
>              env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;
> +            return;
>          }
> +
> +        if (!env->pv) {
> +            cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len));
> +        } else {
> +            s390_cpu_pv_mem_write(cpu, 0, iplb, be32_to_cpu(iplb->len));
> +        }
> +
> +        env->regs[r1 + 1] = DIAG_308_RC_OK;
>          break;
>      case DIAG308_PV_START:
>          iplb = s390_ipl_get_iplb_secure();
> 

I really do wonder if you should squash in patch #2 and leave it in this
position of the series.

-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 13/18] s390x: protvirt: Disable address checks for PV guest IO emulation
  2020-03-04 11:42 ` [PATCH v6 13/18] s390x: protvirt: Disable address checks for PV guest IO emulation Janosch Frank
@ 2020-03-04 17:55   ` David Hildenbrand
  2020-03-05  9:42     ` Janosch Frank
  0 siblings, 1 reply; 72+ messages in thread
From: David Hildenbrand @ 2020-03-04 17:55 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

On 04.03.20 12:42, Janosch Frank wrote:
> IO instruction data is routed through SIDAD for protected guests, so
> adresses do not need to be checked, as this is kernel memory.
> 
> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
> Reviewed-by: Thomas Huth <thuth@redhat.com>
> ---
>  target/s390x/ioinst.c | 26 +++++++++++++++++++-------
>  1 file changed, 19 insertions(+), 7 deletions(-)
> 
> diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c
> index c437a1d8c6..e4102430aa 100644
> --- a/target/s390x/ioinst.c
> +++ b/target/s390x/ioinst.c
> @@ -17,6 +17,16 @@
>  #include "trace.h"
>  #include "hw/s390x/s390-pci-bus.h"
>  
> +static uint64_t get_address_from_regs(CPUS390XState *env, uint32_t ipb,
> +                                      uint8_t *ar)
> +{

Please add a comment here why this is done. (e.g., make all address
checks - like alignment checks - in the caller succeed, and we don't
need the address).

> +    if (env->pv) {
> +        *ar = 0;
> +        return 0;
> +    }
> +    return decode_basedisp_s(env, ipb, ar);
> +}
> +

Reviewed-by: David Hildenbrand <david@redhat.com>


-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 15/18] s390x: protvirt: Handle SIGP store status correctly
  2020-03-04 11:42 ` [PATCH v6 15/18] s390x: protvirt: Handle SIGP store status correctly Janosch Frank
@ 2020-03-04 18:41   ` David Hildenbrand
  2020-03-05  9:59     ` Janosch Frank
  0 siblings, 1 reply; 72+ messages in thread
From: David Hildenbrand @ 2020-03-04 18:41 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

On 04.03.20 12:42, Janosch Frank wrote:
> Status storing is not done by QEMU anymore, but is handled by SIE.
> 
> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
> Reviewed-by: Thomas Huth <thuth@redhat.com>
> ---
>  target/s390x/helper.c | 4 ++++
>  target/s390x/sigp.c   | 1 +
>  2 files changed, 5 insertions(+)
> 
> diff --git a/target/s390x/helper.c b/target/s390x/helper.c
> index ed72684911..8b91ed68f0 100644
> --- a/target/s390x/helper.c
> +++ b/target/s390x/helper.c
> @@ -246,6 +246,10 @@ int s390_store_status(S390CPU *cpu, hwaddr addr, bool store_arch)
>      hwaddr len = sizeof(*sa);
>      int i;
>  
> +    if (cpu->env.pv) {
> +        return 0;
> +    }
> +
>      sa = cpu_physical_memory_map(addr, &len, true);
>      if (!sa) {
>          return -EFAULT;
> diff --git a/target/s390x/sigp.c b/target/s390x/sigp.c
> index c604f17710..e1c8071464 100644
> --- a/target/s390x/sigp.c
> +++ b/target/s390x/sigp.c
> @@ -497,6 +497,7 @@ void do_stop_interrupt(CPUS390XState *env)
>      if (s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu) == 0) {
>          qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
>      }
> +    /* Storing will occur on next SIE entry for protected VMs */

I think this comment would be better next to the cpu->env.pv check.

>      if (cpu->env.sigp_order == SIGP_STOP_STORE_STATUS) {
>          s390_store_status(cpu, S390_STORE_STATUS_DEF_ADDR, true);
>      }
> 


Apart from that

Reviewed-by: David Hildenbrand <david@redhat.com>

-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 16/18] s390x: Add unpack facility feature to GA1
  2020-03-04 11:42 ` [PATCH v6 16/18] s390x: Add unpack facility feature to GA1 Janosch Frank
@ 2020-03-04 18:42   ` David Hildenbrand
  2020-03-06 10:14   ` Janosch Frank
  1 sibling, 0 replies; 72+ messages in thread
From: David Hildenbrand @ 2020-03-04 18:42 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

On 04.03.20 12:42, Janosch Frank wrote:
> From: Christian Borntraeger <borntraeger@de.ibm.com>
> 
> The unpack facility is an indication that diagnose 308 subcodes 8-10
> are available to the guest. That means, that the guest can put itself
> into protected mode.
> 
> Once it is in protected mode, the hardware stops any attempt of VM
> introspection by the hypervisor.
> 
> Some features are currently not supported in protected mode:
>      * Passthrough devices
>      * Migration
>      * Huge page backings
> 
> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
> ---
>  target/s390x/gen-features.c | 1 +
>  target/s390x/kvm.c          | 5 +++++
>  2 files changed, 6 insertions(+)
> 
> diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
> index 6278845b12..8ddeebc544 100644
> --- a/target/s390x/gen-features.c
> +++ b/target/s390x/gen-features.c
> @@ -562,6 +562,7 @@ static uint16_t full_GEN15_GA1[] = {
>      S390_FEAT_GROUP_MSA_EXT_9,
>      S390_FEAT_GROUP_MSA_EXT_9_PCKMO,
>      S390_FEAT_ETOKEN,
> +    S390_FEAT_UNPACK,
>  };
>  
>  /* Default features (in order of release)
> diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
> index a4cbdc5fc6..bf807793bc 100644
> --- a/target/s390x/kvm.c
> +++ b/target/s390x/kvm.c
> @@ -2396,6 +2396,11 @@ void kvm_s390_get_host_cpu_model(S390CPUModel *model, Error **errp)
>          clear_bit(S390_FEAT_BPB, model->features);
>      }
>  
> +    /* we do have the IPL enhancements */
> +    if (cap_protected) {
> +        set_bit(S390_FEAT_UNPACK, model->features);
> +    }
> +
>      /* We emulate a zPCI bus and AEN, therefore we don't need HW support */
>      set_bit(S390_FEAT_ZPCI, model->features);
>      set_bit(S390_FEAT_ADAPTER_EVENT_NOTIFICATION, model->features);
> 

Reviewed-by: David Hildenbrand <david@redhat.com>

-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 14/18] s390x: protvirt: Move IO control structures over SIDA
  2020-03-04 11:42 ` [PATCH v6 14/18] s390x: protvirt: Move IO control structures over SIDA Janosch Frank
@ 2020-03-04 18:56   ` David Hildenbrand
  2020-03-05  9:55     ` Janosch Frank
  0 siblings, 1 reply; 72+ messages in thread
From: David Hildenbrand @ 2020-03-04 18:56 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

On 04.03.20 12:42, Janosch Frank wrote:
> For protected guests, we need to put the IO emulation results into the
> SIDA, so SIE will write them into the guest at the next entry.
> 

[...]

>  
>      if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
> +        if (env->pv) {
> +            return;
> +        }

Can you elaborate why we don't have to do anything here? I can
understand why we don't/cannot probe for writes. But what about the
PGM_OPERAND?


[...]

Apart from that, looks good to me.


-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 02/18] s390x: protvirt: Add diag308 subcodes 8 - 10
  2020-03-04 11:42 ` [PATCH v6 02/18] s390x: protvirt: Add diag308 subcodes 8 - 10 Janosch Frank
                     ` (2 preceding siblings ...)
  2020-03-04 17:06   ` David Hildenbrand
@ 2020-03-04 18:59   ` Christian Borntraeger
  2020-03-05 14:39     ` Janosch Frank
  3 siblings, 1 reply; 72+ messages in thread
From: Christian Borntraeger @ 2020-03-04 18:59 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: qemu-s390x, cohuck, david



On 04.03.20 12:42, Janosch Frank wrote:
> For diag308 subcodes 8 - 10 we have a new ipib of type 5. The ipib
> holds the address and length of the secure execution header, as well
> as a list of guest components.
> 
> Each component is a block of memory, for example kernel or initrd,
> which needs to be decrypted by the Ultravisor in order to run a
> protected VM. The secure execution header instructs the Ultravisor on
> how to handle the protected VM and its components.
> 
> Subcodes 8 and 9 are similiar to 5 and 6 and subcode 10 will finally
> start the protected guest.
> 
> Subcodes 8-10 are not valid in protected mode, we have to do a subcode
> 3 and then the 8 and 10 combination for a protected reboot.
> 
> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
> ---
>  hw/s390x/ipl.c      | 47 ++++++++++++++++++++++++++++++++++++++++++---
>  hw/s390x/ipl.h      | 32 ++++++++++++++++++++++++++++++
>  target/s390x/diag.c | 26 ++++++++++++++++++++++---
>  3 files changed, 99 insertions(+), 6 deletions(-)
> 
> diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
> index 9c1ecd423c..80c6ab233a 100644
> --- a/hw/s390x/ipl.c
> +++ b/hw/s390x/ipl.c

Can you update the copyright dates for files that you touch?

> @@ -538,15 +538,55 @@ static bool is_virtio_scsi_device(IplParameterBlock *iplb)
>      return is_virtio_ccw_device_of_type(iplb, VIRTIO_ID_SCSI);
>  }
>  
> +int s390_ipl_pv_check_components(IplParameterBlock *iplb)
> +{
> +    int i;
> +    IPLBlockPV *ipib_pv = &iplb->pv;
> +
> +    if (ipib_pv->num_comp == 0) {
> +        return -EINVAL;
> +    }
> +
> +    for (i = 0; i < ipib_pv->num_comp; i++) {
> +        /* Addr must be 4k aligned */
> +        if (ipib_pv->components[i].addr & ~TARGET_PAGE_MASK) {
> +            return -EINVAL;
> +        }
> +
> +        /* Tweak prefix is monotonously increasing with each component */
> +        if (i < ipib_pv->num_comp - 1 &&

Why do we need this check? Isnt that already ensured by the for loop?

> +            ipib_pv->components[i].tweak_pref >
> +            ipib_pv->components[i + 1].tweak_pref) {

I think i+1 must be greater than i. So ">=" instead?

> +            return -EINVAL;
> +        }
> +    }
> +    return 0;
> +}
> +
>  void s390_ipl_update_diag308(IplParameterBlock *iplb)

maybe add a comment that explains that a guest can have 2 IPLBs. one for
the secure guest and one thsat we go back to when rebooting.
>  {
>      S390IPLState *ipl = get_ipl_device();
>  
> -    ipl->iplb = *iplb;
> -    ipl->iplb_valid = true;
> +    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_secure(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 +601,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 {
> diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
> index d4813105db..04be63cee1 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  reserved[87];
> +    uint8_t  version;
> +    uint32_t reserved70;

Here you have 70 (the offset in hex I guess), I tßhink this is an odd name. In addition the reserved field 2 lines above has no address part in its
name. 



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 17/18] docs: Add protvirt docs
  2020-03-04 11:42 ` [PATCH v6 17/18] docs: Add protvirt docs Janosch Frank
@ 2020-03-04 19:09   ` David Hildenbrand
  2020-03-09  9:51     ` Janosch Frank
  0 siblings, 1 reply; 72+ messages in thread
From: David Hildenbrand @ 2020-03-04 19:09 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

On 04.03.20 12:42, Janosch Frank wrote:
> Lets add some documentation for the Protected VM functionality.
> 
> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
> ---
>  docs/system/index.rst    |  1 +
>  docs/system/protvirt.rst | 57 ++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 58 insertions(+)
>  create mode 100644 docs/system/protvirt.rst
> 
> diff --git a/docs/system/index.rst b/docs/system/index.rst
> index 1a4b2c82ac..d2dc63b973 100644
> --- a/docs/system/index.rst
> +++ b/docs/system/index.rst
> @@ -16,3 +16,4 @@ Contents:
>  
>     qemu-block-drivers
>     vfio-ap
> +   protvirt
> diff --git a/docs/system/protvirt.rst b/docs/system/protvirt.rst
> new file mode 100644
> index 0000000000..a1902cc47c
> --- /dev/null
> +++ b/docs/system/protvirt.rst
> @@ -0,0 +1,57 @@
> +Protected Virtualization on s390x
> +=================================
> +
> +The memory and most of the register contents of Protected Virtual

s/register contents/registers/

> +Machines (PVMs) are inaccessible to the hypervisor, effectively

s/inaccessible/encrypted or even inaccessible/ ?

> +prohibiting VM introspection when the VM is running. At rest, PVMs are
> +encrypted and can only be decrypted by the firmware of specific IBM Z
> +machines.

maybe "(a.k.a. the Ultravisor)"

> +
> +
> +Prerequisites
> +-------------
> +
> +To run PVMs, you need to have a machine with the Protected

"a machine with the Protected Virtualization feature is required"

> +Virtualization feature, which is indicated by the Ultravisor Call
> +facility (stfle bit 158). This is a KVM only feature, therefore you

", therefore, "

I don't understand the "KVM only" feature part. Just say that an updated
KVM + right HW is required and how it is to be updated.

> +need a KVM which is able to support PVMs and activate the Ultravisor

"a KVM version"

> +initialization by setting `prot_virt=1` on the kernel command line.
> +
> +If those requirements are met, the capability `KVM_CAP_S390_PROTECTED`
> +will indicate that KVM can support PVMs on that LPAR.
> +
> +
> +QEMU Settings
> +-------------
> +
> +To indicate to the VM that it can move into protected mode, the

s/move/transition/ ?

> +`Unpack facility` (stfle bit 161) needs to be part of the cpu model of
> +the VM.

Maybe mention the CPU feature name here.

> +
> +All I/O devices need to use the IOMMU.
> +Passthrough (vfio) devices are currently not supported.
> +
> +Host huge page backings are not supported. The guest however can use

"However, the guest can ..."

> +huge pages as indicated by its facilities.
> +
> +
> +Boot Process
> +------------
> +
> +A secure guest image can be both booted from disk and using the QEMU

"either be loaded from disk or supplied on the QEMU command line" ?

> +command line. Booting from disk is done by the unmodified s390-ccw
> +BIOS. I.e., the bootmap is interpreted and a number of components is

"interpreted, multiple components are"

> +read into memory and control is transferred to one of the components
> +(zipl stage3), which does some fixups and then transfers control to
> +some program residing in guest memory, which is normally the OS

to many ", which". Better split that up for readability.

> +kernel. The secure image has another component prepended (stage3a)
> +which uses the new diag308 subcodes 8 and 10 to trigger the transition
> +into secure mode.
> +
> +Booting from the command line requires that the file passed

"from the image supplied on the QEMU command line" ?

> +via -kernel has the same memory layout as would result from the disk
> +boot. This memory layout includes the encrypted components (kernel,
> +initrd, cmdline), the stage3a loader and metadata. In case this boot
> +method is used, the command line options -initrd and -cmdline are
> +ineffective.  The preparation of secure guest image is done by a

s/of secure/of a PMV image/

> +program (name tbd) of the s390-tools package.
> 


General: secure guest -> PMV

-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 04/18] s390x: protvirt: Add migration blocker
  2020-03-04 17:13   ` David Hildenbrand
@ 2020-03-05  9:16     ` Janosch Frank
  2020-03-05  9:30       ` David Hildenbrand
  0 siblings, 1 reply; 72+ messages in thread
From: Janosch Frank @ 2020-03-05  9:16 UTC (permalink / raw)
  To: David Hildenbrand, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck


[-- Attachment #1.1: Type: text/plain, Size: 3756 bytes --]

On 3/4/20 6:13 PM, David Hildenbrand wrote:
> On 04.03.20 12:42, Janosch Frank wrote:
>> Migration is not yet supported.
>>
>> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
>> ---
>>  hw/s390x/s390-virtio-ccw.c | 33 ++++++++++++++++++++++++---------
>>  1 file changed, 24 insertions(+), 9 deletions(-)
>>
>> diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
>> index dd39890f89..272531a9ee 100644
>> --- a/hw/s390x/s390-virtio-ccw.c
>> +++ b/hw/s390x/s390-virtio-ccw.c
>> @@ -43,6 +43,9 @@
>>  #include "sysemu/sysemu.h"
>>  #include "hw/s390x/pv.h"
>>  #include <linux/kvm.h>
>> +#include "migration/blocker.h"
>> +
>> +static Error *pv_mig_blocker;
>>  
>>  S390CPU *s390_cpu_addr2state(uint16_t cpu_addr)
>>  {
>> @@ -324,19 +327,30 @@ static void s390_machine_unprotect(S390CcwMachineState *ms)
>>  {
>>      CPUState *t;
>>  
>> -    if (!ms->pv)
>> -        return;
>> -    s390_pv_vm_disable();
>> -    CPU_FOREACH(t) {
>> -        S390_CPU(t)->env.pv = false;
>> +    if (ms->pv) {
>> +        s390_pv_vm_disable();
>> +        CPU_FOREACH(t) {
>> +            S390_CPU(t)->env.pv = false;
>> +        }
>> +        ms->pv = false;
>>      }
>> -    ms->pv = false;
>> +    migrate_del_blocker(pv_mig_blocker);
> 
> Is it just me or is this unnecessary code churn that wants to challenge
> my reviewing capabilities? ;) Please perform that rework in the previous
> patch already.

It's rather more of personal style choice to do a "if return" to not
encapsulate everything in ifs.

> 
> Also, I do wonder why the blocker is always removed (IOW, how we could
> end up unprotecting, although there is nothing to unprotect).
> 
> This needs a comment in the patch description.

You mean the error check for migrate_add_blocker()?
I'm still metabolizing my coffee...

> 
> 
>>  }
>>  
>>  static int s390_machine_protect(S390CcwMachineState *ms)
>>  {
>> +    static Error *local_err;
>>      CPUState *t;
>> -    int rc;
>> +    int rc = -1;
>> +
>> +    if (!pv_mig_blocker) {
> 
> I think we should instead error_free() when unprotecting ...

Ack

> 
>> +        error_setg(&pv_mig_blocker,
>> +                   "protected VMs are currently not migrateable.");
>> +    }
>> +    migrate_add_blocker(pv_mig_blocker, &local_err);
>> +    if (local_err) {
>> +        goto out_err;
> 
> ... and on the error path.

To also return the rc code, I changed it to:

    rc = migrate_add_blocker(pv_mig_blocker, &local_err);
    if (local_err) {
        error_free(pv_mig_blocker);
        return rc;
    }


> 
>> +    }
>>  
>>      /* Create SE VM */
>>      rc = s390_pv_vm_enable();
>> @@ -440,11 +454,12 @@ static void s390_machine_reset(MachineState *machine)
>>  
>>          if (s390_machine_protect(ms)) {
>>              s390_machine_inject_pv_error(cs);
> 
> ew, injecting an exception during a reset. (I know this belongs into the
> previous patch)

Yeah, not too proud about this one, but doing it at diag308 time is not
possible, since we need to reset the devices before attempting to protect.

> 
>> -            s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
>> -            return;
>> +            goto pv_err;
> 
> I have no idea why this hunk is in this patch. What am I missing?

The error needs to be communicated to the guest, so we need to resume
CPU operation instead of doing a load which we would do on success.

> 
>>          }
>>  
>>          run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL);
>> +pv_err:
>> +        s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
>>          break;
>>      default:
>>          g_assert_not_reached();
>>
> 
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 08/18] s390x: Add SIDA memory ops
  2020-03-04 17:39   ` David Hildenbrand
@ 2020-03-05  9:23     ` Janosch Frank
  0 siblings, 0 replies; 72+ messages in thread
From: Janosch Frank @ 2020-03-05  9:23 UTC (permalink / raw)
  To: David Hildenbrand, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck


[-- Attachment #1.1: Type: text/plain, Size: 2590 bytes --]

On 3/4/20 6:39 PM, David Hildenbrand wrote:
> On 04.03.20 12:42, Janosch Frank wrote:
>> Protected guests save the instruction control blocks in the SIDA
>> instead of QEMU/KVM directly accessing the guest's memory.
>>
>> Let's introduce new functions to access the SIDA.
> 
> "The new memops are available with KVM_CAP_S390_PROTECTED, so let's
> check for that."

Ack

> 
>>
>> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
>> ---
>>  linux-headers/linux/kvm.h |  2 ++
>>  target/s390x/cpu.h        |  7 ++++++-
>>  target/s390x/kvm.c        | 25 +++++++++++++++++++++++++
>>  target/s390x/kvm_s390x.h  |  2 ++
>>  target/s390x/mmu_helper.c | 14 ++++++++++++++
>>  5 files changed, 49 insertions(+), 1 deletion(-)
>>
>> diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
>> index e36f761194..c30344ab00 100644
>> --- a/linux-headers/linux/kvm.h
>> +++ b/linux-headers/linux/kvm.h
>> @@ -483,6 +483,8 @@ struct kvm_s390_mem_op {
>>  /* types for kvm_s390_mem_op->op */
>>  #define KVM_S390_MEMOP_LOGICAL_READ	0
>>  #define KVM_S390_MEMOP_LOGICAL_WRITE	1
>> +#define KVM_S390_MEMOP_SIDA_READ	2
>> +#define KVM_S390_MEMOP_SIDA_WRITE	3
>>  /* flags for kvm_s390_mem_op->flags */
>>  #define KVM_S390_MEMOP_F_CHECK_ONLY		(1ULL << 0)
>>  #define KVM_S390_MEMOP_F_INJECT_EXCEPTION	(1ULL << 1)
> 
> This should go into the header sync.

Ack

> 
> [...]
> 
>> index 7e4d9d267c..2578c838f8 100644
>> --- a/target/s390x/cpu.h
>> +++ b/target/s390x/cpu.h
>> @@ -824,7 +824,12 @@ int s390_cpu_virt_mem_rw(S390CPU *cpu, vaddr laddr, uint8_t ar, void *hostbuf,
>>  #define s390_cpu_virt_mem_check_write(cpu, laddr, ar, len)   \
>>          s390_cpu_virt_mem_rw(cpu, laddr, ar, NULL, len, true)
>>  void s390_cpu_virt_mem_handle_exc(S390CPU *cpu, uintptr_t ra);
>> -
>> +int s390_cpu_pv_mem_rw(S390CPU *cpu, unsigned int offset,  void *hostbuf,
> 
> double space after "offset,"

Ack

> 
> [...]
> 
>>  
>> +int s390_cpu_pv_mem_rw(S390CPU *cpu, unsigned int offset, void *hostbuf,
>> +                       int len, bool is_write)
>> +{
>> +    int ret;
>> +
>> +    if (kvm_enabled()) {
>> +        ret = kvm_s390_mem_op_pv(cpu, offset, hostbuf, len, is_write);
>> +    } else {
>> +        /* Protected Virtualization is a KVM/Hardware only feature */
>> +        g_assert_not_reached();
>> +    }
>> +    return ret;
>> +}
> 
> 
> I suspect nobody will ever check the return value, correct?
> 
> With the things changed
> 
> Reviewed-by: David Hildenbrand <david@redhat.com>

Thanks!

> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 09/18] s390x: protvirt: Move STSI data over SIDAD
  2020-03-04 17:43   ` David Hildenbrand
@ 2020-03-05  9:27     ` Janosch Frank
  0 siblings, 0 replies; 72+ messages in thread
From: Janosch Frank @ 2020-03-05  9:27 UTC (permalink / raw)
  To: David Hildenbrand, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck


[-- Attachment #1.1: Type: text/plain, Size: 1357 bytes --]

On 3/4/20 6:43 PM, David Hildenbrand wrote:
> On 04.03.20 12:42, Janosch Frank wrote:
>> For protected guests, we need to put the STSI emulation results into
>> the SIDA, so SIE will write them into the guest at the next entry.
>>
>> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
>> Acked-by: David Hildenbrand <david@redhat.com>
>> ---
>>  target/s390x/kvm.c | 15 ++++++++++++---
>>  1 file changed, 12 insertions(+), 3 deletions(-)
>>
>> diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
>> index cdcd538b4f..43fc0c088b 100644
>> --- a/target/s390x/kvm.c
>> +++ b/target/s390x/kvm.c
>> @@ -1797,11 +1797,16 @@ static int handle_tsch(S390CPU *cpu)
>>  
>>  static void insert_stsi_3_2_2(S390CPU *cpu, __u64 addr, uint8_t ar)
>>  {
>> +    CPUS390XState *env = &cpu->env;
>>      SysIB_322 sysib;
>>      int del;
>>  
>> -    if (s390_cpu_virt_mem_read(cpu, addr, ar, &sysib, sizeof(sysib))) {
>> -        return;
>> +    if (env->pv) {
>> +        s390_cpu_pv_mem_read(cpu, 0, &sysib, sizeof(sysib));
>> +    } else {
> 
> else if please (not sure if I mentioned that already)

Ack

> 
>> +        if (s390_cpu_virt_mem_read(cpu, addr, ar, &sysib, sizeof(sysib))) {
>> +            return;
> 
> With that, you can convert the ack to a
> 
> Reviewed-by: David Hildenbrand <david@redhat.com>

Thanks!



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 04/18] s390x: protvirt: Add migration blocker
  2020-03-05  9:16     ` Janosch Frank
@ 2020-03-05  9:30       ` David Hildenbrand
  0 siblings, 0 replies; 72+ messages in thread
From: David Hildenbrand @ 2020-03-05  9:30 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

On 05.03.20 10:16, Janosch Frank wrote:
> On 3/4/20 6:13 PM, David Hildenbrand wrote:
>> On 04.03.20 12:42, Janosch Frank wrote:
>>> Migration is not yet supported.
>>>
>>> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
>>> ---
>>>  hw/s390x/s390-virtio-ccw.c | 33 ++++++++++++++++++++++++---------
>>>  1 file changed, 24 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
>>> index dd39890f89..272531a9ee 100644
>>> --- a/hw/s390x/s390-virtio-ccw.c
>>> +++ b/hw/s390x/s390-virtio-ccw.c
>>> @@ -43,6 +43,9 @@
>>>  #include "sysemu/sysemu.h"
>>>  #include "hw/s390x/pv.h"
>>>  #include <linux/kvm.h>
>>> +#include "migration/blocker.h"
>>> +
>>> +static Error *pv_mig_blocker;
>>>  
>>>  S390CPU *s390_cpu_addr2state(uint16_t cpu_addr)
>>>  {
>>> @@ -324,19 +327,30 @@ static void s390_machine_unprotect(S390CcwMachineState *ms)
>>>  {
>>>      CPUState *t;
>>>  
>>> -    if (!ms->pv)
>>> -        return;
>>> -    s390_pv_vm_disable();
>>> -    CPU_FOREACH(t) {
>>> -        S390_CPU(t)->env.pv = false;
>>> +    if (ms->pv) {
>>> +        s390_pv_vm_disable();
>>> +        CPU_FOREACH(t) {
>>> +            S390_CPU(t)->env.pv = false;
>>> +        }
>>> +        ms->pv = false;
>>>      }
>>> -    ms->pv = false;
>>> +    migrate_del_blocker(pv_mig_blocker);
>>
>> Is it just me or is this unnecessary code churn that wants to challenge
>> my reviewing capabilities? ;) Please perform that rework in the previous
>> patch already.
> 
> It's rather more of personal style choice to do a "if return" to not
> encapsulate everything in ifs.

Yes, but please do that in the previous patch instead. This makes review
of this patch unnecessary complicated.


>> Also, I do wonder why the blocker is always removed (IOW, how we could
>> end up unprotecting, although there is nothing to unprotect).
>>
>> This needs a comment in the patch description.
> 
> You mean the error check for migrate_add_blocker()?
> I'm still metabolizing my coffee...

Why could we get a call to s390_machine_unprotect() and
- have !ms->pv
- still need to do a migrate_del_blocker()

Not clear to me.

>>
>>> -            s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
>>> -            return;
>>> +            goto pv_err;
>>
>> I have no idea why this hunk is in this patch. What am I missing?
> 
> The error needs to be communicated to the guest, so we need to resume
> CPU operation instead of doing a load which we would do on success.
> 

The point I am making: This change should go into the previous patch
unless I am missing something important.


-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 10/18] s390x: protvirt: SCLP interpretation
  2020-03-04 17:48   ` David Hildenbrand
@ 2020-03-05  9:34     ` Janosch Frank
  2020-03-05 10:09       ` David Hildenbrand
  0 siblings, 1 reply; 72+ messages in thread
From: Janosch Frank @ 2020-03-05  9:34 UTC (permalink / raw)
  To: David Hildenbrand, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck


[-- Attachment #1.1: Type: text/plain, Size: 3678 bytes --]

On 3/4/20 6:48 PM, David Hildenbrand wrote:
> On 04.03.20 12:42, Janosch Frank wrote:
>> SCLP for a protected guest is done over the SIDAD, so we need to use
>> the s390_cpu_virt_mem_* functions to access the SIDAD instead of guest
> 
> nope :)
> 
> s390_cpu_pv_mem_*

Ack

> 
>> memory when reading/writing SCBs.
>>
>> To not confuse the sclp emulation, we set 0x4000 as the SCCB address,
>> since the function that injects the sclp external interrupt would
>> reject a zero sccb address.
> 
> Please add that as a comment to SCLP_PV_DUMMY_ADDR.
> 
>>
>> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
>> ---
>>  hw/s390x/sclp.c         | 17 +++++++++++++++++
>>  include/hw/s390x/sclp.h |  2 ++
>>  target/s390x/kvm.c      |  5 +++++
>>  3 files changed, 24 insertions(+)
>>
>> diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
>> index af0bfbc2ec..5136f5fcbe 100644
>> --- a/hw/s390x/sclp.c
>> +++ b/hw/s390x/sclp.c
>> @@ -193,6 +193,23 @@ static void sclp_execute(SCLPDevice *sclp, SCCB *sccb, uint32_t code)
>>      }
>>  }
>>  
>> +#define SCLP_PV_DUMMY_ADDR 0x4000
> 
> Should we move that to sclp_c->service_interrupt instead and document it
> properly?
> 
> Or what about providing a
> 
> sclp_c->service_interrupt_pv(sclp) that handles this internally?

The less functions with a pv suffix I have, the happier I am.
I'll have a look into the first suggestion.

> 
>> +int sclp_service_call_protected(CPUS390XState *env, uint64_t sccb,
>> +                                uint32_t code)
>> +{
>> +    SCLPDevice *sclp = get_sclp_device();
>> +    SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp);
>> +    SCCB work_sccb;
>> +    hwaddr sccb_len = sizeof(SCCB);
>> +
>> +    s390_cpu_pv_mem_read(env_archcpu(env), 0, &work_sccb, sccb_len);
> 
> I assume it's valid to always read the full SCCB length?

SIDA and SCCB are currently both 4k, so no problem there.
If we use extended SCCB, we would also need to increase the SIDA.

> 
>> +    sclp_c->execute(sclp, &work_sccb, code);
>> +    s390_cpu_pv_mem_write(env_archcpu(env), 0, &work_sccb,
>> +                          be16_to_cpu(work_sccb.h.length));
>> +    sclp_c->service_interrupt(sclp, SCLP_PV_DUMMY_ADDR);
>> +    return 0;
>> +}
>> +
>>  int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code)
>>  {
>>      SCLPDevice *sclp = get_sclp_device();
>> diff --git a/include/hw/s390x/sclp.h b/include/hw/s390x/sclp.h
>> index c54413b78c..c0a3faa37d 100644
>> --- a/include/hw/s390x/sclp.h
>> +++ b/include/hw/s390x/sclp.h
>> @@ -217,5 +217,7 @@ void s390_sclp_init(void);
>>  void sclp_service_interrupt(uint32_t sccb);
>>  void raise_irq_cpu_hotplug(void);
>>  int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code);
>> +int sclp_service_call_protected(CPUS390XState *env, uint64_t sccb,
>> +                                uint32_t code);
>>  
>>  #endif
>> diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
>> index 43fc0c088b..a4cbdc5fc6 100644
>> --- a/target/s390x/kvm.c
>> +++ b/target/s390x/kvm.c
>> @@ -1226,6 +1226,11 @@ static void kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run,
>>      sccb = env->regs[ipbh0 & 0xf];
>>      code = env->regs[(ipbh0 & 0xf0) >> 4];
>>  
>> +    if (run->s390_sieic.icptcode == ICPT_PV_INSTR) {
> 
> I still somewhat prefer checking for env->pv instead - similar to patch #9.

Since we also have a notification for SCLP, I'd like to avoid that.
And that reminds me that we should add a check for the notification
here, so we get notified if KVM changes and let's those through without
qemu being prepared for it.




[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 13/18] s390x: protvirt: Disable address checks for PV guest IO emulation
  2020-03-04 17:55   ` David Hildenbrand
@ 2020-03-05  9:42     ` Janosch Frank
  2020-03-05 10:00       ` David Hildenbrand
  0 siblings, 1 reply; 72+ messages in thread
From: Janosch Frank @ 2020-03-05  9:42 UTC (permalink / raw)
  To: David Hildenbrand, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck


[-- Attachment #1.1: Type: text/plain, Size: 1539 bytes --]

On 3/4/20 6:55 PM, David Hildenbrand wrote:
> On 04.03.20 12:42, Janosch Frank wrote:
>> IO instruction data is routed through SIDAD for protected guests, so
>> adresses do not need to be checked, as this is kernel memory.
>>
>> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
>> Reviewed-by: Thomas Huth <thuth@redhat.com>
>> ---
>>  target/s390x/ioinst.c | 26 +++++++++++++++++++-------
>>  1 file changed, 19 insertions(+), 7 deletions(-)
>>
>> diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c
>> index c437a1d8c6..e4102430aa 100644
>> --- a/target/s390x/ioinst.c
>> +++ b/target/s390x/ioinst.c
>> @@ -17,6 +17,16 @@
>>  #include "trace.h"
>>  #include "hw/s390x/s390-pci-bus.h"
>>  
>> +static uint64_t get_address_from_regs(CPUS390XState *env, uint32_t ipb,
>> +                                      uint8_t *ar)
>> +{
> 
> Please add a comment here why this is done. (e.g., make all address
> checks - like alignment checks - in the caller succeed, and we don't
> need the address).

     * Addresses for protected guests are all offsets into the


     * satellite block which holds the IO control structures. Those


     * control structures are always aligned and accessible, so we can


     * return 0 here which will pass the following address checks.

?

> 
>> +    if (env->pv) {
>> +        *ar = 0;
>> +        return 0;
>> +    }
>> +    return decode_basedisp_s(env, ipb, ar);
>> +}
>> +
> 
> Reviewed-by: David Hildenbrand <david@redhat.com>
> 
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 14/18] s390x: protvirt: Move IO control structures over SIDA
  2020-03-04 18:56   ` David Hildenbrand
@ 2020-03-05  9:55     ` Janosch Frank
  2020-03-05 10:01       ` David Hildenbrand
  0 siblings, 1 reply; 72+ messages in thread
From: Janosch Frank @ 2020-03-05  9:55 UTC (permalink / raw)
  To: David Hildenbrand, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck


[-- Attachment #1.1: Type: text/plain, Size: 697 bytes --]

On 3/4/20 7:56 PM, David Hildenbrand wrote:
> On 04.03.20 12:42, Janosch Frank wrote:
>> For protected guests, we need to put the IO emulation results into the
>> SIDA, so SIE will write them into the guest at the next entry.
>>
> 
> [...]
> 
>>  
>>      if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
>> +        if (env->pv) {
>> +            return;
>> +        }
> 
> Can you elaborate why we don't have to do anything here? I can
> understand why we don't/cannot probe for writes. But what about the
> PGM_OPERAND?

CSSID and the schid one check are done by the Ultravisor/SIE

> 
> 
> [...]
> 
> Apart from that, looks good to me.
> 
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 15/18] s390x: protvirt: Handle SIGP store status correctly
  2020-03-04 18:41   ` David Hildenbrand
@ 2020-03-05  9:59     ` Janosch Frank
  0 siblings, 0 replies; 72+ messages in thread
From: Janosch Frank @ 2020-03-05  9:59 UTC (permalink / raw)
  To: David Hildenbrand, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck


[-- Attachment #1.1: Type: text/plain, Size: 1660 bytes --]

On 3/4/20 7:41 PM, David Hildenbrand wrote:
> On 04.03.20 12:42, Janosch Frank wrote:
>> Status storing is not done by QEMU anymore, but is handled by SIE.
>>
>> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
>> Reviewed-by: Thomas Huth <thuth@redhat.com>
>> ---
>>  target/s390x/helper.c | 4 ++++
>>  target/s390x/sigp.c   | 1 +
>>  2 files changed, 5 insertions(+)
>>
>> diff --git a/target/s390x/helper.c b/target/s390x/helper.c
>> index ed72684911..8b91ed68f0 100644
>> --- a/target/s390x/helper.c
>> +++ b/target/s390x/helper.c
>> @@ -246,6 +246,10 @@ int s390_store_status(S390CPU *cpu, hwaddr addr, bool store_arch)
>>      hwaddr len = sizeof(*sa);
>>      int i;
>>  
>> +    if (cpu->env.pv) {
>> +        return 0;
>> +    }
>> +
>>      sa = cpu_physical_memory_map(addr, &len, true);
>>      if (!sa) {
>>          return -EFAULT;
>> diff --git a/target/s390x/sigp.c b/target/s390x/sigp.c
>> index c604f17710..e1c8071464 100644
>> --- a/target/s390x/sigp.c
>> +++ b/target/s390x/sigp.c
>> @@ -497,6 +497,7 @@ void do_stop_interrupt(CPUS390XState *env)
>>      if (s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu) == 0) {
>>          qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
>>      }
>> +    /* Storing will occur on next SIE entry for protected VMs */
> 
> I think this comment would be better next to the cpu->env.pv check.

Ack

> 
>>      if (cpu->env.sigp_order == SIGP_STOP_STORE_STATUS) {
>>          s390_store_status(cpu, S390_STORE_STATUS_DEF_ADDR, true);
>>      }
>>
> 
> 
> Apart from that
> 
> Reviewed-by: David Hildenbrand <david@redhat.com>

Thanks



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 13/18] s390x: protvirt: Disable address checks for PV guest IO emulation
  2020-03-05  9:42     ` Janosch Frank
@ 2020-03-05 10:00       ` David Hildenbrand
  2020-03-05 11:26         ` Janosch Frank
  0 siblings, 1 reply; 72+ messages in thread
From: David Hildenbrand @ 2020-03-05 10:00 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

On 05.03.20 10:42, Janosch Frank wrote:
> On 3/4/20 6:55 PM, David Hildenbrand wrote:
>> On 04.03.20 12:42, Janosch Frank wrote:
>>> IO instruction data is routed through SIDAD for protected guests, so
>>> adresses do not need to be checked, as this is kernel memory.
>>>
>>> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
>>> Reviewed-by: Thomas Huth <thuth@redhat.com>
>>> ---
>>>  target/s390x/ioinst.c | 26 +++++++++++++++++++-------
>>>  1 file changed, 19 insertions(+), 7 deletions(-)
>>>
>>> diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c
>>> index c437a1d8c6..e4102430aa 100644
>>> --- a/target/s390x/ioinst.c
>>> +++ b/target/s390x/ioinst.c
>>> @@ -17,6 +17,16 @@
>>>  #include "trace.h"
>>>  #include "hw/s390x/s390-pci-bus.h"
>>>  
>>> +static uint64_t get_address_from_regs(CPUS390XState *env, uint32_t ipb,
>>> +                                      uint8_t *ar)
>>> +{
>>
>> Please add a comment here why this is done. (e.g., make all address
>> checks - like alignment checks - in the caller succeed, and we don't
>> need the address).
> 
>      * Addresses for protected guests are all offsets into the
> 
> 
>      * satellite block which holds the IO control structures. Those

maybe mention SIDA as well

> 
> 
>      * control structures are always aligned and accessible, so we can
> 
> 
>      * return 0 here which will pass the following address checks.
> 
> ?


Sounds good!


-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 14/18] s390x: protvirt: Move IO control structures over SIDA
  2020-03-05  9:55     ` Janosch Frank
@ 2020-03-05 10:01       ` David Hildenbrand
  0 siblings, 0 replies; 72+ messages in thread
From: David Hildenbrand @ 2020-03-05 10:01 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

On 05.03.20 10:55, Janosch Frank wrote:
> On 3/4/20 7:56 PM, David Hildenbrand wrote:
>> On 04.03.20 12:42, Janosch Frank wrote:
>>> For protected guests, we need to put the IO emulation results into the
>>> SIDA, so SIE will write them into the guest at the next entry.
>>>
>>
>> [...]
>>
>>>  
>>>      if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
>>> +        if (env->pv) {
>>> +            return;
>>> +        }
>>
>> Can you elaborate why we don't have to do anything here? I can
>> understand why we don't/cannot probe for writes. But what about the
>> PGM_OPERAND?
> 
> CSSID and the schid one check are done by the Ultravisor/SIE
> 

So can we even reach this path?


-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 10/18] s390x: protvirt: SCLP interpretation
  2020-03-05  9:34     ` Janosch Frank
@ 2020-03-05 10:09       ` David Hildenbrand
  0 siblings, 0 replies; 72+ messages in thread
From: David Hildenbrand @ 2020-03-05 10:09 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck


>>>  #endif
>>> diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
>>> index 43fc0c088b..a4cbdc5fc6 100644
>>> --- a/target/s390x/kvm.c
>>> +++ b/target/s390x/kvm.c
>>> @@ -1226,6 +1226,11 @@ static void kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run,
>>>      sccb = env->regs[ipbh0 & 0xf];
>>>      code = env->regs[(ipbh0 & 0xf0) >> 4];
>>>  
>>> +    if (run->s390_sieic.icptcode == ICPT_PV_INSTR) {
>>
>> I still somewhat prefer checking for env->pv instead - similar to patch #9.
> 
> Since we also have a notification for SCLP, I'd like to avoid that.
> And that reminds me that we should add a check for the notification
> here, so we get notified if KVM changes and let's those through without
> qemu being prepared for it.

Makes sense then! This will also make it clearer why we're not checking
against pv.


-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 13/18] s390x: protvirt: Disable address checks for PV guest IO emulation
  2020-03-05 10:00       ` David Hildenbrand
@ 2020-03-05 11:26         ` Janosch Frank
  2020-03-05 11:37           ` David Hildenbrand
  0 siblings, 1 reply; 72+ messages in thread
From: Janosch Frank @ 2020-03-05 11:26 UTC (permalink / raw)
  To: David Hildenbrand, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck


[-- Attachment #1.1: Type: text/plain, Size: 1606 bytes --]

On 3/5/20 11:00 AM, David Hildenbrand wrote:
> On 05.03.20 10:42, Janosch Frank wrote:
>> On 3/4/20 6:55 PM, David Hildenbrand wrote:
>>> On 04.03.20 12:42, Janosch Frank wrote:
>>>> IO instruction data is routed through SIDAD for protected guests, so
>>>> adresses do not need to be checked, as this is kernel memory.
>>>>
>>>> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
>>>> Reviewed-by: Thomas Huth <thuth@redhat.com>
>>>> ---
>>>>  target/s390x/ioinst.c | 26 +++++++++++++++++++-------
>>>>  1 file changed, 19 insertions(+), 7 deletions(-)
>>>>
>>>> diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c
>>>> index c437a1d8c6..e4102430aa 100644
>>>> --- a/target/s390x/ioinst.c
>>>> +++ b/target/s390x/ioinst.c
>>>> @@ -17,6 +17,16 @@
>>>>  #include "trace.h"
>>>>  #include "hw/s390x/s390-pci-bus.h"
>>>>  
>>>> +static uint64_t get_address_from_regs(CPUS390XState *env, uint32_t ipb,
>>>> +                                      uint8_t *ar)
>>>> +{
>>>
>>> Please add a comment here why this is done. (e.g., make all address
>>> checks - like alignment checks - in the caller succeed, and we don't
>>> need the address).
>>
>>      * Addresses for protected guests are all offsets into the
>>
>>
>>      * satellite block which holds the IO control structures. Those
> 
> maybe mention SIDA as well

huh? SIDA is the satellite block

> 
>>
>>
>>      * control structures are always aligned and accessible, so we can
>>
>>
>>      * return 0 here which will pass the following address checks.
>>
>> ?
> 
> 
> Sounds good!
> 
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 13/18] s390x: protvirt: Disable address checks for PV guest IO emulation
  2020-03-05 11:26         ` Janosch Frank
@ 2020-03-05 11:37           ` David Hildenbrand
  0 siblings, 0 replies; 72+ messages in thread
From: David Hildenbrand @ 2020-03-05 11:37 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

On 05.03.20 12:26, Janosch Frank wrote:
> On 3/5/20 11:00 AM, David Hildenbrand wrote:
>> On 05.03.20 10:42, Janosch Frank wrote:
>>> On 3/4/20 6:55 PM, David Hildenbrand wrote:
>>>> On 04.03.20 12:42, Janosch Frank wrote:
>>>>> IO instruction data is routed through SIDAD for protected guests, so
>>>>> adresses do not need to be checked, as this is kernel memory.
>>>>>
>>>>> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
>>>>> Reviewed-by: Thomas Huth <thuth@redhat.com>
>>>>> ---
>>>>>  target/s390x/ioinst.c | 26 +++++++++++++++++++-------
>>>>>  1 file changed, 19 insertions(+), 7 deletions(-)
>>>>>
>>>>> diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c
>>>>> index c437a1d8c6..e4102430aa 100644
>>>>> --- a/target/s390x/ioinst.c
>>>>> +++ b/target/s390x/ioinst.c
>>>>> @@ -17,6 +17,16 @@
>>>>>  #include "trace.h"
>>>>>  #include "hw/s390x/s390-pci-bus.h"
>>>>>  
>>>>> +static uint64_t get_address_from_regs(CPUS390XState *env, uint32_t ipb,
>>>>> +                                      uint8_t *ar)
>>>>> +{
>>>>
>>>> Please add a comment here why this is done. (e.g., make all address
>>>> checks - like alignment checks - in the caller succeed, and we don't
>>>> need the address).
>>>
>>>      * Addresses for protected guests are all offsets into the
>>>
>>>
>>>      * satellite block which holds the IO control structures. Those
>>
>> maybe mention SIDA as well
> 
> huh? SIDA is the satellite block

Yes, please stick to a consistent terminology. Mix and matching "SIDA"
and "satellite block" does not improve readability IMHO.

-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 06/18] s390x: protvirt: Inhibit balloon when switching to protected mode
  2020-03-04 11:42 ` [PATCH v6 06/18] s390x: protvirt: Inhibit balloon when switching to protected mode Janosch Frank
@ 2020-03-05 12:00   ` Christian Borntraeger
  0 siblings, 0 replies; 72+ messages in thread
From: Christian Borntraeger @ 2020-03-05 12:00 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: qemu-s390x, cohuck, david



On 04.03.20 12:42, Janosch Frank wrote:
> Ballooning in protected VMs can only be done when the guest shares the
> pages it gives to the host. If pages are not shared, the integrity
> checks will fail once those pages have been altered and are given back
> to the guest.
> 
> Hence, until we have a solution for this in the guest kernel, we
> inhibit ballooning when switching into protected mode and reverse that
> once we move out of it.

Can you maybe add the roadmap how to enable things.

1. we block ballooning now in QEMU (take this patch now)
2. Later Halil will provide a change to virtio that removes the blocker and adds
VIRTIO_F_IOMMU_PLATFORM automatically by QEMU when doing the protvirt switch. This
is ok as the guest balloon driver will reject to work with the IOMMU change
3. later we can fix the guest balloon driver to accept the IOMMU thing and then
do the right thing (make shared).

With an updated patch description:

Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com>


> 
> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
> Reviewed-by: David Hildenbrand <david@redhat.com>
> ---
>  hw/s390x/s390-virtio-ccw.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
> index 038bad54cd..b039178004 100644
> --- a/hw/s390x/s390-virtio-ccw.c
> +++ b/hw/s390x/s390-virtio-ccw.c
> @@ -41,6 +41,7 @@
>  #include "hw/qdev-properties.h"
>  #include "hw/s390x/tod.h"
>  #include "sysemu/sysemu.h"
> +#include "sysemu/balloon.h"
>  #include "hw/s390x/pv.h"
>  #include <linux/kvm.h>
>  #include "migration/blocker.h"
> @@ -335,6 +336,7 @@ static void s390_machine_unprotect(S390CcwMachineState *ms)
>          ms->pv = false;
>      }
>      migrate_del_blocker(pv_mig_blocker);
> +    qemu_balloon_inhibit(false);
>  }
>  
>  static int s390_machine_protect(S390CcwMachineState *ms)
> @@ -343,6 +345,7 @@ static int s390_machine_protect(S390CcwMachineState *ms)
>      CPUState *t;
>      int rc = -1;
>  
> +    qemu_balloon_inhibit(true);
>      if (!pv_mig_blocker) {
>          error_setg(&pv_mig_blocker,
>                     "protected VMs are currently not migrateable.");
> 



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 02/18] s390x: protvirt: Add diag308 subcodes 8 - 10
  2020-03-04 17:04   ` David Hildenbrand
@ 2020-03-05 12:04     ` Janosch Frank
  2020-03-05 12:24       ` Janosch Frank
  0 siblings, 1 reply; 72+ messages in thread
From: Janosch Frank @ 2020-03-05 12:04 UTC (permalink / raw)
  To: David Hildenbrand, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck


[-- Attachment #1.1: Type: text/plain, Size: 9401 bytes --]

On 3/4/20 6:04 PM, David Hildenbrand wrote:
> On 04.03.20 12:42, Janosch Frank wrote:
>> For diag308 subcodes 8 - 10 we have a new ipib of type 5. The ipib
>> holds the address and length of the secure execution header, as well
>> as a list of guest components.
>>
>> Each component is a block of memory, for example kernel or initrd,
>> which needs to be decrypted by the Ultravisor in order to run a
>> protected VM. The secure execution header instructs the Ultravisor on
>> how to handle the protected VM and its components.
>>
>> Subcodes 8 and 9 are similiar to 5 and 6 and subcode 10 will finally
>> start the protected guest.
>>
>> Subcodes 8-10 are not valid in protected mode, we have to do a subcode
>> 3 and then the 8 and 10 combination for a protected reboot.
>>
>> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
>> ---
>>  hw/s390x/ipl.c      | 47 ++++++++++++++++++++++++++++++++++++++++++---
>>  hw/s390x/ipl.h      | 32 ++++++++++++++++++++++++++++++
>>  target/s390x/diag.c | 26 ++++++++++++++++++++++---
>>  3 files changed, 99 insertions(+), 6 deletions(-)
>>
>> diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
>> index 9c1ecd423c..80c6ab233a 100644
>> --- a/hw/s390x/ipl.c
>> +++ b/hw/s390x/ipl.c
>> @@ -538,15 +538,55 @@ static bool is_virtio_scsi_device(IplParameterBlock *iplb)
>>      return is_virtio_ccw_device_of_type(iplb, VIRTIO_ID_SCSI);
>>  }
>>  
>> +int s390_ipl_pv_check_components(IplParameterBlock *iplb)
> 
> What about making this
> 
> bool s390_ipl_pv_valid(IplParameterBlock *iplb)
> 
> and return true/false?

We already have iplb_valid_pv() and ipl->iplb_valid_pv.
Do you have any other more expressive name we could use?

> 
>> +{
>> +    int i;
>> +    IPLBlockPV *ipib_pv = &iplb->pv;
> 
> nit: place "int i;" down here

Ack

> 
>> +
>> +    if (ipib_pv->num_comp == 0) {
>> +        return -EINVAL;
>> +    }
>> +
>> +    for (i = 0; i < ipib_pv->num_comp; i++) {
>> +        /* Addr must be 4k aligned */
>> +        if (ipib_pv->components[i].addr & ~TARGET_PAGE_MASK) {
>> +            return -EINVAL;
>> +        }
>> +
>> +        /* Tweak prefix is monotonously increasing with each component */
> 
> should that be "monotonically increasing" ?

Ooooooh, yeah...

> 
>> +        if (i < ipib_pv->num_comp - 1 &&
>> +            ipib_pv->components[i].tweak_pref >
>> +            ipib_pv->components[i + 1].tweak_pref) {
> 
> and I assume "==" is valid then.

Nope, it should be >= in this check

> 
>> +            return -EINVAL;
>> +        }
>> +    }
>> +    return 0;
>> +}
>> +
>>  void s390_ipl_update_diag308(IplParameterBlock *iplb)
>>  {
>>      S390IPLState *ipl = get_ipl_device();
>>  
>> -    ipl->iplb = *iplb;
>> -    ipl->iplb_valid = true;
>> +    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_secure(void)
> 
> Why suddenly the "secure" ? s390_ipl_get_iplb_pv?

Remnants of former times

> 
>> +{
>> +    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 +601,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) {
> 
> What about a switch-case now instead?
> 
>>          /* use CPU 0 for full resets */
>>          ipl->reset_cpu_index = 0;
>>      } else {
>> diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
>> index d4813105db..04be63cee1 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;
> 
> Do we need the packed here? All members are naturally aligned.

No, I'll remove them

> 
>> +typedef struct IPLBlockPVComp IPLBlockPVComp;
>> +
>> +struct IPLBlockPV {
>> +    uint8_t  reserved[87];
>> +    uint8_t  version;
>> +    uint32_t reserved70;
>> +    uint32_t num_comp;
>> +    uint64_t pv_header_addr;
>> +    uint64_t pv_header_len;
>> +    struct IPLBlockPVComp components[];
>> +} QEMU_PACKED;
> 
> Dito.
> 
> [...]
> 
>>      uint64_t compat_bios_start_addr;
>>      bool enforce_bios;
>>      bool iplb_valid;
>> +    bool iplb_valid_pv;
> 
> I'd name this "iplb_pv_valid" to match "iplb_pv".

I like matching prefixes :)

> 
>>      bool netboot;
>>      /* reset related properties don't have to be migrated or reset */
>>      enum s390_reset reset_type;
>> @@ -161,9 +185,11 @@ QEMU_BUILD_BUG_MSG(offsetof(S390IPLState, iplb) & 3, "alignment of iplb wrong");
>>  
>>  #define S390_IPL_TYPE_FCP 0x00
>>  #define S390_IPL_TYPE_CCW 0x02
>> +#define S390_IPL_TYPE_PV 0x05
>>  #define S390_IPL_TYPE_QEMU_SCSI 0xff
>>  
>>  #define S390_IPLB_HEADER_LEN 8
>> +#define S390_IPLB_MIN_PV_LEN 148
>>  #define S390_IPLB_MIN_CCW_LEN 200
>>  #define S390_IPLB_MIN_FCP_LEN 384
>>  #define S390_IPLB_MIN_QEMU_SCSI_LEN 200
>> @@ -185,4 +211,10 @@ static inline bool iplb_valid_fcp(IplParameterBlock *iplb)
>>             iplb->pbt == S390_IPL_TYPE_FCP;
>>  }
>>  
>> +static inline bool iplb_valid_pv(IplParameterBlock *iplb)
>> +{
>> +    return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_PV_LEN &&
>> +           iplb->pbt == S390_IPL_TYPE_PV;
>> +}
>> +
>>  #endif
>> diff --git a/target/s390x/diag.c b/target/s390x/diag.c
>> index b5aec06d6b..945b263f0a 100644
>> --- a/target/s390x/diag.c
>> +++ b/target/s390x/diag.c
>> @@ -52,6 +52,7 @@ int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
>>  #define DIAG_308_RC_OK              0x0001
>>  #define DIAG_308_RC_NO_CONF         0x0102
>>  #define DIAG_308_RC_INVALID         0x0402
>> +#define DIAG_308_RC_NO_PV_CONF      0x0902
>>  
>>  #define DIAG308_RESET_MOD_CLR       0
>>  #define DIAG308_RESET_LOAD_NORM     1
>> @@ -59,6 +60,9 @@ int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
>>  #define DIAG308_LOAD_NORMAL_DUMP    4
>>  #define DIAG308_SET                 5
>>  #define DIAG308_STORE               6
>> +#define DIAG308_PV_SET              8
>> +#define DIAG308_PV_STORE            9
>> +#define DIAG308_PV_START            10
>>  
>>  static int diag308_parm_check(CPUS390XState *env, uint64_t r1, uint64_t addr,
>>                                uintptr_t ra, bool write)
>> @@ -105,6 +109,7 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
>>          s390_ipl_reset_request(cs, S390_RESET_REIPL);
>>          break;
>>      case DIAG308_SET:
>> +    case DIAG308_PV_SET:
>>          if (diag308_parm_check(env, r1, addr, ra, false)) {
>>              return;
>>          }
>> @@ -117,7 +122,8 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
>>  
>>          cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len));
>>  
>> -        if (!iplb_valid_ccw(iplb) && !iplb_valid_fcp(iplb)) {
>> +        if (!iplb_valid_ccw(iplb) && !iplb_valid_fcp(iplb) &&
>> +            !(iplb_valid_pv(iplb) && !s390_ipl_pv_check_components(iplb))) {
> 
> I really think we should make this s390_ipl_pv_valid(), we're mixing
> functions that return true on success with functions that return 0 on
> success. Also, can't we simply move that check into iplb_valid_pv(iplb)
> to make this here easier to read?

Yes, let me figure something out

> 
>>              env->regs[r1 + 1] = DIAG_308_RC_INVALID;
>>              goto out;
>>          }
>> @@ -128,17 +134,31 @@ out:
>>          g_free(iplb);
>>          return;
>>      case DIAG308_STORE:
>> +    case DIAG308_PV_STORE:
>>          if (diag308_parm_check(env, r1, addr, ra, true)) {
>>              return;
>>          }
>> -        iplb = s390_ipl_get_iplb();
>> +        if (subcode == DIAG308_PV_STORE) {
>> +            iplb = s390_ipl_get_iplb_secure();
>> +        } else {
>> +            iplb = s390_ipl_get_iplb();
>> +        }
>>          if (iplb) {
>>              cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len));
>>              env->regs[r1 + 1] = DIAG_308_RC_OK;
>>          } else {
>>              env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;
>>          }
>> -        return;
>> +        break;
>> +    case DIAG308_PV_START:
>> +        iplb = s390_ipl_get_iplb_secure();
>> +        if (!iplb || !iplb_valid_pv(iplb)) {
> 
> Why do we need another iplb_valid_pv() check? I thought we would verify
> this when setting and marking valid.

Good question, I'll look into it and give this patch a dust off

> 
>> +            env->regs[r1 + 1] = DIAG_308_RC_NO_PV_CONF;
>> +            return;
>> +        }
>> +
> 
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 02/18] s390x: protvirt: Add diag308 subcodes 8 - 10
  2020-03-05 12:04     ` Janosch Frank
@ 2020-03-05 12:24       ` Janosch Frank
  2020-03-05 12:30         ` David Hildenbrand
  0 siblings, 1 reply; 72+ messages in thread
From: Janosch Frank @ 2020-03-05 12:24 UTC (permalink / raw)
  To: David Hildenbrand, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck


[-- Attachment #1.1: Type: text/plain, Size: 10753 bytes --]

On 3/5/20 1:04 PM, Janosch Frank wrote:
> On 3/4/20 6:04 PM, David Hildenbrand wrote:
>> On 04.03.20 12:42, Janosch Frank wrote:
>>> For diag308 subcodes 8 - 10 we have a new ipib of type 5. The ipib
>>> holds the address and length of the secure execution header, as well
>>> as a list of guest components.
>>>
>>> Each component is a block of memory, for example kernel or initrd,
>>> which needs to be decrypted by the Ultravisor in order to run a
>>> protected VM. The secure execution header instructs the Ultravisor on
>>> how to handle the protected VM and its components.
>>>
>>> Subcodes 8 and 9 are similiar to 5 and 6 and subcode 10 will finally
>>> start the protected guest.
>>>
>>> Subcodes 8-10 are not valid in protected mode, we have to do a subcode
>>> 3 and then the 8 and 10 combination for a protected reboot.
>>>
>>> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
>>> ---
>>>  hw/s390x/ipl.c      | 47 ++++++++++++++++++++++++++++++++++++++++++---
>>>  hw/s390x/ipl.h      | 32 ++++++++++++++++++++++++++++++
>>>  target/s390x/diag.c | 26 ++++++++++++++++++++++---
>>>  3 files changed, 99 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
>>> index 9c1ecd423c..80c6ab233a 100644
>>> --- a/hw/s390x/ipl.c
>>> +++ b/hw/s390x/ipl.c
>>> @@ -538,15 +538,55 @@ static bool is_virtio_scsi_device(IplParameterBlock *iplb)
>>>      return is_virtio_ccw_device_of_type(iplb, VIRTIO_ID_SCSI);
>>>  }
>>>  
>>> +int s390_ipl_pv_check_components(IplParameterBlock *iplb)
>>
>> What about making this
>>
>> bool s390_ipl_pv_valid(IplParameterBlock *iplb)
>>
>> and return true/false?
> 
> We already have iplb_valid_pv() and ipl->iplb_valid_pv.
> Do you have any other more expressive name we could use?

I think it makes more sense to rip out these tiny functions and
consolidate them like this:

+static inline bool iplb_valid(IplParameterBlock *iplb)
 {
-    return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_FCP_LEN &&
-           iplb->pbt == S390_IPL_TYPE_FCP;
+    switch (iplb->pbt) {
+        case S390_IPL_TYPE_FCP:
+            return (be32_to_cpu(iplb->len) >= S390_IPLB_MIN_FCP_LEN &&
+                    iplb->pbt == S390_IPL_TYPE_FCP);
+        case S390_IPL_TYPE_CCW:
+            return (be32_to_cpu(iplb->len) >= S390_IPLB_MIN_CCW_LEN &&
+                    iplb->pbt == S390_IPL_TYPE_CCW);
+        case S390_IPL_TYPE_PV:
+            if(be32_to_cpu(iplb->len) < S390_IPLB_MIN_PV_LEN ||
+               iplb->pbt != S390_IPL_TYPE_PV) {
+                return false;
+            }
+            return s390_ipl_pv_check_components(iplb);
+    default:
+        return false;
+    }
 }

The component check is still a separate function right above this one in
ipl.h

> 
>>
>>> +{
>>> +    int i;
>>> +    IPLBlockPV *ipib_pv = &iplb->pv;
>>
>> nit: place "int i;" down here
> 
> Ack
> 
>>
>>> +
>>> +    if (ipib_pv->num_comp == 0) {
>>> +        return -EINVAL;
>>> +    }
>>> +
>>> +    for (i = 0; i < ipib_pv->num_comp; i++) {
>>> +        /* Addr must be 4k aligned */
>>> +        if (ipib_pv->components[i].addr & ~TARGET_PAGE_MASK) {
>>> +            return -EINVAL;
>>> +        }
>>> +
>>> +        /* Tweak prefix is monotonously increasing with each component */
>>
>> should that be "monotonically increasing" ?
> 
> Ooooooh, yeah...
> 
>>
>>> +        if (i < ipib_pv->num_comp - 1 &&
>>> +            ipib_pv->components[i].tweak_pref >
>>> +            ipib_pv->components[i + 1].tweak_pref) {
>>
>> and I assume "==" is valid then.
> 
> Nope, it should be >= in this check
> 
>>
>>> +            return -EINVAL;
>>> +        }
>>> +    }
>>> +    return 0;
>>> +}
>>> +
>>>  void s390_ipl_update_diag308(IplParameterBlock *iplb)
>>>  {
>>>      S390IPLState *ipl = get_ipl_device();
>>>  
>>> -    ipl->iplb = *iplb;
>>> -    ipl->iplb_valid = true;
>>> +    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_secure(void)
>>
>> Why suddenly the "secure" ? s390_ipl_get_iplb_pv?
> 
> Remnants of former times
> 
>>
>>> +{
>>> +    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 +601,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) {
>>
>> What about a switch-case now instead?
>>
>>>          /* use CPU 0 for full resets */
>>>          ipl->reset_cpu_index = 0;
>>>      } else {
>>> diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
>>> index d4813105db..04be63cee1 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;
>>
>> Do we need the packed here? All members are naturally aligned.
> 
> No, I'll remove them
> 
>>
>>> +typedef struct IPLBlockPVComp IPLBlockPVComp;
>>> +
>>> +struct IPLBlockPV {
>>> +    uint8_t  reserved[87];
>>> +    uint8_t  version;
>>> +    uint32_t reserved70;
>>> +    uint32_t num_comp;
>>> +    uint64_t pv_header_addr;
>>> +    uint64_t pv_header_len;
>>> +    struct IPLBlockPVComp components[];
>>> +} QEMU_PACKED;
>>
>> Dito.
>>
>> [...]
>>
>>>      uint64_t compat_bios_start_addr;
>>>      bool enforce_bios;
>>>      bool iplb_valid;
>>> +    bool iplb_valid_pv;
>>
>> I'd name this "iplb_pv_valid" to match "iplb_pv".
> 
> I like matching prefixes :)
> 
>>
>>>      bool netboot;
>>>      /* reset related properties don't have to be migrated or reset */
>>>      enum s390_reset reset_type;
>>> @@ -161,9 +185,11 @@ QEMU_BUILD_BUG_MSG(offsetof(S390IPLState, iplb) & 3, "alignment of iplb wrong");
>>>  
>>>  #define S390_IPL_TYPE_FCP 0x00
>>>  #define S390_IPL_TYPE_CCW 0x02
>>> +#define S390_IPL_TYPE_PV 0x05
>>>  #define S390_IPL_TYPE_QEMU_SCSI 0xff
>>>  
>>>  #define S390_IPLB_HEADER_LEN 8
>>> +#define S390_IPLB_MIN_PV_LEN 148
>>>  #define S390_IPLB_MIN_CCW_LEN 200
>>>  #define S390_IPLB_MIN_FCP_LEN 384
>>>  #define S390_IPLB_MIN_QEMU_SCSI_LEN 200
>>> @@ -185,4 +211,10 @@ static inline bool iplb_valid_fcp(IplParameterBlock *iplb)
>>>             iplb->pbt == S390_IPL_TYPE_FCP;
>>>  }
>>>  
>>> +static inline bool iplb_valid_pv(IplParameterBlock *iplb)
>>> +{
>>> +    return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_PV_LEN &&
>>> +           iplb->pbt == S390_IPL_TYPE_PV;
>>> +}
>>> +
>>>  #endif
>>> diff --git a/target/s390x/diag.c b/target/s390x/diag.c
>>> index b5aec06d6b..945b263f0a 100644
>>> --- a/target/s390x/diag.c
>>> +++ b/target/s390x/diag.c
>>> @@ -52,6 +52,7 @@ int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
>>>  #define DIAG_308_RC_OK              0x0001
>>>  #define DIAG_308_RC_NO_CONF         0x0102
>>>  #define DIAG_308_RC_INVALID         0x0402
>>> +#define DIAG_308_RC_NO_PV_CONF      0x0902
>>>  
>>>  #define DIAG308_RESET_MOD_CLR       0
>>>  #define DIAG308_RESET_LOAD_NORM     1
>>> @@ -59,6 +60,9 @@ int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
>>>  #define DIAG308_LOAD_NORMAL_DUMP    4
>>>  #define DIAG308_SET                 5
>>>  #define DIAG308_STORE               6
>>> +#define DIAG308_PV_SET              8
>>> +#define DIAG308_PV_STORE            9
>>> +#define DIAG308_PV_START            10
>>>  
>>>  static int diag308_parm_check(CPUS390XState *env, uint64_t r1, uint64_t addr,
>>>                                uintptr_t ra, bool write)
>>> @@ -105,6 +109,7 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
>>>          s390_ipl_reset_request(cs, S390_RESET_REIPL);
>>>          break;
>>>      case DIAG308_SET:
>>> +    case DIAG308_PV_SET:
>>>          if (diag308_parm_check(env, r1, addr, ra, false)) {
>>>              return;
>>>          }
>>> @@ -117,7 +122,8 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
>>>  
>>>          cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len));
>>>  
>>> -        if (!iplb_valid_ccw(iplb) && !iplb_valid_fcp(iplb)) {
>>> +        if (!iplb_valid_ccw(iplb) && !iplb_valid_fcp(iplb) &&
>>> +            !(iplb_valid_pv(iplb) && !s390_ipl_pv_check_components(iplb))) {
>>
>> I really think we should make this s390_ipl_pv_valid(), we're mixing
>> functions that return true on success with functions that return 0 on
>> success. Also, can't we simply move that check into iplb_valid_pv(iplb)
>> to make this here easier to read?
> 
> Yes, let me figure something out
> 
>>
>>>              env->regs[r1 + 1] = DIAG_308_RC_INVALID;
>>>              goto out;
>>>          }
>>> @@ -128,17 +134,31 @@ out:
>>>          g_free(iplb);
>>>          return;
>>>      case DIAG308_STORE:
>>> +    case DIAG308_PV_STORE:
>>>          if (diag308_parm_check(env, r1, addr, ra, true)) {
>>>              return;
>>>          }
>>> -        iplb = s390_ipl_get_iplb();
>>> +        if (subcode == DIAG308_PV_STORE) {
>>> +            iplb = s390_ipl_get_iplb_secure();
>>> +        } else {
>>> +            iplb = s390_ipl_get_iplb();
>>> +        }
>>>          if (iplb) {
>>>              cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len));
>>>              env->regs[r1 + 1] = DIAG_308_RC_OK;
>>>          } else {
>>>              env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;
>>>          }
>>> -        return;
>>> +        break;
>>> +    case DIAG308_PV_START:
>>> +        iplb = s390_ipl_get_iplb_secure();
>>> +        if (!iplb || !iplb_valid_pv(iplb)) {
>>
>> Why do we need another iplb_valid_pv() check? I thought we would verify
>> this when setting and marking valid.
> 
> Good question, I'll look into it and give this patch a dust off
> 
>>
>>> +            env->regs[r1 + 1] = DIAG_308_RC_NO_PV_CONF;
>>> +            return;
>>> +        }
>>> +
>>
>>
> 
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 02/18] s390x: protvirt: Add diag308 subcodes 8 - 10
  2020-03-05 12:24       ` Janosch Frank
@ 2020-03-05 12:30         ` David Hildenbrand
  0 siblings, 0 replies; 72+ messages in thread
From: David Hildenbrand @ 2020-03-05 12:30 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

On 05.03.20 13:24, Janosch Frank wrote:
> On 3/5/20 1:04 PM, Janosch Frank wrote:
>> On 3/4/20 6:04 PM, David Hildenbrand wrote:
>>> On 04.03.20 12:42, Janosch Frank wrote:
>>>> For diag308 subcodes 8 - 10 we have a new ipib of type 5. The ipib
>>>> holds the address and length of the secure execution header, as well
>>>> as a list of guest components.
>>>>
>>>> Each component is a block of memory, for example kernel or initrd,
>>>> which needs to be decrypted by the Ultravisor in order to run a
>>>> protected VM. The secure execution header instructs the Ultravisor on
>>>> how to handle the protected VM and its components.
>>>>
>>>> Subcodes 8 and 9 are similiar to 5 and 6 and subcode 10 will finally
>>>> start the protected guest.
>>>>
>>>> Subcodes 8-10 are not valid in protected mode, we have to do a subcode
>>>> 3 and then the 8 and 10 combination for a protected reboot.
>>>>
>>>> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
>>>> ---
>>>>  hw/s390x/ipl.c      | 47 ++++++++++++++++++++++++++++++++++++++++++---
>>>>  hw/s390x/ipl.h      | 32 ++++++++++++++++++++++++++++++
>>>>  target/s390x/diag.c | 26 ++++++++++++++++++++++---
>>>>  3 files changed, 99 insertions(+), 6 deletions(-)
>>>>
>>>> diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
>>>> index 9c1ecd423c..80c6ab233a 100644
>>>> --- a/hw/s390x/ipl.c
>>>> +++ b/hw/s390x/ipl.c
>>>> @@ -538,15 +538,55 @@ static bool is_virtio_scsi_device(IplParameterBlock *iplb)
>>>>      return is_virtio_ccw_device_of_type(iplb, VIRTIO_ID_SCSI);
>>>>  }
>>>>  
>>>> +int s390_ipl_pv_check_components(IplParameterBlock *iplb)
>>>
>>> What about making this
>>>
>>> bool s390_ipl_pv_valid(IplParameterBlock *iplb)
>>>
>>> and return true/false?
>>
>> We already have iplb_valid_pv() and ipl->iplb_valid_pv.
>> Do you have any other more expressive name we could use?
> 
> I think it makes more sense to rip out these tiny functions and
> consolidate them like this:
> 
> +static inline bool iplb_valid(IplParameterBlock *iplb)
>  {
> -    return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_FCP_LEN &&
> -           iplb->pbt == S390_IPL_TYPE_FCP;
> +    switch (iplb->pbt) {
> +        case S390_IPL_TYPE_FCP:
> +            return (be32_to_cpu(iplb->len) >= S390_IPLB_MIN_FCP_LEN &&
> +                    iplb->pbt == S390_IPL_TYPE_FCP);
> +        case S390_IPL_TYPE_CCW:
> +            return (be32_to_cpu(iplb->len) >= S390_IPLB_MIN_CCW_LEN &&
> +                    iplb->pbt == S390_IPL_TYPE_CCW);
> +        case S390_IPL_TYPE_PV:
> +            if(be32_to_cpu(iplb->len) < S390_IPLB_MIN_PV_LEN ||
> +               iplb->pbt != S390_IPL_TYPE_PV) {
> +                return false;
> +            }
> +            return s390_ipl_pv_check_components(iplb);

yeah, and maybe even inline s390_ipl_pv_check_components().

-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 03/18] s390x: protvirt: Support unpack facility
  2020-03-04 11:42 ` [PATCH v6 03/18] s390x: protvirt: Support unpack facility Janosch Frank
@ 2020-03-05 13:51   ` David Hildenbrand
  2020-03-05 14:10     ` Janosch Frank
  2020-03-05 13:52   ` David Hildenbrand
  2020-03-06 11:48   ` Christian Borntraeger
  2 siblings, 1 reply; 72+ messages in thread
From: David Hildenbrand @ 2020-03-05 13:51 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

On 04.03.20 12:42, Janosch Frank wrote:
> When a guest has saved a ipib of type 5 and calls diagnose308 with

s/a/an/

> subcode 10, we have to setup the protected processing environment via
> Ultravisor calls. The calls are done by KVM and are exposed via an
> API.
> 
> The following steps are necessary:
> 1. Enable protected mode for the VM (register it and its cpus with the Ultravisor)
> 2. Forward the secure header to the Ultravisor (has all information on
> how to decrypt the image and VM information)
> 3. Protect image pages from the host and decrypt them
> 4. Verify the image integrity
> 
> Only after step 4 a protected VM is allowed to run.
> 
> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> [Changes
> to machine]
> ---
>  hw/s390x/Makefile.objs              |   1 +
>  hw/s390x/ipl.c                      |  33 +++++++++
>  hw/s390x/ipl.h                      |   2 +
>  hw/s390x/pv.c                       | 106 ++++++++++++++++++++++++++++
>  hw/s390x/pv.h                       |  34 +++++++++
>  hw/s390x/s390-virtio-ccw.c          |  91 ++++++++++++++++++++++++
>  include/hw/s390x/s390-virtio-ccw.h  |   1 +
>  target/s390x/cpu.c                  |   4 ++
>  target/s390x/cpu.h                  |   1 +
>  target/s390x/cpu_features_def.inc.h |   1 +
>  10 files changed, 274 insertions(+)
>  create mode 100644 hw/s390x/pv.c
>  create mode 100644 hw/s390x/pv.h

[...]

>  
>  #define KERN_IMAGE_START                0x010000UL
>  #define LINUX_MAGIC_ADDR                0x010008UL
> @@ -676,6 +677,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;
> +        }

You can check for " && !rc" in the loop condition

> +    }
> +    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 04be63cee1..ad8090a02c 100644
> --- a/hw/s390x/ipl.h
> +++ b/hw/s390x/ipl.h
> @@ -105,6 +105,8 @@ typedef union IplParameterBlock IplParameterBlock;
>  int s390_ipl_set_loadparm(uint8_t *loadparm);
>  int s390_ipl_pv_check_components(IplParameterBlock *iplb);
>  void s390_ipl_update_diag308(IplParameterBlock *iplb);
> +int s390_ipl_prepare_pv_header(void);
> +int s390_ipl_pv_unpack(void);
>  void s390_ipl_prepare_cpu(S390CPU *cpu);
>  IplParameterBlock *s390_ipl_get_iplb(void);
>  IplParameterBlock *s390_ipl_get_iplb_secure(void);
> diff --git a/hw/s390x/pv.c b/hw/s390x/pv.c
> new file mode 100644
> index 0000000000..50b68b6c34
> --- /dev/null
> +++ b/hw/s390x/pv.c
> @@ -0,0 +1,106 @@
> +/*
> + * Secure execution functions
> + *
> + * Copyright IBM Corp. 2020
> + * Author(s):
> + *  Janosch Frank <frankja@linux.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or (at
> + * your option) any later version. See the COPYING file in the top-level
> + * directory.
> + */
> +#include "qemu/osdep.h"
> +#include <sys/ioctl.h>
> +
> +#include <linux/kvm.h>
> +
> +#include "qemu/error-report.h"
> +#include "sysemu/kvm.h"
> +#include "pv.h"
> +
> +const char *cmd_names[] = {
> +    "VM_ENABLE",
> +    "VM_DISABLE",
> +    "VM_SET_SEC_PARAMS",
> +    "VM_UNPACK",
> +    "VM_VERIFY",
> +    "VM_PREP_RESET",
> +    "VM_UNSHARE_ALL",
> +    NULL

Is the NULL really needed? This will be somewhat error prone when we add
new PV commands. Not sure if guarding this by an access function (chack
against ARRAY_SIZE() makes sense).

> diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
> index a89cf4c129..dd39890f89 100644
> --- a/hw/s390x/s390-virtio-ccw.c
> +++ b/hw/s390x/s390-virtio-ccw.c
> @@ -41,6 +41,8 @@
>  #include "hw/qdev-properties.h"
>  #include "hw/s390x/tod.h"
>  #include "sysemu/sysemu.h"
> +#include "hw/s390x/pv.h"
> +#include <linux/kvm.h>
>  
>  S390CPU *s390_cpu_addr2state(uint16_t cpu_addr)
>  {
> @@ -238,9 +240,11 @@ static void s390_create_sclpconsole(const char *type, Chardev *chardev)
>  static void ccw_init(MachineState *machine)
>  {
>      int ret;
> +    S390CcwMachineState *ms = S390_CCW_MACHINE(machine);
>      VirtualCssBus *css_bus;
>      DeviceState *dev;
>  
> +    ms->pv = false;

Should not be necessary, default is false.

>      s390_sclp_init();
>      /* init memory + setup max page size. Required for the CPU model */
>      s390_memory_init(machine->ram);
> @@ -316,10 +320,75 @@ static inline void s390_do_cpu_ipl(CPUState *cs, run_on_cpu_data arg)
>      s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
>  }
>  
> +static void s390_machine_unprotect(S390CcwMachineState *ms)
> +{
> +    CPUState *t;
> +
> +    if (!ms->pv)
> +        return;

How can this ever happen? g_assert(ms->pv) ?

Also, i don't see this function getting called from anywhere else except
when s390_machine_protect() fails. That looks wrong. This has to be
called when going out of PV mode.


> +    s390_pv_vm_disable();
> +    CPU_FOREACH(t) {
> +        S390_CPU(t)->env.pv = false;
> +    }
> +    ms->pv = false;
> +}
> +
> +static int s390_machine_protect(S390CcwMachineState *ms)
> +{
> +    CPUState *t;
> +    int rc;
> +

g_assert(!ms->pv) ?

> +    /* Create SE VM */
> +    rc = s390_pv_vm_enable();
> +    if (rc) {
> +        return rc;
> +    }
> +
> +    CPU_FOREACH(t) {
> +        S390_CPU(t)->env.pv = true;
> +    }
> +    ms->pv = true;
> +
> +    /* Set SE header and unpack */
> +    rc = s390_ipl_prepare_pv_header();
> +    if (rc) {
> +        goto out_err;
> +    }
> +
> +    /* Decrypt image */
> +    rc = s390_ipl_pv_unpack();
> +    if (rc) {
> +        goto out_err;
> +    }
> +
> +    /* Verify integrity */
> +    rc = s390_pv_verify();
> +    if (rc) {
> +        goto out_err;
> +    }
> +    return rc;
> +
> +out_err:
> +    s390_machine_unprotect(ms);
> +    return rc;
> +}
> +
> +#define DIAG_308_RC_INVAL_FOR_PV    0x0a02
> +static void s390_machine_inject_pv_error(CPUState *cs)
> +{
> +    int r1 = (cs->kvm_run->s390_sieic.ipa & 0x00f0) >> 4;
> +    CPUS390XState *env = &S390_CPU(cs)->env;
> +
> +    /* Report that we are unable to enter protected mode */
> +    env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV;
> +}
> +

[...]
>      switch (reset_type) {
>      case S390_RESET_EXTERNAL:
>      case S390_RESET_REIPL:
> @@ -353,6 +424,26 @@ static void s390_machine_reset(MachineState *machine)
>          }
>          subsystem_reset();
>          run_on_cpu(cs, s390_do_cpu_initial_reset, RUN_ON_CPU_NULL);
> +        run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL);

This does look unrelated and wrong?

> +        break;
> +    case S390_RESET_PV: /* Subcode 10 */
> +        subsystem_reset();
> +        s390_crypto_reset();
> +
> +        CPU_FOREACH(t) {
> +            if (t == cs) {
> +                continue;
> +            }
> +            run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
> +        }
> +        run_on_cpu(cs, s390_do_cpu_reset, RUN_ON_CPU_NULL);
> +
> +        if (s390_machine_protect(ms)) {
> +            s390_machine_inject_pv_error(cs);

Ah, so it's not an actual exception. BUT: All other guest cpus were
reset, can the guest deal with that?

(run_on_cpu(cs, s390_do_cpu_reset, RUN_ON_CPU_NULL) should go after the
s390_machine_protect() I assume - the change you had in the other patch)

> +            s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
> +            return;
> +        }
> +
>          run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL);
>          break;
>      default:


-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 03/18] s390x: protvirt: Support unpack facility
  2020-03-04 11:42 ` [PATCH v6 03/18] s390x: protvirt: Support unpack facility Janosch Frank
  2020-03-05 13:51   ` David Hildenbrand
@ 2020-03-05 13:52   ` David Hildenbrand
  2020-03-05 14:15     ` Janosch Frank
  2020-03-06 11:48   ` Christian Borntraeger
  2 siblings, 1 reply; 72+ messages in thread
From: David Hildenbrand @ 2020-03-05 13:52 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

On 04.03.20 12:42, Janosch Frank wrote:
> When a guest has saved a ipib of type 5 and calls diagnose308 with
> subcode 10, we have to setup the protected processing environment via
> Ultravisor calls. The calls are done by KVM and are exposed via an
> API.
> 
> The following steps are necessary:
> 1. Enable protected mode for the VM (register it and its cpus with the Ultravisor)
> 2. Forward the secure header to the Ultravisor (has all information on
> how to decrypt the image and VM information)
> 3. Protect image pages from the host and decrypt them
> 4. Verify the image integrity
> 
> Only after step 4 a protected VM is allowed to run.
> 
> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> [Changes
> to machine]
> ---
>  hw/s390x/Makefile.objs              |   1 +
>  hw/s390x/ipl.c                      |  33 +++++++++
>  hw/s390x/ipl.h                      |   2 +
>  hw/s390x/pv.c                       | 106 ++++++++++++++++++++++++++++
>  hw/s390x/pv.h                       |  34 +++++++++
>  hw/s390x/s390-virtio-ccw.c          |  91 ++++++++++++++++++++++++
>  include/hw/s390x/s390-virtio-ccw.h  |   1 +
>  target/s390x/cpu.c                  |   4 ++
>  target/s390x/cpu.h                  |   1 +
>  target/s390x/cpu_features_def.inc.h |   1 +
>  10 files changed, 274 insertions(+)
>  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 80c6ab233a..3b241ea549 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
> @@ -676,6 +677,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 04be63cee1..ad8090a02c 100644
> --- a/hw/s390x/ipl.h
> +++ b/hw/s390x/ipl.h
> @@ -105,6 +105,8 @@ typedef union IplParameterBlock IplParameterBlock;
>  int s390_ipl_set_loadparm(uint8_t *loadparm);
>  int s390_ipl_pv_check_components(IplParameterBlock *iplb);
>  void s390_ipl_update_diag308(IplParameterBlock *iplb);
> +int s390_ipl_prepare_pv_header(void);
> +int s390_ipl_pv_unpack(void);
>  void s390_ipl_prepare_cpu(S390CPU *cpu);
>  IplParameterBlock *s390_ipl_get_iplb(void);
>  IplParameterBlock *s390_ipl_get_iplb_secure(void);
> diff --git a/hw/s390x/pv.c b/hw/s390x/pv.c
> new file mode 100644
> index 0000000000..50b68b6c34
> --- /dev/null
> +++ b/hw/s390x/pv.c
> @@ -0,0 +1,106 @@
> +/*
> + * Secure execution functions
> + *
> + * Copyright IBM Corp. 2020
> + * Author(s):
> + *  Janosch Frank <frankja@linux.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or (at
> + * your option) any later version. See the COPYING file in the top-level
> + * directory.
> + */
> +#include "qemu/osdep.h"
> +#include <sys/ioctl.h>

Do you really need that include? You're using kvm_vm_ioctl().

-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 03/18] s390x: protvirt: Support unpack facility
  2020-03-05 13:51   ` David Hildenbrand
@ 2020-03-05 14:10     ` Janosch Frank
  2020-03-05 14:15       ` David Hildenbrand
  0 siblings, 1 reply; 72+ messages in thread
From: Janosch Frank @ 2020-03-05 14:10 UTC (permalink / raw)
  To: David Hildenbrand, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck


[-- Attachment #1.1: Type: text/plain, Size: 9657 bytes --]

On 3/5/20 2:51 PM, David Hildenbrand wrote:
> On 04.03.20 12:42, Janosch Frank wrote:
>> When a guest has saved a ipib of type 5 and calls diagnose308 with
> 
> s/a/an/
> 
>> subcode 10, we have to setup the protected processing environment via
>> Ultravisor calls. The calls are done by KVM and are exposed via an
>> API.
>>
>> The following steps are necessary:
>> 1. Enable protected mode for the VM (register it and its cpus with the Ultravisor)
>> 2. Forward the secure header to the Ultravisor (has all information on
>> how to decrypt the image and VM information)
>> 3. Protect image pages from the host and decrypt them
>> 4. Verify the image integrity
>>
>> Only after step 4 a protected VM is allowed to run.
>>
>> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
>> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> [Changes
>> to machine]
>> ---
>>  hw/s390x/Makefile.objs              |   1 +
>>  hw/s390x/ipl.c                      |  33 +++++++++
>>  hw/s390x/ipl.h                      |   2 +
>>  hw/s390x/pv.c                       | 106 ++++++++++++++++++++++++++++
>>  hw/s390x/pv.h                       |  34 +++++++++
>>  hw/s390x/s390-virtio-ccw.c          |  91 ++++++++++++++++++++++++
>>  include/hw/s390x/s390-virtio-ccw.h  |   1 +
>>  target/s390x/cpu.c                  |   4 ++
>>  target/s390x/cpu.h                  |   1 +
>>  target/s390x/cpu_features_def.inc.h |   1 +
>>  10 files changed, 274 insertions(+)
>>  create mode 100644 hw/s390x/pv.c
>>  create mode 100644 hw/s390x/pv.h
> 
> [...]
> 
>>  
>>  #define KERN_IMAGE_START                0x010000UL
>>  #define LINUX_MAGIC_ADDR                0x010008UL
>> @@ -676,6 +677,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;
>> +        }
> 
> You can check for " && !rc" in the loop condition

Not sure if that would make it more readable...

> 
>> +    }
>> +    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 04be63cee1..ad8090a02c 100644
>> --- a/hw/s390x/ipl.h
>> +++ b/hw/s390x/ipl.h
>> @@ -105,6 +105,8 @@ typedef union IplParameterBlock IplParameterBlock;
>>  int s390_ipl_set_loadparm(uint8_t *loadparm);
>>  int s390_ipl_pv_check_components(IplParameterBlock *iplb);
>>  void s390_ipl_update_diag308(IplParameterBlock *iplb);
>> +int s390_ipl_prepare_pv_header(void);
>> +int s390_ipl_pv_unpack(void);
>>  void s390_ipl_prepare_cpu(S390CPU *cpu);
>>  IplParameterBlock *s390_ipl_get_iplb(void);
>>  IplParameterBlock *s390_ipl_get_iplb_secure(void);
>> diff --git a/hw/s390x/pv.c b/hw/s390x/pv.c
>> new file mode 100644
>> index 0000000000..50b68b6c34
>> --- /dev/null
>> +++ b/hw/s390x/pv.c
>> @@ -0,0 +1,106 @@
>> +/*
>> + * Secure execution functions
>> + *
>> + * Copyright IBM Corp. 2020
>> + * Author(s):
>> + *  Janosch Frank <frankja@linux.ibm.com>
>> + *
>> + * This work is licensed under the terms of the GNU GPL, version 2 or (at
>> + * your option) any later version. See the COPYING file in the top-level
>> + * directory.
>> + */
>> +#include "qemu/osdep.h"
>> +#include <sys/ioctl.h>
>> +
>> +#include <linux/kvm.h>
>> +
>> +#include "qemu/error-report.h"
>> +#include "sysemu/kvm.h"
>> +#include "pv.h"
>> +
>> +const char *cmd_names[] = {
>> +    "VM_ENABLE",
>> +    "VM_DISABLE",
>> +    "VM_SET_SEC_PARAMS",
>> +    "VM_UNPACK",
>> +    "VM_VERIFY",
>> +    "VM_PREP_RESET",
>> +    "VM_UNSHARE_ALL",
>> +    NULL
> 
> Is the NULL really needed? This will be somewhat error prone when we add
> new PV commands. Not sure if guarding this by an access function (chack
> against ARRAY_SIZE() makes sense).
> 
>> diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
>> index a89cf4c129..dd39890f89 100644
>> --- a/hw/s390x/s390-virtio-ccw.c
>> +++ b/hw/s390x/s390-virtio-ccw.c
>> @@ -41,6 +41,8 @@
>>  #include "hw/qdev-properties.h"
>>  #include "hw/s390x/tod.h"
>>  #include "sysemu/sysemu.h"
>> +#include "hw/s390x/pv.h"
>> +#include <linux/kvm.h>
>>  
>>  S390CPU *s390_cpu_addr2state(uint16_t cpu_addr)
>>  {
>> @@ -238,9 +240,11 @@ static void s390_create_sclpconsole(const char *type, Chardev *chardev)
>>  static void ccw_init(MachineState *machine)
>>  {
>>      int ret;
>> +    S390CcwMachineState *ms = S390_CCW_MACHINE(machine);
>>      VirtualCssBus *css_bus;
>>      DeviceState *dev;
>>  
>> +    ms->pv = false;
> 
> Should not be necessary, default is false.

ok

> 
>>      s390_sclp_init();
>>      /* init memory + setup max page size. Required for the CPU model */
>>      s390_memory_init(machine->ram);
>> @@ -316,10 +320,75 @@ static inline void s390_do_cpu_ipl(CPUState *cs, run_on_cpu_data arg)
>>      s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
>>  }
>>  
>> +static void s390_machine_unprotect(S390CcwMachineState *ms)
>> +{
>> +    CPUState *t;
>> +
>> +    if (!ms->pv)
>> +        return;
> 
> How can this ever happen? g_assert(ms->pv) ?

Currently not, that's only used in the follow up patches with the ballon
and migration blocker

> 
> Also, i don't see this function getting called from anywhere else except
> when s390_machine_protect() fails. That looks wrong. This has to be
> called when going out of PV mode.

Yes, but that's in the diag308 1-4 patch.

> 
> 
>> +    s390_pv_vm_disable();
>> +    CPU_FOREACH(t) {
>> +        S390_CPU(t)->env.pv = false;
>> +    }
>> +    ms->pv = false;
>> +}
>> +
>> +static int s390_machine_protect(S390CcwMachineState *ms)
>> +{
>> +    CPUState *t;
>> +    int rc;
>> +
> 
> g_assert(!ms->pv) ?

Ok

> 
>> +    /* Create SE VM */
>> +    rc = s390_pv_vm_enable();
>> +    if (rc) {
>> +        return rc;
>> +    }
>> +
>> +    CPU_FOREACH(t) {
>> +        S390_CPU(t)->env.pv = true;
>> +    }
>> +    ms->pv = true;
>> +
>> +    /* Set SE header and unpack */
>> +    rc = s390_ipl_prepare_pv_header();
>> +    if (rc) {
>> +        goto out_err;
>> +    }
>> +
>> +    /* Decrypt image */
>> +    rc = s390_ipl_pv_unpack();
>> +    if (rc) {
>> +        goto out_err;
>> +    }
>> +
>> +    /* Verify integrity */
>> +    rc = s390_pv_verify();
>> +    if (rc) {
>> +        goto out_err;
>> +    }
>> +    return rc;
>> +
>> +out_err:
>> +    s390_machine_unprotect(ms);
>> +    return rc;
>> +}
>> +
>> +#define DIAG_308_RC_INVAL_FOR_PV    0x0a02
>> +static void s390_machine_inject_pv_error(CPUState *cs)
>> +{
>> +    int r1 = (cs->kvm_run->s390_sieic.ipa & 0x00f0) >> 4;
>> +    CPUS390XState *env = &S390_CPU(cs)->env;
>> +
>> +    /* Report that we are unable to enter protected mode */
>> +    env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV;
>> +}
>> +
> 
> [...]
>>      switch (reset_type) {
>>      case S390_RESET_EXTERNAL:
>>      case S390_RESET_REIPL:
>> @@ -353,6 +424,26 @@ static void s390_machine_reset(MachineState *machine)
>>          }
>>          subsystem_reset();
>>          run_on_cpu(cs, s390_do_cpu_initial_reset, RUN_ON_CPU_NULL);
>> +        run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL);
> 
> This does look unrelated and wrong?

Indeed, that looks dodgy

> 
>> +        break;
>> +    case S390_RESET_PV: /* Subcode 10 */
>> +        subsystem_reset();
>> +        s390_crypto_reset();
>> +
>> +        CPU_FOREACH(t) {
>> +            if (t == cs) {
>> +                continue;
>> +            }
>> +            run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
>> +        }
>> +        run_on_cpu(cs, s390_do_cpu_reset, RUN_ON_CPU_NULL);
>> +
>> +        if (s390_machine_protect(ms)) {
>> +            s390_machine_inject_pv_error(cs);
> 
> Ah, so it's not an actual exception. BUT: All other guest cpus were
> reset, can the guest deal with that?

Well, all other CPUs should be stopped for diag308, no?
Also it's done by the bootloader and not a OS which just stops its cpus
and goes into protected mode.

> 
> (run_on_cpu(cs, s390_do_cpu_reset, RUN_ON_CPU_NULL) should go after the
> s390_machine_protect() I assume - the change you had in the other patch)

That's not a good idea, I want to reset before we automatically call the
UV routines on a reset.

> 
>> +            s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
>> +            return;
>> +        }
>> +
>>          run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL);
>>          break;
>>      default:
> 
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 03/18] s390x: protvirt: Support unpack facility
  2020-03-05 14:10     ` Janosch Frank
@ 2020-03-05 14:15       ` David Hildenbrand
  2020-03-05 14:20         ` Janosch Frank
  0 siblings, 1 reply; 72+ messages in thread
From: David Hildenbrand @ 2020-03-05 14:15 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

>>>  
>>> +static void s390_machine_unprotect(S390CcwMachineState *ms)
>>> +{
>>> +    CPUState *t;
>>> +
>>> +    if (!ms->pv)
>>> +        return;
>>
>> How can this ever happen? g_assert(ms->pv) ?
> 
> Currently not, that's only used in the follow up patches with the ballon
> and migration blocker

Even then, why should we unprotect when not protected. That looks wrong
to me and has to be fixed in the other patches,

> 
>>
>> Also, i don't see this function getting called from anywhere else except
>> when s390_machine_protect() fails. That looks wrong. This has to be
>> called when going out of PV mode.
> 
> Yes, but that's in the diag308 1-4 patch.

The way patches were split up is somewhat sub-optimal for review.

[...]

>>> +        break;
>>> +    case S390_RESET_PV: /* Subcode 10 */
>>> +        subsystem_reset();
>>> +        s390_crypto_reset();
>>> +
>>> +        CPU_FOREACH(t) {
>>> +            if (t == cs) {
>>> +                continue;
>>> +            }
>>> +            run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
>>> +        }
>>> +        run_on_cpu(cs, s390_do_cpu_reset, RUN_ON_CPU_NULL);
>>> +
>>> +        if (s390_machine_protect(ms)) {
>>> +            s390_machine_inject_pv_error(cs);
>>
>> Ah, so it's not an actual exception. BUT: All other guest cpus were
>> reset, can the guest deal with that?
> 
> Well, all other CPUs should be stopped for diag308, no?
> Also it's done by the bootloader and not a OS which just stops its cpus
> and goes into protected mode.
> 
>>
>> (run_on_cpu(cs, s390_do_cpu_reset, RUN_ON_CPU_NULL) should go after the
>> s390_machine_protect() I assume - the change you had in the other patch)
> 
> That's not a good idea, I want to reset before we automatically call the
> UV routines on a reset.

But how can s390_machine_inject_pv_error(cs) be any effective if you
already reset the CPU?

-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 03/18] s390x: protvirt: Support unpack facility
  2020-03-05 13:52   ` David Hildenbrand
@ 2020-03-05 14:15     ` Janosch Frank
  0 siblings, 0 replies; 72+ messages in thread
From: Janosch Frank @ 2020-03-05 14:15 UTC (permalink / raw)
  To: David Hildenbrand, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck


[-- Attachment #1.1: Type: text/plain, Size: 4984 bytes --]

On 3/5/20 2:52 PM, David Hildenbrand wrote:
> On 04.03.20 12:42, Janosch Frank wrote:
>> When a guest has saved a ipib of type 5 and calls diagnose308 with
>> subcode 10, we have to setup the protected processing environment via
>> Ultravisor calls. The calls are done by KVM and are exposed via an
>> API.
>>
>> The following steps are necessary:
>> 1. Enable protected mode for the VM (register it and its cpus with the Ultravisor)
>> 2. Forward the secure header to the Ultravisor (has all information on
>> how to decrypt the image and VM information)
>> 3. Protect image pages from the host and decrypt them
>> 4. Verify the image integrity
>>
>> Only after step 4 a protected VM is allowed to run.
>>
>> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
>> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> [Changes
>> to machine]
>> ---
>>  hw/s390x/Makefile.objs              |   1 +
>>  hw/s390x/ipl.c                      |  33 +++++++++
>>  hw/s390x/ipl.h                      |   2 +
>>  hw/s390x/pv.c                       | 106 ++++++++++++++++++++++++++++
>>  hw/s390x/pv.h                       |  34 +++++++++
>>  hw/s390x/s390-virtio-ccw.c          |  91 ++++++++++++++++++++++++
>>  include/hw/s390x/s390-virtio-ccw.h  |   1 +
>>  target/s390x/cpu.c                  |   4 ++
>>  target/s390x/cpu.h                  |   1 +
>>  target/s390x/cpu_features_def.inc.h |   1 +
>>  10 files changed, 274 insertions(+)
>>  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 80c6ab233a..3b241ea549 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
>> @@ -676,6 +677,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 04be63cee1..ad8090a02c 100644
>> --- a/hw/s390x/ipl.h
>> +++ b/hw/s390x/ipl.h
>> @@ -105,6 +105,8 @@ typedef union IplParameterBlock IplParameterBlock;
>>  int s390_ipl_set_loadparm(uint8_t *loadparm);
>>  int s390_ipl_pv_check_components(IplParameterBlock *iplb);
>>  void s390_ipl_update_diag308(IplParameterBlock *iplb);
>> +int s390_ipl_prepare_pv_header(void);
>> +int s390_ipl_pv_unpack(void);
>>  void s390_ipl_prepare_cpu(S390CPU *cpu);
>>  IplParameterBlock *s390_ipl_get_iplb(void);
>>  IplParameterBlock *s390_ipl_get_iplb_secure(void);
>> diff --git a/hw/s390x/pv.c b/hw/s390x/pv.c
>> new file mode 100644
>> index 0000000000..50b68b6c34
>> --- /dev/null
>> +++ b/hw/s390x/pv.c
>> @@ -0,0 +1,106 @@
>> +/*
>> + * Secure execution functions
>> + *
>> + * Copyright IBM Corp. 2020
>> + * Author(s):
>> + *  Janosch Frank <frankja@linux.ibm.com>
>> + *
>> + * This work is licensed under the terms of the GNU GPL, version 2 or (at
>> + * your option) any later version. See the COPYING file in the top-level
>> + * directory.
>> + */
>> +#include "qemu/osdep.h"
>> +#include <sys/ioctl.h>
> 
> Do you really need that include? You're using kvm_vm_ioctl().
> 

Compiles without it, so I removed it :)


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 03/18] s390x: protvirt: Support unpack facility
  2020-03-05 14:15       ` David Hildenbrand
@ 2020-03-05 14:20         ` Janosch Frank
  2020-03-05 14:23           ` David Hildenbrand
  0 siblings, 1 reply; 72+ messages in thread
From: Janosch Frank @ 2020-03-05 14:20 UTC (permalink / raw)
  To: David Hildenbrand, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck


[-- Attachment #1.1: Type: text/plain, Size: 2209 bytes --]

On 3/5/20 3:15 PM, David Hildenbrand wrote:
>>>>  
>>>> +static void s390_machine_unprotect(S390CcwMachineState *ms)
>>>> +{
>>>> +    CPUState *t;
>>>> +
>>>> +    if (!ms->pv)
>>>> +        return;
>>>
>>> How can this ever happen? g_assert(ms->pv) ?
>>
>> Currently not, that's only used in the follow up patches with the ballon
>> and migration blocker
> 
> Even then, why should we unprotect when not protected. That looks wrong
> to me and has to be fixed in the other patches,

I fixed it this morning :)

> 
>>
>>>
>>> Also, i don't see this function getting called from anywhere else except
>>> when s390_machine_protect() fails. That looks wrong. This has to be
>>> called when going out of PV mode.
>>
>> Yes, but that's in the diag308 1-4 patch.
> 
> The way patches were split up is somewhat sub-optimal for review.

Thanks
I'll try to find a better split up of the code

> 
> [...]
> 
>>>> +        break;
>>>> +    case S390_RESET_PV: /* Subcode 10 */
>>>> +        subsystem_reset();
>>>> +        s390_crypto_reset();
>>>> +
>>>> +        CPU_FOREACH(t) {
>>>> +            if (t == cs) {
>>>> +                continue;
>>>> +            }
>>>> +            run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
>>>> +        }
>>>> +        run_on_cpu(cs, s390_do_cpu_reset, RUN_ON_CPU_NULL);
>>>> +
>>>> +        if (s390_machine_protect(ms)) {
>>>> +            s390_machine_inject_pv_error(cs);
>>>
>>> Ah, so it's not an actual exception. BUT: All other guest cpus were
>>> reset, can the guest deal with that?
>>
>> Well, all other CPUs should be stopped for diag308, no?
>> Also it's done by the bootloader and not a OS which just stops its cpus
>> and goes into protected mode.
>>
>>>
>>> (run_on_cpu(cs, s390_do_cpu_reset, RUN_ON_CPU_NULL) should go after the
>>> s390_machine_protect() I assume - the change you had in the other patch)
>>
>> That's not a good idea, I want to reset before we automatically call the
>> UV routines on a reset.
> 
> But how can s390_machine_inject_pv_error(cs) be any effective if you
> already reset the CPU?
> 

Because a normal cpu reset does not clear out the registers.


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 03/18] s390x: protvirt: Support unpack facility
  2020-03-05 14:20         ` Janosch Frank
@ 2020-03-05 14:23           ` David Hildenbrand
  2020-03-05 14:24             ` Janosch Frank
  0 siblings, 1 reply; 72+ messages in thread
From: David Hildenbrand @ 2020-03-05 14:23 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

On 05.03.20 15:20, Janosch Frank wrote:
> On 3/5/20 3:15 PM, David Hildenbrand wrote:
>>>>>  
>>>>> +static void s390_machine_unprotect(S390CcwMachineState *ms)
>>>>> +{
>>>>> +    CPUState *t;
>>>>> +
>>>>> +    if (!ms->pv)
>>>>> +        return;
>>>>
>>>> How can this ever happen? g_assert(ms->pv) ?
>>>
>>> Currently not, that's only used in the follow up patches with the ballon
>>> and migration blocker
>>
>> Even then, why should we unprotect when not protected. That looks wrong
>> to me and has to be fixed in the other patches,
> 
> I fixed it this morning :)
> 
>>
>>>
>>>>
>>>> Also, i don't see this function getting called from anywhere else except
>>>> when s390_machine_protect() fails. That looks wrong. This has to be
>>>> called when going out of PV mode.
>>>
>>> Yes, but that's in the diag308 1-4 patch.
>>
>> The way patches were split up is somewhat sub-optimal for review.
> 
> Thanks
> I'll try to find a better split up of the code
> 
>>
>> [...]
>>
>>>>> +        break;
>>>>> +    case S390_RESET_PV: /* Subcode 10 */
>>>>> +        subsystem_reset();
>>>>> +        s390_crypto_reset();
>>>>> +
>>>>> +        CPU_FOREACH(t) {
>>>>> +            if (t == cs) {
>>>>> +                continue;
>>>>> +            }
>>>>> +            run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
>>>>> +        }
>>>>> +        run_on_cpu(cs, s390_do_cpu_reset, RUN_ON_CPU_NULL);
>>>>> +
>>>>> +        if (s390_machine_protect(ms)) {
>>>>> +            s390_machine_inject_pv_error(cs);
>>>>
>>>> Ah, so it's not an actual exception. BUT: All other guest cpus were
>>>> reset, can the guest deal with that?
>>>
>>> Well, all other CPUs should be stopped for diag308, no?
>>> Also it's done by the bootloader and not a OS which just stops its cpus
>>> and goes into protected mode.
>>>
>>>>
>>>> (run_on_cpu(cs, s390_do_cpu_reset, RUN_ON_CPU_NULL) should go after the
>>>> s390_machine_protect() I assume - the change you had in the other patch)
>>>
>>> That's not a good idea, I want to reset before we automatically call the
>>> UV routines on a reset.
>>
>> But how can s390_machine_inject_pv_error(cs) be any effective if you
>> already reset the CPU?
>>
> 
> Because a normal cpu reset does not clear out the registers.

Okay, so a guest (e.g., Linux) can deal with some other things getting
reset I assume?


-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 03/18] s390x: protvirt: Support unpack facility
  2020-03-05 14:23           ` David Hildenbrand
@ 2020-03-05 14:24             ` Janosch Frank
  0 siblings, 0 replies; 72+ messages in thread
From: Janosch Frank @ 2020-03-05 14:24 UTC (permalink / raw)
  To: David Hildenbrand, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck


[-- Attachment #1.1: Type: text/plain, Size: 2619 bytes --]

On 3/5/20 3:23 PM, David Hildenbrand wrote:
> On 05.03.20 15:20, Janosch Frank wrote:
>> On 3/5/20 3:15 PM, David Hildenbrand wrote:
>>>>>>  
>>>>>> +static void s390_machine_unprotect(S390CcwMachineState *ms)
>>>>>> +{
>>>>>> +    CPUState *t;
>>>>>> +
>>>>>> +    if (!ms->pv)
>>>>>> +        return;
>>>>>
>>>>> How can this ever happen? g_assert(ms->pv) ?
>>>>
>>>> Currently not, that's only used in the follow up patches with the ballon
>>>> and migration blocker
>>>
>>> Even then, why should we unprotect when not protected. That looks wrong
>>> to me and has to be fixed in the other patches,
>>
>> I fixed it this morning :)
>>
>>>
>>>>
>>>>>
>>>>> Also, i don't see this function getting called from anywhere else except
>>>>> when s390_machine_protect() fails. That looks wrong. This has to be
>>>>> called when going out of PV mode.
>>>>
>>>> Yes, but that's in the diag308 1-4 patch.
>>>
>>> The way patches were split up is somewhat sub-optimal for review.
>>
>> Thanks
>> I'll try to find a better split up of the code
>>
>>>
>>> [...]
>>>
>>>>>> +        break;
>>>>>> +    case S390_RESET_PV: /* Subcode 10 */
>>>>>> +        subsystem_reset();
>>>>>> +        s390_crypto_reset();
>>>>>> +
>>>>>> +        CPU_FOREACH(t) {
>>>>>> +            if (t == cs) {
>>>>>> +                continue;
>>>>>> +            }
>>>>>> +            run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
>>>>>> +        }
>>>>>> +        run_on_cpu(cs, s390_do_cpu_reset, RUN_ON_CPU_NULL);
>>>>>> +
>>>>>> +        if (s390_machine_protect(ms)) {
>>>>>> +            s390_machine_inject_pv_error(cs);
>>>>>
>>>>> Ah, so it's not an actual exception. BUT: All other guest cpus were
>>>>> reset, can the guest deal with that?
>>>>
>>>> Well, all other CPUs should be stopped for diag308, no?
>>>> Also it's done by the bootloader and not a OS which just stops its cpus
>>>> and goes into protected mode.
>>>>
>>>>>
>>>>> (run_on_cpu(cs, s390_do_cpu_reset, RUN_ON_CPU_NULL) should go after the
>>>>> s390_machine_protect() I assume - the change you had in the other patch)
>>>>
>>>> That's not a good idea, I want to reset before we automatically call the
>>>> UV routines on a reset.
>>>
>>> But how can s390_machine_inject_pv_error(cs) be any effective if you
>>> already reset the CPU?
>>>
>>
>> Because a normal cpu reset does not clear out the registers.
> 
> Okay, so a guest (e.g., Linux) can deal with some other things getting
> reset I assume?

At this point in time only the bootloader runs, which survives a normal
reset.



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 02/18] s390x: protvirt: Add diag308 subcodes 8 - 10
  2020-03-04 18:59   ` Christian Borntraeger
@ 2020-03-05 14:39     ` Janosch Frank
  0 siblings, 0 replies; 72+ messages in thread
From: Janosch Frank @ 2020-03-05 14:39 UTC (permalink / raw)
  To: Christian Borntraeger, qemu-devel; +Cc: qemu-s390x, cohuck, david


[-- Attachment #1.1: Type: text/plain, Size: 4789 bytes --]

On 3/4/20 7:59 PM, Christian Borntraeger wrote:
> 
> 
> On 04.03.20 12:42, Janosch Frank wrote:
>> For diag308 subcodes 8 - 10 we have a new ipib of type 5. The ipib
>> holds the address and length of the secure execution header, as well
>> as a list of guest components.
>>
>> Each component is a block of memory, for example kernel or initrd,
>> which needs to be decrypted by the Ultravisor in order to run a
>> protected VM. The secure execution header instructs the Ultravisor on
>> how to handle the protected VM and its components.
>>
>> Subcodes 8 and 9 are similiar to 5 and 6 and subcode 10 will finally
>> start the protected guest.
>>
>> Subcodes 8-10 are not valid in protected mode, we have to do a subcode
>> 3 and then the 8 and 10 combination for a protected reboot.
>>
>> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
>> ---
>>  hw/s390x/ipl.c      | 47 ++++++++++++++++++++++++++++++++++++++++++---
>>  hw/s390x/ipl.h      | 32 ++++++++++++++++++++++++++++++
>>  target/s390x/diag.c | 26 ++++++++++++++++++++++---
>>  3 files changed, 99 insertions(+), 6 deletions(-)
>>
>> diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
>> index 9c1ecd423c..80c6ab233a 100644
>> --- a/hw/s390x/ipl.c
>> +++ b/hw/s390x/ipl.c
> 
> Can you update the copyright dates for files that you touch?
> 
>> @@ -538,15 +538,55 @@ static bool is_virtio_scsi_device(IplParameterBlock *iplb)
>>      return is_virtio_ccw_device_of_type(iplb, VIRTIO_ID_SCSI);
>>  }
>>  
>> +int s390_ipl_pv_check_components(IplParameterBlock *iplb)
>> +{
>> +    int i;
>> +    IPLBlockPV *ipib_pv = &iplb->pv;
>> +
>> +    if (ipib_pv->num_comp == 0) {
>> +        return -EINVAL;
>> +    }
>> +
>> +    for (i = 0; i < ipib_pv->num_comp; i++) {
>> +        /* Addr must be 4k aligned */
>> +        if (ipib_pv->components[i].addr & ~TARGET_PAGE_MASK) {
>> +            return -EINVAL;
>> +        }
>> +
>> +        /* Tweak prefix is monotonously increasing with each component */
>> +        if (i < ipib_pv->num_comp - 1 &&
> 
> Why do we need this check? Isnt that already ensured by the for loop?

This is "i < ipib_pv->num_comp - 1" because we use i + 1 below, not "i <
ipib_pv->num_comp"

> 
>> +            ipib_pv->components[i].tweak_pref >
>> +            ipib_pv->components[i + 1].tweak_pref) {
> 
> I think i+1 must be greater than i. So ">=" instead?

Ack

> 
>> +            return -EINVAL;
>> +        }
>> +    }
>> +    return 0;
>> +}
>> +
>>  void s390_ipl_update_diag308(IplParameterBlock *iplb)
> 
> maybe add a comment that explains that a guest can have 2 IPLBs. one for
> the secure guest and one thsat we go back to when rebooting.

Sure

>>  {
>>      S390IPLState *ipl = get_ipl_device();
>>  
>> -    ipl->iplb = *iplb;
>> -    ipl->iplb_valid = true;
>> +    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_secure(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 +601,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 {
>> diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
>> index d4813105db..04be63cee1 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  reserved[87];
>> +    uint8_t  version;
>> +    uint32_t reserved70;
> 
> Here you have 70 (the offset in hex I guess), I tßhink this is an odd name. In addition the reserved field 2 lines above has no address part in its
> name. 

I wanted to prepare for my ipl cleanup patch set which adds offsets to
all the reserved fields. Do you want me to remove it or make the first
one "reserved18" ?



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 18/18] pc-bios: s390x: Save iplb location in lowcore
  2020-03-04 11:42 ` [PATCH v6 18/18] pc-bios: s390x: Save iplb location in lowcore Janosch Frank
  2020-03-04 12:40   ` David Hildenbrand
  2020-03-04 13:25   ` Christian Borntraeger
@ 2020-03-05 17:04   ` Christian Borntraeger
  2 siblings, 0 replies; 72+ messages in thread
From: Christian Borntraeger @ 2020-03-05 17:04 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: qemu-s390x, cohuck, david


On 04.03.20 12:42, Janosch Frank wrote:
> The POP states that for a list directed IPL the IPLB is stored into
> memory by the machine loader and its address is stored at offset 0x14
> of the lowcore.
> 
> ZIPL currently uses the address in offset 0x14 to access the IPLB and
> acquire flags about secure boot. If the IPLB address points into
> memory which has an unsupported mix of flags set, ZIPL will panic
> instead of booting the OS.
> 
> As the lowcore can have quite a high entropy for a guest that did drop
> out of protected mode (i.e. rebooted) we encountered the ZIPL panic
> quite often.
> 
> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
> Tested-by: Marc Hartmayer <mhartmay@linux.ibm.com>

Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com>

Thanks applied.

> ---
>  pc-bios/s390-ccw/jump2ipl.c  |  1 +
>  pc-bios/s390-ccw/main.c      |  8 +++++++-
>  pc-bios/s390-ccw/netmain.c   |  1 +
>  pc-bios/s390-ccw/s390-arch.h | 10 ++++++++--
>  pc-bios/s390-ccw/s390-ccw.h  |  1 +
>  5 files changed, 18 insertions(+), 3 deletions(-)
> 
> diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c
> index da13c43cc0..4eba2510b0 100644
> --- a/pc-bios/s390-ccw/jump2ipl.c
> +++ b/pc-bios/s390-ccw/jump2ipl.c
> @@ -35,6 +35,7 @@ void jump_to_IPL_code(uint64_t address)
>  {
>      /* store the subsystem information _after_ the bootmap was loaded */
>      write_subsystem_identification();
> +    write_iplb_location();
>  
>      /* prevent unknown IPL types in the guest */
>      if (iplb.pbt == S390_IPL_TYPE_QEMU_SCSI) {
> diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
> index a21b386280..4e65b411e1 100644
> --- a/pc-bios/s390-ccw/main.c
> +++ b/pc-bios/s390-ccw/main.c
> @@ -9,6 +9,7 @@
>   */
>  
>  #include "libc.h"
> +#include "helper.h"
>  #include "s390-arch.h"
>  #include "s390-ccw.h"
>  #include "cio.h"
> @@ -22,7 +23,7 @@ QemuIplParameters qipl;
>  IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
>  static bool have_iplb;
>  static uint16_t cutype;
> -LowCore const *lowcore; /* Yes, this *is* a pointer to address 0 */
> +LowCore *lowcore; /* Yes, this *is* a pointer to address 0 */
>  
>  #define LOADPARM_PROMPT "PROMPT  "
>  #define LOADPARM_EMPTY  "        "
> @@ -42,6 +43,11 @@ void write_subsystem_identification(void)
>      *zeroes = 0;
>  }
>  
> +void write_iplb_location(void)
> +{
> +    lowcore->ptr_iplb = ptr2u32(&iplb);
> +}
> +
>  void panic(const char *string)
>  {
>      sclp_print(string);
> diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c
> index f2dcc01e27..309ffa30d9 100644
> --- a/pc-bios/s390-ccw/netmain.c
> +++ b/pc-bios/s390-ccw/netmain.c
> @@ -40,6 +40,7 @@
>  #define DEFAULT_TFTP_RETRIES 20
>  
>  extern char _start[];
> +void write_iplb_location(void) {}
>  
>  #define KERNEL_ADDR             ((void *)0L)
>  #define KERNEL_MAX_SIZE         ((long)_start)
> diff --git a/pc-bios/s390-ccw/s390-arch.h b/pc-bios/s390-ccw/s390-arch.h
> index 504fc7c2f0..5f36361c02 100644
> --- a/pc-bios/s390-ccw/s390-arch.h
> +++ b/pc-bios/s390-ccw/s390-arch.h
> @@ -36,7 +36,13 @@ typedef struct LowCore {
>      /* prefix area: defined by architecture */
>      PSWLegacy       ipl_psw;                  /* 0x000 */
>      uint32_t        ccw1[2];                  /* 0x008 */
> -    uint32_t        ccw2[2];                  /* 0x010 */
> +    union {
> +        uint32_t        ccw2[2];                  /* 0x010 */
> +        struct {
> +            uint32_t reserved10;
> +            uint32_t ptr_iplb;
> +        };
> +    };
>      uint8_t         pad1[0x80 - 0x18];        /* 0x018 */
>      uint32_t        ext_params;               /* 0x080 */
>      uint16_t        cpu_addr;                 /* 0x084 */
> @@ -85,7 +91,7 @@ typedef struct LowCore {
>      PSW             io_new_psw;               /* 0x1f0 */
>  } __attribute__((packed, aligned(8192))) LowCore;
>  
> -extern LowCore const *lowcore;
> +extern LowCore *lowcore;
>  
>  static inline void set_prefix(uint32_t address)
>  {
> diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
> index 11bce7d73c..21f27e7990 100644
> --- a/pc-bios/s390-ccw/s390-ccw.h
> +++ b/pc-bios/s390-ccw/s390-ccw.h
> @@ -57,6 +57,7 @@ void consume_io_int(void);
>  /* main.c */
>  void panic(const char *string);
>  void write_subsystem_identification(void);
> +void write_iplb_location(void);
>  extern char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
>  unsigned int get_loadparm_index(void);
>  
> 



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 02/18] s390x: protvirt: Add diag308 subcodes 8 - 10
  2020-03-04 17:06   ` David Hildenbrand
@ 2020-03-06  9:59     ` Janosch Frank
  0 siblings, 0 replies; 72+ messages in thread
From: Janosch Frank @ 2020-03-06  9:59 UTC (permalink / raw)
  To: David Hildenbrand, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck


[-- Attachment #1.1: Type: text/plain, Size: 10090 bytes --]

On 3/4/20 6:06 PM, David Hildenbrand wrote:
> On 04.03.20 12:42, Janosch Frank wrote:
>> For diag308 subcodes 8 - 10 we have a new ipib of type 5. The ipib
>> holds the address and length of the secure execution header, as well
>> as a list of guest components.
>>
>> Each component is a block of memory, for example kernel or initrd,
>> which needs to be decrypted by the Ultravisor in order to run a
>> protected VM. The secure execution header instructs the Ultravisor on
>> how to handle the protected VM and its components.
>>
>> Subcodes 8 and 9 are similiar to 5 and 6 and subcode 10 will finally
>> start the protected guest.
>>
>> Subcodes 8-10 are not valid in protected mode, we have to do a subcode
>> 3 and then the 8 and 10 combination for a protected reboot.
>>
>> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
>> ---
>>  hw/s390x/ipl.c      | 47 ++++++++++++++++++++++++++++++++++++++++++---
>>  hw/s390x/ipl.h      | 32 ++++++++++++++++++++++++++++++
>>  target/s390x/diag.c | 26 ++++++++++++++++++++++---
>>  3 files changed, 99 insertions(+), 6 deletions(-)
>>
>> diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
>> index 9c1ecd423c..80c6ab233a 100644
>> --- a/hw/s390x/ipl.c
>> +++ b/hw/s390x/ipl.c
>> @@ -538,15 +538,55 @@ static bool is_virtio_scsi_device(IplParameterBlock *iplb)
>>      return is_virtio_ccw_device_of_type(iplb, VIRTIO_ID_SCSI);
>>  }
>>  
>> +int s390_ipl_pv_check_components(IplParameterBlock *iplb)
>> +{
>> +    int i;
>> +    IPLBlockPV *ipib_pv = &iplb->pv;
>> +
>> +    if (ipib_pv->num_comp == 0) {
>> +        return -EINVAL;
>> +    }
>> +
>> +    for (i = 0; i < ipib_pv->num_comp; i++) {
>> +        /* Addr must be 4k aligned */
>> +        if (ipib_pv->components[i].addr & ~TARGET_PAGE_MASK) {
>> +            return -EINVAL;
>> +        }
>> +
>> +        /* Tweak prefix is monotonously increasing with each component */
>> +        if (i < ipib_pv->num_comp - 1 &&
>> +            ipib_pv->components[i].tweak_pref >
>> +            ipib_pv->components[i + 1].tweak_pref) {
>> +            return -EINVAL;
>> +        }
>> +    }
>> +    return 0;
>> +}
>> +
>>  void s390_ipl_update_diag308(IplParameterBlock *iplb)
>>  {
>>      S390IPLState *ipl = get_ipl_device();
>>  
>> -    ipl->iplb = *iplb;
>> -    ipl->iplb_valid = true;
>> +    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_secure(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 +601,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 {
>> diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
>> index d4813105db..04be63cee1 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  reserved[87];
>> +    uint8_t  version;
>> +    uint32_t reserved70;
>> +    uint32_t num_comp;
>> +    uint64_t pv_header_addr;
>> +    uint64_t pv_header_len;
>> +    struct IPLBlockPVComp components[];
>> +} QEMU_PACKED;
>> +typedef struct IPLBlockPV IPLBlockPV;
>> +
>>  struct IplBlockCcw {
>>      uint8_t  reserved0[85];
>>      uint8_t  ssid;
>> @@ -71,6 +89,7 @@ union IplParameterBlock {
>>          union {
>>              IplBlockCcw ccw;
>>              IplBlockFcp fcp;
>> +            IPLBlockPV pv;
>>              IplBlockQemuScsi scsi;
>>          };
>>      } QEMU_PACKED;
>> @@ -84,9 +103,11 @@ union IplParameterBlock {
>>  typedef union IplParameterBlock IplParameterBlock;
>>  
>>  int s390_ipl_set_loadparm(uint8_t *loadparm);
>> +int s390_ipl_pv_check_components(IplParameterBlock *iplb);
>>  void s390_ipl_update_diag308(IplParameterBlock *iplb);
>>  void s390_ipl_prepare_cpu(S390CPU *cpu);
>>  IplParameterBlock *s390_ipl_get_iplb(void);
>> +IplParameterBlock *s390_ipl_get_iplb_secure(void);
>>  
>>  enum s390_reset {
>>      /* default is a reset not triggered by a CPU e.g. issued by QMP */
>> @@ -94,6 +115,7 @@ enum s390_reset {
>>      S390_RESET_REIPL,
>>      S390_RESET_MODIFIED_CLEAR,
>>      S390_RESET_LOAD_NORMAL,
>> +    S390_RESET_PV,
>>  };
>>  void s390_ipl_reset_request(CPUState *cs, enum s390_reset reset_type);
>>  void s390_ipl_get_reset_request(CPUState **cs, enum s390_reset *reset_type);
>> @@ -133,6 +155,7 @@ struct S390IPLState {
>>      /*< private >*/
>>      DeviceState parent_obj;
>>      IplParameterBlock iplb;
>> +    IplParameterBlock iplb_pv;
>>      QemuIplParameters qipl;
>>      uint64_t start_addr;
>>      uint64_t compat_start_addr;
>> @@ -140,6 +163,7 @@ struct S390IPLState {
>>      uint64_t compat_bios_start_addr;
>>      bool enforce_bios;
>>      bool iplb_valid;
>> +    bool iplb_valid_pv;
>>      bool netboot;
>>      /* reset related properties don't have to be migrated or reset */
>>      enum s390_reset reset_type;
>> @@ -161,9 +185,11 @@ QEMU_BUILD_BUG_MSG(offsetof(S390IPLState, iplb) & 3, "alignment of iplb wrong");
>>  
>>  #define S390_IPL_TYPE_FCP 0x00
>>  #define S390_IPL_TYPE_CCW 0x02
>> +#define S390_IPL_TYPE_PV 0x05
>>  #define S390_IPL_TYPE_QEMU_SCSI 0xff
>>  
>>  #define S390_IPLB_HEADER_LEN 8
>> +#define S390_IPLB_MIN_PV_LEN 148
>>  #define S390_IPLB_MIN_CCW_LEN 200
>>  #define S390_IPLB_MIN_FCP_LEN 384
>>  #define S390_IPLB_MIN_QEMU_SCSI_LEN 200
>> @@ -185,4 +211,10 @@ static inline bool iplb_valid_fcp(IplParameterBlock *iplb)
>>             iplb->pbt == S390_IPL_TYPE_FCP;
>>  }
>>  
>> +static inline bool iplb_valid_pv(IplParameterBlock *iplb)
>> +{
>> +    return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_PV_LEN &&
>> +           iplb->pbt == S390_IPL_TYPE_PV;
>> +}
>> +
>>  #endif
>> diff --git a/target/s390x/diag.c b/target/s390x/diag.c
>> index b5aec06d6b..945b263f0a 100644
>> --- a/target/s390x/diag.c
>> +++ b/target/s390x/diag.c
>> @@ -52,6 +52,7 @@ int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
>>  #define DIAG_308_RC_OK              0x0001
>>  #define DIAG_308_RC_NO_CONF         0x0102
>>  #define DIAG_308_RC_INVALID         0x0402
>> +#define DIAG_308_RC_NO_PV_CONF      0x0902
>>  
>>  #define DIAG308_RESET_MOD_CLR       0
>>  #define DIAG308_RESET_LOAD_NORM     1
>> @@ -59,6 +60,9 @@ int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
>>  #define DIAG308_LOAD_NORMAL_DUMP    4
>>  #define DIAG308_SET                 5
>>  #define DIAG308_STORE               6
>> +#define DIAG308_PV_SET              8
>> +#define DIAG308_PV_STORE            9
>> +#define DIAG308_PV_START            10
>>  
>>  static int diag308_parm_check(CPUS390XState *env, uint64_t r1, uint64_t addr,
>>                                uintptr_t ra, bool write)
>> @@ -105,6 +109,7 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
>>          s390_ipl_reset_request(cs, S390_RESET_REIPL);
>>          break;
>>      case DIAG308_SET:
>> +    case DIAG308_PV_SET:
>>          if (diag308_parm_check(env, r1, addr, ra, false)) {
>>              return;
>>          }
>> @@ -117,7 +122,8 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
>>  
>>          cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len));
>>  
>> -        if (!iplb_valid_ccw(iplb) && !iplb_valid_fcp(iplb)) {
>> +        if (!iplb_valid_ccw(iplb) && !iplb_valid_fcp(iplb) &&
>> +            !(iplb_valid_pv(iplb) && !s390_ipl_pv_check_components(iplb))) {
>>              env->regs[r1 + 1] = DIAG_308_RC_INVALID;
>>              goto out;
>>          }
>> @@ -128,17 +134,31 @@ out:
>>          g_free(iplb);
>>          return;
>>      case DIAG308_STORE:
>> +    case DIAG308_PV_STORE:
>>          if (diag308_parm_check(env, r1, addr, ra, true)) {
>>              return;
>>          }
>> -        iplb = s390_ipl_get_iplb();
>> +        if (subcode == DIAG308_PV_STORE) {
>> +            iplb = s390_ipl_get_iplb_secure();
>> +        } else {
>> +            iplb = s390_ipl_get_iplb();
>> +        }
>>          if (iplb) {
>>              cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len));
>>              env->regs[r1 + 1] = DIAG_308_RC_OK;
>>          } else {
>>              env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;
>>          }
>> -        return;
>> +        break;
>> +    case DIAG308_PV_START:
>> +        iplb = s390_ipl_get_iplb_secure();
>> +        if (!iplb || !iplb_valid_pv(iplb)) {
>> +            env->regs[r1 + 1] = DIAG_308_RC_NO_PV_CONF;
>> +            return;
>> +        }
>> +
>> +        s390_ipl_reset_request(cs, S390_RESET_PV);
>> +        break;
>>      default:
>>          s390_program_interrupt(env, PGM_SPECIFICATION, ra);
>>          break;
>>
> 
> Sorry, another comment. The new subcodes should be fenced via the cpu
> model or similar. Applying this patch and triggering one of these
> subcodes will end in a questionable state.
> 

Ahh, yes, we removed the KVM check for this.
Will add.


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 16/18] s390x: Add unpack facility feature to GA1
  2020-03-04 11:42 ` [PATCH v6 16/18] s390x: Add unpack facility feature to GA1 Janosch Frank
  2020-03-04 18:42   ` David Hildenbrand
@ 2020-03-06 10:14   ` Janosch Frank
  2020-03-06 10:22     ` David Hildenbrand
  1 sibling, 1 reply; 72+ messages in thread
From: Janosch Frank @ 2020-03-06 10:14 UTC (permalink / raw)
  To: qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck, david


[-- Attachment #1.1: Type: text/plain, Size: 1969 bytes --]

On 3/4/20 12:42 PM, Janosch Frank wrote:
> From: Christian Borntraeger <borntraeger@de.ibm.com>
> 
> The unpack facility is an indication that diagnose 308 subcodes 8-10
> are available to the guest. That means, that the guest can put itself
> into protected mode.
> 
> Once it is in protected mode, the hardware stops any attempt of VM
> introspection by the hypervisor.
> 
> Some features are currently not supported in protected mode:
>      * Passthrough devices
>      * Migration
>      * Huge page backings
> 
> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>

This one will be the first patch (after sync) and will also get the
DEF_FEAT definition, so I can use it in the diag 308 8-10 patch


> ---
>  target/s390x/gen-features.c | 1 +
>  target/s390x/kvm.c          | 5 +++++
>  2 files changed, 6 insertions(+)
> 
> diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
> index 6278845b12..8ddeebc544 100644
> --- a/target/s390x/gen-features.c
> +++ b/target/s390x/gen-features.c
> @@ -562,6 +562,7 @@ static uint16_t full_GEN15_GA1[] = {
>      S390_FEAT_GROUP_MSA_EXT_9,
>      S390_FEAT_GROUP_MSA_EXT_9_PCKMO,
>      S390_FEAT_ETOKEN,
> +    S390_FEAT_UNPACK,
>  };
>  
>  /* Default features (in order of release)
> diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
> index a4cbdc5fc6..bf807793bc 100644
> --- a/target/s390x/kvm.c
> +++ b/target/s390x/kvm.c
> @@ -2396,6 +2396,11 @@ void kvm_s390_get_host_cpu_model(S390CPUModel *model, Error **errp)
>          clear_bit(S390_FEAT_BPB, model->features);
>      }
>  
> +    /* we do have the IPL enhancements */
> +    if (cap_protected) {
> +        set_bit(S390_FEAT_UNPACK, model->features);
> +    }
> +
>      /* We emulate a zPCI bus and AEN, therefore we don't need HW support */
>      set_bit(S390_FEAT_ZPCI, model->features);
>      set_bit(S390_FEAT_ADAPTER_EVENT_NOTIFICATION, model->features);
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 16/18] s390x: Add unpack facility feature to GA1
  2020-03-06 10:14   ` Janosch Frank
@ 2020-03-06 10:22     ` David Hildenbrand
  0 siblings, 0 replies; 72+ messages in thread
From: David Hildenbrand @ 2020-03-06 10:22 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck

On 06.03.20 11:14, Janosch Frank wrote:
> On 3/4/20 12:42 PM, Janosch Frank wrote:
>> From: Christian Borntraeger <borntraeger@de.ibm.com>
>>
>> The unpack facility is an indication that diagnose 308 subcodes 8-10
>> are available to the guest. That means, that the guest can put itself
>> into protected mode.
>>
>> Once it is in protected mode, the hardware stops any attempt of VM
>> introspection by the hypervisor.
>>
>> Some features are currently not supported in protected mode:
>>      * Passthrough devices
>>      * Migration
>>      * Huge page backings
>>
>> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
> 
> This one will be the first patch (after sync) and will also get the
> DEF_FEAT definition, so I can use it in the diag 308 8-10 patch

You should still enable the whole machinery only after everything has
been implemented. Moving the feature is fine.


-- 
Thanks,

David / dhildenb



^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 03/18] s390x: protvirt: Support unpack facility
  2020-03-04 11:42 ` [PATCH v6 03/18] s390x: protvirt: Support unpack facility Janosch Frank
  2020-03-05 13:51   ` David Hildenbrand
  2020-03-05 13:52   ` David Hildenbrand
@ 2020-03-06 11:48   ` Christian Borntraeger
  2020-03-06 13:36     ` Janosch Frank
  2 siblings, 1 reply; 72+ messages in thread
From: Christian Borntraeger @ 2020-03-06 11:48 UTC (permalink / raw)
  To: Janosch Frank, qemu-devel; +Cc: qemu-s390x, cohuck, david



On 04.03.20 12:42, Janosch Frank wrote:
[...]
> diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
> index 3dd396e870..69b1cc5dfc 100644
> --- a/target/s390x/cpu.c
> +++ b/target/s390x/cpu.c
> @@ -37,6 +37,8 @@
>  #include "sysemu/hw_accel.h"
>  #include "hw/qdev-properties.h"
>  #ifndef CONFIG_USER_ONLY
> +#include "hw/s390x/s390-virtio-ccw.h"
> +#include "hw/s390x/pv.h"
>  #include "hw/boards.h"
>  #include "sysemu/arch_init.h"
>  #include "sysemu/sysemu.h"
> @@ -191,6 +193,7 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
>  
>  #if !defined(CONFIG_USER_ONLY)
>      MachineState *ms = MACHINE(qdev_get_machine());
> +    S390CcwMachineState *ccw = S390_CCW_MACHINE(ms);
>      unsigned int max_cpus = ms->smp.max_cpus;
>      if (cpu->env.core_id >= max_cpus) {
>          error_setg(&err, "Unable to add CPU with core-id: %" PRIu32

I messed this up and this can break for the none machine.

Something like this on top:



diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
index 7840e784f1..1b42b0fa25 100644
--- a/target/s390x/cpu.c
+++ b/target/s390x/cpu.c
@@ -181,6 +181,18 @@ static void s390_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
     info->print_insn = print_insn_s390;
 }
 
+static bool machine_is_pv(MachineState *ms)
+{
+    Object *obj;
+
+    /* we have to bail out for the "none" machine */
+    obj = object_dynamic_cast(OBJECT(ms), TYPE_S390_CCW_MACHINE);
+     if (!obj) {
+        return false;
+    }
+    return S390_CCW_MACHINE(obj)->pv;
+}
+
 static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
 {
     CPUState *cs = CPU(dev);
@@ -198,7 +210,6 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
 
 #if !defined(CONFIG_USER_ONLY)
     MachineState *ms = MACHINE(qdev_get_machine());
-    S390CcwMachineState *ccw = S390_CCW_MACHINE(ms);
     unsigned int max_cpus = ms->smp.max_cpus;
     if (cpu->env.core_id >= max_cpus) {
         error_setg(&err, "Unable to add CPU with core-id: %" PRIu32
@@ -213,7 +224,7 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
         goto out;
     }
 
-    cpu->env.pv = ccw->pv;
+    cpu->env.pv = machine_is_pv(ms);
     /* sync cs->cpu_index and env->core_id. The latter is needed for TCG. */
     cs->cpu_index = cpu->env.core_id;
 #endif



^ permalink raw reply related	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 03/18] s390x: protvirt: Support unpack facility
  2020-03-06 11:48   ` Christian Borntraeger
@ 2020-03-06 13:36     ` Janosch Frank
  0 siblings, 0 replies; 72+ messages in thread
From: Janosch Frank @ 2020-03-06 13:36 UTC (permalink / raw)
  To: Christian Borntraeger, qemu-devel; +Cc: qemu-s390x, cohuck, david


[-- Attachment #1.1: Type: text/plain, Size: 2767 bytes --]

On 3/6/20 12:48 PM, Christian Borntraeger wrote:
> 
> 
> On 04.03.20 12:42, Janosch Frank wrote:
> [...]
>> diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
>> index 3dd396e870..69b1cc5dfc 100644
>> --- a/target/s390x/cpu.c
>> +++ b/target/s390x/cpu.c
>> @@ -37,6 +37,8 @@
>>  #include "sysemu/hw_accel.h"
>>  #include "hw/qdev-properties.h"
>>  #ifndef CONFIG_USER_ONLY
>> +#include "hw/s390x/s390-virtio-ccw.h"
>> +#include "hw/s390x/pv.h"
>>  #include "hw/boards.h"
>>  #include "sysemu/arch_init.h"
>>  #include "sysemu/sysemu.h"
>> @@ -191,6 +193,7 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
>>  
>>  #if !defined(CONFIG_USER_ONLY)
>>      MachineState *ms = MACHINE(qdev_get_machine());
>> +    S390CcwMachineState *ccw = S390_CCW_MACHINE(ms);
>>      unsigned int max_cpus = ms->smp.max_cpus;
>>      if (cpu->env.core_id >= max_cpus) {
>>          error_setg(&err, "Unable to add CPU with core-id: %" PRIu32
> 
> I messed this up and this can break for the none machine.
> 
> Something like this on top:

Christian and I found out that we also need to fence CONFIG_USER_ONLY,
so machine_is_pv is now in an ifdef and I squashed the changes into the
support unpack facility patch.

CI is now happy again ;-)


> 
> 
> 
> diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
> index 7840e784f1..1b42b0fa25 100644
> --- a/target/s390x/cpu.c
> +++ b/target/s390x/cpu.c
> @@ -181,6 +181,18 @@ static void s390_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
>      info->print_insn = print_insn_s390;
>  }
>  
> +static bool machine_is_pv(MachineState *ms)
> +{
> +    Object *obj;
> +
> +    /* we have to bail out for the "none" machine */
> +    obj = object_dynamic_cast(OBJECT(ms), TYPE_S390_CCW_MACHINE);
> +     if (!obj) {
> +        return false;
> +    }
> +    return S390_CCW_MACHINE(obj)->pv;
> +}
> +
>  static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
>  {
>      CPUState *cs = CPU(dev);
> @@ -198,7 +210,6 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
>  
>  #if !defined(CONFIG_USER_ONLY)
>      MachineState *ms = MACHINE(qdev_get_machine());
> -    S390CcwMachineState *ccw = S390_CCW_MACHINE(ms);
>      unsigned int max_cpus = ms->smp.max_cpus;
>      if (cpu->env.core_id >= max_cpus) {
>          error_setg(&err, "Unable to add CPU with core-id: %" PRIu32
> @@ -213,7 +224,7 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
>          goto out;
>      }
>  
> -    cpu->env.pv = ccw->pv;
> +    cpu->env.pv = machine_is_pv(ms);
>      /* sync cs->cpu_index and env->core_id. The latter is needed for TCG. */
>      cs->cpu_index = cpu->env.core_id;
>  #endif
> 
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 72+ messages in thread

* Re: [PATCH v6 17/18] docs: Add protvirt docs
  2020-03-04 19:09   ` David Hildenbrand
@ 2020-03-09  9:51     ` Janosch Frank
  0 siblings, 0 replies; 72+ messages in thread
From: Janosch Frank @ 2020-03-09  9:51 UTC (permalink / raw)
  To: David Hildenbrand, qemu-devel; +Cc: borntraeger, qemu-s390x, cohuck


[-- Attachment #1.1: Type: text/plain, Size: 4912 bytes --]

On 3/4/20 8:09 PM, David Hildenbrand wrote:
> On 04.03.20 12:42, Janosch Frank wrote:
>> Lets add some documentation for the Protected VM functionality.
>>
>> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
>> ---
>>  docs/system/index.rst    |  1 +
>>  docs/system/protvirt.rst | 57 ++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 58 insertions(+)
>>  create mode 100644 docs/system/protvirt.rst
>>
>> diff --git a/docs/system/index.rst b/docs/system/index.rst
>> index 1a4b2c82ac..d2dc63b973 100644
>> --- a/docs/system/index.rst
>> +++ b/docs/system/index.rst
>> @@ -16,3 +16,4 @@ Contents:
>>  
>>     qemu-block-drivers
>>     vfio-ap
>> +   protvirt
>> diff --git a/docs/system/protvirt.rst b/docs/system/protvirt.rst
>> new file mode 100644
>> index 0000000000..a1902cc47c
>> --- /dev/null
>> +++ b/docs/system/protvirt.rst
>> @@ -0,0 +1,57 @@
>> +Protected Virtualization on s390x
>> +=================================
>> +
>> +The memory and most of the register contents of Protected Virtual
> 
> s/register contents/registers/

Ack

> 
>> +Machines (PVMs) are inaccessible to the hypervisor, effectively
> 
> s/inaccessible/encrypted or even inaccessible/ ?
> 
>> +prohibiting VM introspection when the VM is running. At rest, PVMs are
>> +encrypted and can only be decrypted by the firmware of specific IBM Z
>> +machines.
> 
> maybe "(a.k.a. the Ultravisor)"

At rest, PVMs are
encrypted and can only be decrypted by the firmware, represented by an
entity called Ultravisor, of specific IBM Z machines.

> 
>> +
>> +
>> +Prerequisites
>> +-------------
>> +
>> +To run PVMs, you need to have a machine with the Protected
> 
> "a machine with the Protected Virtualization feature is required"

Ack

> 
>> +Virtualization feature, which is indicated by the Ultravisor Call
>> +facility (stfle bit 158). This is a KVM only feature, therefore you
> 
> ", therefore, "
> 
> I don't understand the "KVM only" feature part. Just say that an updated
> KVM + right HW is required and how it is to be updated.

The KVM only part is mostly messaging that this can't be run under TCG

> 
>> +need a KVM which is able to support PVMs and activate the Ultravisor
> 
> "a KVM version"
> 
>> +initialization by setting `prot_virt=1` on the kernel command line.

To run PVMs a machine with the Protected Virtualization feature
which is indicated by the Ultravisor Call facility (stfle bit
158) is required. The Ultravisor needs to be initialized at boot by
setting `prot_virt=1` on the kernel command line.



>> +
>> +If those requirements are met, the capability `KVM_CAP_S390_PROTECTED`
>> +will indicate that KVM can support PVMs on that LPAR.
>> +
>> +
>> +QEMU Settings
>> +-------------
>> +
>> +To indicate to the VM that it can move into protected mode, the
> 
> s/move/transition/ ?

Ack
I also took most of the suggestions below with some forms of modification.

> 
>> +`Unpack facility` (stfle bit 161) needs to be part of the cpu model of
>> +the VM.
> 
> Maybe mention the CPU feature name here.
> 
>> +
>> +All I/O devices need to use the IOMMU.
>> +Passthrough (vfio) devices are currently not supported.
>> +
>> +Host huge page backings are not supported. The guest however can use
> 
> "However, the guest can ..."
> 
>> +huge pages as indicated by its facilities.
>> +
>> +
>> +Boot Process
>> +------------
>> +
>> +A secure guest image can be both booted from disk and using the QEMU
> 
> "either be loaded from disk or supplied on the QEMU command line" ?
> 
>> +command line. Booting from disk is done by the unmodified s390-ccw
>> +BIOS. I.e., the bootmap is interpreted and a number of components is
> 
> "interpreted, multiple components are"
> 
>> +read into memory and control is transferred to one of the components
>> +(zipl stage3), which does some fixups and then transfers control to
>> +some program residing in guest memory, which is normally the OS
> 
> to many ", which". Better split that up for readability.
> 
>> +kernel. The secure image has another component prepended (stage3a)
>> +which uses the new diag308 subcodes 8 and 10 to trigger the transition
>> +into secure mode.
>> +
>> +Booting from the command line requires that the file passed
> 
> "from the image supplied on the QEMU command line" ?
> 
>> +via -kernel has the same memory layout as would result from the disk
>> +boot. This memory layout includes the encrypted components (kernel,
>> +initrd, cmdline), the stage3a loader and metadata. In case this boot
>> +method is used, the command line options -initrd and -cmdline are
>> +ineffective.  The preparation of secure guest image is done by a
> 
> s/of secure/of a PMV image/
> 
>> +program (name tbd) of the s390-tools package.
>>
> 
> 
> General: secure guest -> PMV
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 72+ messages in thread

end of thread, other threads:[~2020-03-09  9:52 UTC | newest]

Thread overview: 72+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-04 11:42 [PATCH v6 00/18] s390x: Protected Virtualization support Janosch Frank
2020-03-04 11:42 ` [PATCH v6 01/18] Sync pv Janosch Frank
2020-03-04 11:42 ` [PATCH v6 02/18] s390x: protvirt: Add diag308 subcodes 8 - 10 Janosch Frank
2020-03-04 17:04   ` David Hildenbrand
2020-03-05 12:04     ` Janosch Frank
2020-03-05 12:24       ` Janosch Frank
2020-03-05 12:30         ` David Hildenbrand
2020-03-04 17:04   ` David Hildenbrand
2020-03-04 17:06   ` David Hildenbrand
2020-03-06  9:59     ` Janosch Frank
2020-03-04 18:59   ` Christian Borntraeger
2020-03-05 14:39     ` Janosch Frank
2020-03-04 11:42 ` [PATCH v6 03/18] s390x: protvirt: Support unpack facility Janosch Frank
2020-03-05 13:51   ` David Hildenbrand
2020-03-05 14:10     ` Janosch Frank
2020-03-05 14:15       ` David Hildenbrand
2020-03-05 14:20         ` Janosch Frank
2020-03-05 14:23           ` David Hildenbrand
2020-03-05 14:24             ` Janosch Frank
2020-03-05 13:52   ` David Hildenbrand
2020-03-05 14:15     ` Janosch Frank
2020-03-06 11:48   ` Christian Borntraeger
2020-03-06 13:36     ` Janosch Frank
2020-03-04 11:42 ` [PATCH v6 04/18] s390x: protvirt: Add migration blocker Janosch Frank
2020-03-04 17:13   ` David Hildenbrand
2020-03-05  9:16     ` Janosch Frank
2020-03-05  9:30       ` David Hildenbrand
2020-03-04 11:42 ` [PATCH v6 05/18] s390x: protvirt: Handle diag 308 subcodes 0,1,3,4 Janosch Frank
2020-03-04 11:42 ` [PATCH v6 06/18] s390x: protvirt: Inhibit balloon when switching to protected mode Janosch Frank
2020-03-05 12:00   ` Christian Borntraeger
2020-03-04 11:42 ` [PATCH v6 07/18] s390x: protvirt: KVM intercept changes Janosch Frank
2020-03-04 11:42 ` [PATCH v6 08/18] s390x: Add SIDA memory ops Janosch Frank
2020-03-04 17:39   ` David Hildenbrand
2020-03-05  9:23     ` Janosch Frank
2020-03-04 11:42 ` [PATCH v6 09/18] s390x: protvirt: Move STSI data over SIDAD Janosch Frank
2020-03-04 17:43   ` David Hildenbrand
2020-03-05  9:27     ` Janosch Frank
2020-03-04 11:42 ` [PATCH v6 10/18] s390x: protvirt: SCLP interpretation Janosch Frank
2020-03-04 17:48   ` David Hildenbrand
2020-03-05  9:34     ` Janosch Frank
2020-03-05 10:09       ` David Hildenbrand
2020-03-04 11:42 ` [PATCH v6 11/18] s390x: protvirt: Set guest IPL PSW Janosch Frank
2020-03-04 17:51   ` David Hildenbrand
2020-03-04 11:42 ` [PATCH v6 12/18] s390x: protvirt: Move diag 308 data over SIDAD Janosch Frank
2020-03-04 17:54   ` David Hildenbrand
2020-03-04 11:42 ` [PATCH v6 13/18] s390x: protvirt: Disable address checks for PV guest IO emulation Janosch Frank
2020-03-04 17:55   ` David Hildenbrand
2020-03-05  9:42     ` Janosch Frank
2020-03-05 10:00       ` David Hildenbrand
2020-03-05 11:26         ` Janosch Frank
2020-03-05 11:37           ` David Hildenbrand
2020-03-04 11:42 ` [PATCH v6 14/18] s390x: protvirt: Move IO control structures over SIDA Janosch Frank
2020-03-04 18:56   ` David Hildenbrand
2020-03-05  9:55     ` Janosch Frank
2020-03-05 10:01       ` David Hildenbrand
2020-03-04 11:42 ` [PATCH v6 15/18] s390x: protvirt: Handle SIGP store status correctly Janosch Frank
2020-03-04 18:41   ` David Hildenbrand
2020-03-05  9:59     ` Janosch Frank
2020-03-04 11:42 ` [PATCH v6 16/18] s390x: Add unpack facility feature to GA1 Janosch Frank
2020-03-04 18:42   ` David Hildenbrand
2020-03-06 10:14   ` Janosch Frank
2020-03-06 10:22     ` David Hildenbrand
2020-03-04 11:42 ` [PATCH v6 17/18] docs: Add protvirt docs Janosch Frank
2020-03-04 19:09   ` David Hildenbrand
2020-03-09  9:51     ` Janosch Frank
2020-03-04 11:42 ` [PATCH v6 18/18] pc-bios: s390x: Save iplb location in lowcore Janosch Frank
2020-03-04 12:40   ` David Hildenbrand
2020-03-04 13:25   ` Christian Borntraeger
2020-03-04 13:37     ` David Hildenbrand
2020-03-05 17:04   ` Christian Borntraeger
2020-03-04 17:15 ` [PATCH v6 00/18] s390x: Protected Virtualization support David Hildenbrand
2020-03-04 17:45   ` Christian Borntraeger

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.