linux-s390.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [kvm-unit-tests PATCH v2 00/10] s390x: sie: Add PV snippet support
@ 2021-12-07 15:59 Janosch Frank
  2021-12-07 15:59 ` [kvm-unit-tests PATCH v2 01/10] lib: s390x: sie: Add sca allocation and freeing Janosch Frank
                   ` (9 more replies)
  0 siblings, 10 replies; 16+ messages in thread
From: Janosch Frank @ 2021-12-07 15:59 UTC (permalink / raw)
  To: kvm; +Cc: linux-s390, imbrenda, david, thuth, seiden

Adding PV virtualization support was only a matter of time so here it
is.

The biggest problem that needed solving was having the SE header as a
separate file. The genprotimg tool generates the header and adds a
short bit of code to the image which will put the guest into PV mode
via the diagnose 308 PV subcodes. We don't have and want an emulation
for the diagnose so we don't support this way of starting a PV guest.

Therefore we needed a new tool that generates the PV image separate
from the SE header so we can link both as binary blobs. Marc created
this tool by writing a library which lets users create a SE header and
has bindings to multiple languages. Unfortunately we didn't yet have
time to upstream this but we plan to publish it once we find some.

The first PV snippet test checks the "easy" diagnose calls 0x44, 0x9c,
0x288 and 0x500. We check register contents and responses to PGM
injects.

v2:
	- Moved snippet management code into library uv.h and snippet.h files
	- Added a fixpatch for mvpg-sie.c making it use the snippet helpers

Janosch Frank (10):
  lib: s390x: sie: Add sca allocation and freeing
  s390x: sie: Add PV fields to SIE control block
  s390x: sie: Add UV information into VM struct
  s390x: uv: Add more UV call functions
  s390x: lib: Extend UV library with PV guest management
  lib: s390: sie: Add PV guest register handling
  s390x: snippets: Add PV support
  lib: s390x: Introduce snippet helpers
  s390x: mvpg-sie: Use snippet helpers
  s390x: sie: Add PV diag test

 .gitignore                                 |   2 +
 configure                                  |   8 +
 lib/s390x/asm/uv.h                         |  99 +++++++++++
 lib/s390x/sie.c                            |  20 +++
 lib/s390x/sie.h                            |  54 +++++-
 lib/s390x/snippet.h                        | 110 ++++++++++++
 lib/s390x/uv.c                             | 128 ++++++++++++++
 lib/s390x/uv.h                             |  28 +++
 s390x/Makefile                             |  73 ++++++--
 s390x/mvpg-sie.c                           |  24 +--
 s390x/pv-diags.c                           | 187 +++++++++++++++++++++
 s390x/snippets/asm/snippet-pv-diag-288.S   |  25 +++
 s390x/snippets/asm/snippet-pv-diag-500.S   |  39 +++++
 s390x/snippets/asm/snippet-pv-diag-yield.S |   7 +
 14 files changed, 770 insertions(+), 34 deletions(-)
 create mode 100644 s390x/pv-diags.c
 create mode 100644 s390x/snippets/asm/snippet-pv-diag-288.S
 create mode 100644 s390x/snippets/asm/snippet-pv-diag-500.S
 create mode 100644 s390x/snippets/asm/snippet-pv-diag-yield.S

-- 
2.32.0


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

* [kvm-unit-tests PATCH v2 01/10] lib: s390x: sie: Add sca allocation and freeing
  2021-12-07 15:59 [kvm-unit-tests PATCH v2 00/10] s390x: sie: Add PV snippet support Janosch Frank
@ 2021-12-07 15:59 ` Janosch Frank
  2021-12-07 15:59 ` [kvm-unit-tests PATCH v2 02/10] s390x: sie: Add PV fields to SIE control block Janosch Frank
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Janosch Frank @ 2021-12-07 15:59 UTC (permalink / raw)
  To: kvm; +Cc: linux-s390, imbrenda, david, thuth, seiden

For protected guests we always need a ESCA so let's add functions to
create and destroy SCAs on demand. We don't have scheduling and I
don't expect multiple VCPU SIE in the next few months so SCA content
handling is not added.

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
---
 lib/s390x/sie.c | 12 ++++++++++++
 lib/s390x/sie.h |  2 ++
 2 files changed, 14 insertions(+)

diff --git a/lib/s390x/sie.c b/lib/s390x/sie.c
index b965b314..51d3b94e 100644
--- a/lib/s390x/sie.c
+++ b/lib/s390x/sie.c
@@ -55,6 +55,16 @@ void sie(struct vm *vm)
 	vm->save_area.guest.grs[15] = vm->sblk->gg15;
 }
 
+void sie_guest_sca_create(struct vm *vm)
+{
+	vm->sca = (struct esca_block *)alloc_page();
+
+	/* Let's start out with one page of ESCA for now */
+	vm->sblk->scaoh = ((uint64_t)vm->sca >> 32);
+	vm->sblk->scaol = (uint64_t)vm->sca & ~0x3fU;
+	vm->sblk->ecb2 |= ECB2_ESCA;
+}
+
 /* Initializes the struct vm members like the SIE control block. */
 void sie_guest_create(struct vm *vm, uint64_t guest_mem, uint64_t guest_mem_len)
 {
@@ -80,4 +90,6 @@ void sie_guest_destroy(struct vm *vm)
 {
 	free_page(vm->crycb);
 	free_page(vm->sblk);
+	if (vm->sblk->ecb2 & ECB2_ESCA)
+		free_page(vm->sca);
 }
diff --git a/lib/s390x/sie.h b/lib/s390x/sie.h
index 7ef7251b..f34e3c80 100644
--- a/lib/s390x/sie.h
+++ b/lib/s390x/sie.h
@@ -191,6 +191,7 @@ struct vm_save_area {
 struct vm {
 	struct kvm_s390_sie_block *sblk;
 	struct vm_save_area save_area;
+	void *sca;				/* System Control Area */
 	uint8_t *crycb;				/* Crypto Control Block */
 	/* Ptr to first guest page */
 	uint8_t *guest_mem;
@@ -203,6 +204,7 @@ void sie(struct vm *vm);
 void sie_expect_validity(void);
 void sie_check_validity(uint16_t vir_exp);
 void sie_handle_validity(struct vm *vm);
+void sie_guest_sca_create(struct vm *vm);
 void sie_guest_create(struct vm *vm, uint64_t guest_mem, uint64_t guest_mem_len);
 void sie_guest_destroy(struct vm *vm);
 
-- 
2.32.0


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

* [kvm-unit-tests PATCH v2 02/10] s390x: sie: Add PV fields to SIE control block
  2021-12-07 15:59 [kvm-unit-tests PATCH v2 00/10] s390x: sie: Add PV snippet support Janosch Frank
  2021-12-07 15:59 ` [kvm-unit-tests PATCH v2 01/10] lib: s390x: sie: Add sca allocation and freeing Janosch Frank
@ 2021-12-07 15:59 ` Janosch Frank
  2021-12-07 15:59 ` [kvm-unit-tests PATCH v2 03/10] s390x: sie: Add UV information into VM struct Janosch Frank
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Janosch Frank @ 2021-12-07 15:59 UTC (permalink / raw)
  To: kvm; +Cc: linux-s390, imbrenda, david, thuth, seiden

We need those fields for format 4 SIE tests (protected VMs).

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
---
 lib/s390x/sie.h | 41 ++++++++++++++++++++++++++++++++++-------
 1 file changed, 34 insertions(+), 7 deletions(-)

diff --git a/lib/s390x/sie.h b/lib/s390x/sie.h
index f34e3c80..c6eb6441 100644
--- a/lib/s390x/sie.h
+++ b/lib/s390x/sie.h
@@ -38,7 +38,13 @@ struct kvm_s390_sie_block {
 	uint8_t		reserved08[4];		/* 0x0008 */
 #define PROG_IN_SIE (1<<0)
 	uint32_t	prog0c;			/* 0x000c */
-	uint8_t		reserved10[16];		/* 0x0010 */
+union {
+		uint8_t	reserved10[16];		/* 0x0010 */
+		struct {
+			uint64_t	pv_handle_cpu;
+			uint64_t	pv_handle_config;
+		};
+	};
 #define PROG_BLOCK_SIE	(1<<0)
 #define PROG_REQUEST	(1<<1)
 	uint32_t 	prog20;		/* 0x0020 */
@@ -87,10 +93,22 @@ struct kvm_s390_sie_block {
 #define ICPT_PARTEXEC	0x38
 #define ICPT_IOINST	0x40
 #define ICPT_KSS	0x5c
+#define ICPT_INT_ENABLE	0x64
+#define ICPT_PV_INSTR	0x68
+#define ICPT_PV_NOTIFY	0x6c
+#define ICPT_PV_PREF	0x70
 	uint8_t		icptcode;		/* 0x0050 */
 	uint8_t		icptstatus;		/* 0x0051 */
 	uint16_t	ihcpu;			/* 0x0052 */
-	uint8_t		reserved54[2];		/* 0x0054 */
+	uint8_t		reserved54;		/* 0x0054 */
+#define IICTL_CODE_NONE		 0x00
+#define IICTL_CODE_MCHK		 0x01
+#define IICTL_CODE_EXT		 0x02
+#define IICTL_CODE_IO		 0x03
+#define IICTL_CODE_RESTART	 0x04
+#define IICTL_CODE_SPECIFICATION 0x10
+#define IICTL_CODE_OPERAND	 0x11
+	uint8_t		iictl;			/* 0x0055 */
 	uint16_t	ipa;			/* 0x0056 */
 	uint32_t	ipb;			/* 0x0058 */
 	uint32_t	scaoh;			/* 0x005c */
@@ -112,7 +130,7 @@ struct kvm_s390_sie_block {
 #define ECB3_RI  0x01
 	uint8_t    	ecb3;			/* 0x0063 */
 	uint32_t	scaol;			/* 0x0064 */
-	uint8_t		reserved68;		/* 0x0068 */
+	uint8_t		sdf;			/* 0x0068 */
 	uint8_t    	epdx;			/* 0x0069 */
 	uint8_t    	reserved6a[2];		/* 0x006a */
 	uint32_t	todpr;			/* 0x006c */
@@ -128,9 +146,15 @@ struct kvm_s390_sie_block {
 #define HPID_KVM	0x4
 #define HPID_VSIE	0x5
 	uint8_t		hpid;			/* 0x00b8 */
-	uint8_t		reservedb9[11];		/* 0x00b9 */
-	uint16_t	extcpuaddr;		/* 0x00c4 */
-	uint16_t	eic;			/* 0x00c6 */
+	uint8_t		reservedb9[7];		/* 0x00b9 */
+	union {
+		struct {
+			uint32_t	eiparams;	/* 0x00c0 */
+			uint16_t	extcpuaddr;	/* 0x00c4 */
+			uint16_t	eic;		/* 0x00c6 */
+		};
+		uint64_t	mcic;			/* 0x00c0 */
+	} __attribute__ ((__packed__));
 	uint32_t	reservedc8;		/* 0x00c8 */
 	uint16_t	pgmilc;			/* 0x00cc */
 	uint16_t	iprcc;			/* 0x00ce */
@@ -152,7 +176,10 @@ struct kvm_s390_sie_block {
 #define CRYCB_FORMAT2 0x00000003
 	uint32_t	crycbd;			/* 0x00fc */
 	uint64_t	gcr[16];		/* 0x0100 */
-	uint64_t	gbea;			/* 0x0180 */
+	union {
+		uint64_t	gbea;			/* 0x0180 */
+		uint64_t	sidad;
+	};
 	uint8_t		reserved188[8];		/* 0x0188 */
 	uint64_t   	sdnxo;			/* 0x0190 */
 	uint8_t    	reserved198[8];		/* 0x0198 */
-- 
2.32.0


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

* [kvm-unit-tests PATCH v2 03/10] s390x: sie: Add UV information into VM struct
  2021-12-07 15:59 [kvm-unit-tests PATCH v2 00/10] s390x: sie: Add PV snippet support Janosch Frank
  2021-12-07 15:59 ` [kvm-unit-tests PATCH v2 01/10] lib: s390x: sie: Add sca allocation and freeing Janosch Frank
  2021-12-07 15:59 ` [kvm-unit-tests PATCH v2 02/10] s390x: sie: Add PV fields to SIE control block Janosch Frank
@ 2021-12-07 15:59 ` Janosch Frank
  2021-12-07 15:59 ` [kvm-unit-tests PATCH v2 04/10] s390x: uv: Add more UV call functions Janosch Frank
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Janosch Frank @ 2021-12-07 15:59 UTC (permalink / raw)
  To: kvm; +Cc: linux-s390, imbrenda, david, thuth, seiden

We need to save the handles for the VM and the VCPU so we can retrieve
them easily after their creation. Since the SIE lib is single guest
cpu only we only save one vcpu handle.

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
---
 lib/s390x/sie.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/lib/s390x/sie.h b/lib/s390x/sie.h
index c6eb6441..1a12faa7 100644
--- a/lib/s390x/sie.h
+++ b/lib/s390x/sie.h
@@ -200,6 +200,11 @@ union {
 	uint64_t	gvrd;			/* 0x01f8 */
 } __attribute__((packed));
 
+struct vm_uv {
+	uint64_t vm_handle;
+	uint64_t vcpu_handle;
+};
+
 struct vm_save_regs {
 	uint64_t grs[16];
 	uint64_t fprs[16];
@@ -220,6 +225,7 @@ struct vm {
 	struct vm_save_area save_area;
 	void *sca;				/* System Control Area */
 	uint8_t *crycb;				/* Crypto Control Block */
+	struct vm_uv uv;			/* PV UV information */
 	/* Ptr to first guest page */
 	uint8_t *guest_mem;
 };
-- 
2.32.0


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

* [kvm-unit-tests PATCH v2 04/10] s390x: uv: Add more UV call functions
  2021-12-07 15:59 [kvm-unit-tests PATCH v2 00/10] s390x: sie: Add PV snippet support Janosch Frank
                   ` (2 preceding siblings ...)
  2021-12-07 15:59 ` [kvm-unit-tests PATCH v2 03/10] s390x: sie: Add UV information into VM struct Janosch Frank
@ 2021-12-07 15:59 ` Janosch Frank
  2021-12-07 16:00 ` [kvm-unit-tests PATCH v2 05/10] s390x: lib: Extend UV library with PV guest management Janosch Frank
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Janosch Frank @ 2021-12-07 15:59 UTC (permalink / raw)
  To: kvm; +Cc: linux-s390, imbrenda, david, thuth, seiden

To manage protected guests we need a few more UV calls:
   * import / export
   * destroy page
   * set SE header
   * set cpu state

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
---
 lib/s390x/asm/uv.h | 85 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 85 insertions(+)

diff --git a/lib/s390x/asm/uv.h b/lib/s390x/asm/uv.h
index 8baf896f..6e331211 100644
--- a/lib/s390x/asm/uv.h
+++ b/lib/s390x/asm/uv.h
@@ -33,6 +33,7 @@
 #define UVC_CMD_DESTROY_SEC_CPU		0x0121
 #define UVC_CMD_CONV_TO_SEC_STOR	0x0200
 #define UVC_CMD_CONV_FROM_SEC_STOR	0x0201
+#define UVC_CMD_DESTR_SEC_STOR		0x0202
 #define UVC_CMD_SET_SEC_CONF_PARAMS	0x0300
 #define UVC_CMD_UNPACK_IMG		0x0301
 #define UVC_CMD_VERIFY_IMG		0x0302
@@ -256,6 +257,63 @@ static inline int uv_remove_shared(unsigned long addr)
 	return share(addr, UVC_CMD_REMOVE_SHARED_ACCESS);
 }
 
+static inline int uv_cmd_nodata(uint64_t handle, uint16_t cmd, uint16_t *rc, uint16_t *rrc)
+{
+	struct uv_cb_nodata uvcb = {
+		.header.cmd = cmd,
+		.header.len = sizeof(uvcb),
+		.handle = handle,
+	};
+	int cc;
+
+	assert(handle);
+	cc = uv_call(0, (uint64_t)&uvcb);
+	*rc = uvcb.header.rc;
+	*rrc = uvcb.header.rrc;
+	return cc;
+}
+
+static inline int uv_import(uint64_t handle, unsigned long gaddr)
+{
+	struct uv_cb_cts uvcb = {
+		.header.cmd = UVC_CMD_CONV_TO_SEC_STOR,
+		.header.len = sizeof(uvcb),
+		.guest_handle = handle,
+		.gaddr = gaddr,
+	};
+
+	return uv_call(0, (uint64_t)&uvcb);
+}
+
+static inline int uv_export(unsigned long paddr)
+{
+	struct uv_cb_cfs uvcb = {
+		.header.cmd = UVC_CMD_CONV_FROM_SEC_STOR,
+		.header.len = sizeof(uvcb),
+		.paddr = paddr
+	};
+
+	return uv_call(0, (u64)&uvcb);
+}
+
+/*
+ * Requests the Ultravisor to destroy a guest page and make it
+ * accessible to the host. The destroy clears the page instead of
+ * exporting.
+ *
+ * @paddr: Absolute host address of page to be destroyed
+ */
+static inline int uv_destroy_page(unsigned long paddr)
+{
+	struct uv_cb_cfs uvcb = {
+		.header.cmd = UVC_CMD_DESTR_SEC_STOR,
+		.header.len = sizeof(uvcb),
+		.paddr = paddr
+	};
+
+	return uv_call(0, (uint64_t)&uvcb);
+}
+
 struct uv_cb_cpu_set_state {
 	struct uv_cb_header header;
 	u64 reserved08[2];
@@ -270,4 +328,31 @@ struct uv_cb_cpu_set_state {
 #define PV_CPU_STATE_CHKSTP	3
 #define PV_CPU_STATE_OPR_LOAD	5
 
+static inline int uv_set_cpu_state(uint64_t handle, uint8_t state)
+{
+	struct uv_cb_cpu_set_state uvcb = {
+		.header.cmd = UVC_CMD_CPU_SET_STATE,
+		.header.len = sizeof(uvcb),
+		.cpu_handle = handle,
+		.state = state,
+	};
+
+	assert(handle);
+	return uv_call(0, (uint64_t)&uvcb);
+}
+
+static inline int uv_set_se_hdr(uint64_t handle, void *hdr, size_t len)
+{
+	struct uv_cb_ssc uvcb = {
+		.header.cmd = UVC_CMD_SET_SEC_CONF_PARAMS,
+		.header.len = sizeof(uvcb),
+		.sec_header_origin = (uint64_t)hdr,
+		.sec_header_len = len,
+		.guest_handle = handle,
+	};
+
+	assert(handle);
+	return uv_call(0, (uint64_t)&uvcb);
+}
+
 #endif
-- 
2.32.0


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

* [kvm-unit-tests PATCH v2 05/10] s390x: lib: Extend UV library with PV guest management
  2021-12-07 15:59 [kvm-unit-tests PATCH v2 00/10] s390x: sie: Add PV snippet support Janosch Frank
                   ` (3 preceding siblings ...)
  2021-12-07 15:59 ` [kvm-unit-tests PATCH v2 04/10] s390x: uv: Add more UV call functions Janosch Frank
@ 2021-12-07 16:00 ` Janosch Frank
  2021-12-07 16:00 ` [kvm-unit-tests PATCH v2 06/10] lib: s390: sie: Add PV guest register handling Janosch Frank
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Janosch Frank @ 2021-12-07 16:00 UTC (permalink / raw)
  To: kvm; +Cc: linux-s390, imbrenda, david, thuth, seiden

Let's extend the UV lib with guest 1 code to be able to manage
protected VMs in the future.

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
---
 lib/s390x/asm/uv.h |  14 +++++
 lib/s390x/sie.h    |   3 ++
 lib/s390x/uv.c     | 128 +++++++++++++++++++++++++++++++++++++++++++++
 lib/s390x/uv.h     |   7 +++
 4 files changed, 152 insertions(+)

diff --git a/lib/s390x/asm/uv.h b/lib/s390x/asm/uv.h
index 6e331211..97c90e81 100644
--- a/lib/s390x/asm/uv.h
+++ b/lib/s390x/asm/uv.h
@@ -355,4 +355,18 @@ static inline int uv_set_se_hdr(uint64_t handle, void *hdr, size_t len)
 	return uv_call(0, (uint64_t)&uvcb);
 }
 
+static inline int uv_unp_page(uint64_t handle, uint64_t gaddr, uint64_t tweak1, uint64_t tweak2)
+{
+	struct uv_cb_unp uvcb = {
+		.header.cmd = UVC_CMD_UNPACK_IMG,
+		.header.len = sizeof(uvcb),
+		.guest_handle = handle,
+		.gaddr = gaddr,
+		.tweak[0] = tweak1,
+		.tweak[1] = tweak2,
+	};
+
+	return uv_call(0, (uint64_t)&uvcb);
+}
+
 #endif
diff --git a/lib/s390x/sie.h b/lib/s390x/sie.h
index 1a12faa7..6d209793 100644
--- a/lib/s390x/sie.h
+++ b/lib/s390x/sie.h
@@ -203,6 +203,9 @@ union {
 struct vm_uv {
 	uint64_t vm_handle;
 	uint64_t vcpu_handle;
+	void *conf_base_stor;
+	void *conf_var_stor;
+	void *cpu_stor;
 };
 
 struct vm_save_regs {
diff --git a/lib/s390x/uv.c b/lib/s390x/uv.c
index c5c69c47..6fe11dff 100644
--- a/lib/s390x/uv.c
+++ b/lib/s390x/uv.c
@@ -17,11 +17,14 @@
 #include <asm/facility.h>
 #include <asm/uv.h>
 #include <uv.h>
+#include <sie.h>
 
 static struct uv_cb_qui uvcb_qui = {
 	.header.cmd = UVC_CMD_QUI,
 	.header.len = sizeof(uvcb_qui),
 };
+static uint64_t uv_init_mem;
+
 
 bool uv_os_is_guest(void)
 {
@@ -54,3 +57,128 @@ int uv_setup(void)
 	assert(uvcb_qui.header.rc == 1 || uvcb_qui.header.rc == 0x100);
 	return 1;
 }
+
+void uv_init(void)
+{
+	struct uv_cb_init uvcb_init = {
+		.header.len = sizeof(uvcb_init),
+		.header.cmd = UVC_CMD_INIT_UV,
+	};
+	static bool initialized;
+	int cc;
+
+	/* Let's not do this twice */
+	assert(!initialized);
+	/* Query is done on initialization but let's check anyway */
+	assert(uvcb_qui.header.rc == 1 || uvcb_qui.header.rc == 0x100);
+
+	/* Donated storage needs to be over 2GB aligned to 1MB */
+	uv_init_mem = (uint64_t)memalign_pages_flags(HPAGE_SIZE, uvcb_qui.uv_base_stor_len, AREA_NORMAL);
+	uvcb_init.stor_origin = uv_init_mem;
+	uvcb_init.stor_len = uvcb_qui.uv_base_stor_len;
+
+	cc = uv_call(0, (uint64_t)&uvcb_init);
+	assert(cc == 0);
+	initialized = true;
+}
+
+void uv_create_guest(struct vm *vm)
+{
+	struct uv_cb_cgc uvcb_cgc = {
+		.header.cmd = UVC_CMD_CREATE_SEC_CONF,
+		.header.len = sizeof(uvcb_cgc),
+	};
+	struct uv_cb_csc uvcb_csc = {
+		.header.len = sizeof(uvcb_csc),
+		.header.cmd = UVC_CMD_CREATE_SEC_CPU,
+		.state_origin = (uint64_t)vm->sblk,
+		.num = 0,
+	};
+	unsigned long vsize;
+	int cc;
+
+	uvcb_cgc.guest_stor_origin = vm->sblk->mso;
+	uvcb_cgc.guest_stor_len = vm->sblk->msl;
+
+	/* Config allocation */
+	vsize = uvcb_qui.conf_base_virt_stor_len +
+		((uvcb_cgc.guest_stor_len / HPAGE_SIZE) * uvcb_qui.conf_virt_var_stor_len);
+
+	vm->uv.conf_base_stor = memalign_pages_flags(PAGE_SIZE * 4, uvcb_qui.conf_base_phys_stor_len, 0);
+	/*
+	 * This allocation needs to be below the max guest storage
+	 * address so let's simply put it into the physical memory
+	 */
+	vm->uv.conf_var_stor = memalign_pages_flags(PAGE_SIZE, vsize,0);
+	uvcb_cgc.conf_base_stor_origin = (uint64_t)vm->uv.conf_base_stor;
+	uvcb_cgc.conf_var_stor_origin = (uint64_t)vm->uv.conf_var_stor;
+
+	/* CPU allocation */
+	vm->uv.cpu_stor = memalign_pages_flags(PAGE_SIZE, uvcb_qui.cpu_stor_len, 0);
+	uvcb_csc.stor_origin = (uint64_t)vm->uv.cpu_stor;
+
+	uvcb_cgc.guest_asce = (uint64_t)stctg(1);
+	uvcb_cgc.guest_sca = (uint64_t)vm->sca;
+
+	cc = uv_call(0, (uint64_t)&uvcb_cgc);
+	assert(!cc);
+
+	vm->uv.vm_handle = uvcb_cgc.guest_handle;
+	uvcb_csc.guest_handle = uvcb_cgc.guest_handle;
+	cc = uv_call(0, (uint64_t)&uvcb_csc);
+	vm->uv.vcpu_handle = uvcb_csc.cpu_handle;
+	assert(!cc);
+
+	/*
+	 * Convert guest to format 4:
+	 *
+	 *  - Set format 4
+	 *  - Write UV handles into sblk
+	 *  - Allocate and set SIDA
+	 */
+	vm->sblk->sdf = 2;
+	vm->sblk->sidad = (uint64_t)alloc_page();
+	vm->sblk->pv_handle_cpu = uvcb_csc.cpu_handle;
+	vm->sblk->pv_handle_config = uvcb_cgc.guest_handle;
+}
+
+void uv_destroy_guest(struct vm *vm)
+{
+	int cc;
+	u16 rc, rrc;
+
+	cc = uv_cmd_nodata(vm->sblk->pv_handle_cpu,
+			   UVC_CMD_DESTROY_SEC_CPU, &rc, &rrc);
+	assert(cc == 0);
+	free_page((void *)vm->sblk->sidad);
+	free_pages(vm->uv.cpu_stor);
+
+	cc = uv_cmd_nodata(vm->sblk->pv_handle_config,
+			   UVC_CMD_DESTROY_SEC_CONF, &rc, &rrc);
+	assert(cc == 0);
+	free_pages(vm->uv.conf_base_stor);
+	free_pages(vm->uv.conf_var_stor);
+}
+
+int uv_unpack(struct vm *vm, uint64_t addr, uint64_t len, uint64_t tweak)
+{
+	int i, cc;
+
+	for (i = 0; i < len / PAGE_SIZE; i++) {
+		cc = uv_unp_page(vm->uv.vm_handle, addr, tweak, i * PAGE_SIZE);
+		assert(!cc);
+		addr += PAGE_SIZE;
+	}
+	return cc;
+}
+
+void uv_verify_load(struct vm *vm)
+{
+	uint16_t rc, rrc;
+	int cc;
+
+	cc = uv_cmd_nodata(vm->uv.vm_handle, UVC_CMD_VERIFY_IMG, &rc, &rrc);
+	assert(!cc);
+	cc = uv_set_cpu_state(vm->uv.vcpu_handle, PV_CPU_STATE_OPR_LOAD);
+	assert(!cc);
+}
diff --git a/lib/s390x/uv.h b/lib/s390x/uv.h
index 2b23407a..6ffe537a 100644
--- a/lib/s390x/uv.h
+++ b/lib/s390x/uv.h
@@ -2,9 +2,16 @@
 #ifndef _S390X_UV_H_
 #define _S390X_UV_H_
 
+#include <sie.h>
+
 bool uv_os_is_guest(void);
 bool uv_os_is_host(void);
 bool uv_query_test_call(unsigned int nr);
+void uv_init(void);
 int uv_setup(void);
+void uv_create_guest(struct vm *vm);
+void uv_destroy_guest(struct vm *vm);
+int uv_unpack(struct vm *vm, uint64_t addr, uint64_t len, uint64_t tweak);
+void uv_verify_load(struct vm *vm);
 
 #endif /* UV_H */
-- 
2.32.0


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

* [kvm-unit-tests PATCH v2 06/10] lib: s390: sie: Add PV guest register handling
  2021-12-07 15:59 [kvm-unit-tests PATCH v2 00/10] s390x: sie: Add PV snippet support Janosch Frank
                   ` (4 preceding siblings ...)
  2021-12-07 16:00 ` [kvm-unit-tests PATCH v2 05/10] s390x: lib: Extend UV library with PV guest management Janosch Frank
@ 2021-12-07 16:00 ` Janosch Frank
  2021-12-07 16:00 ` [kvm-unit-tests PATCH v2 07/10] s390x: snippets: Add PV support Janosch Frank
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Janosch Frank @ 2021-12-07 16:00 UTC (permalink / raw)
  To: kvm; +Cc: linux-s390, imbrenda, david, thuth, seiden

Protected guests have their registers stored to / loaded from offset 0x380
of the sie control block. So we need to copy over the GRs to/from that
offset for format 4 (PV) guests before and after we enter SIE.

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
---
 lib/s390x/sie.c | 8 ++++++++
 lib/s390x/sie.h | 2 ++
 2 files changed, 10 insertions(+)

diff --git a/lib/s390x/sie.c b/lib/s390x/sie.c
index 51d3b94e..00aff713 100644
--- a/lib/s390x/sie.c
+++ b/lib/s390x/sie.c
@@ -44,6 +44,10 @@ void sie_handle_validity(struct vm *vm)
 
 void sie(struct vm *vm)
 {
+	if (vm->sblk->sdf == 2)
+		memcpy(vm->sblk->pv_grregs, vm->save_area.guest.grs,
+		       sizeof(vm->save_area.guest.grs));
+
 	/* Reset icptcode so we don't trip over it below */
 	vm->sblk->icptcode = 0;
 
@@ -53,6 +57,10 @@ void sie(struct vm *vm)
 	}
 	vm->save_area.guest.grs[14] = vm->sblk->gg14;
 	vm->save_area.guest.grs[15] = vm->sblk->gg15;
+
+	if (vm->sblk->sdf == 2)
+		memcpy(vm->save_area.guest.grs, vm->sblk->pv_grregs,
+		       sizeof(vm->save_area.guest.grs));
 }
 
 void sie_guest_sca_create(struct vm *vm)
diff --git a/lib/s390x/sie.h b/lib/s390x/sie.h
index 6d209793..de91ea5a 100644
--- a/lib/s390x/sie.h
+++ b/lib/s390x/sie.h
@@ -198,6 +198,8 @@ union {
 	uint64_t	itdba;			/* 0x01e8 */
 	uint64_t   	riccbd;			/* 0x01f0 */
 	uint64_t	gvrd;			/* 0x01f8 */
+	uint64_t	reserved200[48];	/* 0x0200 */
+	uint64_t	pv_grregs[16];		/* 0x0380 */
 } __attribute__((packed));
 
 struct vm_uv {
-- 
2.32.0


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

* [kvm-unit-tests PATCH v2 07/10] s390x: snippets: Add PV support
  2021-12-07 15:59 [kvm-unit-tests PATCH v2 00/10] s390x: sie: Add PV snippet support Janosch Frank
                   ` (5 preceding siblings ...)
  2021-12-07 16:00 ` [kvm-unit-tests PATCH v2 06/10] lib: s390: sie: Add PV guest register handling Janosch Frank
@ 2021-12-07 16:00 ` Janosch Frank
  2021-12-08 12:57   ` Claudio Imbrenda
  2021-12-07 16:00 ` [kvm-unit-tests PATCH v2 08/10] lib: s390x: Introduce snippet helpers Janosch Frank
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 16+ messages in thread
From: Janosch Frank @ 2021-12-07 16:00 UTC (permalink / raw)
  To: kvm; +Cc: linux-s390, imbrenda, david, thuth, seiden

To create a pv-snippet we need to generate an se-header. This can be
done using a currently not released tool. This tool creates a
se-header similar to `genprotimg` with the difference that the image
itself will not be encrypted.

The image for which we want to create a header must be a binary and
padded to 4k. Therefore, we convert the compiled snippet to a binary,
padd it to 4k, generate the header and convert it back to s390-64bit
elf.

The name of the tool can be specified using the config argument
`--gen-se-header=`. The pv-snipptes will only be built when this
option is specified. Furthermore, the Hostkey-Document must be
specified. If not the build will be skipped.

The host-snippet relation can be specified using the `pv-snippets`
variable in s390x/Makefile, similar to the non-pv-snippets in
2f6fdb4a (s390x: snippets: Add snippet compilation, 2021-06-22)

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
---
 .gitignore          |  2 ++
 configure           |  8 ++++++
 lib/s390x/snippet.h |  7 +++++
 s390x/Makefile      | 67 +++++++++++++++++++++++++++++++++++++--------
 4 files changed, 73 insertions(+), 11 deletions(-)

diff --git a/.gitignore b/.gitignore
index 3d5be622..28a197bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,3 +25,5 @@ cscope.*
 /api/dirty-log-perf
 /s390x/*.bin
 /s390x/snippets/*/*.gbin
+/s390x/snippets/*/*.hdr
+/s390x/snippets/*/*.*obj
\ No newline at end of file
diff --git a/configure b/configure
index 1d4d855e..9210912f 100755
--- a/configure
+++ b/configure
@@ -26,6 +26,7 @@ target=
 errata_force=0
 erratatxt="$srcdir/errata.txt"
 host_key_document=
+gen_se_header=
 page_size=
 earlycon=
 
@@ -54,6 +55,9 @@ usage() {
 	    --host-key-document=HOST_KEY_DOCUMENT
 	                           Specify the machine-specific host-key document for creating
 	                           a PVM image with 'genprotimg' (s390x only)
+	    --gen-se-header=GEN_SE_HEADER
+	                           Provide an executable to generate a PV header
+				   requires --host-key-document. (s390x-snippets only)
 	    --page-size=PAGE_SIZE
 	                           Specify the page size (translation granule) (4k, 16k or
 	                           64k, default is 64k, arm64 only)
@@ -127,6 +131,9 @@ while [[ "$1" = -* ]]; do
 	--host-key-document)
 	    host_key_document="$arg"
 	    ;;
+	--gen-se-header)
+	    gen_se_header="$arg"
+	    ;;
 	--page-size)
 	    page_size="$arg"
 	    ;;
@@ -341,6 +348,7 @@ U32_LONG_FMT=$u32_long
 WA_DIVIDE=$wa_divide
 GENPROTIMG=${GENPROTIMG-genprotimg}
 HOST_KEY_DOCUMENT=$host_key_document
+GEN_SE_HEADER=$gen_se_header
 EOF
 if [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then
     echo "TARGET=$target" >> config.mak
diff --git a/lib/s390x/snippet.h b/lib/s390x/snippet.h
index 8e4765f8..6b77a8a9 100644
--- a/lib/s390x/snippet.h
+++ b/lib/s390x/snippet.h
@@ -14,10 +14,17 @@
 	_binary_s390x_snippets_##type##_##file##_gbin_start
 #define SNIPPET_NAME_END(type, file) \
 	_binary_s390x_snippets_##type##_##file##_gbin_end
+#define SNIPPET_HDR_START(type, file) \
+	_binary_s390x_snippets_##type##_##file##_hdr_start
+#define SNIPPET_HDR_END(type, file) \
+	_binary_s390x_snippets_##type##_##file##_hdr_end
+
 
 /* Returns the length of the snippet */
 #define SNIPPET_LEN(type, file) \
 	((uintptr_t)SNIPPET_NAME_END(type, file) - (uintptr_t)SNIPPET_NAME_START(type, file))
+#define SNIPPET_HDR_LEN(type, file) \
+	((uintptr_t)SNIPPET_HDR_END(type, file) - (uintptr_t)SNIPPET_HDR_START(type, file))
 
 /*
  * C snippet instructions start at 0x4000 due to the prefix and the
diff --git a/s390x/Makefile b/s390x/Makefile
index f95f2e61..55e6d962 100644
--- a/s390x/Makefile
+++ b/s390x/Makefile
@@ -26,12 +26,20 @@ tests += $(TEST_DIR)/edat.elf
 tests += $(TEST_DIR)/mvpg-sie.elf
 tests += $(TEST_DIR)/spec_ex-sie.elf
 
+ifneq ($(HOST_KEY_DOCUMENT),)
+ifneq ($(GEN_SE_HEADER),)
+tests += $(pv-tests)
+endif
+endif
+
 tests_binary = $(patsubst %.elf,%.bin,$(tests))
 ifneq ($(HOST_KEY_DOCUMENT),)
 tests_pv_binary = $(patsubst %.bin,%.pv.bin,$(tests_binary))
 else
 tests_pv_binary =
+GEN_SE_HEADER =
 endif
+snippets-obj = $(patsubst %.gbin,%.gobj,$(snippets))
 
 all: directories test_cases test_cases_binary test_cases_pv
 
@@ -82,26 +90,59 @@ asmlib = $(TEST_DIR)/cstart64.o $(TEST_DIR)/cpu.o
 FLATLIBS = $(libcflat)
 
 SNIPPET_DIR = $(TEST_DIR)/snippets
-snippet_asmlib = $(SNIPPET_DIR)/c/cstart.o lib/auxinfo.o
+snippet_asmlib = $(SNIPPET_DIR)/c/cstart.o
+snippet_lib = $(snippet_asmlib) lib/auxinfo.o
 
 # perquisites (=guests) for the snippet hosts.
 # $(TEST_DIR)/<snippet-host>.elf: snippets = $(SNIPPET_DIR)/<c/asm>/<snippet>.gbin
 $(TEST_DIR)/mvpg-sie.elf: snippets = $(SNIPPET_DIR)/c/mvpg-snippet.gbin
 $(TEST_DIR)/spec_ex-sie.elf: snippets = $(SNIPPET_DIR)/c/spec_ex.gbin
 
-$(SNIPPET_DIR)/asm/%.gbin: $(SNIPPET_DIR)/asm/%.o $(FLATLIBS)
-	$(OBJCOPY) -O binary $(patsubst %.gbin,%.o,$@) $@
-	$(OBJCOPY) -I binary -O elf64-s390 -B "s390:64-bit" $@ $@
+ifneq ($(GEN_SE_HEADER),)
+snippets += $(pv-snippets)
+tests += $(pv-tests)
+snippet-hdr-obj = $(patsubst %.gbin,%.hdr.obj,$(pv-snippets))
+else
+snippet-hdr-obj =
+endif
+
+# the asm/c snippets %.o have additional generated files as dependencies
+$(SNIPPET_DIR)/asm/%.o: $(SNIPPET_DIR)/asm/%.S $(asm-offsets)
+	$(CC) $(CFLAGS) -c -nostdlib -o $@ $<
+
+$(SNIPPET_DIR)/c/%.o: $(SNIPPET_DIR)/c/%.c $(asm-offsets)
+	$(CC) $(CFLAGS) -c -nostdlib -o $@ $<
+
+$(SNIPPET_DIR)/asm/%.gbin: $(SNIPPET_DIR)/asm/%.o
+	$(OBJCOPY) -O binary -j ".rodata" -j ".text" -j ".data" -j ".bss" --set-section-flags .bss=alloc,load,contents $(patsubst %.gbin,%.o,$@) $@
+	truncate -s '%4096' $@
+
+$(SNIPPET_DIR)/c/%.gbin: $(SNIPPET_DIR)/c/%.o $(snippet_lib) $(FLATLIBS)
+	$(CC) $(LDFLAGS) -o $@ -T $(SRCDIR)/s390x/snippets/c/flat.lds $(patsubst %.gbin,%.o,$@) $(snippet_lib) $(FLATLIBS)
+	$(OBJCOPY) -O binary -j ".rodata" -j ".lowcore" -j ".text" -j ".data" -j ".bss" --set-section-flags .bss=alloc,load,contents $@ $@
+	truncate -s '%4096' $@
+
+$(SNIPPET_DIR)/asm/%.hdr: $(SNIPPET_DIR)/asm/%.gbin $(HOST_KEY_DOCUMENT)
+	$(GEN_SE_HEADER) -k $(HOST_KEY_DOCUMENT) -c $<,0x4000,0x00000000000000420000000000000000 --psw-addr 0x4000 -o $@
+
+$(SNIPPET_DIR)/c/%.hdr: $(SNIPPET_DIR)/c/%.gbin $(HOST_KEY_DOCUMENT)
+	$(GEN_SE_HEADER) -k $(HOST_KEY_DOCUMENT) -c $<,0x0,0x00000000000000420000000000000000 --psw-addr 0x4000 -o $@
+
+.SECONDARY:
+%.gobj: %.gbin
+	$(OBJCOPY) -I binary -O elf64-s390 -B "s390:64-bit" $< $@
+
+.SECONDARY:
+%.hdr.obj: %.hdr
+	$(OBJCOPY) -I binary -O elf64-s390 -B "s390:64-bit" $< $@
 
-$(SNIPPET_DIR)/c/%.gbin: $(SNIPPET_DIR)/c/%.o $(snippet_asmlib) $(FLATLIBS)
-	$(CC) $(LDFLAGS) -o $@ -T $(SRCDIR)/s390x/snippets/c/flat.lds $(patsubst %.gbin,%.o,$@) $(snippet_asmlib) $(FLATLIBS)
-	$(OBJCOPY) -O binary $@ $@
-	$(OBJCOPY) -I binary -O elf64-s390 -B "s390:64-bit" $@ $@
 
 .SECONDEXPANSION:
-%.elf: $$(snippets) %.o $(FLATLIBS) $(SRCDIR)/s390x/flat.lds $(asmlib)
+%.elf: $(FLATLIBS) $(asmlib) $(SRCDIR)/s390x/flat.lds $$(snippets-obj) $$(snippet-hdr-obj) %.o
 	$(CC) $(CFLAGS) -c -o $(@:.elf=.aux.o) $(SRCDIR)/lib/auxinfo.c -DPROGNAME=\"$@\"
-	$(CC) $(LDFLAGS) -o $@ -T $(SRCDIR)/s390x/flat.lds $(filter %.o, $^) $(FLATLIBS) $(snippets) $(@:.elf=.aux.o)
+	@$(CC) $(LDFLAGS) -o $@ -T $(SRCDIR)/s390x/flat.lds \
+		$(filter %.o, $^) $(FLATLIBS) $(snippets-obj) $(snippet-hdr-obj) $(@:.elf=.aux.o) || \
+		{ echo "Failure probably caused by missing definition of gen-se-header executable"; exit 1; }
 	$(RM) $(@:.elf=.aux.o)
 	@chmod a-x $@
 
@@ -114,8 +155,12 @@ $(SNIPPET_DIR)/c/%.gbin: $(SNIPPET_DIR)/c/%.o $(snippet_asmlib) $(FLATLIBS)
 %.pv.bin: %.bin $(HOST_KEY_DOCUMENT)
 	$(GENPROTIMG) --host-key-document $(HOST_KEY_DOCUMENT) --no-verify --image $< -o $@
 
+$(snippet_asmlib): $$(patsubst %.o,%.S,$$@) $(asm-offsets)
+	$(CC) $(CFLAGS) -c -nostdlib -o $@ $<
+
+
 arch_clean: asm_offsets_clean
-	$(RM) $(TEST_DIR)/*.{o,elf,bin} $(TEST_DIR)/.*.d $(SNIPPET_DIR)/c/*.{o,gbin} $(SNIPPET_DIR)/c/.*.d lib/s390x/.*.d
+	$(RM) $(TEST_DIR)/*.{o,elf,bin} $(SNIPPET_DIR)/*/*.{o,elf,*bin,*obj,hdr} $(SNIPPET_DIR)/asm/.*.d $(TEST_DIR)/.*.d lib/s390x/.*.d
 
 generated-files = $(asm-offsets)
 $(tests:.elf=.o) $(asmlib) $(cflatobjs): $(generated-files)
-- 
2.32.0


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

* [kvm-unit-tests PATCH v2 08/10] lib: s390x: Introduce snippet helpers
  2021-12-07 15:59 [kvm-unit-tests PATCH v2 00/10] s390x: sie: Add PV snippet support Janosch Frank
                   ` (6 preceding siblings ...)
  2021-12-07 16:00 ` [kvm-unit-tests PATCH v2 07/10] s390x: snippets: Add PV support Janosch Frank
@ 2021-12-07 16:00 ` Janosch Frank
  2021-12-08 11:46   ` Claudio Imbrenda
  2021-12-07 16:00 ` [kvm-unit-tests PATCH v2 09/10] s390x: mvpg-sie: Use " Janosch Frank
  2021-12-07 16:00 ` [kvm-unit-tests PATCH v2 10/10] s390x: sie: Add PV diag test Janosch Frank
  9 siblings, 1 reply; 16+ messages in thread
From: Janosch Frank @ 2021-12-07 16:00 UTC (permalink / raw)
  To: kvm; +Cc: linux-s390, imbrenda, david, thuth, seiden

These helpers reduce code duplication for PV snippet tests.

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
---
 lib/s390x/snippet.h | 103 ++++++++++++++++++++++++++++++++++++++++++++
 lib/s390x/uv.h      |  21 +++++++++
 2 files changed, 124 insertions(+)

diff --git a/lib/s390x/snippet.h b/lib/s390x/snippet.h
index 6b77a8a9..b17b2a4c 100644
--- a/lib/s390x/snippet.h
+++ b/lib/s390x/snippet.h
@@ -9,6 +9,10 @@
 #ifndef _S390X_SNIPPET_H_
 #define _S390X_SNIPPET_H_
 
+#include <sie.h>
+#include <uv.h>
+#include <asm/uv.h>
+
 /* This macro cuts down the length of the pointers to snippets */
 #define SNIPPET_NAME_START(type, file) \
 	_binary_s390x_snippets_##type##_##file##_gbin_start
@@ -26,6 +30,12 @@
 #define SNIPPET_HDR_LEN(type, file) \
 	((uintptr_t)SNIPPET_HDR_END(type, file) - (uintptr_t)SNIPPET_HDR_START(type, file))
 
+#define SNIPPET_PV_TWEAK0	0x42UL
+#define SNIPPET_PV_TWEAK1	0UL
+#define SNIPPET_OFF_C		0
+#define SNIPPET_OFF_ASM		0x4000
+
+
 /*
  * C snippet instructions start at 0x4000 due to the prefix and the
  * stack being before that. ASM snippets don't strictly need a stack
@@ -38,4 +48,97 @@ static const struct psw snippet_psw = {
 	.mask = PSW_MASK_64,
 	.addr = SNIPPET_ENTRY_ADDR,
 };
+
+/*
+ * Sets up a snippet guest on top of an existing and initialized SIE
+ * vm struct.
+ * Once this function has finished without errors the guest can be started.
+ *
+ * @vm: VM that this function will populated, has to be initialized already
+ * @gbin: Snippet gbin data pointer
+ * @gbin_len: Length of the gbin data
+ * @off: Offset from guest absolute 0x0 where snippet is copied to
+ */
+static inline void snippet_init(struct vm *vm, const char *gbin,
+				uint64_t gbin_len, uint64_t off)
+{
+	uint64_t mso = vm->sblk->mso;
+
+	/* Copy test image to guest memory */
+	memcpy((void *)mso + off, gbin, gbin_len);
+
+	/* Setup guest PSW */
+	vm->sblk->gpsw = snippet_psw;
+
+	/*
+	 * We want to exit on PGM exceptions so we don't need
+	 * exception handlers in the guest.
+	 */
+	vm->sblk->ictl = ICTL_OPEREXC | ICTL_PINT;
+}
+
+/*
+ * Sets up a snippet UV/PV guest on top of an existing and initialized
+ * SIE vm struct.
+ * Once this function has finished without errors the guest can be started.
+ *
+ * @vm: VM that this function will populated, has to be initialized already
+ * @gbin: Snippet gbin data pointer
+ * @hdr: Snippet SE header data pointer
+ * @gbin_len: Length of the gbin data
+ * @hdr_len: Length of the hdr data
+ * @off: Offset from guest absolute 0x0 where snippet is copied to
+ */
+static inline void snippet_pv_init(struct vm *vm, const char *gbin,
+				   const char *hdr, uint64_t gbin_len,
+				   uint64_t hdr_len, uint64_t off)
+{
+	uint64_t tweak[2] = {SNIPPET_PV_TWEAK0, SNIPPET_PV_TWEAK1};
+	uint64_t mso = vm->sblk->mso;
+	int i;
+
+	snippet_init(vm, gbin, gbin_len, off);
+
+	uv_create_guest(vm);
+	uv_set_se_hdr(vm->uv.vm_handle, (void *)hdr, hdr_len);
+
+	/* Unpack works on guest addresses so we only need off */
+	uv_unpack(vm, off, gbin_len, tweak[0]);
+	uv_verify_load(vm);
+
+	/*
+	 * Manually import:
+	 * - lowcore 0x0 - 0x1000 (asm)
+	 * - stack 0x3000 (C)
+	 */
+	for (i = 0; i < 4; i++) {
+		uv_import(vm->uv.vm_handle, mso + PAGE_SIZE * i);
+	}
+}
+
+/* Allocates and sets up a snippet based guest */
+static inline void snippet_setup_guest(struct vm *vm, bool is_pv)
+{
+	u8 *guest;
+
+	/* Allocate 1MB as guest memory */
+	guest = alloc_pages(8);
+	memset(guest, 0, HPAGE_SIZE);
+
+	/* Initialize the vm struct and allocate control blocks */
+	sie_guest_create(vm, (uint64_t)guest, HPAGE_SIZE);
+
+	if (is_pv) {
+		/* FMT4 needs a ESCA */
+		sie_guest_sca_create(vm);
+
+		/*
+		 * Initialize UV and setup the address spaces needed
+		 * to run a PV guest.
+		 */
+		uv_init();
+		uv_setup_asces();
+	}
+}
+
 #endif
diff --git a/lib/s390x/uv.h b/lib/s390x/uv.h
index 6ffe537a..8175d9c6 100644
--- a/lib/s390x/uv.h
+++ b/lib/s390x/uv.h
@@ -3,6 +3,7 @@
 #define _S390X_UV_H_
 
 #include <sie.h>
+#include <asm/pgtable.h>
 
 bool uv_os_is_guest(void);
 bool uv_os_is_host(void);
@@ -14,4 +15,24 @@ void uv_destroy_guest(struct vm *vm);
 int uv_unpack(struct vm *vm, uint64_t addr, uint64_t len, uint64_t tweak);
 void uv_verify_load(struct vm *vm);
 
+/*
+ * To run PV guests we need to setup a few things:
+ * - A valid primary ASCE that contains the guest memory and has the P bit set.
+ * - A valid home space ASCE for the UV calls that use home space addresses.
+ */
+static inline void uv_setup_asces(void)
+{
+	uint64_t asce;
+
+	/* We need to have a valid primary ASCE to run guests. */
+	setup_vm();
+
+	/* Set P bit in ASCE as it is required for PV guests */
+	asce = stctg(1) | ASCE_P;
+	lctlg(1, asce);
+
+	/* Copy ASCE into home space CR */
+	lctlg(13, asce);
+}
+
 #endif /* UV_H */
-- 
2.32.0


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

* [kvm-unit-tests PATCH v2 09/10] s390x: mvpg-sie: Use snippet helpers
  2021-12-07 15:59 [kvm-unit-tests PATCH v2 00/10] s390x: sie: Add PV snippet support Janosch Frank
                   ` (7 preceding siblings ...)
  2021-12-07 16:00 ` [kvm-unit-tests PATCH v2 08/10] lib: s390x: Introduce snippet helpers Janosch Frank
@ 2021-12-07 16:00 ` Janosch Frank
  2021-12-08 11:19   ` Claudio Imbrenda
  2021-12-07 16:00 ` [kvm-unit-tests PATCH v2 10/10] s390x: sie: Add PV diag test Janosch Frank
  9 siblings, 1 reply; 16+ messages in thread
From: Janosch Frank @ 2021-12-07 16:00 UTC (permalink / raw)
  To: kvm; +Cc: linux-s390, imbrenda, david, thuth, seiden

Time to use our shiny new snippet helpers.

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
---
 s390x/mvpg-sie.c | 24 ++++++++----------------
 1 file changed, 8 insertions(+), 16 deletions(-)

diff --git a/s390x/mvpg-sie.c b/s390x/mvpg-sie.c
index d526069d..8ae9a52a 100644
--- a/s390x/mvpg-sie.c
+++ b/s390x/mvpg-sie.c
@@ -21,17 +21,12 @@
 #include <sie.h>
 #include <snippet.h>
 
-static u8 *guest;
 static struct vm vm;
 
 static uint8_t *src;
 static uint8_t *dst;
 static uint8_t *cmp;
 
-extern const char SNIPPET_NAME_START(c, mvpg_snippet)[];
-extern const char SNIPPET_NAME_END(c, mvpg_snippet)[];
-int binary_size;
-
 static void test_mvpg_pei(void)
 {
 	uint64_t **pei_dst = (uint64_t **)((uintptr_t) vm.sblk + 0xc0);
@@ -78,9 +73,6 @@ static void test_mvpg_pei(void)
 
 static void test_mvpg(void)
 {
-	int binary_size = SNIPPET_LEN(c, mvpg_snippet);
-
-	memcpy(guest, SNIPPET_NAME_START(c, mvpg_snippet), binary_size);
 	memset(src, 0x42, PAGE_SIZE);
 	memset(dst, 0x43, PAGE_SIZE);
 	sie(&vm);
@@ -89,20 +81,20 @@ static void test_mvpg(void)
 
 static void setup_guest(void)
 {
+	extern const char SNIPPET_NAME_START(c, mvpg_snippet)[];
+	extern const char SNIPPET_NAME_END(c, mvpg_snippet)[];
+
 	setup_vm();
 
-	/* Allocate 1MB as guest memory */
-	guest = alloc_pages(8);
+	snippet_setup_guest(&vm, false);
+	snippet_init(&vm, SNIPPET_NAME_START(c, mvpg_snippet),
+		     SNIPPET_LEN(c, mvpg_snippet), SNIPPET_OFF_C);
 
-	sie_guest_create(&vm, (uint64_t)guest, HPAGE_SIZE);
-
-	vm.sblk->gpsw = snippet_psw;
-	vm.sblk->ictl = ICTL_OPEREXC | ICTL_PINT;
 	/* Enable MVPG interpretation as we want to test KVM and not ourselves */
 	vm.sblk->eca = ECA_MVPGI;
 
-	src = guest + PAGE_SIZE * 6;
-	dst = guest + PAGE_SIZE * 5;
+	src = (uint8_t *) vm.sblk->mso + PAGE_SIZE * 6;
+	dst = (uint8_t *) vm.sblk->mso + PAGE_SIZE * 5;
 	cmp = alloc_page();
 	memset(cmp, 0, PAGE_SIZE);
 }
-- 
2.32.0


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

* [kvm-unit-tests PATCH v2 10/10] s390x: sie: Add PV diag test
  2021-12-07 15:59 [kvm-unit-tests PATCH v2 00/10] s390x: sie: Add PV snippet support Janosch Frank
                   ` (8 preceding siblings ...)
  2021-12-07 16:00 ` [kvm-unit-tests PATCH v2 09/10] s390x: mvpg-sie: Use " Janosch Frank
@ 2021-12-07 16:00 ` Janosch Frank
  2021-12-08 12:55   ` Claudio Imbrenda
  9 siblings, 1 reply; 16+ messages in thread
From: Janosch Frank @ 2021-12-07 16:00 UTC (permalink / raw)
  To: kvm; +Cc: linux-s390, imbrenda, david, thuth, seiden

Let's start testing the format 4 (PV) SIE via the diagnose
instructions since most of them are pretty simple to handle.

The tests check for the intercept values like ipa/ipb and icptcode as
well as the values in the registers and handling of the exception
injection.

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
---
 s390x/Makefile                             |   6 +
 s390x/pv-diags.c                           | 187 +++++++++++++++++++++
 s390x/snippets/asm/snippet-pv-diag-288.S   |  25 +++
 s390x/snippets/asm/snippet-pv-diag-500.S   |  39 +++++
 s390x/snippets/asm/snippet-pv-diag-yield.S |   7 +
 5 files changed, 264 insertions(+)
 create mode 100644 s390x/pv-diags.c
 create mode 100644 s390x/snippets/asm/snippet-pv-diag-288.S
 create mode 100644 s390x/snippets/asm/snippet-pv-diag-500.S
 create mode 100644 s390x/snippets/asm/snippet-pv-diag-yield.S

diff --git a/s390x/Makefile b/s390x/Makefile
index 55e6d962..0cb90466 100644
--- a/s390x/Makefile
+++ b/s390x/Makefile
@@ -26,6 +26,8 @@ tests += $(TEST_DIR)/edat.elf
 tests += $(TEST_DIR)/mvpg-sie.elf
 tests += $(TEST_DIR)/spec_ex-sie.elf
 
+pv-tests += $(TEST_DIR)/pv-diags.elf
+
 ifneq ($(HOST_KEY_DOCUMENT),)
 ifneq ($(GEN_SE_HEADER),)
 tests += $(pv-tests)
@@ -98,6 +100,10 @@ snippet_lib = $(snippet_asmlib) lib/auxinfo.o
 $(TEST_DIR)/mvpg-sie.elf: snippets = $(SNIPPET_DIR)/c/mvpg-snippet.gbin
 $(TEST_DIR)/spec_ex-sie.elf: snippets = $(SNIPPET_DIR)/c/spec_ex.gbin
 
+$(TEST_DIR)/pv-diags.elf: pv-snippets += $(SNIPPET_DIR)/asm/snippet-pv-diag-yield.gbin
+$(TEST_DIR)/pv-diags.elf: pv-snippets += $(SNIPPET_DIR)/asm/snippet-pv-diag-288.gbin
+$(TEST_DIR)/pv-diags.elf: pv-snippets += $(SNIPPET_DIR)/asm/snippet-pv-diag-500.gbin
+
 ifneq ($(GEN_SE_HEADER),)
 snippets += $(pv-snippets)
 tests += $(pv-tests)
diff --git a/s390x/pv-diags.c b/s390x/pv-diags.c
new file mode 100644
index 00000000..110547ad
--- /dev/null
+++ b/s390x/pv-diags.c
@@ -0,0 +1,187 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * PV virtualization interception tests for diagnose instructions.
+ *
+ * Copyright (c) 2021 IBM Corp
+ *
+ * Authors:
+ *  Janosch Frank <frankja@linux.ibm.com>
+ */
+#include <libcflat.h>
+#include <asm/asm-offsets.h>
+#include <asm-generic/barrier.h>
+#include <asm/interrupt.h>
+#include <asm/pgtable.h>
+#include <mmu.h>
+#include <asm/page.h>
+#include <asm/facility.h>
+#include <asm/mem.h>
+#include <asm/sigp.h>
+#include <smp.h>
+#include <alloc_page.h>
+#include <vm.h>
+#include <vmalloc.h>
+#include <sclp.h>
+#include <snippet.h>
+#include <sie.h>
+#include <uv.h>
+#include <asm/uv.h>
+
+static struct vm vm;
+
+static void test_diag_500(void)
+{
+	extern const char SNIPPET_NAME_START(asm, snippet_pv_diag_500)[];
+	extern const char SNIPPET_NAME_END(asm, snippet_pv_diag_500)[];
+	extern const char SNIPPET_HDR_START(asm, snippet_pv_diag_500)[];
+	extern const char SNIPPET_HDR_END(asm, snippet_pv_diag_500)[];
+	int size_hdr = SNIPPET_HDR_LEN(asm, snippet_pv_diag_500);
+	int size_gbin = SNIPPET_LEN(asm, snippet_pv_diag_500);
+
+	report_prefix_push("diag 0x500");
+
+	snippet_pv_init(&vm, SNIPPET_NAME_START(asm, snippet_pv_diag_500),
+			SNIPPET_HDR_START(asm, snippet_pv_diag_500),
+			size_gbin, size_hdr, SNIPPET_OFF_ASM);
+
+	sie(&vm);
+	report(vm.sblk->icptcode == ICPT_PV_INSTR && vm.sblk->ipa == 0x8302 &&
+	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x500,
+	       "intercept values");
+	report(vm.save_area.guest.grs[1] == 1 &&
+	       vm.save_area.guest.grs[2] == 2 &&
+	       vm.save_area.guest.grs[3] == 3 &&
+	       vm.save_area.guest.grs[4] == 4,
+	       "register values");
+	/*
+	 * Check if we can inject a PGM operand which we are always
+	 * allowed to do after a diag500 exit.
+	 */
+	vm.sblk->iictl = IICTL_CODE_OPERAND;
+	sie(&vm);
+	report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 &&
+	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c
+	       && vm.save_area.guest.grs[0] == PGM_INT_CODE_OPERAND,
+	       "operand exception");
+
+	/*
+	 * Check if we can inject a PGM specification which we are always
+	 * allowed to do after a diag500 exit.
+	 */
+	sie(&vm);
+	vm.sblk->iictl = IICTL_CODE_SPECIFICATION;
+	/* Inject PGM, next exit should be 9c */
+	sie(&vm);
+	report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 &&
+	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c
+	       && vm.save_area.guest.grs[0] == PGM_INT_CODE_SPECIFICATION,
+	       "specification exception");
+
+	/* No need for cleanup, just tear down the VM */
+	uv_destroy_guest(&vm);
+
+	report_prefix_pop();
+}
+
+
+static void test_diag_288(void)
+{
+	extern const char SNIPPET_NAME_START(asm, snippet_pv_diag_288)[];
+	extern const char SNIPPET_NAME_END(asm, snippet_pv_diag_288)[];
+	extern const char SNIPPET_HDR_START(asm, snippet_pv_diag_288)[];
+	extern const char SNIPPET_HDR_END(asm, snippet_pv_diag_288)[];
+	int size_hdr = SNIPPET_HDR_LEN(asm, snippet_pv_diag_288);
+	int size_gbin = SNIPPET_LEN(asm, snippet_pv_diag_288);
+
+	report_prefix_push("diag 0x288");
+
+	snippet_pv_init(&vm, SNIPPET_NAME_START(asm, snippet_pv_diag_288),
+			SNIPPET_HDR_START(asm, snippet_pv_diag_288),
+			size_gbin, size_hdr, SNIPPET_OFF_ASM);
+
+	sie(&vm);
+	report(vm.sblk->icptcode == ICPT_PV_INSTR && vm.sblk->ipa == 0x8302 &&
+	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x288,
+	       "intercept values");
+	report(vm.save_area.guest.grs[0] == 1 &&
+	       vm.save_area.guest.grs[1] == 2 &&
+	       vm.save_area.guest.grs[2] == 3,
+	       "register values");
+
+	/*
+	 * Check if we can inject a PGM spec which we are always
+	 * allowed to do after a diag288 exit.
+	 */
+	vm.sblk->iictl = IICTL_CODE_SPECIFICATION;
+	sie(&vm);
+	report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 &&
+	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c
+	       && vm.save_area.guest.grs[0] == PGM_INT_CODE_SPECIFICATION,
+	       "specification exception");
+
+	/* No need for cleanup, just tear down the VM */
+	uv_destroy_guest(&vm);
+
+	report_prefix_pop();
+}
+
+static void test_diag_yield(void)
+{
+	extern const char SNIPPET_NAME_START(asm, snippet_pv_diag_yield)[];
+	extern const char SNIPPET_NAME_END(asm, snippet_pv_diag_yield)[];
+	extern const char SNIPPET_HDR_START(asm, snippet_pv_diag_yield)[];
+	extern const char SNIPPET_HDR_END(asm, snippet_pv_diag_yield)[];
+	int size_hdr = SNIPPET_HDR_LEN(asm, snippet_pv_diag_yield);
+	int size_gbin = SNIPPET_LEN(asm, snippet_pv_diag_yield);
+
+	report_prefix_push("diag yield");
+
+	snippet_pv_init(&vm, SNIPPET_NAME_START(asm, snippet_pv_diag_yield),
+			SNIPPET_HDR_START(asm, snippet_pv_diag_yield),
+			size_gbin, size_hdr, SNIPPET_OFF_ASM);
+
+	/* 0x44 */
+	report_prefix_push("0x44");
+	sie(&vm);
+	report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 &&
+	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x44,
+	       "intercept values");
+	report_prefix_pop();
+
+	/* 0x9c */
+	report_prefix_push("0x9c");
+	sie(&vm);
+	report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 &&
+	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c,
+	       "intercept values");
+	report(vm.save_area.guest.grs[0] == 42, "r1 correct");
+	report_prefix_pop();
+
+	uv_destroy_guest(&vm);
+	report_prefix_pop();
+}
+
+
+int main(void)
+{
+	report_prefix_push("pv-diags");
+	if (!test_facility(158)) {
+		report_skip("UV Call facility unavailable");
+		goto done;
+	}
+	if (!sclp_facilities.has_sief2) {
+		report_skip("SIEF2 facility unavailable");
+		goto done;
+	}
+
+	uv_setup_asces();
+	snippet_setup_guest(&vm, true);
+	test_diag_yield();
+	test_diag_288();
+	test_diag_500();
+	sie_guest_destroy(&vm);
+
+done:
+	report_prefix_pop();
+	return report_summary();
+}
diff --git a/s390x/snippets/asm/snippet-pv-diag-288.S b/s390x/snippets/asm/snippet-pv-diag-288.S
new file mode 100644
index 00000000..e3e63121
--- /dev/null
+++ b/s390x/snippets/asm/snippet-pv-diag-288.S
@@ -0,0 +1,25 @@
+#include <asm/asm-offsets.h>
+.section .text
+
+/* Clean and pre-load registers that are used for diag 288 */
+xgr	%r0, %r0
+xgr	%r1, %r1
+xgr	%r3, %r3
+lghi	%r0, 1
+lghi	%r1, 2
+lghi	%r2, 3
+
+/* Let's jump to the pgm exit label on a PGM */
+larl	%r4, exit_pgm
+stg     %r4, GEN_LC_PGM_NEW_PSW + 8
+
+/* Execute the diag288 */
+diag	%r0, %r2, 0x288
+
+/* Force exit if we don't get a PGM */
+diag	0, 0, 0x44
+
+/* Communicate the PGM code via diag9c(easiest) */
+exit_pgm:
+lh	%r1, GEN_LC_PGM_INT_CODE
+diag	%r1, 0, 0x9c
diff --git a/s390x/snippets/asm/snippet-pv-diag-500.S b/s390x/snippets/asm/snippet-pv-diag-500.S
new file mode 100644
index 00000000..50c06779
--- /dev/null
+++ b/s390x/snippets/asm/snippet-pv-diag-500.S
@@ -0,0 +1,39 @@
+#include <asm/asm-offsets.h>
+.section .text
+
+/* Clean and pre-load registers that are used for diag 500 */
+xgr	%r1, %r1
+xgr	%r2, %r2
+xgr	%r3, %r3
+xgr	%r4, %r4
+lghi	%r1, 1
+lghi	%r2, 2
+lghi	%r3, 3
+lghi	%r4, 4
+
+/* Let's jump to the next label on a PGM */
+xgr	%r5, %r5
+stg	%r5, GEN_LC_PGM_NEW_PSW
+larl	%r5, next
+stg	%r5, GEN_LC_PGM_NEW_PSW + 8
+
+/* Execute the diag500 */
+diag	0, 0, 0x500
+
+/* Should never be executed because of the PGM */
+diag	0, 0, 0x44
+
+/* Execute again to test spec PGM injection*/
+next:
+lh	%r1, GEN_LC_PGM_INT_CODE
+diag	%r1, 0, 0x9c
+larl	%r5, done
+stg	%r5, GEN_LC_PGM_NEW_PSW + 8
+diag	0, 0, 0x500
+
+/* Should never be executed because of the PGM */
+diag	0, 0, 0x44
+
+done:
+lh	%r1, GEN_LC_PGM_INT_CODE
+diag	%r1, 0, 0x9c
diff --git a/s390x/snippets/asm/snippet-pv-diag-yield.S b/s390x/snippets/asm/snippet-pv-diag-yield.S
new file mode 100644
index 00000000..5795cf0f
--- /dev/null
+++ b/s390x/snippets/asm/snippet-pv-diag-yield.S
@@ -0,0 +1,7 @@
+.section .text
+
+xgr	%r0, %r0
+xgr	%r1, %r1
+diag	0,0,0x44
+lghi	%r1, 42
+diag	1,0,0x9c
-- 
2.32.0


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

* Re: [kvm-unit-tests PATCH v2 09/10] s390x: mvpg-sie: Use snippet helpers
  2021-12-07 16:00 ` [kvm-unit-tests PATCH v2 09/10] s390x: mvpg-sie: Use " Janosch Frank
@ 2021-12-08 11:19   ` Claudio Imbrenda
  0 siblings, 0 replies; 16+ messages in thread
From: Claudio Imbrenda @ 2021-12-08 11:19 UTC (permalink / raw)
  To: Janosch Frank; +Cc: kvm, linux-s390, david, thuth, seiden

On Tue,  7 Dec 2021 16:00:04 +0000
Janosch Frank <frankja@linux.ibm.com> wrote:

> Time to use our shiny new snippet helpers.
> 
> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>

Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>

> ---
>  s390x/mvpg-sie.c | 24 ++++++++----------------
>  1 file changed, 8 insertions(+), 16 deletions(-)
> 
> diff --git a/s390x/mvpg-sie.c b/s390x/mvpg-sie.c
> index d526069d..8ae9a52a 100644
> --- a/s390x/mvpg-sie.c
> +++ b/s390x/mvpg-sie.c
> @@ -21,17 +21,12 @@
>  #include <sie.h>
>  #include <snippet.h>
>  
> -static u8 *guest;
>  static struct vm vm;
>  
>  static uint8_t *src;
>  static uint8_t *dst;
>  static uint8_t *cmp;
>  
> -extern const char SNIPPET_NAME_START(c, mvpg_snippet)[];
> -extern const char SNIPPET_NAME_END(c, mvpg_snippet)[];
> -int binary_size;
> -
>  static void test_mvpg_pei(void)
>  {
>  	uint64_t **pei_dst = (uint64_t **)((uintptr_t) vm.sblk + 0xc0);
> @@ -78,9 +73,6 @@ static void test_mvpg_pei(void)
>  
>  static void test_mvpg(void)
>  {
> -	int binary_size = SNIPPET_LEN(c, mvpg_snippet);
> -
> -	memcpy(guest, SNIPPET_NAME_START(c, mvpg_snippet), binary_size);
>  	memset(src, 0x42, PAGE_SIZE);
>  	memset(dst, 0x43, PAGE_SIZE);
>  	sie(&vm);
> @@ -89,20 +81,20 @@ static void test_mvpg(void)
>  
>  static void setup_guest(void)
>  {
> +	extern const char SNIPPET_NAME_START(c, mvpg_snippet)[];
> +	extern const char SNIPPET_NAME_END(c, mvpg_snippet)[];
> +
>  	setup_vm();
>  
> -	/* Allocate 1MB as guest memory */
> -	guest = alloc_pages(8);
> +	snippet_setup_guest(&vm, false);
> +	snippet_init(&vm, SNIPPET_NAME_START(c, mvpg_snippet),
> +		     SNIPPET_LEN(c, mvpg_snippet), SNIPPET_OFF_C);
>  
> -	sie_guest_create(&vm, (uint64_t)guest, HPAGE_SIZE);
> -
> -	vm.sblk->gpsw = snippet_psw;
> -	vm.sblk->ictl = ICTL_OPEREXC | ICTL_PINT;
>  	/* Enable MVPG interpretation as we want to test KVM and not ourselves */
>  	vm.sblk->eca = ECA_MVPGI;
>  
> -	src = guest + PAGE_SIZE * 6;
> -	dst = guest + PAGE_SIZE * 5;
> +	src = (uint8_t *) vm.sblk->mso + PAGE_SIZE * 6;
> +	dst = (uint8_t *) vm.sblk->mso + PAGE_SIZE * 5;
>  	cmp = alloc_page();
>  	memset(cmp, 0, PAGE_SIZE);
>  }


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

* Re: [kvm-unit-tests PATCH v2 08/10] lib: s390x: Introduce snippet helpers
  2021-12-07 16:00 ` [kvm-unit-tests PATCH v2 08/10] lib: s390x: Introduce snippet helpers Janosch Frank
@ 2021-12-08 11:46   ` Claudio Imbrenda
  2021-12-08 13:56     ` Janosch Frank
  0 siblings, 1 reply; 16+ messages in thread
From: Claudio Imbrenda @ 2021-12-08 11:46 UTC (permalink / raw)
  To: Janosch Frank; +Cc: kvm, linux-s390, david, thuth, seiden

On Tue,  7 Dec 2021 16:00:03 +0000
Janosch Frank <frankja@linux.ibm.com> wrote:

> These helpers reduce code duplication for PV snippet tests.
> 
> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>

Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>

although I'd prefer different names for the functions.

snippet_setup_guest sounds like it is actually doing something
snippet-related, whereas it is just preparing an empty guest, the
actual snippet part comes later when you call snippet_init.

Maybe rename snippet_setup_guest to something like
"prepare_guest_for_snippet"? (or maybe something shorter, but you get
what I mean) maybe even "prepare_1m_guest"

> ---
>  lib/s390x/snippet.h | 103 ++++++++++++++++++++++++++++++++++++++++++++
>  lib/s390x/uv.h      |  21 +++++++++
>  2 files changed, 124 insertions(+)
> 
> diff --git a/lib/s390x/snippet.h b/lib/s390x/snippet.h
> index 6b77a8a9..b17b2a4c 100644
> --- a/lib/s390x/snippet.h
> +++ b/lib/s390x/snippet.h
> @@ -9,6 +9,10 @@
>  #ifndef _S390X_SNIPPET_H_
>  #define _S390X_SNIPPET_H_
>  
> +#include <sie.h>
> +#include <uv.h>
> +#include <asm/uv.h>
> +
>  /* This macro cuts down the length of the pointers to snippets */
>  #define SNIPPET_NAME_START(type, file) \
>  	_binary_s390x_snippets_##type##_##file##_gbin_start
> @@ -26,6 +30,12 @@
>  #define SNIPPET_HDR_LEN(type, file) \
>  	((uintptr_t)SNIPPET_HDR_END(type, file) - (uintptr_t)SNIPPET_HDR_START(type, file))
>  
> +#define SNIPPET_PV_TWEAK0	0x42UL
> +#define SNIPPET_PV_TWEAK1	0UL
> +#define SNIPPET_OFF_C		0
> +#define SNIPPET_OFF_ASM		0x4000
> +
> +
>  /*
>   * C snippet instructions start at 0x4000 due to the prefix and the
>   * stack being before that. ASM snippets don't strictly need a stack
> @@ -38,4 +48,97 @@ static const struct psw snippet_psw = {
>  	.mask = PSW_MASK_64,
>  	.addr = SNIPPET_ENTRY_ADDR,
>  };
> +
> +/*
> + * Sets up a snippet guest on top of an existing and initialized SIE
> + * vm struct.
> + * Once this function has finished without errors the guest can be started.
> + *
> + * @vm: VM that this function will populated, has to be initialized already
> + * @gbin: Snippet gbin data pointer
> + * @gbin_len: Length of the gbin data
> + * @off: Offset from guest absolute 0x0 where snippet is copied to
> + */
> +static inline void snippet_init(struct vm *vm, const char *gbin,
> +				uint64_t gbin_len, uint64_t off)
> +{
> +	uint64_t mso = vm->sblk->mso;
> +
> +	/* Copy test image to guest memory */
> +	memcpy((void *)mso + off, gbin, gbin_len);
> +
> +	/* Setup guest PSW */
> +	vm->sblk->gpsw = snippet_psw;
> +
> +	/*
> +	 * We want to exit on PGM exceptions so we don't need
> +	 * exception handlers in the guest.
> +	 */
> +	vm->sblk->ictl = ICTL_OPEREXC | ICTL_PINT;
> +}
> +
> +/*
> + * Sets up a snippet UV/PV guest on top of an existing and initialized
> + * SIE vm struct.
> + * Once this function has finished without errors the guest can be started.
> + *
> + * @vm: VM that this function will populated, has to be initialized already
> + * @gbin: Snippet gbin data pointer
> + * @hdr: Snippet SE header data pointer
> + * @gbin_len: Length of the gbin data
> + * @hdr_len: Length of the hdr data
> + * @off: Offset from guest absolute 0x0 where snippet is copied to
> + */
> +static inline void snippet_pv_init(struct vm *vm, const char *gbin,
> +				   const char *hdr, uint64_t gbin_len,
> +				   uint64_t hdr_len, uint64_t off)
> +{
> +	uint64_t tweak[2] = {SNIPPET_PV_TWEAK0, SNIPPET_PV_TWEAK1};
> +	uint64_t mso = vm->sblk->mso;
> +	int i;
> +
> +	snippet_init(vm, gbin, gbin_len, off);
> +
> +	uv_create_guest(vm);
> +	uv_set_se_hdr(vm->uv.vm_handle, (void *)hdr, hdr_len);
> +
> +	/* Unpack works on guest addresses so we only need off */
> +	uv_unpack(vm, off, gbin_len, tweak[0]);
> +	uv_verify_load(vm);
> +
> +	/*
> +	 * Manually import:
> +	 * - lowcore 0x0 - 0x1000 (asm)
> +	 * - stack 0x3000 (C)
> +	 */
> +	for (i = 0; i < 4; i++) {
> +		uv_import(vm->uv.vm_handle, mso + PAGE_SIZE * i);
> +	}
> +}
> +
> +/* Allocates and sets up a snippet based guest */
> +static inline void snippet_setup_guest(struct vm *vm, bool is_pv)
> +{
> +	u8 *guest;
> +
> +	/* Allocate 1MB as guest memory */
> +	guest = alloc_pages(8);
> +	memset(guest, 0, HPAGE_SIZE);
> +
> +	/* Initialize the vm struct and allocate control blocks */
> +	sie_guest_create(vm, (uint64_t)guest, HPAGE_SIZE);
> +
> +	if (is_pv) {
> +		/* FMT4 needs a ESCA */
> +		sie_guest_sca_create(vm);
> +
> +		/*
> +		 * Initialize UV and setup the address spaces needed
> +		 * to run a PV guest.
> +		 */
> +		uv_init();
> +		uv_setup_asces();
> +	}
> +}
> +
>  #endif
> diff --git a/lib/s390x/uv.h b/lib/s390x/uv.h
> index 6ffe537a..8175d9c6 100644
> --- a/lib/s390x/uv.h
> +++ b/lib/s390x/uv.h
> @@ -3,6 +3,7 @@
>  #define _S390X_UV_H_
>  
>  #include <sie.h>
> +#include <asm/pgtable.h>
>  
>  bool uv_os_is_guest(void);
>  bool uv_os_is_host(void);
> @@ -14,4 +15,24 @@ void uv_destroy_guest(struct vm *vm);
>  int uv_unpack(struct vm *vm, uint64_t addr, uint64_t len, uint64_t
> tweak); void uv_verify_load(struct vm *vm);
>  
> +/*
> + * To run PV guests we need to setup a few things:
> + * - A valid primary ASCE that contains the guest memory and has the
> P bit set.
> + * - A valid home space ASCE for the UV calls that use home space
> addresses.
> + */
> +static inline void uv_setup_asces(void)
> +{
> +	uint64_t asce;
> +
> +	/* We need to have a valid primary ASCE to run guests. */
> +	setup_vm();
> +
> +	/* Set P bit in ASCE as it is required for PV guests */
> +	asce = stctg(1) | ASCE_P;
> +	lctlg(1, asce);
> +
> +	/* Copy ASCE into home space CR */
> +	lctlg(13, asce);
> +}
> +
>  #endif /* UV_H */


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

* Re: [kvm-unit-tests PATCH v2 10/10] s390x: sie: Add PV diag test
  2021-12-07 16:00 ` [kvm-unit-tests PATCH v2 10/10] s390x: sie: Add PV diag test Janosch Frank
@ 2021-12-08 12:55   ` Claudio Imbrenda
  0 siblings, 0 replies; 16+ messages in thread
From: Claudio Imbrenda @ 2021-12-08 12:55 UTC (permalink / raw)
  To: Janosch Frank; +Cc: kvm, linux-s390, david, thuth, seiden

On Tue,  7 Dec 2021 16:00:05 +0000
Janosch Frank <frankja@linux.ibm.com> wrote:

> Let's start testing the format 4 (PV) SIE via the diagnose
> instructions since most of them are pretty simple to handle.
> 
> The tests check for the intercept values like ipa/ipb and icptcode as
> well as the values in the registers and handling of the exception
> injection.
> 
> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>

Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>

this is ok for now; in the future it would be nice to also test
injection of program interrupts that are not allowed.

> ---
>  s390x/Makefile                             |   6 +
>  s390x/pv-diags.c                           | 187 +++++++++++++++++++++
>  s390x/snippets/asm/snippet-pv-diag-288.S   |  25 +++
>  s390x/snippets/asm/snippet-pv-diag-500.S   |  39 +++++
>  s390x/snippets/asm/snippet-pv-diag-yield.S |   7 +
>  5 files changed, 264 insertions(+)
>  create mode 100644 s390x/pv-diags.c
>  create mode 100644 s390x/snippets/asm/snippet-pv-diag-288.S
>  create mode 100644 s390x/snippets/asm/snippet-pv-diag-500.S
>  create mode 100644 s390x/snippets/asm/snippet-pv-diag-yield.S
> 
> diff --git a/s390x/Makefile b/s390x/Makefile
> index 55e6d962..0cb90466 100644
> --- a/s390x/Makefile
> +++ b/s390x/Makefile
> @@ -26,6 +26,8 @@ tests += $(TEST_DIR)/edat.elf
>  tests += $(TEST_DIR)/mvpg-sie.elf
>  tests += $(TEST_DIR)/spec_ex-sie.elf
>  
> +pv-tests += $(TEST_DIR)/pv-diags.elf
> +
>  ifneq ($(HOST_KEY_DOCUMENT),)
>  ifneq ($(GEN_SE_HEADER),)
>  tests += $(pv-tests)
> @@ -98,6 +100,10 @@ snippet_lib = $(snippet_asmlib) lib/auxinfo.o
>  $(TEST_DIR)/mvpg-sie.elf: snippets = $(SNIPPET_DIR)/c/mvpg-snippet.gbin
>  $(TEST_DIR)/spec_ex-sie.elf: snippets = $(SNIPPET_DIR)/c/spec_ex.gbin
>  
> +$(TEST_DIR)/pv-diags.elf: pv-snippets += $(SNIPPET_DIR)/asm/snippet-pv-diag-yield.gbin
> +$(TEST_DIR)/pv-diags.elf: pv-snippets += $(SNIPPET_DIR)/asm/snippet-pv-diag-288.gbin
> +$(TEST_DIR)/pv-diags.elf: pv-snippets += $(SNIPPET_DIR)/asm/snippet-pv-diag-500.gbin
> +
>  ifneq ($(GEN_SE_HEADER),)
>  snippets += $(pv-snippets)
>  tests += $(pv-tests)
> diff --git a/s390x/pv-diags.c b/s390x/pv-diags.c
> new file mode 100644
> index 00000000..110547ad
> --- /dev/null
> +++ b/s390x/pv-diags.c
> @@ -0,0 +1,187 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * PV virtualization interception tests for diagnose instructions.
> + *
> + * Copyright (c) 2021 IBM Corp
> + *
> + * Authors:
> + *  Janosch Frank <frankja@linux.ibm.com>
> + */
> +#include <libcflat.h>
> +#include <asm/asm-offsets.h>
> +#include <asm-generic/barrier.h>
> +#include <asm/interrupt.h>
> +#include <asm/pgtable.h>
> +#include <mmu.h>
> +#include <asm/page.h>
> +#include <asm/facility.h>
> +#include <asm/mem.h>
> +#include <asm/sigp.h>
> +#include <smp.h>
> +#include <alloc_page.h>
> +#include <vm.h>
> +#include <vmalloc.h>
> +#include <sclp.h>
> +#include <snippet.h>
> +#include <sie.h>
> +#include <uv.h>
> +#include <asm/uv.h>
> +
> +static struct vm vm;
> +
> +static void test_diag_500(void)
> +{
> +	extern const char SNIPPET_NAME_START(asm, snippet_pv_diag_500)[];
> +	extern const char SNIPPET_NAME_END(asm, snippet_pv_diag_500)[];
> +	extern const char SNIPPET_HDR_START(asm, snippet_pv_diag_500)[];
> +	extern const char SNIPPET_HDR_END(asm, snippet_pv_diag_500)[];
> +	int size_hdr = SNIPPET_HDR_LEN(asm, snippet_pv_diag_500);
> +	int size_gbin = SNIPPET_LEN(asm, snippet_pv_diag_500);
> +
> +	report_prefix_push("diag 0x500");
> +
> +	snippet_pv_init(&vm, SNIPPET_NAME_START(asm, snippet_pv_diag_500),
> +			SNIPPET_HDR_START(asm, snippet_pv_diag_500),
> +			size_gbin, size_hdr, SNIPPET_OFF_ASM);
> +
> +	sie(&vm);
> +	report(vm.sblk->icptcode == ICPT_PV_INSTR && vm.sblk->ipa == 0x8302 &&
> +	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x500,
> +	       "intercept values");
> +	report(vm.save_area.guest.grs[1] == 1 &&
> +	       vm.save_area.guest.grs[2] == 2 &&
> +	       vm.save_area.guest.grs[3] == 3 &&
> +	       vm.save_area.guest.grs[4] == 4,
> +	       "register values");
> +	/*
> +	 * Check if we can inject a PGM operand which we are always
> +	 * allowed to do after a diag500 exit.
> +	 */
> +	vm.sblk->iictl = IICTL_CODE_OPERAND;
> +	sie(&vm);
> +	report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 &&
> +	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c
> +	       && vm.save_area.guest.grs[0] == PGM_INT_CODE_OPERAND,
> +	       "operand exception");
> +
> +	/*
> +	 * Check if we can inject a PGM specification which we are always
> +	 * allowed to do after a diag500 exit.
> +	 */
> +	sie(&vm);
> +	vm.sblk->iictl = IICTL_CODE_SPECIFICATION;
> +	/* Inject PGM, next exit should be 9c */
> +	sie(&vm);
> +	report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 &&
> +	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c
> +	       && vm.save_area.guest.grs[0] == PGM_INT_CODE_SPECIFICATION,
> +	       "specification exception");
> +
> +	/* No need for cleanup, just tear down the VM */
> +	uv_destroy_guest(&vm);
> +
> +	report_prefix_pop();
> +}
> +
> +
> +static void test_diag_288(void)
> +{
> +	extern const char SNIPPET_NAME_START(asm, snippet_pv_diag_288)[];
> +	extern const char SNIPPET_NAME_END(asm, snippet_pv_diag_288)[];
> +	extern const char SNIPPET_HDR_START(asm, snippet_pv_diag_288)[];
> +	extern const char SNIPPET_HDR_END(asm, snippet_pv_diag_288)[];
> +	int size_hdr = SNIPPET_HDR_LEN(asm, snippet_pv_diag_288);
> +	int size_gbin = SNIPPET_LEN(asm, snippet_pv_diag_288);
> +
> +	report_prefix_push("diag 0x288");
> +
> +	snippet_pv_init(&vm, SNIPPET_NAME_START(asm, snippet_pv_diag_288),
> +			SNIPPET_HDR_START(asm, snippet_pv_diag_288),
> +			size_gbin, size_hdr, SNIPPET_OFF_ASM);
> +
> +	sie(&vm);
> +	report(vm.sblk->icptcode == ICPT_PV_INSTR && vm.sblk->ipa == 0x8302 &&
> +	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x288,
> +	       "intercept values");
> +	report(vm.save_area.guest.grs[0] == 1 &&
> +	       vm.save_area.guest.grs[1] == 2 &&
> +	       vm.save_area.guest.grs[2] == 3,
> +	       "register values");
> +
> +	/*
> +	 * Check if we can inject a PGM spec which we are always
> +	 * allowed to do after a diag288 exit.
> +	 */
> +	vm.sblk->iictl = IICTL_CODE_SPECIFICATION;
> +	sie(&vm);
> +	report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 &&
> +	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c
> +	       && vm.save_area.guest.grs[0] == PGM_INT_CODE_SPECIFICATION,
> +	       "specification exception");
> +
> +	/* No need for cleanup, just tear down the VM */
> +	uv_destroy_guest(&vm);
> +
> +	report_prefix_pop();
> +}
> +
> +static void test_diag_yield(void)
> +{
> +	extern const char SNIPPET_NAME_START(asm, snippet_pv_diag_yield)[];
> +	extern const char SNIPPET_NAME_END(asm, snippet_pv_diag_yield)[];
> +	extern const char SNIPPET_HDR_START(asm, snippet_pv_diag_yield)[];
> +	extern const char SNIPPET_HDR_END(asm, snippet_pv_diag_yield)[];
> +	int size_hdr = SNIPPET_HDR_LEN(asm, snippet_pv_diag_yield);
> +	int size_gbin = SNIPPET_LEN(asm, snippet_pv_diag_yield);
> +
> +	report_prefix_push("diag yield");
> +
> +	snippet_pv_init(&vm, SNIPPET_NAME_START(asm, snippet_pv_diag_yield),
> +			SNIPPET_HDR_START(asm, snippet_pv_diag_yield),
> +			size_gbin, size_hdr, SNIPPET_OFF_ASM);
> +
> +	/* 0x44 */
> +	report_prefix_push("0x44");
> +	sie(&vm);
> +	report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 &&
> +	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x44,
> +	       "intercept values");
> +	report_prefix_pop();
> +
> +	/* 0x9c */
> +	report_prefix_push("0x9c");
> +	sie(&vm);
> +	report(vm.sblk->icptcode == ICPT_PV_NOTIFY && vm.sblk->ipa == 0x8302 &&
> +	       vm.sblk->ipb == 0x50000000 && vm.save_area.guest.grs[5] == 0x9c,
> +	       "intercept values");
> +	report(vm.save_area.guest.grs[0] == 42, "r1 correct");
> +	report_prefix_pop();
> +
> +	uv_destroy_guest(&vm);
> +	report_prefix_pop();
> +}
> +
> +
> +int main(void)
> +{
> +	report_prefix_push("pv-diags");
> +	if (!test_facility(158)) {
> +		report_skip("UV Call facility unavailable");
> +		goto done;
> +	}
> +	if (!sclp_facilities.has_sief2) {
> +		report_skip("SIEF2 facility unavailable");
> +		goto done;
> +	}
> +
> +	uv_setup_asces();
> +	snippet_setup_guest(&vm, true);
> +	test_diag_yield();
> +	test_diag_288();
> +	test_diag_500();
> +	sie_guest_destroy(&vm);
> +
> +done:
> +	report_prefix_pop();
> +	return report_summary();
> +}
> diff --git a/s390x/snippets/asm/snippet-pv-diag-288.S b/s390x/snippets/asm/snippet-pv-diag-288.S
> new file mode 100644
> index 00000000..e3e63121
> --- /dev/null
> +++ b/s390x/snippets/asm/snippet-pv-diag-288.S
> @@ -0,0 +1,25 @@
> +#include <asm/asm-offsets.h>
> +.section .text
> +
> +/* Clean and pre-load registers that are used for diag 288 */
> +xgr	%r0, %r0
> +xgr	%r1, %r1
> +xgr	%r3, %r3
> +lghi	%r0, 1
> +lghi	%r1, 2
> +lghi	%r2, 3
> +
> +/* Let's jump to the pgm exit label on a PGM */
> +larl	%r4, exit_pgm
> +stg     %r4, GEN_LC_PGM_NEW_PSW + 8
> +
> +/* Execute the diag288 */
> +diag	%r0, %r2, 0x288
> +
> +/* Force exit if we don't get a PGM */
> +diag	0, 0, 0x44
> +
> +/* Communicate the PGM code via diag9c(easiest) */
> +exit_pgm:
> +lh	%r1, GEN_LC_PGM_INT_CODE
> +diag	%r1, 0, 0x9c
> diff --git a/s390x/snippets/asm/snippet-pv-diag-500.S b/s390x/snippets/asm/snippet-pv-diag-500.S
> new file mode 100644
> index 00000000..50c06779
> --- /dev/null
> +++ b/s390x/snippets/asm/snippet-pv-diag-500.S
> @@ -0,0 +1,39 @@
> +#include <asm/asm-offsets.h>
> +.section .text
> +
> +/* Clean and pre-load registers that are used for diag 500 */
> +xgr	%r1, %r1
> +xgr	%r2, %r2
> +xgr	%r3, %r3
> +xgr	%r4, %r4
> +lghi	%r1, 1
> +lghi	%r2, 2
> +lghi	%r3, 3
> +lghi	%r4, 4
> +
> +/* Let's jump to the next label on a PGM */
> +xgr	%r5, %r5
> +stg	%r5, GEN_LC_PGM_NEW_PSW
> +larl	%r5, next
> +stg	%r5, GEN_LC_PGM_NEW_PSW + 8
> +
> +/* Execute the diag500 */
> +diag	0, 0, 0x500
> +
> +/* Should never be executed because of the PGM */
> +diag	0, 0, 0x44
> +
> +/* Execute again to test spec PGM injection*/
> +next:
> +lh	%r1, GEN_LC_PGM_INT_CODE
> +diag	%r1, 0, 0x9c
> +larl	%r5, done
> +stg	%r5, GEN_LC_PGM_NEW_PSW + 8
> +diag	0, 0, 0x500
> +
> +/* Should never be executed because of the PGM */
> +diag	0, 0, 0x44
> +
> +done:
> +lh	%r1, GEN_LC_PGM_INT_CODE
> +diag	%r1, 0, 0x9c
> diff --git a/s390x/snippets/asm/snippet-pv-diag-yield.S b/s390x/snippets/asm/snippet-pv-diag-yield.S
> new file mode 100644
> index 00000000..5795cf0f
> --- /dev/null
> +++ b/s390x/snippets/asm/snippet-pv-diag-yield.S
> @@ -0,0 +1,7 @@
> +.section .text
> +
> +xgr	%r0, %r0
> +xgr	%r1, %r1
> +diag	0,0,0x44
> +lghi	%r1, 42
> +diag	1,0,0x9c


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

* Re: [kvm-unit-tests PATCH v2 07/10] s390x: snippets: Add PV support
  2021-12-07 16:00 ` [kvm-unit-tests PATCH v2 07/10] s390x: snippets: Add PV support Janosch Frank
@ 2021-12-08 12:57   ` Claudio Imbrenda
  0 siblings, 0 replies; 16+ messages in thread
From: Claudio Imbrenda @ 2021-12-08 12:57 UTC (permalink / raw)
  To: Janosch Frank; +Cc: kvm, linux-s390, david, thuth, seiden

On Tue,  7 Dec 2021 16:00:02 +0000
Janosch Frank <frankja@linux.ibm.com> wrote:

> To create a pv-snippet we need to generate an se-header. This can be
> done using a currently not released tool. This tool creates a
> se-header similar to `genprotimg` with the difference that the image
> itself will not be encrypted.
> 
> The image for which we want to create a header must be a binary and
> padded to 4k. Therefore, we convert the compiled snippet to a binary,
> padd it to 4k, generate the header and convert it back to s390-64bit
> elf.
> 
> The name of the tool can be specified using the config argument
> `--gen-se-header=`. The pv-snipptes will only be built when this
> option is specified. Furthermore, the Hostkey-Document must be
> specified. If not the build will be skipped.
> 
> The host-snippet relation can be specified using the `pv-snippets`
> variable in s390x/Makefile, similar to the non-pv-snippets in
> 2f6fdb4a (s390x: snippets: Add snippet compilation, 2021-06-22)
> 
> Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>

Acked-by: Claudio Imbrenda <imbrenda@linux.ibm.com>

it looks ok and I guess it works because otherwise the new tests would
not build.

> ---
>  .gitignore          |  2 ++
>  configure           |  8 ++++++
>  lib/s390x/snippet.h |  7 +++++
>  s390x/Makefile      | 67 +++++++++++++++++++++++++++++++++++++--------
>  4 files changed, 73 insertions(+), 11 deletions(-)
> 
> diff --git a/.gitignore b/.gitignore
> index 3d5be622..28a197bf 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -25,3 +25,5 @@ cscope.*
>  /api/dirty-log-perf
>  /s390x/*.bin
>  /s390x/snippets/*/*.gbin
> +/s390x/snippets/*/*.hdr
> +/s390x/snippets/*/*.*obj
> \ No newline at end of file
> diff --git a/configure b/configure
> index 1d4d855e..9210912f 100755
> --- a/configure
> +++ b/configure
> @@ -26,6 +26,7 @@ target=
>  errata_force=0
>  erratatxt="$srcdir/errata.txt"
>  host_key_document=
> +gen_se_header=
>  page_size=
>  earlycon=
>  
> @@ -54,6 +55,9 @@ usage() {
>  	    --host-key-document=HOST_KEY_DOCUMENT
>  	                           Specify the machine-specific host-key document for creating
>  	                           a PVM image with 'genprotimg' (s390x only)
> +	    --gen-se-header=GEN_SE_HEADER
> +	                           Provide an executable to generate a PV header
> +				   requires --host-key-document. (s390x-snippets only)
>  	    --page-size=PAGE_SIZE
>  	                           Specify the page size (translation granule) (4k, 16k or
>  	                           64k, default is 64k, arm64 only)
> @@ -127,6 +131,9 @@ while [[ "$1" = -* ]]; do
>  	--host-key-document)
>  	    host_key_document="$arg"
>  	    ;;
> +	--gen-se-header)
> +	    gen_se_header="$arg"
> +	    ;;
>  	--page-size)
>  	    page_size="$arg"
>  	    ;;
> @@ -341,6 +348,7 @@ U32_LONG_FMT=$u32_long
>  WA_DIVIDE=$wa_divide
>  GENPROTIMG=${GENPROTIMG-genprotimg}
>  HOST_KEY_DOCUMENT=$host_key_document
> +GEN_SE_HEADER=$gen_se_header
>  EOF
>  if [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then
>      echo "TARGET=$target" >> config.mak
> diff --git a/lib/s390x/snippet.h b/lib/s390x/snippet.h
> index 8e4765f8..6b77a8a9 100644
> --- a/lib/s390x/snippet.h
> +++ b/lib/s390x/snippet.h
> @@ -14,10 +14,17 @@
>  	_binary_s390x_snippets_##type##_##file##_gbin_start
>  #define SNIPPET_NAME_END(type, file) \
>  	_binary_s390x_snippets_##type##_##file##_gbin_end
> +#define SNIPPET_HDR_START(type, file) \
> +	_binary_s390x_snippets_##type##_##file##_hdr_start
> +#define SNIPPET_HDR_END(type, file) \
> +	_binary_s390x_snippets_##type##_##file##_hdr_end
> +
>  
>  /* Returns the length of the snippet */
>  #define SNIPPET_LEN(type, file) \
>  	((uintptr_t)SNIPPET_NAME_END(type, file) - (uintptr_t)SNIPPET_NAME_START(type, file))
> +#define SNIPPET_HDR_LEN(type, file) \
> +	((uintptr_t)SNIPPET_HDR_END(type, file) - (uintptr_t)SNIPPET_HDR_START(type, file))
>  
>  /*
>   * C snippet instructions start at 0x4000 due to the prefix and the
> diff --git a/s390x/Makefile b/s390x/Makefile
> index f95f2e61..55e6d962 100644
> --- a/s390x/Makefile
> +++ b/s390x/Makefile
> @@ -26,12 +26,20 @@ tests += $(TEST_DIR)/edat.elf
>  tests += $(TEST_DIR)/mvpg-sie.elf
>  tests += $(TEST_DIR)/spec_ex-sie.elf
>  
> +ifneq ($(HOST_KEY_DOCUMENT),)
> +ifneq ($(GEN_SE_HEADER),)
> +tests += $(pv-tests)
> +endif
> +endif
> +
>  tests_binary = $(patsubst %.elf,%.bin,$(tests))
>  ifneq ($(HOST_KEY_DOCUMENT),)
>  tests_pv_binary = $(patsubst %.bin,%.pv.bin,$(tests_binary))
>  else
>  tests_pv_binary =
> +GEN_SE_HEADER =
>  endif
> +snippets-obj = $(patsubst %.gbin,%.gobj,$(snippets))
>  
>  all: directories test_cases test_cases_binary test_cases_pv
>  
> @@ -82,26 +90,59 @@ asmlib = $(TEST_DIR)/cstart64.o $(TEST_DIR)/cpu.o
>  FLATLIBS = $(libcflat)
>  
>  SNIPPET_DIR = $(TEST_DIR)/snippets
> -snippet_asmlib = $(SNIPPET_DIR)/c/cstart.o lib/auxinfo.o
> +snippet_asmlib = $(SNIPPET_DIR)/c/cstart.o
> +snippet_lib = $(snippet_asmlib) lib/auxinfo.o
>  
>  # perquisites (=guests) for the snippet hosts.
>  # $(TEST_DIR)/<snippet-host>.elf: snippets = $(SNIPPET_DIR)/<c/asm>/<snippet>.gbin
>  $(TEST_DIR)/mvpg-sie.elf: snippets = $(SNIPPET_DIR)/c/mvpg-snippet.gbin
>  $(TEST_DIR)/spec_ex-sie.elf: snippets = $(SNIPPET_DIR)/c/spec_ex.gbin
>  
> -$(SNIPPET_DIR)/asm/%.gbin: $(SNIPPET_DIR)/asm/%.o $(FLATLIBS)
> -	$(OBJCOPY) -O binary $(patsubst %.gbin,%.o,$@) $@
> -	$(OBJCOPY) -I binary -O elf64-s390 -B "s390:64-bit" $@ $@
> +ifneq ($(GEN_SE_HEADER),)
> +snippets += $(pv-snippets)
> +tests += $(pv-tests)
> +snippet-hdr-obj = $(patsubst %.gbin,%.hdr.obj,$(pv-snippets))
> +else
> +snippet-hdr-obj =
> +endif
> +
> +# the asm/c snippets %.o have additional generated files as dependencies
> +$(SNIPPET_DIR)/asm/%.o: $(SNIPPET_DIR)/asm/%.S $(asm-offsets)
> +	$(CC) $(CFLAGS) -c -nostdlib -o $@ $<
> +
> +$(SNIPPET_DIR)/c/%.o: $(SNIPPET_DIR)/c/%.c $(asm-offsets)
> +	$(CC) $(CFLAGS) -c -nostdlib -o $@ $<
> +
> +$(SNIPPET_DIR)/asm/%.gbin: $(SNIPPET_DIR)/asm/%.o
> +	$(OBJCOPY) -O binary -j ".rodata" -j ".text" -j ".data" -j ".bss" --set-section-flags .bss=alloc,load,contents $(patsubst %.gbin,%.o,$@) $@
> +	truncate -s '%4096' $@
> +
> +$(SNIPPET_DIR)/c/%.gbin: $(SNIPPET_DIR)/c/%.o $(snippet_lib) $(FLATLIBS)
> +	$(CC) $(LDFLAGS) -o $@ -T $(SRCDIR)/s390x/snippets/c/flat.lds $(patsubst %.gbin,%.o,$@) $(snippet_lib) $(FLATLIBS)
> +	$(OBJCOPY) -O binary -j ".rodata" -j ".lowcore" -j ".text" -j ".data" -j ".bss" --set-section-flags .bss=alloc,load,contents $@ $@
> +	truncate -s '%4096' $@
> +
> +$(SNIPPET_DIR)/asm/%.hdr: $(SNIPPET_DIR)/asm/%.gbin $(HOST_KEY_DOCUMENT)
> +	$(GEN_SE_HEADER) -k $(HOST_KEY_DOCUMENT) -c $<,0x4000,0x00000000000000420000000000000000 --psw-addr 0x4000 -o $@
> +
> +$(SNIPPET_DIR)/c/%.hdr: $(SNIPPET_DIR)/c/%.gbin $(HOST_KEY_DOCUMENT)
> +	$(GEN_SE_HEADER) -k $(HOST_KEY_DOCUMENT) -c $<,0x0,0x00000000000000420000000000000000 --psw-addr 0x4000 -o $@
> +
> +.SECONDARY:
> +%.gobj: %.gbin
> +	$(OBJCOPY) -I binary -O elf64-s390 -B "s390:64-bit" $< $@
> +
> +.SECONDARY:
> +%.hdr.obj: %.hdr
> +	$(OBJCOPY) -I binary -O elf64-s390 -B "s390:64-bit" $< $@
>  
> -$(SNIPPET_DIR)/c/%.gbin: $(SNIPPET_DIR)/c/%.o $(snippet_asmlib) $(FLATLIBS)
> -	$(CC) $(LDFLAGS) -o $@ -T $(SRCDIR)/s390x/snippets/c/flat.lds $(patsubst %.gbin,%.o,$@) $(snippet_asmlib) $(FLATLIBS)
> -	$(OBJCOPY) -O binary $@ $@
> -	$(OBJCOPY) -I binary -O elf64-s390 -B "s390:64-bit" $@ $@
>  
>  .SECONDEXPANSION:
> -%.elf: $$(snippets) %.o $(FLATLIBS) $(SRCDIR)/s390x/flat.lds $(asmlib)
> +%.elf: $(FLATLIBS) $(asmlib) $(SRCDIR)/s390x/flat.lds $$(snippets-obj) $$(snippet-hdr-obj) %.o
>  	$(CC) $(CFLAGS) -c -o $(@:.elf=.aux.o) $(SRCDIR)/lib/auxinfo.c -DPROGNAME=\"$@\"
> -	$(CC) $(LDFLAGS) -o $@ -T $(SRCDIR)/s390x/flat.lds $(filter %.o, $^) $(FLATLIBS) $(snippets) $(@:.elf=.aux.o)
> +	@$(CC) $(LDFLAGS) -o $@ -T $(SRCDIR)/s390x/flat.lds \
> +		$(filter %.o, $^) $(FLATLIBS) $(snippets-obj) $(snippet-hdr-obj) $(@:.elf=.aux.o) || \
> +		{ echo "Failure probably caused by missing definition of gen-se-header executable"; exit 1; }
>  	$(RM) $(@:.elf=.aux.o)
>  	@chmod a-x $@
>  
> @@ -114,8 +155,12 @@ $(SNIPPET_DIR)/c/%.gbin: $(SNIPPET_DIR)/c/%.o $(snippet_asmlib) $(FLATLIBS)
>  %.pv.bin: %.bin $(HOST_KEY_DOCUMENT)
>  	$(GENPROTIMG) --host-key-document $(HOST_KEY_DOCUMENT) --no-verify --image $< -o $@
>  
> +$(snippet_asmlib): $$(patsubst %.o,%.S,$$@) $(asm-offsets)
> +	$(CC) $(CFLAGS) -c -nostdlib -o $@ $<
> +
> +
>  arch_clean: asm_offsets_clean
> -	$(RM) $(TEST_DIR)/*.{o,elf,bin} $(TEST_DIR)/.*.d $(SNIPPET_DIR)/c/*.{o,gbin} $(SNIPPET_DIR)/c/.*.d lib/s390x/.*.d
> +	$(RM) $(TEST_DIR)/*.{o,elf,bin} $(SNIPPET_DIR)/*/*.{o,elf,*bin,*obj,hdr} $(SNIPPET_DIR)/asm/.*.d $(TEST_DIR)/.*.d lib/s390x/.*.d
>  
>  generated-files = $(asm-offsets)
>  $(tests:.elf=.o) $(asmlib) $(cflatobjs): $(generated-files)


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

* Re: [kvm-unit-tests PATCH v2 08/10] lib: s390x: Introduce snippet helpers
  2021-12-08 11:46   ` Claudio Imbrenda
@ 2021-12-08 13:56     ` Janosch Frank
  0 siblings, 0 replies; 16+ messages in thread
From: Janosch Frank @ 2021-12-08 13:56 UTC (permalink / raw)
  To: Claudio Imbrenda; +Cc: kvm, linux-s390, david, thuth, seiden

On 12/8/21 12:46, Claudio Imbrenda wrote:
> On Tue,  7 Dec 2021 16:00:03 +0000
> Janosch Frank <frankja@linux.ibm.com> wrote:
> 
>> These helpers reduce code duplication for PV snippet tests.
>>
>> Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
> 
> Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
> 
> although I'd prefer different names for the functions.
> 
> snippet_setup_guest sounds like it is actually doing something
> snippet-related, whereas it is just preparing an empty guest, the
> actual snippet part comes later when you call snippet_init.
> 
> Maybe rename snippet_setup_guest to something like
> "prepare_guest_for_snippet"? (or maybe something shorter, but you get
> what I mean) maybe even "prepare_1m_guest"

snippet_setup_guest_shell() ?

> 
>> ---
>>   lib/s390x/snippet.h | 103 ++++++++++++++++++++++++++++++++++++++++++++
>>   lib/s390x/uv.h      |  21 +++++++++
>>   2 files changed, 124 insertions(+)
>>
>> diff --git a/lib/s390x/snippet.h b/lib/s390x/snippet.h
>> index 6b77a8a9..b17b2a4c 100644
>> --- a/lib/s390x/snippet.h
>> +++ b/lib/s390x/snippet.h
>> @@ -9,6 +9,10 @@
>>   #ifndef _S390X_SNIPPET_H_
>>   #define _S390X_SNIPPET_H_
>>   
>> +#include <sie.h>
>> +#include <uv.h>
>> +#include <asm/uv.h>
>> +
>>   /* This macro cuts down the length of the pointers to snippets */
>>   #define SNIPPET_NAME_START(type, file) \
>>   	_binary_s390x_snippets_##type##_##file##_gbin_start
>> @@ -26,6 +30,12 @@
>>   #define SNIPPET_HDR_LEN(type, file) \
>>   	((uintptr_t)SNIPPET_HDR_END(type, file) - (uintptr_t)SNIPPET_HDR_START(type, file))
>>   
>> +#define SNIPPET_PV_TWEAK0	0x42UL
>> +#define SNIPPET_PV_TWEAK1	0UL
>> +#define SNIPPET_OFF_C		0
>> +#define SNIPPET_OFF_ASM		0x4000
>> +
>> +
>>   /*
>>    * C snippet instructions start at 0x4000 due to the prefix and the
>>    * stack being before that. ASM snippets don't strictly need a stack
>> @@ -38,4 +48,97 @@ static const struct psw snippet_psw = {
>>   	.mask = PSW_MASK_64,
>>   	.addr = SNIPPET_ENTRY_ADDR,
>>   };
>> +
>> +/*
>> + * Sets up a snippet guest on top of an existing and initialized SIE
>> + * vm struct.
>> + * Once this function has finished without errors the guest can be started.
>> + *
>> + * @vm: VM that this function will populated, has to be initialized already
>> + * @gbin: Snippet gbin data pointer
>> + * @gbin_len: Length of the gbin data
>> + * @off: Offset from guest absolute 0x0 where snippet is copied to
>> + */
>> +static inline void snippet_init(struct vm *vm, const char *gbin,
>> +				uint64_t gbin_len, uint64_t off)
>> +{
>> +	uint64_t mso = vm->sblk->mso;
>> +
>> +	/* Copy test image to guest memory */
>> +	memcpy((void *)mso + off, gbin, gbin_len);
>> +
>> +	/* Setup guest PSW */
>> +	vm->sblk->gpsw = snippet_psw;
>> +
>> +	/*
>> +	 * We want to exit on PGM exceptions so we don't need
>> +	 * exception handlers in the guest.
>> +	 */
>> +	vm->sblk->ictl = ICTL_OPEREXC | ICTL_PINT;
>> +}
>> +
>> +/*
>> + * Sets up a snippet UV/PV guest on top of an existing and initialized
>> + * SIE vm struct.
>> + * Once this function has finished without errors the guest can be started.
>> + *
>> + * @vm: VM that this function will populated, has to be initialized already
>> + * @gbin: Snippet gbin data pointer
>> + * @hdr: Snippet SE header data pointer
>> + * @gbin_len: Length of the gbin data
>> + * @hdr_len: Length of the hdr data
>> + * @off: Offset from guest absolute 0x0 where snippet is copied to
>> + */
>> +static inline void snippet_pv_init(struct vm *vm, const char *gbin,
>> +				   const char *hdr, uint64_t gbin_len,
>> +				   uint64_t hdr_len, uint64_t off)
>> +{
>> +	uint64_t tweak[2] = {SNIPPET_PV_TWEAK0, SNIPPET_PV_TWEAK1};
>> +	uint64_t mso = vm->sblk->mso;
>> +	int i;
>> +
>> +	snippet_init(vm, gbin, gbin_len, off);
>> +
>> +	uv_create_guest(vm);
>> +	uv_set_se_hdr(vm->uv.vm_handle, (void *)hdr, hdr_len);
>> +
>> +	/* Unpack works on guest addresses so we only need off */
>> +	uv_unpack(vm, off, gbin_len, tweak[0]);
>> +	uv_verify_load(vm);
>> +
>> +	/*
>> +	 * Manually import:
>> +	 * - lowcore 0x0 - 0x1000 (asm)
>> +	 * - stack 0x3000 (C)
>> +	 */
>> +	for (i = 0; i < 4; i++) {
>> +		uv_import(vm->uv.vm_handle, mso + PAGE_SIZE * i);
>> +	}
>> +}
>> +
>> +/* Allocates and sets up a snippet based guest */
>> +static inline void snippet_setup_guest(struct vm *vm, bool is_pv)
>> +{
>> +	u8 *guest;
>> +
>> +	/* Allocate 1MB as guest memory */
>> +	guest = alloc_pages(8);
>> +	memset(guest, 0, HPAGE_SIZE);
>> +
>> +	/* Initialize the vm struct and allocate control blocks */
>> +	sie_guest_create(vm, (uint64_t)guest, HPAGE_SIZE);
>> +
>> +	if (is_pv) {
>> +		/* FMT4 needs a ESCA */
>> +		sie_guest_sca_create(vm);
>> +
>> +		/*
>> +		 * Initialize UV and setup the address spaces needed
>> +		 * to run a PV guest.
>> +		 */
>> +		uv_init();
>> +		uv_setup_asces();
>> +	}
>> +}
>> +
>>   #endif
>> diff --git a/lib/s390x/uv.h b/lib/s390x/uv.h
>> index 6ffe537a..8175d9c6 100644
>> --- a/lib/s390x/uv.h
>> +++ b/lib/s390x/uv.h
>> @@ -3,6 +3,7 @@
>>   #define _S390X_UV_H_
>>   
>>   #include <sie.h>
>> +#include <asm/pgtable.h>
>>   
>>   bool uv_os_is_guest(void);
>>   bool uv_os_is_host(void);
>> @@ -14,4 +15,24 @@ void uv_destroy_guest(struct vm *vm);
>>   int uv_unpack(struct vm *vm, uint64_t addr, uint64_t len, uint64_t
>> tweak); void uv_verify_load(struct vm *vm);
>>   
>> +/*
>> + * To run PV guests we need to setup a few things:
>> + * - A valid primary ASCE that contains the guest memory and has the
>> P bit set.
>> + * - A valid home space ASCE for the UV calls that use home space
>> addresses.
>> + */
>> +static inline void uv_setup_asces(void)
>> +{
>> +	uint64_t asce;
>> +
>> +	/* We need to have a valid primary ASCE to run guests. */
>> +	setup_vm();
>> +
>> +	/* Set P bit in ASCE as it is required for PV guests */
>> +	asce = stctg(1) | ASCE_P;
>> +	lctlg(1, asce);
>> +
>> +	/* Copy ASCE into home space CR */
>> +	lctlg(13, asce);
>> +}
>> +
>>   #endif /* UV_H */
> 


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

end of thread, other threads:[~2021-12-08 13:56 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-12-07 15:59 [kvm-unit-tests PATCH v2 00/10] s390x: sie: Add PV snippet support Janosch Frank
2021-12-07 15:59 ` [kvm-unit-tests PATCH v2 01/10] lib: s390x: sie: Add sca allocation and freeing Janosch Frank
2021-12-07 15:59 ` [kvm-unit-tests PATCH v2 02/10] s390x: sie: Add PV fields to SIE control block Janosch Frank
2021-12-07 15:59 ` [kvm-unit-tests PATCH v2 03/10] s390x: sie: Add UV information into VM struct Janosch Frank
2021-12-07 15:59 ` [kvm-unit-tests PATCH v2 04/10] s390x: uv: Add more UV call functions Janosch Frank
2021-12-07 16:00 ` [kvm-unit-tests PATCH v2 05/10] s390x: lib: Extend UV library with PV guest management Janosch Frank
2021-12-07 16:00 ` [kvm-unit-tests PATCH v2 06/10] lib: s390: sie: Add PV guest register handling Janosch Frank
2021-12-07 16:00 ` [kvm-unit-tests PATCH v2 07/10] s390x: snippets: Add PV support Janosch Frank
2021-12-08 12:57   ` Claudio Imbrenda
2021-12-07 16:00 ` [kvm-unit-tests PATCH v2 08/10] lib: s390x: Introduce snippet helpers Janosch Frank
2021-12-08 11:46   ` Claudio Imbrenda
2021-12-08 13:56     ` Janosch Frank
2021-12-07 16:00 ` [kvm-unit-tests PATCH v2 09/10] s390x: mvpg-sie: Use " Janosch Frank
2021-12-08 11:19   ` Claudio Imbrenda
2021-12-07 16:00 ` [kvm-unit-tests PATCH v2 10/10] s390x: sie: Add PV diag test Janosch Frank
2021-12-08 12:55   ` Claudio Imbrenda

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).