linux-s390.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH RFC v2 00/11] KVM: s390: Add VSIE SIGP Interpretation (vsie_sigpif)
@ 2025-11-10 17:16 Christoph Schlameuss
  2025-11-10 17:16 ` [PATCH RFC v2 01/11] KVM: s390: Add SCAO read and write helpers Christoph Schlameuss
                   ` (10 more replies)
  0 siblings, 11 replies; 23+ messages in thread
From: Christoph Schlameuss @ 2025-11-10 17:16 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Janosch Frank, Claudio Imbrenda,
	Nico Boehr, David Hildenbrand, Sven Schnelle, Paolo Bonzini,
	Shuah Khan, Christoph Schlameuss, Hendrik Brueckner

In the upcoming IBM Z machine generation (gen17) the s390x architecture
adds a new VSIE Interpretation Extension Facility (vsie_sigpif) to
improve guest-3 guest performance.

To exploit the new machine support the guest-1 KVM needs to create and
maintain shadow structures pointing to the original state descriptions
and system control areas of currently running guest-3 configurations.
These pointers are followed by the machines firmware and modifications
of the original SCA for guest-3 (located in guest-2) are monitored and
handled by firmware. This results in fewer VSIE exits.

---
There are still some problems with the current state but I think it is
in a good state to gather some feedback.

Known Functional Problems:
- reuse of sca allocation with sigpif enabled does hang

Known Non-Functional Problems:
- Performance of the initial configuration shadowing can be streamlined
- Performance for reentry can likely be improved
- Locking can be improved to allow for more concurrency

---
Christoph Schlameuss (11):
      KVM: s390: Add SCAO read and write helpers
      KVM: s390: Remove double 64bscao feature check
      KVM: s390: Move scao validation into a function
      KVM: s390: Add vsie_sigpif detection
      KVM: s390: Add ssca_block and ssca_entry structs for vsie_ie
      KVM: s390: Add helper to pin multiple guest pages
      KVM: s390: Shadow VSIE SCA in guest-1
      KVM: s390: Allow guest-3 cpu add and remove with vsie sigpif
      KVM: s390: Allow guest-3 switch to extended sca with vsie sigpif
      KVM: s390: Add VSIE shadow configuration
      KVM: s390: Add VSIE shadow stat counters

 arch/s390/include/asm/kvm_host.h               |  16 +-
 arch/s390/include/asm/kvm_host_types.h         |  24 +-
 arch/s390/include/asm/sclp.h                   |   1 +
 arch/s390/kvm/kvm-s390.c                       |  14 +-
 arch/s390/kvm/kvm-s390.h                       |   2 +-
 arch/s390/kvm/vsie.c                           | 852 +++++++++++++++++++++----
 drivers/s390/char/sclp_early.c                 |   1 +
 tools/testing/selftests/kvm/include/s390/sie.h |   2 +-
 8 files changed, 773 insertions(+), 139 deletions(-)
---
base-commit: 62ad2b01b0c7dba966c6843b77e99b06a3b12d27
change-id: 20250228-vsieie-07be34fc3984
prerequisite-change-id: 20250513-rm-bsca-ab1e8649aca7:v7
prerequisite-patch-id: 52dadcc65bc9fddfee7499ed55a3fa909051ab1c
prerequisite-change-id: 20250602-rm-sca-lock-d7c1eca252b1:v2
prerequisite-patch-id: 52dadcc65bc9fddfee7499ed55a3fa909051ab1c
prerequisite-patch-id: 7117176d5763754fc7c1474288bcbe4de567c60e

Best regards,
-- 
Christoph Schlameuss <schlameuss@linux.ibm.com>


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

* [PATCH RFC v2 01/11] KVM: s390: Add SCAO read and write helpers
  2025-11-10 17:16 [PATCH RFC v2 00/11] KVM: s390: Add VSIE SIGP Interpretation (vsie_sigpif) Christoph Schlameuss
@ 2025-11-10 17:16 ` Christoph Schlameuss
  2025-11-11 13:45   ` Claudio Imbrenda
  2025-11-10 17:16 ` [PATCH RFC v2 02/11] KVM: s390: Remove double 64bscao feature check Christoph Schlameuss
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 23+ messages in thread
From: Christoph Schlameuss @ 2025-11-10 17:16 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Janosch Frank, Claudio Imbrenda,
	Nico Boehr, David Hildenbrand, Sven Schnelle, Paolo Bonzini,
	Shuah Khan, Christoph Schlameuss

Introduce some small helper functions to get and set the system control
area origin address from the SIE control block.

Signed-off-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
---
 arch/s390/kvm/vsie.c | 29 +++++++++++++++++++++--------
 1 file changed, 21 insertions(+), 8 deletions(-)

diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c
index 347268f89f2f186bea623a3adff7376cabc305b2..ced2ca4ce5b584403d900ed11cb064919feda8e9 100644
--- a/arch/s390/kvm/vsie.c
+++ b/arch/s390/kvm/vsie.c
@@ -123,6 +123,23 @@ static int prefix_is_mapped(struct vsie_page *vsie_page)
 	return !(atomic_read(&vsie_page->scb_s.prog20) & PROG_REQUEST);
 }
 
+static gpa_t read_scao(struct kvm *kvm, struct kvm_s390_sie_block *scb)
+{
+	gpa_t sca;
+
+	sca = READ_ONCE(scb->scaol) & ~0xfUL;
+	if (test_kvm_cpu_feat(kvm, KVM_S390_VM_CPU_FEAT_64BSCAO))
+		sca |= (u64)READ_ONCE(scb->scaoh) << 32;
+
+	return sca;
+}
+
+static void write_scao(struct kvm_s390_sie_block *scb, hpa_t hpa)
+{
+	scb->scaoh = (u32)((u64)hpa >> 32);
+	scb->scaol = (u32)(u64)hpa;
+}
+
 /* copy the updated intervention request bits into the shadow scb */
 static void update_intervention_requests(struct vsie_page *vsie_page)
 {
@@ -714,12 +731,11 @@ static void unpin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
 	struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
 	hpa_t hpa;
 
-	hpa = (u64) scb_s->scaoh << 32 | scb_s->scaol;
+	hpa = read_scao(vcpu->kvm, scb_s);
 	if (hpa) {
 		unpin_guest_page(vcpu->kvm, vsie_page->sca_gpa, hpa);
 		vsie_page->sca_gpa = 0;
-		scb_s->scaol = 0;
-		scb_s->scaoh = 0;
+		write_scao(scb_s, 0);
 	}
 
 	hpa = scb_s->itdba;
@@ -773,9 +789,7 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
 	gpa_t gpa;
 	int rc = 0;
 
-	gpa = READ_ONCE(scb_o->scaol) & ~0xfUL;
-	if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_64BSCAO))
-		gpa |= (u64) READ_ONCE(scb_o->scaoh) << 32;
+	gpa = read_scao(vcpu->kvm, scb_o);
 	if (gpa) {
 		if (gpa < 2 * PAGE_SIZE)
 			rc = set_validity_icpt(scb_s, 0x0038U);
@@ -792,8 +806,7 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
 		if (rc)
 			goto unpin;
 		vsie_page->sca_gpa = gpa;
-		scb_s->scaoh = (u32)((u64)hpa >> 32);
-		scb_s->scaol = (u32)(u64)hpa;
+		write_scao(scb_s, hpa);
 	}
 
 	gpa = READ_ONCE(scb_o->itdba) & ~0xffUL;

-- 
2.51.1


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

* [PATCH RFC v2 02/11] KVM: s390: Remove double 64bscao feature check
  2025-11-10 17:16 [PATCH RFC v2 00/11] KVM: s390: Add VSIE SIGP Interpretation (vsie_sigpif) Christoph Schlameuss
  2025-11-10 17:16 ` [PATCH RFC v2 01/11] KVM: s390: Add SCAO read and write helpers Christoph Schlameuss
@ 2025-11-10 17:16 ` Christoph Schlameuss
  2025-11-10 21:32   ` Eric Farman
                     ` (2 more replies)
  2025-11-10 17:16 ` [PATCH RFC v2 03/11] KVM: s390: Move scao validation into a function Christoph Schlameuss
                   ` (8 subsequent siblings)
  10 siblings, 3 replies; 23+ messages in thread
From: Christoph Schlameuss @ 2025-11-10 17:16 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Janosch Frank, Claudio Imbrenda,
	Nico Boehr, David Hildenbrand, Sven Schnelle, Paolo Bonzini,
	Shuah Khan, Christoph Schlameuss

sclp.has_64bscao is already verified in the guard clause a few lines
above this. So we cannot reach this code if it is not true.

Signed-off-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
---
 arch/s390/kvm/kvm-s390.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 769820e3a2431c16c7ec85dbf313f61f7ba1a3cc..984baa5f5ded1e05e389abc485c63c0bf35eee4c 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -455,8 +455,7 @@ static void __init kvm_s390_cpu_feat_init(void)
 	    !test_facility(3) || !nested)
 		return;
 	allow_cpu_feat(KVM_S390_VM_CPU_FEAT_SIEF2);
-	if (sclp.has_64bscao)
-		allow_cpu_feat(KVM_S390_VM_CPU_FEAT_64BSCAO);
+	allow_cpu_feat(KVM_S390_VM_CPU_FEAT_64BSCAO);
 	if (sclp.has_siif)
 		allow_cpu_feat(KVM_S390_VM_CPU_FEAT_SIIF);
 	if (sclp.has_gpere)

-- 
2.51.1


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

* [PATCH RFC v2 03/11] KVM: s390: Move scao validation into a function
  2025-11-10 17:16 [PATCH RFC v2 00/11] KVM: s390: Add VSIE SIGP Interpretation (vsie_sigpif) Christoph Schlameuss
  2025-11-10 17:16 ` [PATCH RFC v2 01/11] KVM: s390: Add SCAO read and write helpers Christoph Schlameuss
  2025-11-10 17:16 ` [PATCH RFC v2 02/11] KVM: s390: Remove double 64bscao feature check Christoph Schlameuss
@ 2025-11-10 17:16 ` Christoph Schlameuss
  2025-11-10 21:30   ` Eric Farman
  2025-11-10 17:16 ` [PATCH RFC v2 04/11] KVM: s390: Add vsie_sigpif detection Christoph Schlameuss
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 23+ messages in thread
From: Christoph Schlameuss @ 2025-11-10 17:16 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Janosch Frank, Claudio Imbrenda,
	Nico Boehr, David Hildenbrand, Sven Schnelle, Paolo Bonzini,
	Shuah Khan, Christoph Schlameuss

This improves readability as well as allows re-use in coming patches.

Signed-off-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
---
 arch/s390/kvm/vsie.c | 27 ++++++++++++++++++++-------
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c
index ced2ca4ce5b584403d900ed11cb064919feda8e9..3d602bbd1f70b7bd8ddc2c54d43027dc37a6e032 100644
--- a/arch/s390/kvm/vsie.c
+++ b/arch/s390/kvm/vsie.c
@@ -95,6 +95,25 @@ static int set_validity_icpt(struct kvm_s390_sie_block *scb,
 	return 1;
 }
 
+/* The sca header must not cross pages etc. */
+static int validate_scao(struct kvm_vcpu *vcpu, struct kvm_s390_sie_block *scb, gpa_t gpa)
+{
+	int offset;
+
+	if (gpa < 2 * PAGE_SIZE)
+		return set_validity_icpt(scb, 0x0038U);
+	if ((gpa & ~0x1fffUL) == kvm_s390_get_prefix(vcpu))
+		return set_validity_icpt(scb, 0x0011U);
+
+	if (sie_uses_esca(scb))
+		offset = offsetof(struct esca_block, cpu[0]) - 1;
+	else
+		offset = offsetof(struct bsca_block, cpu[0]) - 1;
+	if ((gpa & PAGE_MASK) != ((gpa + offset) & PAGE_MASK))
+		return set_validity_icpt(scb, 0x003bU);
+	return false;
+}
+
 /* mark the prefix as unmapped, this will block the VSIE */
 static void prefix_unmapped(struct vsie_page *vsie_page)
 {
@@ -791,13 +810,7 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
 
 	gpa = read_scao(vcpu->kvm, scb_o);
 	if (gpa) {
-		if (gpa < 2 * PAGE_SIZE)
-			rc = set_validity_icpt(scb_s, 0x0038U);
-		else if ((gpa & ~0x1fffUL) == kvm_s390_get_prefix(vcpu))
-			rc = set_validity_icpt(scb_s, 0x0011U);
-		else if ((gpa & PAGE_MASK) !=
-			 ((gpa + sizeof(struct bsca_block) - 1) & PAGE_MASK))
-			rc = set_validity_icpt(scb_s, 0x003bU);
+		rc = validate_scao(vcpu, scb_o, gpa);
 		if (!rc) {
 			rc = pin_guest_page(vcpu->kvm, gpa, &hpa);
 			if (rc)

-- 
2.51.1


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

* [PATCH RFC v2 04/11] KVM: s390: Add vsie_sigpif detection
  2025-11-10 17:16 [PATCH RFC v2 00/11] KVM: s390: Add VSIE SIGP Interpretation (vsie_sigpif) Christoph Schlameuss
                   ` (2 preceding siblings ...)
  2025-11-10 17:16 ` [PATCH RFC v2 03/11] KVM: s390: Move scao validation into a function Christoph Schlameuss
@ 2025-11-10 17:16 ` Christoph Schlameuss
  2025-11-10 17:16 ` [PATCH RFC v2 05/11] KVM: s390: Add ssca_block and ssca_entry structs for vsie_ie Christoph Schlameuss
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 23+ messages in thread
From: Christoph Schlameuss @ 2025-11-10 17:16 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Janosch Frank, Claudio Imbrenda,
	Nico Boehr, David Hildenbrand, Sven Schnelle, Paolo Bonzini,
	Shuah Khan, Christoph Schlameuss, Hendrik Brueckner

Add sensing of the VSIE Interpretation Extension Facility as vsie_sigpif
from SCLP. This facility is introduced with IBM Z gen17.

Signed-off-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
---
 arch/s390/include/asm/kvm_host.h | 1 +
 arch/s390/include/asm/sclp.h     | 1 +
 arch/s390/kvm/kvm-s390.c         | 1 +
 drivers/s390/char/sclp_early.c   | 1 +
 4 files changed, 4 insertions(+)

diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 22cedcaea4756be50dcd65bdd85b83cdb0386dbb..647014edd3de8abc15067e7203c4855c066c53ad 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -644,6 +644,7 @@ struct kvm_arch {
 	int use_pfmfi;
 	int use_skf;
 	int use_zpci_interp;
+	int use_vsie_sigpif;
 	int user_cpu_state_ctrl;
 	int user_sigp;
 	int user_stsi;
diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h
index 0f184dbdbe5e0748fcecbca38b9e55a56968dc79..e4545d96e4bf67243583f184c2d4e734a9605007 100644
--- a/arch/s390/include/asm/sclp.h
+++ b/arch/s390/include/asm/sclp.h
@@ -101,6 +101,7 @@ struct sclp_info {
 	unsigned char has_dirq : 1;
 	unsigned char has_iplcc : 1;
 	unsigned char has_zpci_lsi : 1;
+	unsigned char has_vsie_sigpif : 1;
 	unsigned char has_aisii : 1;
 	unsigned char has_aeni : 1;
 	unsigned char has_aisi : 1;
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 984baa5f5ded1e05e389abc485c63c0bf35eee4c..ab672aa93f758711af4defb13875fd49a6609758 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -3439,6 +3439,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 
 	kvm->arch.use_pfmfi = sclp.has_pfmfi;
 	kvm->arch.use_skf = sclp.has_skey;
+	kvm->arch.use_vsie_sigpif = sclp.has_vsie_sigpif;
 	spin_lock_init(&kvm->arch.start_stop_lock);
 	kvm_s390_vsie_init(kvm);
 	if (use_gisa)
diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c
index bd5e5ba50c0acaedce899702433a7f075dc56258..7211d85a8d4e9c97745fd13955c742407c0ab22f 100644
--- a/drivers/s390/char/sclp_early.c
+++ b/drivers/s390/char/sclp_early.c
@@ -57,6 +57,7 @@ static void __init sclp_early_facilities_detect(void)
 		sclp.has_diag318 = !!(sccb->byte_134 & 0x80);
 		sclp.has_diag320 = !!(sccb->byte_134 & 0x04);
 		sclp.has_iplcc = !!(sccb->byte_134 & 0x02);
+		sclp.has_vsie_sigpif = !!(sccb->byte_134 & 0x01);
 	}
 	if (sccb->cpuoff > 137) {
 		sclp.has_sipl = !!(sccb->cbl & 0x4000);

-- 
2.51.1


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

* [PATCH RFC v2 05/11] KVM: s390: Add ssca_block and ssca_entry structs for vsie_ie
  2025-11-10 17:16 [PATCH RFC v2 00/11] KVM: s390: Add VSIE SIGP Interpretation (vsie_sigpif) Christoph Schlameuss
                   ` (3 preceding siblings ...)
  2025-11-10 17:16 ` [PATCH RFC v2 04/11] KVM: s390: Add vsie_sigpif detection Christoph Schlameuss
@ 2025-11-10 17:16 ` Christoph Schlameuss
  2025-11-10 17:16 ` [PATCH RFC v2 06/11] KVM: s390: Add helper to pin multiple guest pages Christoph Schlameuss
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 23+ messages in thread
From: Christoph Schlameuss @ 2025-11-10 17:16 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Janosch Frank, Claudio Imbrenda,
	Nico Boehr, David Hildenbrand, Sven Schnelle, Paolo Bonzini,
	Shuah Khan, Christoph Schlameuss

Add the required guest-1 structures for the vsie_sigpif to the SIE
control block and vsie_page for use in later patches.

The shadow SCA features the address of the original SCA as well as an
entry for each original SIGP entry. The entries contain the addresses of
the shadow state description and original SIGP entry.

Signed-off-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
---
 arch/s390/include/asm/kvm_host_types.h         | 21 ++++++++++++++++++++-
 tools/testing/selftests/kvm/include/s390/sie.h |  2 +-
 2 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/arch/s390/include/asm/kvm_host_types.h b/arch/s390/include/asm/kvm_host_types.h
index 1394d3fb648f1e46dba2c513ed26e5dfd275fad4..ce52608449735d6ca629008c554e7df09f97e67b 100644
--- a/arch/s390/include/asm/kvm_host_types.h
+++ b/arch/s390/include/asm/kvm_host_types.h
@@ -45,6 +45,13 @@ struct bsca_entry {
 	__u64	reserved2[2];
 };
 
+struct ssca_entry {
+	__u64	reserved1;
+	__u64	ssda;
+	__u64	ossea;
+	__u64	reserved2;
+};
+
 union ipte_control {
 	unsigned long val;
 	struct {
@@ -86,6 +93,18 @@ struct esca_block {
 	struct esca_entry cpu[KVM_S390_ESCA_CPU_SLOTS];
 };
 
+/*
+ * The shadow sca / ssca needs to cover both bsca and esca depending on what the
+ * guest uses so we allocate space for 256 entries that are defined in the
+ * architecture.
+ * The header part of the struct must not cross page boundaries.
+ */
+struct ssca_block {
+	__u64	osca;
+	__u64	reserved08[7];
+	struct ssca_entry cpu[KVM_MAX_VCPUS];
+};
+
 /*
  * This struct is used to store some machine check info from lowcore
  * for machine checks that happen while the guest is running.
@@ -316,7 +335,7 @@ struct kvm_s390_sie_block {
 	__u32	fac;			/* 0x01a0 */
 	__u8	reserved1a4[20];	/* 0x01a4 */
 	__u64	cbrlo;			/* 0x01b8 */
-	__u8	reserved1c0[8];		/* 0x01c0 */
+	__u64	osda;			/* 0x01c0 */
 #define ECD_HOSTREGMGMT	0x20000000
 #define ECD_MEF		0x08000000
 #define ECD_ETOKENF	0x02000000
diff --git a/tools/testing/selftests/kvm/include/s390/sie.h b/tools/testing/selftests/kvm/include/s390/sie.h
index 160acd4a1db92d6129c0f084db82c8c147d5c23e..4ff1c1a354af51d322042c03d59a8cf56685abd3 100644
--- a/tools/testing/selftests/kvm/include/s390/sie.h
+++ b/tools/testing/selftests/kvm/include/s390/sie.h
@@ -223,7 +223,7 @@ struct kvm_s390_sie_block {
 	__u32	fac;			/* 0x01a0 */
 	__u8	reserved1a4[20];	/* 0x01a4 */
 	__u64	cbrlo;			/* 0x01b8 */
-	__u8	reserved1c0[8];		/* 0x01c0 */
+	__u64	osda;			/* 0x01c0 */
 #define ECD_HOSTREGMGMT	0x20000000
 #define ECD_MEF		0x08000000
 #define ECD_ETOKENF	0x02000000

-- 
2.51.1


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

* [PATCH RFC v2 06/11] KVM: s390: Add helper to pin multiple guest pages
  2025-11-10 17:16 [PATCH RFC v2 00/11] KVM: s390: Add VSIE SIGP Interpretation (vsie_sigpif) Christoph Schlameuss
                   ` (4 preceding siblings ...)
  2025-11-10 17:16 ` [PATCH RFC v2 05/11] KVM: s390: Add ssca_block and ssca_entry structs for vsie_ie Christoph Schlameuss
@ 2025-11-10 17:16 ` Christoph Schlameuss
  2025-11-10 17:16 ` [PATCH RFC v2 07/11] KVM: s390: Shadow VSIE SCA in guest-1 Christoph Schlameuss
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 23+ messages in thread
From: Christoph Schlameuss @ 2025-11-10 17:16 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Janosch Frank, Claudio Imbrenda,
	Nico Boehr, David Hildenbrand, Sven Schnelle, Paolo Bonzini,
	Shuah Khan, Christoph Schlameuss

In the main patch of this set we need to pin and unpin multiple
consecutive guest-2 pages in guest-1. As these might not be consecutive
in guest-1 it is necessary to iterate over all pages and store guest and
host addresses for later use.

As the new methods to use the existing {,un}pin_guest_page() methods
these are moved up unchanged in the file to prevent to have to resort to
forward declarations later on.

Signed-off-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
---
 arch/s390/kvm/vsie.c | 91 +++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 65 insertions(+), 26 deletions(-)

diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c
index 3d602bbd1f70b7bd8ddc2c54d43027dc37a6e032..e86fef0fa3919668902c766813991572c2311b09 100644
--- a/arch/s390/kvm/vsie.c
+++ b/arch/s390/kvm/vsie.c
@@ -67,6 +67,11 @@ struct vsie_page {
 	__u8 fac[S390_ARCH_FAC_LIST_SIZE_BYTE];	/* 0x0800 */
 };
 
+struct kvm_address_pair {
+	gpa_t gpa;
+	hpa_t hpa;
+};
+
 /**
  * gmap_shadow_valid() - check if a shadow guest address space matches the
  *                       given properties and is still valid
@@ -159,6 +164,66 @@ static void write_scao(struct kvm_s390_sie_block *scb, hpa_t hpa)
 	scb->scaol = (u32)(u64)hpa;
 }
 
+/*
+ * Pin the guest page given by gpa and set hpa to the pinned host address.
+ * Will always be pinned writable.
+ *
+ * Returns: - 0 on success
+ *          - -EINVAL if the gpa is not valid guest storage
+ */
+static int pin_guest_page(struct kvm *kvm, gpa_t gpa, hpa_t *hpa)
+{
+	struct page *page;
+
+	page = gfn_to_page(kvm, gpa_to_gfn(gpa));
+	if (!page)
+		return -EINVAL;
+	*hpa = (hpa_t)page_to_phys(page) + (gpa & ~PAGE_MASK);
+	return 0;
+}
+
+/* Unpins a page previously pinned via pin_guest_page, marking it as dirty. */
+static void unpin_guest_page(struct kvm *kvm, gpa_t gpa, hpa_t hpa)
+{
+	kvm_release_page_dirty(pfn_to_page(hpa >> PAGE_SHIFT));
+	/* mark the page always as dirty for migration */
+	mark_page_dirty(kvm, gpa_to_gfn(gpa));
+}
+
+/* unpin multiple guest pages pinned with pin_guest_pages() */
+static void unpin_guest_pages(struct kvm *kvm, struct kvm_address_pair *addr, unsigned int nr_pages)
+{
+	int i;
+
+	for (i = 0; i < nr_pages; i++) {
+		unpin_guest_page(kvm, addr[i].gpa, addr[i].hpa);
+		addr[i].gpa = 0;
+		addr[i].hpa = 0;
+	}
+}
+
+/* pin nr_pages consecutive guest pages */
+static int pin_guest_pages(struct kvm *kvm, gpa_t gpa, unsigned int nr_pages,
+			   struct kvm_address_pair *addr)
+{
+	hpa_t hpa;
+	int i, rc;
+
+	/* the guest pages may not be mapped continuously, so pin each page */
+	for (i = 0; i < nr_pages; i++) {
+		rc = pin_guest_page(kvm, gpa + PAGE_SIZE * i, &hpa);
+		if (rc)
+			goto err;
+		addr[i].gpa = gpa + PAGE_SIZE * i;
+		addr[i].hpa = hpa;
+	}
+	return i;
+
+err:
+	unpin_guest_pages(kvm, addr, i);
+	return -EFAULT;
+}
+
 /* copy the updated intervention request bits into the shadow scb */
 static void update_intervention_requests(struct vsie_page *vsie_page)
 {
@@ -718,32 +783,6 @@ static int map_prefix(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
 	return rc;
 }
 
-/*
- * Pin the guest page given by gpa and set hpa to the pinned host address.
- * Will always be pinned writable.
- *
- * Returns: - 0 on success
- *          - -EINVAL if the gpa is not valid guest storage
- */
-static int pin_guest_page(struct kvm *kvm, gpa_t gpa, hpa_t *hpa)
-{
-	struct page *page;
-
-	page = gfn_to_page(kvm, gpa_to_gfn(gpa));
-	if (!page)
-		return -EINVAL;
-	*hpa = (hpa_t)page_to_phys(page) + (gpa & ~PAGE_MASK);
-	return 0;
-}
-
-/* Unpins a page previously pinned via pin_guest_page, marking it as dirty. */
-static void unpin_guest_page(struct kvm *kvm, gpa_t gpa, hpa_t hpa)
-{
-	kvm_release_page_dirty(pfn_to_page(hpa >> PAGE_SHIFT));
-	/* mark the page always as dirty for migration */
-	mark_page_dirty(kvm, gpa_to_gfn(gpa));
-}
-
 /* unpin all blocks previously pinned by pin_blocks(), marking them dirty */
 static void unpin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
 {

-- 
2.51.1


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

* [PATCH RFC v2 07/11] KVM: s390: Shadow VSIE SCA in guest-1
  2025-11-10 17:16 [PATCH RFC v2 00/11] KVM: s390: Add VSIE SIGP Interpretation (vsie_sigpif) Christoph Schlameuss
                   ` (5 preceding siblings ...)
  2025-11-10 17:16 ` [PATCH RFC v2 06/11] KVM: s390: Add helper to pin multiple guest pages Christoph Schlameuss
@ 2025-11-10 17:16 ` Christoph Schlameuss
  2025-11-10 17:16 ` [PATCH RFC v2 08/11] KVM: s390: Allow guest-3 cpu add and remove with vsie sigpif Christoph Schlameuss
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 23+ messages in thread
From: Christoph Schlameuss @ 2025-11-10 17:16 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Janosch Frank, Claudio Imbrenda,
	Nico Boehr, David Hildenbrand, Sven Schnelle, Paolo Bonzini,
	Shuah Khan, Christoph Schlameuss

Restructure kvm_s390_handle_vsie() to create a guest-1 shadow of the SCA
if guest-2 attempts to enter SIE with an SCA. If the SCA is used the
vsie_pages are stored in a new vsie_sca struct instead of the arch vsie
struct.

When the VSIE-Interpretation-Extension Facility is active (minimum z17)
the shadow SCA (ssca_block) will be created and shadows of all CPUs
defined in the configuration are created.
SCAOL/H in the VSIE control block are overwritten with references to the
shadow SCA.

The shadow SCA contains the addresses of the original guest-3 SCA as
well as the original VSIE control blocks. With these addresses the
machine can directly monitor the intervention bits within the original
SCA entries, enabling it to handle SENSE_RUNNING and EXTERNAL_CALL sigp
instructions without exiting VSIE.

The original SCA will be pinned in guest-2 memory and only be unpinned
before reuse. This means some pages might still be pinned even after the
guest 3 VM does no longer exist.

The ssca_blocks are also kept within a radix tree to reuse already
existing ssca_blocks efficiently. While the radix tree and array with
references to the ssca_blocks are held in the vsie_sca struct.
The use of vsie_scas is tracked using an ref_count.

Signed-off-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
---
 arch/s390/include/asm/kvm_host.h       |  11 +-
 arch/s390/include/asm/kvm_host_types.h |   5 +-
 arch/s390/kvm/kvm-s390.c               |   6 +-
 arch/s390/kvm/kvm-s390.h               |   2 +-
 arch/s390/kvm/vsie.c                   | 672 ++++++++++++++++++++++++++++-----
 5 files changed, 596 insertions(+), 100 deletions(-)

diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 647014edd3de8abc15067e7203c4855c066c53ad..191b23edf0ac7e9a3e1fd9cdc6fc4c9a9e6769f8 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -597,13 +597,22 @@ struct sie_page2 {
 };
 
 struct vsie_page;
+struct vsie_sca;
 
+/*
+ * vsie_pages, scas and accompanied management vars
+ */
 struct kvm_s390_vsie {
 	struct mutex mutex;
 	struct radix_tree_root addr_to_page;
 	int page_count;
 	int next;
-	struct vsie_page *pages[KVM_MAX_VCPUS];
+	struct vsie_page *pages[KVM_S390_MAX_VSIE_VCPUS];
+	struct rw_semaphore ssca_lock;
+	struct radix_tree_root osca_to_sca;
+	int sca_count;
+	int sca_next;
+	struct vsie_sca *scas[KVM_S390_MAX_VSIE_VCPUS];
 };
 
 struct kvm_s390_gisa_iam {
diff --git a/arch/s390/include/asm/kvm_host_types.h b/arch/s390/include/asm/kvm_host_types.h
index ce52608449735d6ca629008c554e7df09f97e67b..3141a7163518c8fc1584c36efe216ff237722b7e 100644
--- a/arch/s390/include/asm/kvm_host_types.h
+++ b/arch/s390/include/asm/kvm_host_types.h
@@ -6,6 +6,9 @@
 #include <linux/atomic.h>
 #include <linux/types.h>
 
+#define KVM_S390_MAX_VSIE_VCPUS 256
+#define KVM_S390_MAX_SCA_PAGES 5
+
 #define KVM_S390_BSCA_CPU_SLOTS 64
 #define KVM_S390_ESCA_CPU_SLOTS 248
 
@@ -102,7 +105,7 @@ struct esca_block {
 struct ssca_block {
 	__u64	osca;
 	__u64	reserved08[7];
-	struct ssca_entry cpu[KVM_MAX_VCPUS];
+	struct ssca_entry cpu[KVM_S390_MAX_VSIE_VCPUS];
 };
 
 /*
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index ab672aa93f758711af4defb13875fd49a6609758..e3fc53e33e90be7dab75f73ebd0b949c13d22939 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -470,6 +470,9 @@ static void __init kvm_s390_cpu_feat_init(void)
 		allow_cpu_feat(KVM_S390_VM_CPU_FEAT_IBS);
 	if (sclp.has_kss)
 		allow_cpu_feat(KVM_S390_VM_CPU_FEAT_KSS);
+	if (sclp.has_vsie_sigpif)
+		allow_cpu_feat(KVM_S390_VM_CPU_FEAT_SIGPIF);
+
 	/*
 	 * KVM_S390_VM_CPU_FEAT_SKEY: Wrong shadow of PTE.I bits will make
 	 * all skey handling functions read/set the skey from the PGSTE
@@ -484,9 +487,6 @@ static void __init kvm_s390_cpu_feat_init(void)
 	 * For KVM_S390_VM_CPU_FEAT_SKEY, KVM_S390_VM_CPU_FEAT_CMMA and
 	 * KVM_S390_VM_CPU_FEAT_PFMFI, all PTE.I and PGSTE bits have to be
 	 * correctly shadowed. We can do that for the PGSTE but not for PTE.I.
-	 *
-	 * KVM_S390_VM_CPU_FEAT_SIGPIF: Wrong SCB addresses in the SCA. We
-	 * cannot easily shadow the SCA because of the ipte lock.
 	 */
 }
 
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 65c950760993467398b68f3763d6f81f52c52385..0e33f00cd63e8b9f261a0c52add86560f2918d05 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -577,7 +577,7 @@ static inline int kvm_s390_use_sca_entries(void)
 	 * might use the entries. By not setting the entries and keeping them
 	 * invalid, hardware will not access them but intercept.
 	 */
-	return sclp.has_sigpif && sclp.has_esca;
+	return sclp.has_sigpif;
 }
 void kvm_s390_reinject_machine_check(struct kvm_vcpu *vcpu,
 				     struct mcck_volatile_info *mcck_info);
diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c
index e86fef0fa3919668902c766813991572c2311b09..72c794945be916cc107aba74e1609d3b4780d4b9 100644
--- a/arch/s390/kvm/vsie.c
+++ b/arch/s390/kvm/vsie.c
@@ -26,6 +26,12 @@
 
 enum vsie_page_flags {
 	VSIE_PAGE_IN_USE = 0,
+	VSIE_PAGE_PINNED = 1,
+};
+
+enum vsie_sca_flags {
+	VSIE_SCA_ESCA = 0,
+	VSIE_SCA_PINNED = 1,
 };
 
 struct vsie_page {
@@ -62,7 +68,9 @@ struct vsie_page {
 	 * looked up by other CPUs.
 	 */
 	unsigned long flags;			/* 0x0260 */
-	__u8 reserved[0x0700 - 0x0268];		/* 0x0268 */
+	/* vsie system control area */
+	struct vsie_sca *sca;			/* 0x0268 */
+	__u8 reserved[0x0700 - 0x0270];		/* 0x0270 */
 	struct kvm_s390_crypto_cb crycb;	/* 0x0700 */
 	__u8 fac[S390_ARCH_FAC_LIST_SIZE_BYTE];	/* 0x0800 */
 };
@@ -72,6 +80,41 @@ struct kvm_address_pair {
 	hpa_t hpa;
 };
 
+/*
+ * Store the vsie system configuration data.
+ */
+struct vsie_sca {
+	/* calculated guest addresses of the sca */
+	gpa_t			sca_gpa;
+	atomic_t		ref_count;
+	/* defined in enum vsie_sca_flags */
+	unsigned long		flags;
+	unsigned long		sca_o_nr_pages;
+	struct kvm_address_pair	sca_o_pages[KVM_S390_MAX_SCA_PAGES];
+	u64			mcn[4];
+	struct ssca_block	*ssca;
+	int			page_count;
+	int			page_next;
+	struct vsie_page	*pages[KVM_S390_MAX_VSIE_VCPUS];
+};
+
+static inline bool use_vsie_sigpif(struct kvm *kvm)
+{
+	return kvm->arch.use_vsie_sigpif;
+}
+
+static inline bool use_vsie_sigpif_for(struct kvm *kvm, struct vsie_page *vsie_page)
+{
+	return use_vsie_sigpif(kvm) &&
+	       (vsie_page->scb_o->eca & ECA_SIGPI) &&
+	       (vsie_page->scb_o->ecb & ECB_SRSI);
+}
+
+static inline bool sie_uses_esca(struct kvm_s390_sie_block *scb)
+{
+	return (scb->ecb2 & ECB2_ESCA);
+}
+
 /**
  * gmap_shadow_valid() - check if a shadow guest address space matches the
  *                       given properties and is still valid
@@ -630,6 +673,8 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
 		scb_s->ictl |= ICTL_ISKE | ICTL_SSKE | ICTL_RRBE;
 
 	scb_s->icpua = scb_o->icpua;
+	write_scao(scb_s, virt_to_phys(vsie_page->sca->ssca));
+	scb_s->osda = virt_to_phys(scb_o);
 
 	if (!(atomic_read(&scb_s->cpuflags) & CPUSTAT_SM))
 		new_mso = READ_ONCE(scb_o->mso) & 0xfffffffffff00000UL;
@@ -681,6 +726,8 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
 	/* Instruction Execution Prevention */
 	if (test_kvm_facility(vcpu->kvm, 130))
 		scb_s->ecb2 |= scb_o->ecb2 & ECB2_IEP;
+	/* extended SCA */
+	scb_s->ecb2 |= scb_o->ecb2 & ECB2_ESCA;
 	/* Guarded Storage */
 	if (test_kvm_facility(vcpu->kvm, 133)) {
 		scb_s->ecb |= scb_o->ecb & ECB_GS;
@@ -713,12 +760,250 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
 	return rc;
 }
 
+/* Called with ssca_lock held. */
+static void unpin_sca(struct kvm *kvm, struct vsie_sca *sca)
+{
+	if (!test_bit(VSIE_SCA_PINNED, &sca->flags))
+		return;
+
+	unpin_guest_pages(kvm, sca->sca_o_pages, sca->sca_o_nr_pages);
+	sca->sca_o_nr_pages = 0;
+
+	__clear_bit(VSIE_SCA_PINNED, &sca->flags);
+}
+
+/* pin g2s original sca in g1 memory */
+static int pin_sca(struct kvm *kvm, struct vsie_page *vsie_page, struct vsie_sca *sca)
+{
+	bool is_esca = sie_uses_esca(vsie_page->scb_o);
+	int nr_pages = KVM_S390_MAX_SCA_PAGES;
+
+	if (test_bit(VSIE_SCA_PINNED, &sca->flags))
+		return 0;
+
+	if (!is_esca) {
+		nr_pages = 1;
+		if ((sca->sca_gpa & ~PAGE_MASK) + sizeof(struct bsca_block) > PAGE_SIZE)
+			nr_pages = 2;
+	}
+
+	sca->sca_o_nr_pages = pin_guest_pages(kvm, sca->sca_gpa, nr_pages, sca->sca_o_pages);
+	if (WARN_ON_ONCE(sca->sca_o_nr_pages != nr_pages)) {
+		set_validity_icpt(&vsie_page->scb_s, 0x0034U);
+		return -EIO;
+	}
+	__set_bit(VSIE_SCA_PINNED, &sca->flags);
+
+	return 0;
+}
+
+static void get_sca_entry_addr(struct kvm *kvm, struct vsie_page *vsie_page, struct vsie_sca *sca,
+			       u16 cpu_nr, gpa_t *gpa, hpa_t *hpa)
+{
+	hpa_t offset;
+	int pn;
+
+	/*
+	 * We cannot simply access the hva since the esca_block has typically
+	 * 4 pages (arch max 5 pages) that might not be continuous in g1 memory.
+	 * The bsca_block may also be stretched over two pages. Only the header
+	 * is guaranteed to be on the same page.
+	 */
+	if (test_bit(VSIE_SCA_ESCA, &sca->flags))
+		offset = offsetof(struct esca_block, cpu[cpu_nr]);
+	else
+		offset = offsetof(struct bsca_block, cpu[cpu_nr]);
+	pn = ((vsie_page->sca->sca_gpa & ~PAGE_MASK) + offset) >> PAGE_SHIFT;
+	if (WARN_ON_ONCE(pn > sca->sca_o_nr_pages))
+		return;
+
+	if (gpa)
+		*gpa = sca->sca_o_pages[pn].gpa + offset;
+	if (hpa)
+		*hpa = sca->sca_o_pages[pn].hpa + offset;
+}
+
+/*
+ * Try to find the address of an existing shadow system control area.
+ * @sca_o_gpa: original system control area address; guest-2 physical
+ *
+ * Called with ssca_lock held.
+ */
+static struct vsie_sca *get_existing_vsie_sca(struct kvm *kvm, hpa_t sca_o_gpa)
+{
+	struct vsie_sca *sca = radix_tree_lookup(&kvm->arch.vsie.osca_to_sca, sca_o_gpa);
+
+	if (sca)
+		WARN_ON_ONCE(atomic_inc_return(&sca->ref_count) < 1);
+	return sca;
+}
+
+/*
+ * Try to find an currently unused ssca_vsie from the vsie struct.
+ *
+ * Called with ssca_lock held.
+ */
+static struct vsie_sca *get_free_existing_vsie_sca(struct kvm *kvm)
+{
+	struct vsie_sca *sca;
+	int i, ref_count;
+
+	for (i = 0; i >= kvm->arch.vsie.sca_count; i++) {
+		sca = kvm->arch.vsie.scas[kvm->arch.vsie.sca_next];
+		kvm->arch.vsie.sca_next++;
+		kvm->arch.vsie.sca_next %= kvm->arch.vsie.sca_count;
+		ref_count = atomic_inc_return(&sca->ref_count);
+		WARN_ON_ONCE(ref_count < 1);
+		if (ref_count == 1)
+			return sca;
+		atomic_dec(&sca->ref_count);
+	}
+	return ERR_PTR(-EFAULT);
+}
+
+static void destroy_vsie_sca(struct kvm *kvm, struct vsie_sca *sca)
+{
+	radix_tree_delete(&kvm->arch.vsie.osca_to_sca, sca->sca_gpa);
+	if (sca->ssca)
+		free_pages_exact(sca->ssca, sca->page_count);
+	sca->ssca = NULL;
+	free_page((unsigned long)sca);
+}
+
+static void put_vsie_sca(struct vsie_sca *sca)
+{
+	if (!sca)
+		return;
+
+	WARN_ON_ONCE(atomic_dec_return(&sca->ref_count) < 0);
+}
+
+/*
+ * Pin and get an existing or new guest system control area.
+ *
+ * May sleep.
+ */
+static struct vsie_sca *get_vsie_sca(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page,
+				     gpa_t sca_addr)
+{
+	struct vsie_sca *sca, *sca_new = NULL;
+	struct kvm *kvm = vcpu->kvm;
+	unsigned int max_sca;
+	int rc;
+
+	rc = validate_scao(vcpu, vsie_page->scb_o, vsie_page->sca_gpa);
+	if (rc)
+		return ERR_PTR(rc);
+
+	/* get existing sca */
+	down_read(&kvm->arch.vsie.ssca_lock);
+	sca = get_existing_vsie_sca(kvm, sca_addr);
+	up_read(&kvm->arch.vsie.ssca_lock);
+	if (sca)
+		return sca;
+
+	/*
+	 * Allocate new ssca, it will likely be needed below.
+	 * We want at least #online_vcpus shadows, so every VCPU can execute the
+	 * VSIE in parallel. (Worst case all single core VMs.)
+	 */
+	max_sca = MIN(atomic_read(&kvm->online_vcpus), KVM_S390_MAX_VSIE_VCPUS);
+	if (kvm->arch.vsie.sca_count < max_sca) {
+		BUILD_BUG_ON(sizeof(struct vsie_sca) > PAGE_SIZE);
+		sca_new = (void *)__get_free_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO);
+		if (!sca_new)
+			return ERR_PTR(-ENOMEM);
+
+		if (use_vsie_sigpif(vcpu->kvm)) {
+			BUILD_BUG_ON(offsetof(struct ssca_block, cpu) != 64);
+			sca_new->ssca = alloc_pages_exact(sizeof(*sca_new->ssca),
+							  GFP_KERNEL_ACCOUNT | __GFP_ZERO);
+			if (!sca_new->ssca) {
+				free_page((unsigned long)sca);
+				sca_new = NULL;
+				return ERR_PTR(-ENOMEM);
+			}
+		}
+	}
+
+	/* enter write lock and recheck to make sure ssca has not been created by other cpu */
+	down_write(&kvm->arch.vsie.ssca_lock);
+	sca = get_existing_vsie_sca(kvm, sca_addr);
+	if (sca)
+		goto out;
+
+	/* check again under write lock if we are still under our sca_count limit */
+	if (sca_new && kvm->arch.vsie.sca_count < max_sca) {
+		/* make use of vsie_sca just created */
+		sca = sca_new;
+		sca_new = NULL;
+
+		kvm->arch.vsie.scas[kvm->arch.vsie.sca_count] = sca;
+	} else {
+		/* reuse previously created vsie_sca allocation for different osca */
+		sca = get_free_existing_vsie_sca(kvm);
+		/* with nr_vcpus scas one must be free */
+		if (IS_ERR(sca))
+			goto out;
+
+		unpin_sca(kvm, sca);
+		radix_tree_delete(&kvm->arch.vsie.osca_to_sca, sca->sca_gpa);
+		memset(sca, 0, sizeof(struct vsie_sca));
+	}
+
+	/* use ECB of shadow scb to determine SCA type */
+	if (sie_uses_esca(vsie_page->scb_o))
+		__set_bit(VSIE_SCA_ESCA, &sca->flags);
+	sca->sca_gpa = sca_addr;
+	sca->pages[vsie_page->scb_o->icpua] = vsie_page;
+
+	if (sca->sca_gpa != 0) {
+		/*
+		 * The pinned original sca will only be unpinned lazily to limit the
+		 * required amount of pins/unpins on each vsie entry/exit.
+		 * The unpin is done in the reuse vsie_sca allocation path above and
+		 * kvm_s390_vsie_destroy().
+		 */
+		rc = pin_sca(kvm, vsie_page, sca);
+		if (rc) {
+			sca = ERR_PTR(rc);
+			goto out;
+		}
+	}
+
+	atomic_set(&sca->ref_count, 1);
+	radix_tree_insert(&kvm->arch.vsie.osca_to_sca, sca->sca_gpa, sca);
+
+out:
+	up_write(&kvm->arch.vsie.ssca_lock);
+	if (sca_new)
+		destroy_vsie_sca(kvm, sca_new);
+	return sca;
+}
+
+static void kvm_s390_vsie_gmap_donotify(struct gmap *gmap, unsigned long start,
+					unsigned long end, struct vsie_page *cur_page)
+{
+	unsigned long prefix;
+
+	if (!cur_page)
+		return;
+	if (READ_ONCE(cur_page->gmap) != gmap)
+		return;
+	prefix = cur_page->scb_s.prefix << GUEST_PREFIX_SHIFT;
+	/* with mso/msl, the prefix lies at an offset */
+	prefix += cur_page->scb_s.mso;
+	if (prefix <= end && start <= prefix + 2 * PAGE_SIZE - 1)
+		prefix_unmapped_sync(cur_page);
+}
+
 void kvm_s390_vsie_gmap_notifier(struct gmap *gmap, unsigned long start,
 				 unsigned long end)
 {
 	struct kvm *kvm = gmap->private;
-	struct vsie_page *cur;
-	unsigned long prefix;
+	struct vsie_page *cur_page;
+	struct vsie_sca *sca;
+	unsigned int cpu_nr;
 	int i;
 
 	if (!gmap_is_shadow(gmap))
@@ -728,16 +1013,17 @@ void kvm_s390_vsie_gmap_notifier(struct gmap *gmap, unsigned long start,
 	 * therefore we can safely reference them all the time.
 	 */
 	for (i = 0; i < kvm->arch.vsie.page_count; i++) {
-		cur = READ_ONCE(kvm->arch.vsie.pages[i]);
-		if (!cur)
-			continue;
-		if (READ_ONCE(cur->gmap) != gmap)
+		cur_page = READ_ONCE(kvm->arch.vsie.pages[i]);
+		kvm_s390_vsie_gmap_donotify(gmap, start, end, cur_page);
+	}
+	for (i = 0; i < kvm->arch.vsie.sca_count; i++) {
+		sca = READ_ONCE(kvm->arch.vsie.scas[i]);
+		if (!sca && atomic_read(&sca->ref_count))
 			continue;
-		prefix = cur->scb_s.prefix << GUEST_PREFIX_SHIFT;
-		/* with mso/msl, the prefix lies at an offset */
-		prefix += cur->scb_s.mso;
-		if (prefix <= end && start <= prefix + 2 * PAGE_SIZE - 1)
-			prefix_unmapped_sync(cur);
+		for_each_set_bit_inv(cpu_nr, (unsigned long *)sca->mcn, KVM_S390_MAX_VSIE_VCPUS) {
+			cur_page = sca->pages[cpu_nr];
+			kvm_s390_vsie_gmap_donotify(gmap, start, end, cur_page);
+		}
 	}
 }
 
@@ -789,13 +1075,6 @@ static void unpin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
 	struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
 	hpa_t hpa;
 
-	hpa = read_scao(vcpu->kvm, scb_s);
-	if (hpa) {
-		unpin_guest_page(vcpu->kvm, vsie_page->sca_gpa, hpa);
-		vsie_page->sca_gpa = 0;
-		write_scao(scb_s, 0);
-	}
-
 	hpa = scb_s->itdba;
 	if (hpa) {
 		unpin_guest_page(vcpu->kvm, vsie_page->itdba_gpa, hpa);
@@ -847,20 +1126,6 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
 	gpa_t gpa;
 	int rc = 0;
 
-	gpa = read_scao(vcpu->kvm, scb_o);
-	if (gpa) {
-		rc = validate_scao(vcpu, scb_o, gpa);
-		if (!rc) {
-			rc = pin_guest_page(vcpu->kvm, gpa, &hpa);
-			if (rc)
-				rc = set_validity_icpt(scb_s, 0x0034U);
-		}
-		if (rc)
-			goto unpin;
-		vsie_page->sca_gpa = gpa;
-		write_scao(scb_s, hpa);
-	}
-
 	gpa = READ_ONCE(scb_o->itdba) & ~0xffUL;
 	if (gpa && (scb_s->ecb & ECB_TE)) {
 		if (gpa < 2 * PAGE_SIZE) {
@@ -948,14 +1213,18 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
 }
 
 /* unpin the scb provided by guest 2, marking it as dirty */
-static void unpin_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page,
-		      gpa_t gpa)
+static void unpin_scb(struct kvm *kvm, struct vsie_page *vsie_page)
 {
-	hpa_t hpa = virt_to_phys(vsie_page->scb_o);
+	hpa_t hpa;
+
+	if (!test_bit(VSIE_PAGE_PINNED, &vsie_page->flags))
+		return;
 
+	hpa = virt_to_phys(vsie_page->scb_o);
 	if (hpa)
-		unpin_guest_page(vcpu->kvm, gpa, hpa);
+		unpin_guest_page(kvm, vsie_page->scb_gpa, hpa);
 	vsie_page->scb_o = NULL;
+	clear_bit(VSIE_PAGE_PINNED, &vsie_page->flags);
 }
 
 /*
@@ -964,19 +1233,22 @@ static void unpin_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page,
  * Returns: - 0 if the scb was pinned.
  *          - > 0 if control has to be given to guest 2
  */
-static int pin_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page,
-		   gpa_t gpa)
+static int pin_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
 {
 	hpa_t hpa;
 	int rc;
 
-	rc = pin_guest_page(vcpu->kvm, gpa, &hpa);
+	if (test_bit(VSIE_PAGE_PINNED, &vsie_page->flags))
+		return 0;
+
+	rc = pin_guest_page(vcpu->kvm, vsie_page->scb_gpa, &hpa);
 	if (rc) {
 		rc = kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
 		WARN_ON_ONCE(rc);
 		return 1;
 	}
 	vsie_page->scb_o = phys_to_virt(hpa);
+	__set_bit(VSIE_PAGE_PINNED, &vsie_page->flags);
 	return 0;
 }
 
@@ -1453,75 +1725,129 @@ static void put_vsie_page(struct vsie_page *vsie_page)
 	clear_bit(VSIE_PAGE_IN_USE, &vsie_page->flags);
 }
 
+static void free_vsie_page(struct vsie_page *vsie_page)
+{
+	free_page((unsigned long)vsie_page);
+}
+
+static struct vsie_page *malloc_vsie_page(struct kvm *kvm)
+{
+	struct vsie_page *vsie_page;
+
+	vsie_page = (void *)__get_free_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO | GFP_DMA);
+	if (!vsie_page)
+		return ERR_PTR(-ENOMEM);
+
+	/* Mark it as invalid until it resides in the tree. */
+	vsie_page->scb_gpa = ULONG_MAX;
+	return vsie_page;
+}
+
 /*
  * Get or create a vsie page for a scb address.
  *
+ * Original control blocks are pinned when the vsie_page pointing to them is
+ * returned.
+ * Newly created vsie_pages only have vsie_page->scb_gpa and vsie_page->sca_gpa
+ * set.
+ *
  * Returns: - address of a vsie page (cached or new one)
  *          - NULL if the same scb address is already used by another VCPU
  *          - ERR_PTR(-ENOMEM) if out of memory
  */
-static struct vsie_page *get_vsie_page(struct kvm *kvm, unsigned long addr)
+static struct vsie_page *get_vsie_page(struct kvm_vcpu *vcpu, unsigned long addr)
 {
-	struct vsie_page *vsie_page;
-	int nr_vcpus;
+	struct vsie_page *vsie_page, *vsie_page_new;
+	struct kvm *kvm = vcpu->kvm;
+	unsigned int max_vsie_page;
+	int rc, pages_idx;
+	gpa_t sca_addr;
 
-	rcu_read_lock();
 	vsie_page = radix_tree_lookup(&kvm->arch.vsie.addr_to_page, addr >> 9);
-	rcu_read_unlock();
-	if (vsie_page) {
-		if (try_get_vsie_page(vsie_page)) {
-			if (vsie_page->scb_gpa == addr)
-				return vsie_page;
-			/*
-			 * We raced with someone reusing + putting this vsie
-			 * page before we grabbed it.
-			 */
-			put_vsie_page(vsie_page);
-		}
+	if (vsie_page && try_get_vsie_page(vsie_page)) {
+		if (vsie_page->scb_gpa == addr)
+			return vsie_page;
+		/*
+		 * We raced with someone reusing + putting this vsie
+		 * page before we grabbed it.
+		 */
+		put_vsie_page(vsie_page);
 	}
 
-	/*
-	 * We want at least #online_vcpus shadows, so every VCPU can execute
-	 * the VSIE in parallel.
-	 */
-	nr_vcpus = atomic_read(&kvm->online_vcpus);
+	max_vsie_page = MIN(atomic_read(&kvm->online_vcpus), KVM_S390_MAX_VSIE_VCPUS);
+
+	/* allocate new vsie_page - we will likely need it */
+	if (addr || kvm->arch.vsie.page_count < max_vsie_page) {
+		vsie_page_new = malloc_vsie_page(kvm);
+		if (IS_ERR(vsie_page_new))
+			return vsie_page_new;
+	}
 
 	mutex_lock(&kvm->arch.vsie.mutex);
-	if (kvm->arch.vsie.page_count < nr_vcpus) {
-		vsie_page = (void *)__get_free_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO | GFP_DMA);
-		if (!vsie_page) {
-			mutex_unlock(&kvm->arch.vsie.mutex);
-			return ERR_PTR(-ENOMEM);
-		}
-		__set_bit(VSIE_PAGE_IN_USE, &vsie_page->flags);
-		kvm->arch.vsie.pages[kvm->arch.vsie.page_count] = vsie_page;
+	if (addr || kvm->arch.vsie.page_count < max_vsie_page) {
+		pages_idx = kvm->arch.vsie.page_count;
+		vsie_page = vsie_page_new;
+		vsie_page_new = NULL;
+		kvm->arch.vsie.pages[kvm->arch.vsie.page_count] = vsie_page_new;
 		kvm->arch.vsie.page_count++;
 	} else {
 		/* reuse an existing entry that belongs to nobody */
+		if (vsie_page_new)
+			free_vsie_page(vsie_page_new);
 		while (true) {
 			vsie_page = kvm->arch.vsie.pages[kvm->arch.vsie.next];
-			if (try_get_vsie_page(vsie_page))
+			if (try_get_vsie_page(vsie_page)) {
+				pages_idx = kvm->arch.vsie.next;
 				break;
+			}
 			kvm->arch.vsie.next++;
-			kvm->arch.vsie.next %= nr_vcpus;
+			kvm->arch.vsie.next %= max_vsie_page;
 		}
+
+		unpin_scb(kvm, vsie_page);
 		if (vsie_page->scb_gpa != ULONG_MAX)
 			radix_tree_delete(&kvm->arch.vsie.addr_to_page,
 					  vsie_page->scb_gpa >> 9);
 	}
-	/* Mark it as invalid until it resides in the tree. */
-	vsie_page->scb_gpa = ULONG_MAX;
+
+	vsie_page->scb_gpa = addr;
+	rc = pin_scb(vcpu, vsie_page);
+	if (rc) {
+		vsie_page->scb_gpa = ULONG_MAX;
+		free_vsie_page(vsie_page);
+		mutex_unlock(&kvm->arch.vsie.mutex);
+		return ERR_PTR(-ENOMEM);
+	}
+	sca_addr = read_scao(kvm, vsie_page->scb_o);
+	vsie_page->sca_gpa = sca_addr;
+	__set_bit(VSIE_PAGE_IN_USE, &vsie_page->flags);
 
 	/* Double use of the same address or allocation failure. */
 	if (radix_tree_insert(&kvm->arch.vsie.addr_to_page, addr >> 9,
 			      vsie_page)) {
+		unpin_scb(kvm, vsie_page);
 		put_vsie_page(vsie_page);
 		mutex_unlock(&kvm->arch.vsie.mutex);
 		return NULL;
 	}
-	vsie_page->scb_gpa = addr;
 	mutex_unlock(&kvm->arch.vsie.mutex);
 
+	/*
+	 * If the vsie cb does use a sca we store the vsie_page within the
+	 * vsie_sca later. But we need to allocate an empty page to leave no
+	 * hole in the arch.vsie.pages.
+	 */
+	if (sca_addr) {
+		vsie_page_new = malloc_vsie_page(kvm);
+		if (IS_ERR(vsie_page_new)) {
+			unpin_scb(kvm, vsie_page);
+			put_vsie_page(vsie_page);
+			return vsie_page_new;
+		}
+		kvm->arch.vsie.pages[pages_idx] = vsie_page_new;
+		vsie_page_new = NULL;
+	}
+
 	memset(&vsie_page->scb_s, 0, sizeof(struct kvm_s390_sie_block));
 	release_gmap_shadow(vsie_page);
 	vsie_page->fault_addr = 0;
@@ -1529,11 +1855,124 @@ static struct vsie_page *get_vsie_page(struct kvm *kvm, unsigned long addr)
 	return vsie_page;
 }
 
+static struct vsie_page *get_vsie_page_cpu_nr(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page,
+					      gpa_t scb_o_gpa, u16 cpu_nr)
+{
+	struct vsie_page *vsie_page_n;
+
+	vsie_page_n = get_vsie_page(vcpu, scb_o_gpa);
+	if (IS_ERR(vsie_page_n))
+		return vsie_page_n;
+	shadow_scb(vcpu, vsie_page_n);
+	vsie_page_n->scb_s.eca |= vsie_page->scb_o->eca & ECA_SIGPI;
+	vsie_page_n->scb_s.ecb |= vsie_page->scb_o->ecb & ECB_SRSI;
+	put_vsie_page(vsie_page_n);
+	WARN_ON_ONCE(!((u64)vsie_page_n->scb_gpa & PAGE_MASK));
+	WARN_ON_ONCE(!((u64)vsie_page_n & PAGE_MASK));
+
+	return vsie_page_n;
+}
+
+/*
+ * Fill the shadow system control area used for vsie sigpif.
+ */
+static int init_ssca(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page, struct vsie_sca *sca)
+{
+	hpa_t sca_o_entry_hpa, osca = sca->sca_o_pages[0].hpa;
+	bool is_esca = sie_uses_esca(vsie_page->scb_o);
+	unsigned int cpu_nr, cpu_slots;
+	struct vsie_page *vsie_page_n;
+	gpa_t scb_o_gpa;
+	int i;
+
+	/* copy mcn to detect updates */
+	if (is_esca)
+		for (i = 0; i < 4; i++)
+			sca->mcn[i] = ((struct esca_block *)phys_to_virt(osca))->mcn[i];
+	else
+		sca->mcn[0] = ((struct bsca_block *)phys_to_virt(osca))->mcn;
+
+	/* pin and make minimal shadow for ALL scb in the sca */
+	cpu_slots = is_esca ? KVM_S390_MAX_VSIE_VCPUS : KVM_S390_BSCA_CPU_SLOTS;
+	for_each_set_bit_inv(cpu_nr, (unsigned long *)&vsie_page->sca->mcn, cpu_slots) {
+		get_sca_entry_addr(vcpu->kvm, vsie_page, sca, cpu_nr, NULL, &sca_o_entry_hpa);
+		if (is_esca)
+			scb_o_gpa = ((struct esca_entry *)sca_o_entry_hpa)->sda;
+		else
+			scb_o_gpa = ((struct bsca_entry *)sca_o_entry_hpa)->sda;
+
+		if (vsie_page->scb_s.icpua == cpu_nr)
+			vsie_page_n = vsie_page;
+		else
+			vsie_page_n = get_vsie_page_cpu_nr(vcpu, vsie_page, scb_o_gpa, cpu_nr);
+		if (IS_ERR(vsie_page_n))
+			goto err;
+
+		if (!sca->pages[vsie_page_n->scb_o->icpua])
+			sca->pages[vsie_page_n->scb_o->icpua] = vsie_page_n;
+		WARN_ON_ONCE(sca->pages[vsie_page_n->scb_o->icpua] != vsie_page_n);
+		sca->ssca->cpu[cpu_nr].ssda = virt_to_phys(&vsie_page_n->scb_s);
+		sca->ssca->cpu[cpu_nr].ossea = sca_o_entry_hpa;
+	}
+
+	sca->ssca->osca = osca;
+	return 0;
+
+err:
+	for_each_set_bit_inv(cpu_nr, (unsigned long *)&vsie_page->sca->mcn, cpu_slots) {
+		sca->ssca->cpu[cpu_nr].ssda = 0;
+		sca->ssca->cpu[cpu_nr].ossea = 0;
+	}
+	return PTR_ERR(vsie_page_n);
+}
+
+/*
+ * Shadow the sca on vsie enter.
+ */
+static int shadow_sca(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page, struct vsie_sca *sca)
+{
+	struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
+	int rc;
+
+	vsie_page->sca = sca;
+	if (!sca)
+		return false;
+
+	if (!sca->pages[vsie_page->scb_o->icpua])
+		sca->pages[vsie_page->scb_o->icpua] = vsie_page;
+	WARN_ON_ONCE(sca->pages[vsie_page->scb_o->icpua] != vsie_page);
+
+	if (!sca->ssca)
+		return false;
+	if (!use_vsie_sigpif_for(vcpu->kvm, vsie_page))
+		return false;
+
+	/* skip if the guest does not have an usable sca */
+	if (!sca->ssca->osca) {
+		rc = init_ssca(vcpu, vsie_page, sca);
+		if (rc)
+			return rc;
+	}
+
+	/*
+	 * only shadow sigpif if we actually have a sca that we can properly
+	 * shadow with vsie_sigpif
+	 */
+	scb_s->eca |= vsie_page->scb_o->eca & ECA_SIGPI;
+	scb_s->ecb |= vsie_page->scb_o->ecb & ECB_SRSI;
+
+	WRITE_ONCE(scb_s->osda, virt_to_phys(vsie_page->scb_o));
+	write_scao(scb_s, virt_to_phys(sca->ssca));
+
+	return false;
+}
+
 int kvm_s390_handle_vsie(struct kvm_vcpu *vcpu)
 {
 	struct vsie_page *vsie_page;
-	unsigned long scb_addr;
-	int rc;
+	struct vsie_sca *sca = NULL;
+	gpa_t scb_addr;
+	int rc = 0;
 
 	vcpu->stat.instruction_sie++;
 	if (!test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_SIEF2))
@@ -1554,31 +1993,45 @@ int kvm_s390_handle_vsie(struct kvm_vcpu *vcpu)
 		return 0;
 	}
 
-	vsie_page = get_vsie_page(vcpu->kvm, scb_addr);
+	/* get the vsie_page including the vsie control block */
+	vsie_page = get_vsie_page(vcpu, scb_addr);
 	if (IS_ERR(vsie_page))
 		return PTR_ERR(vsie_page);
-	else if (!vsie_page)
+	if (!vsie_page)
 		/* double use of sie control block - simply do nothing */
 		return 0;
 
-	rc = pin_scb(vcpu, vsie_page, scb_addr);
-	if (rc)
-		goto out_put;
+	/* get the vsie_sca including references to the original sca and all cbs */
+	if (vsie_page->sca_gpa) {
+		sca = get_vsie_sca(vcpu, vsie_page, vsie_page->sca_gpa);
+		if (IS_ERR(sca)) {
+			rc = PTR_ERR(sca);
+			goto out_put_vsie_page;
+		}
+	}
+
+	/* shadow scb and sca for vsie_run */
 	rc = shadow_scb(vcpu, vsie_page);
 	if (rc)
-		goto out_unpin_scb;
+		goto out_put_vsie_sca;
+	rc = shadow_sca(vcpu, vsie_page, sca);
+	if (rc)
+		goto out_unshadow_scb;
+
 	rc = pin_blocks(vcpu, vsie_page);
 	if (rc)
-		goto out_unshadow;
+		goto out_unshadow_scb;
 	register_shadow_scb(vcpu, vsie_page);
+
 	rc = vsie_run(vcpu, vsie_page);
+
 	unregister_shadow_scb(vcpu);
 	unpin_blocks(vcpu, vsie_page);
-out_unshadow:
+out_unshadow_scb:
 	unshadow_scb(vcpu, vsie_page);
-out_unpin_scb:
-	unpin_scb(vcpu, vsie_page, scb_addr);
-out_put:
+out_put_vsie_sca:
+	put_vsie_sca(sca);
+out_put_vsie_page:
 	put_vsie_page(vsie_page);
 
 	return rc < 0 ? rc : 0;
@@ -1589,27 +2042,58 @@ void kvm_s390_vsie_init(struct kvm *kvm)
 {
 	mutex_init(&kvm->arch.vsie.mutex);
 	INIT_RADIX_TREE(&kvm->arch.vsie.addr_to_page, GFP_KERNEL_ACCOUNT);
+	init_rwsem(&kvm->arch.vsie.ssca_lock);
+	INIT_RADIX_TREE(&kvm->arch.vsie.osca_to_sca, GFP_KERNEL_ACCOUNT);
+}
+
+static void kvm_s390_vsie_destroy_page(struct kvm *kvm, struct vsie_page *vsie_page)
+{
+	if (!vsie_page)
+		return;
+	unpin_scb(kvm, vsie_page);
+	release_gmap_shadow(vsie_page);
+	/* free the radix tree entry */
+	if (vsie_page->scb_gpa != ULONG_MAX)
+		radix_tree_delete(&kvm->arch.vsie.addr_to_page,
+				  vsie_page->scb_gpa >> 9);
+	free_vsie_page(vsie_page);
 }
 
 /* Destroy the vsie data structures. To be called when a vm is destroyed. */
 void kvm_s390_vsie_destroy(struct kvm *kvm)
 {
 	struct vsie_page *vsie_page;
-	int i;
+	struct vsie_sca *sca;
+	int i, j;
 
 	mutex_lock(&kvm->arch.vsie.mutex);
 	for (i = 0; i < kvm->arch.vsie.page_count; i++) {
 		vsie_page = kvm->arch.vsie.pages[i];
 		kvm->arch.vsie.pages[i] = NULL;
-		release_gmap_shadow(vsie_page);
-		/* free the radix tree entry */
-		if (vsie_page->scb_gpa != ULONG_MAX)
-			radix_tree_delete(&kvm->arch.vsie.addr_to_page,
-					  vsie_page->scb_gpa >> 9);
-		free_page((unsigned long)vsie_page);
+		kvm_s390_vsie_destroy_page(kvm, vsie_page);
 	}
-	kvm->arch.vsie.page_count = 0;
 	mutex_unlock(&kvm->arch.vsie.mutex);
+	down_write(&kvm->arch.vsie.ssca_lock);
+	for (i = 0; i < kvm->arch.vsie.sca_count; i++) {
+		sca = kvm->arch.vsie.scas[i];
+		kvm->arch.vsie.scas[i] = NULL;
+
+		mutex_lock(&kvm->arch.vsie.mutex);
+		for (j = 0; j < KVM_S390_MAX_VSIE_VCPUS; j++) {
+			vsie_page = sca->pages[j];
+			sca->pages[j] = NULL;
+			kvm_s390_vsie_destroy_page(kvm, vsie_page);
+		}
+		sca->page_count = 0;
+		mutex_unlock(&kvm->arch.vsie.mutex);
+
+		unpin_sca(kvm, sca);
+		atomic_set(&sca->ref_count, 0);
+		radix_tree_delete(&kvm->arch.vsie.osca_to_sca, sca->sca_gpa);
+		free_pages_exact(sca, sizeof(*sca));
+	}
+	kvm->arch.vsie.sca_count = 0;
+	up_write(&kvm->arch.vsie.ssca_lock);
 }
 
 void kvm_s390_vsie_kick(struct kvm_vcpu *vcpu)

-- 
2.51.1


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

* [PATCH RFC v2 08/11] KVM: s390: Allow guest-3 cpu add and remove with vsie sigpif
  2025-11-10 17:16 [PATCH RFC v2 00/11] KVM: s390: Add VSIE SIGP Interpretation (vsie_sigpif) Christoph Schlameuss
                   ` (6 preceding siblings ...)
  2025-11-10 17:16 ` [PATCH RFC v2 07/11] KVM: s390: Shadow VSIE SCA in guest-1 Christoph Schlameuss
@ 2025-11-10 17:16 ` Christoph Schlameuss
  2025-11-11 15:47   ` Janosch Frank
  2025-11-10 17:16 ` [PATCH RFC v2 09/11] KVM: s390: Allow guest-3 switch to extended sca " Christoph Schlameuss
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 23+ messages in thread
From: Christoph Schlameuss @ 2025-11-10 17:16 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Janosch Frank, Claudio Imbrenda,
	Nico Boehr, David Hildenbrand, Sven Schnelle, Paolo Bonzini,
	Shuah Khan, Christoph Schlameuss

As we are shadowing the SCA we need to add and remove the pointers to
the shadowed control blocks and sca entries whenever the mcn changes.

It is not expected that the mcn changes frequently for a already running
guest-3 configuration. So we can simply re-init the ssca whenever the
mcn changes.
To detect the mcn change we store the expected mcn in the struct
vsie_sca when running the ssca init.

Signed-off-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
---
 arch/s390/kvm/vsie.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c
index 72c794945be916cc107aba74e1609d3b4780d4b9..1e15220e1f1ecfd83b10aa0620ca84ff0ff3c1ac 100644
--- a/arch/s390/kvm/vsie.c
+++ b/arch/s390/kvm/vsie.c
@@ -1926,12 +1926,27 @@ static int init_ssca(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page, struct
 	return PTR_ERR(vsie_page_n);
 }
 
+static bool sca_mcn_equals(struct vsie_sca *sca, u64 *mcn)
+{
+	bool is_esca = test_bit(VSIE_SCA_ESCA, &sca->flags);
+	int i;
+
+	if (!is_esca)
+		return ((struct bsca_block *)phys_to_virt(sca->ssca->osca))->mcn == *mcn;
+
+	for (i = 0; i < 4; i++)
+		if (((struct esca_block *)phys_to_virt(sca->ssca->osca))->mcn[i] != sca->mcn[i])
+			return false;
+	return true;
+}
+
 /*
  * Shadow the sca on vsie enter.
  */
 static int shadow_sca(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page, struct vsie_sca *sca)
 {
 	struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
+	bool do_init_ssca;
 	int rc;
 
 	vsie_page->sca = sca;
@@ -1947,8 +1962,9 @@ static int shadow_sca(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page, struct
 	if (!use_vsie_sigpif_for(vcpu->kvm, vsie_page))
 		return false;
 
-	/* skip if the guest does not have an usable sca */
-	if (!sca->ssca->osca) {
+	do_init_ssca = !sca->ssca->osca;
+	do_init_ssca = do_init_ssca || !sca_mcn_equals(sca, sca->mcn);
+	if (do_init_ssca) {
 		rc = init_ssca(vcpu, vsie_page, sca);
 		if (rc)
 			return rc;

-- 
2.51.1


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

* [PATCH RFC v2 09/11] KVM: s390: Allow guest-3 switch to extended sca with vsie sigpif
  2025-11-10 17:16 [PATCH RFC v2 00/11] KVM: s390: Add VSIE SIGP Interpretation (vsie_sigpif) Christoph Schlameuss
                   ` (7 preceding siblings ...)
  2025-11-10 17:16 ` [PATCH RFC v2 08/11] KVM: s390: Allow guest-3 cpu add and remove with vsie sigpif Christoph Schlameuss
@ 2025-11-10 17:16 ` Christoph Schlameuss
  2025-11-11 14:18   ` Janosch Frank
  2025-11-10 17:16 ` [PATCH RFC v2 10/11] KVM: s390: Add VSIE shadow configuration Christoph Schlameuss
  2025-11-10 17:16 ` [PATCH RFC v2 11/11] KVM: s390: Add VSIE shadow stat counters Christoph Schlameuss
  10 siblings, 1 reply; 23+ messages in thread
From: Christoph Schlameuss @ 2025-11-10 17:16 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Janosch Frank, Claudio Imbrenda,
	Nico Boehr, David Hildenbrand, Sven Schnelle, Paolo Bonzini,
	Shuah Khan, Christoph Schlameuss

If a guest wants to use more than 64 and use sigp interpretation it
needs to use the extended system control area. When the ESCA is not
already used and the 65th cpu is added the VM host will kick all cpus
destroy the old basic system control area (BSCA) and create a new ESCA
for the guest configuration.

In VSIE execution using vsie sigpif this also means the SSCA need to be
updated. The structure of the SSCA remains the same but the pointers to
the original SCA as well as its entries will have changed.

In guest-1 we can detect this change relatively simple as the original
SCA address changes.

Signed-off-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
---
 arch/s390/kvm/vsie.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c
index 1e15220e1f1ecfd83b10aa0620ca84ff0ff3c1ac..b69ef763b55296875522f2e63169446b5e2d5053 100644
--- a/arch/s390/kvm/vsie.c
+++ b/arch/s390/kvm/vsie.c
@@ -932,8 +932,16 @@ static struct vsie_sca *get_vsie_sca(struct kvm_vcpu *vcpu, struct vsie_page *vs
 	if (sca)
 		goto out;
 
+	if (vsie_page->sca) {
+		/* switch to extended system control area (esca) */
+		sca = vsie_page->sca;
+		WARN_ON_ONCE(atomic_read(&sca->ref_count));
+		unpin_sca(kvm, sca);
+		/* trigger init_ssca() later */
+		if (sca->ssca)
+			sca->ssca->osca = 0;
 	/* check again under write lock if we are still under our sca_count limit */
-	if (sca_new && kvm->arch.vsie.sca_count < max_sca) {
+	} else if (sca_new && kvm->arch.vsie.sca_count < max_sca) {
 		/* make use of vsie_sca just created */
 		sca = sca_new;
 		sca_new = NULL;

-- 
2.51.1


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

* [PATCH RFC v2 10/11] KVM: s390: Add VSIE shadow configuration
  2025-11-10 17:16 [PATCH RFC v2 00/11] KVM: s390: Add VSIE SIGP Interpretation (vsie_sigpif) Christoph Schlameuss
                   ` (8 preceding siblings ...)
  2025-11-10 17:16 ` [PATCH RFC v2 09/11] KVM: s390: Allow guest-3 switch to extended sca " Christoph Schlameuss
@ 2025-11-10 17:16 ` Christoph Schlameuss
  2025-11-10 17:16 ` [PATCH RFC v2 11/11] KVM: s390: Add VSIE shadow stat counters Christoph Schlameuss
  10 siblings, 0 replies; 23+ messages in thread
From: Christoph Schlameuss @ 2025-11-10 17:16 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Janosch Frank, Claudio Imbrenda,
	Nico Boehr, David Hildenbrand, Sven Schnelle, Paolo Bonzini,
	Shuah Khan, Christoph Schlameuss

Introduce two new module parameters allowing to keep more shadow
structures

* vsie_shadow_scb_max
  Override the maximum number of VSIE control blocks / vsie_pages to
  shadow in guest-1. KVM will use the maximum of the current number of
  vCPUs and a maximum of 256 or this value if it is lower.
  This is the number of guest-3 control blocks / CPUs to keep shadowed
  to minimize the repeated shadowing effort.

* vsie_shadow_sca_max
  Override the maximum number of VSIE system control areas to
  shadow in guest-1. KVM will use a minimum of the current number of
  vCPUs and a maximum of 256 or this value if it is lower.
  This is the number of guest-3 system control areas / VMs to keep
  shadowed to minimize repeated shadowing effort.

Signed-off-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
---
 arch/s390/kvm/vsie.c | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c
index b69ef763b55296875522f2e63169446b5e2d5053..cd114df5e119bd289d14037d1f1c5bfe148cf5c7 100644
--- a/arch/s390/kvm/vsie.c
+++ b/arch/s390/kvm/vsie.c
@@ -98,9 +98,19 @@ struct vsie_sca {
 	struct vsie_page	*pages[KVM_S390_MAX_VSIE_VCPUS];
 };
 
+/* maximum vsie shadow scb */
+unsigned int vsie_shadow_scb_max;
+module_param(vsie_shadow_scb_max, uint, 0644);
+MODULE_PARM_DESC(vsie_shadow_scb_max, "Maximum number of VSIE shadow control blocks to keep. Values smaller number vcpus uses number of vcpus; maximum 256");
+
+/* maximum vsie shadow sca */
+unsigned int vsie_shadow_sca_max;
+module_param(vsie_shadow_sca_max, uint, 0644);
+MODULE_PARM_DESC(vsie_shadow_sca_max, "Maximum number of VSIE shadow system control areas to keep. Values smaller number of vcpus uses number of vcpus; 0 to disable sca shadowing; maximum 256");
+
 static inline bool use_vsie_sigpif(struct kvm *kvm)
 {
-	return kvm->arch.use_vsie_sigpif;
+	return kvm->arch.use_vsie_sigpif && vsie_shadow_sca_max;
 }
 
 static inline bool use_vsie_sigpif_for(struct kvm *kvm, struct vsie_page *vsie_page)
@@ -907,7 +917,8 @@ static struct vsie_sca *get_vsie_sca(struct kvm_vcpu *vcpu, struct vsie_page *vs
 	 * We want at least #online_vcpus shadows, so every VCPU can execute the
 	 * VSIE in parallel. (Worst case all single core VMs.)
 	 */
-	max_sca = MIN(atomic_read(&kvm->online_vcpus), KVM_S390_MAX_VSIE_VCPUS);
+	max_sca = MIN(MAX(atomic_read(&kvm->online_vcpus), vsie_shadow_sca_max),
+		      KVM_S390_MAX_VSIE_VCPUS);
 	if (kvm->arch.vsie.sca_count < max_sca) {
 		BUILD_BUG_ON(sizeof(struct vsie_sca) > PAGE_SIZE);
 		sca_new = (void *)__get_free_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO);
@@ -1782,7 +1793,8 @@ static struct vsie_page *get_vsie_page(struct kvm_vcpu *vcpu, unsigned long addr
 		put_vsie_page(vsie_page);
 	}
 
-	max_vsie_page = MIN(atomic_read(&kvm->online_vcpus), KVM_S390_MAX_VSIE_VCPUS);
+	max_vsie_page = MIN(MAX(atomic_read(&kvm->online_vcpus), vsie_shadow_scb_max),
+			    KVM_S390_MAX_VSIE_VCPUS);
 
 	/* allocate new vsie_page - we will likely need it */
 	if (addr || kvm->arch.vsie.page_count < max_vsie_page) {

-- 
2.51.1


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

* [PATCH RFC v2 11/11] KVM: s390: Add VSIE shadow stat counters
  2025-11-10 17:16 [PATCH RFC v2 00/11] KVM: s390: Add VSIE SIGP Interpretation (vsie_sigpif) Christoph Schlameuss
                   ` (9 preceding siblings ...)
  2025-11-10 17:16 ` [PATCH RFC v2 10/11] KVM: s390: Add VSIE shadow configuration Christoph Schlameuss
@ 2025-11-10 17:16 ` Christoph Schlameuss
  10 siblings, 0 replies; 23+ messages in thread
From: Christoph Schlameuss @ 2025-11-10 17:16 UTC (permalink / raw)
  To: kvm
  Cc: linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Janosch Frank, Claudio Imbrenda,
	Nico Boehr, David Hildenbrand, Sven Schnelle, Paolo Bonzini,
	Shuah Khan, Christoph Schlameuss

Add new stat counters to VSIE shadowing to be able to verify and monitor
the functionality.

* vsie_shadow_scb shows the number of allocated SIE control block
  shadows. Should count upwards between 0 and the max number of cpus.
* vsie_shadow_sca shows the number of allocated system control area
  shadows. Should count upwards between 0 and the max number of cpus.
* vsie_shadow_sca_create shows the number of newly allocated system
  control area shadows.
* vsie_shadow_sca_reuse shows the number of reused system control area
  shadows.

Signed-off-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
---
 arch/s390/include/asm/kvm_host.h | 4 ++++
 arch/s390/kvm/kvm-s390.c         | 4 ++++
 arch/s390/kvm/vsie.c             | 9 ++++++++-
 3 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 191b23edf0ac7e9a3e1fd9cdc6fc4c9a9e6769f8..ef7bf2d357f8d289b5f163ec95976c5d270d1380 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -457,6 +457,10 @@ struct kvm_vm_stat {
 	u64 gmap_shadow_r3_entry;
 	u64 gmap_shadow_sg_entry;
 	u64 gmap_shadow_pg_entry;
+	u64 vsie_shadow_scb;
+	u64 vsie_shadow_sca;
+	u64 vsie_shadow_sca_create;
+	u64 vsie_shadow_sca_reuse;
 };
 
 struct kvm_arch_memory_slot {
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index e3fc53e33e90be7dab75f73ebd0b949c13d22939..d86bf2206c230ce25fd48610c8305326e260e590 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -79,6 +79,10 @@ const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
 	STATS_DESC_COUNTER(VM, gmap_shadow_r3_entry),
 	STATS_DESC_COUNTER(VM, gmap_shadow_sg_entry),
 	STATS_DESC_COUNTER(VM, gmap_shadow_pg_entry),
+	STATS_DESC_COUNTER(VM, vsie_shadow_scb),
+	STATS_DESC_COUNTER(VM, vsie_shadow_sca),
+	STATS_DESC_COUNTER(VM, vsie_shadow_sca_create),
+	STATS_DESC_COUNTER(VM, vsie_shadow_sca_reuse),
 };
 
 const struct kvm_stats_header kvm_vm_stats_header = {
diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c
index cd114df5e119bd289d14037d1f1c5bfe148cf5c7..f7c1a217173cefe93d0914623df08efa14270771 100644
--- a/arch/s390/kvm/vsie.c
+++ b/arch/s390/kvm/vsie.c
@@ -767,6 +767,8 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
 out:
 	if (rc)
 		unshadow_scb(vcpu, vsie_page);
+	else
+		vcpu->kvm->stat.vsie_shadow_scb++;
 	return rc;
 }
 
@@ -843,8 +845,10 @@ static struct vsie_sca *get_existing_vsie_sca(struct kvm *kvm, hpa_t sca_o_gpa)
 {
 	struct vsie_sca *sca = radix_tree_lookup(&kvm->arch.vsie.osca_to_sca, sca_o_gpa);
 
-	if (sca)
+	if (sca) {
 		WARN_ON_ONCE(atomic_inc_return(&sca->ref_count) < 1);
+		kvm->stat.vsie_shadow_sca_reuse++;
+	}
 	return sca;
 }
 
@@ -958,6 +962,8 @@ static struct vsie_sca *get_vsie_sca(struct kvm_vcpu *vcpu, struct vsie_page *vs
 		sca_new = NULL;
 
 		kvm->arch.vsie.scas[kvm->arch.vsie.sca_count] = sca;
+		kvm->arch.vsie.sca_count++;
+		kvm->stat.vsie_shadow_sca++;
 	} else {
 		/* reuse previously created vsie_sca allocation for different osca */
 		sca = get_free_existing_vsie_sca(kvm);
@@ -992,6 +998,7 @@ static struct vsie_sca *get_vsie_sca(struct kvm_vcpu *vcpu, struct vsie_page *vs
 
 	atomic_set(&sca->ref_count, 1);
 	radix_tree_insert(&kvm->arch.vsie.osca_to_sca, sca->sca_gpa, sca);
+	kvm->stat.vsie_shadow_sca_create++;
 
 out:
 	up_write(&kvm->arch.vsie.ssca_lock);

-- 
2.51.1


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

* Re: [PATCH RFC v2 03/11] KVM: s390: Move scao validation into a function
  2025-11-10 17:16 ` [PATCH RFC v2 03/11] KVM: s390: Move scao validation into a function Christoph Schlameuss
@ 2025-11-10 21:30   ` Eric Farman
  2025-11-11  8:48     ` Christoph Schlameuss
  0 siblings, 1 reply; 23+ messages in thread
From: Eric Farman @ 2025-11-10 21:30 UTC (permalink / raw)
  To: Christoph Schlameuss, kvm
  Cc: linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Janosch Frank, Claudio Imbrenda,
	Nico Boehr, David Hildenbrand, Sven Schnelle, Paolo Bonzini,
	Shuah Khan

On Mon, 2025-11-10 at 18:16 +0100, Christoph Schlameuss wrote:
> This improves readability as well as allows re-use in coming patches.
> 
> Signed-off-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
> ---
>  arch/s390/kvm/vsie.c | 27 ++++++++++++++++++++-------
>  1 file changed, 20 insertions(+), 7 deletions(-)
> 
> diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c
> index ced2ca4ce5b584403d900ed11cb064919feda8e9..3d602bbd1f70b7bd8ddc2c54d43027dc37a6e032 100644
> --- a/arch/s390/kvm/vsie.c
> +++ b/arch/s390/kvm/vsie.c
> @@ -95,6 +95,25 @@ static int set_validity_icpt(struct kvm_s390_sie_block *scb,
>  	return 1;
>  }
>  
> +/* The sca header must not cross pages etc. */
> +static int validate_scao(struct kvm_vcpu *vcpu, struct kvm_s390_sie_block *scb, gpa_t gpa)
> +{
> +	int offset;
> +
> +	if (gpa < 2 * PAGE_SIZE)
> +		return set_validity_icpt(scb, 0x0038U);
> +	if ((gpa & ~0x1fffUL) == kvm_s390_get_prefix(vcpu))
> +		return set_validity_icpt(scb, 0x0011U);
> +
> +	if (sie_uses_esca(scb))

This helper doesn't turn up until patch 7

> +		offset = offsetof(struct esca_block, cpu[0]) - 1;
> +	else
> +		offset = offsetof(struct bsca_block, cpu[0]) - 1;
> +	if ((gpa & PAGE_MASK) != ((gpa + offset) & PAGE_MASK))
> +		return set_validity_icpt(scb, 0x003bU);
> +	return false;
> +}
> +
>  /* mark the prefix as unmapped, this will block the VSIE */
>  static void prefix_unmapped(struct vsie_page *vsie_page)
>  {
> @@ -791,13 +810,7 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
>  
>  	gpa = read_scao(vcpu->kvm, scb_o);
>  	if (gpa) {
> -		if (gpa < 2 * PAGE_SIZE)
> -			rc = set_validity_icpt(scb_s, 0x0038U);
> -		else if ((gpa & ~0x1fffUL) == kvm_s390_get_prefix(vcpu))
> -			rc = set_validity_icpt(scb_s, 0x0011U);
> -		else if ((gpa & PAGE_MASK) !=
> -			 ((gpa + sizeof(struct bsca_block) - 1) & PAGE_MASK))
> -			rc = set_validity_icpt(scb_s, 0x003bU);
> +		rc = validate_scao(vcpu, scb_o, gpa);
>  		if (!rc) {
>  			rc = pin_guest_page(vcpu->kvm, gpa, &hpa);
>  			if (rc)

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

* Re: [PATCH RFC v2 02/11] KVM: s390: Remove double 64bscao feature check
  2025-11-10 17:16 ` [PATCH RFC v2 02/11] KVM: s390: Remove double 64bscao feature check Christoph Schlameuss
@ 2025-11-10 21:32   ` Eric Farman
  2025-11-11  8:13   ` Hendrik Brueckner
  2025-11-11 13:20   ` Janosch Frank
  2 siblings, 0 replies; 23+ messages in thread
From: Eric Farman @ 2025-11-10 21:32 UTC (permalink / raw)
  To: Christoph Schlameuss, kvm
  Cc: linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Janosch Frank, Claudio Imbrenda,
	Nico Boehr, David Hildenbrand, Sven Schnelle, Paolo Bonzini,
	Shuah Khan

On Mon, 2025-11-10 at 18:16 +0100, Christoph Schlameuss wrote:
> sclp.has_64bscao is already verified in the guard clause a few lines
> above this. So we cannot reach this code if it is not true.
> 
> Signed-off-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
> ---
>  arch/s390/kvm/kvm-s390.c | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)
> 
> diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
> index 769820e3a2431c16c7ec85dbf313f61f7ba1a3cc..984baa5f5ded1e05e389abc485c63c0bf35eee4c 100644
> --- a/arch/s390/kvm/kvm-s390.c
> +++ b/arch/s390/kvm/kvm-s390.c
> @@ -455,8 +455,7 @@ static void __init kvm_s390_cpu_feat_init(void)

Context:
        if (!sclp.has_sief2 || !machine_has_esop() || !sclp.has_64bscao ||
>  	    !test_facility(3) || !nested)
>  		return;
>  	allow_cpu_feat(KVM_S390_VM_CPU_FEAT_SIEF2);
> -	if (sclp.has_64bscao)
> -		allow_cpu_feat(KVM_S390_VM_CPU_FEAT_64BSCAO);
> +	allow_cpu_feat(KVM_S390_VM_CPU_FEAT_64BSCAO);

Ha, yup.

Reviewed-by: Eric Farman <farman@linux.ibm.com>

>  	if (sclp.has_siif)
>  		allow_cpu_feat(KVM_S390_VM_CPU_FEAT_SIIF);
>  	if (sclp.has_gpere)

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

* Re: [PATCH RFC v2 02/11] KVM: s390: Remove double 64bscao feature check
  2025-11-10 17:16 ` [PATCH RFC v2 02/11] KVM: s390: Remove double 64bscao feature check Christoph Schlameuss
  2025-11-10 21:32   ` Eric Farman
@ 2025-11-11  8:13   ` Hendrik Brueckner
  2025-11-11 13:20   ` Janosch Frank
  2 siblings, 0 replies; 23+ messages in thread
From: Hendrik Brueckner @ 2025-11-11  8:13 UTC (permalink / raw)
  To: Christoph Schlameuss
  Cc: kvm, linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Janosch Frank, Claudio Imbrenda,
	Nico Boehr, David Hildenbrand, Sven Schnelle, Paolo Bonzini,
	Shuah Khan

On Mon, Nov 10, 2025 at 06:16:42PM +0100, Christoph Schlameuss wrote:
> sclp.has_64bscao is already verified in the guard clause a few lines
> above this. So we cannot reach this code if it is not true.
> 
> Signed-off-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
> ---
>  arch/s390/kvm/kvm-s390.c | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)
> 
> diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
> index 769820e3a2431c16c7ec85dbf313f61f7ba1a3cc..984baa5f5ded1e05e389abc485c63c0bf35eee4c 100644
> --- a/arch/s390/kvm/kvm-s390.c
> +++ b/arch/s390/kvm/kvm-s390.c
> @@ -455,8 +455,7 @@ static void __init kvm_s390_cpu_feat_init(void)
>  	    !test_facility(3) || !nested)
>  		return;
>  	allow_cpu_feat(KVM_S390_VM_CPU_FEAT_SIEF2);
> -	if (sclp.has_64bscao)
> -		allow_cpu_feat(KVM_S390_VM_CPU_FEAT_64BSCAO);
> +	allow_cpu_feat(KVM_S390_VM_CPU_FEAT_64BSCAO);
>  	if (sclp.has_siif)
>  		allow_cpu_feat(KVM_S390_VM_CPU_FEAT_SIIF);
>  	if (sclp.has_gpere)
> 

Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>

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

* Re: [PATCH RFC v2 03/11] KVM: s390: Move scao validation into a function
  2025-11-10 21:30   ` Eric Farman
@ 2025-11-11  8:48     ` Christoph Schlameuss
  0 siblings, 0 replies; 23+ messages in thread
From: Christoph Schlameuss @ 2025-11-11  8:48 UTC (permalink / raw)
  To: Eric Farman, kvm
  Cc: linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Janosch Frank, Claudio Imbrenda,
	Nico Boehr, David Hildenbrand, Sven Schnelle, Paolo Bonzini,
	Shuah Khan

On Mon Nov 10, 2025 at 10:30 PM CET, Eric Farman wrote:
> On Mon, 2025-11-10 at 18:16 +0100, Christoph Schlameuss wrote:
>> This improves readability as well as allows re-use in coming patches.
>> 
>> Signed-off-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
>> ---
>>  arch/s390/kvm/vsie.c | 27 ++++++++++++++++++++-------
>>  1 file changed, 20 insertions(+), 7 deletions(-)
>> 
>> diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c
>> index ced2ca4ce5b584403d900ed11cb064919feda8e9..3d602bbd1f70b7bd8ddc2c54d43027dc37a6e032 100644
>> --- a/arch/s390/kvm/vsie.c
>> +++ b/arch/s390/kvm/vsie.c
>> @@ -95,6 +95,25 @@ static int set_validity_icpt(struct kvm_s390_sie_block *scb,
>>  	return 1;
>>  }
>>  
>> +/* The sca header must not cross pages etc. */
>> +static int validate_scao(struct kvm_vcpu *vcpu, struct kvm_s390_sie_block *scb, gpa_t gpa)
>> +{
>> +	int offset;
>> +
>> +	if (gpa < 2 * PAGE_SIZE)
>> +		return set_validity_icpt(scb, 0x0038U);
>> +	if ((gpa & ~0x1fffUL) == kvm_s390_get_prefix(vcpu))
>> +		return set_validity_icpt(scb, 0x0011U);
>> +
>> +	if (sie_uses_esca(scb))
>
> This helper doesn't turn up until patch 7
>

Good catch, thank you.

I will pull up that helper into this patch then. (Decreasing the size of patch 7
is an absolute plus here.)

>> +		offset = offsetof(struct esca_block, cpu[0]) - 1;
>> +	else
>> +		offset = offsetof(struct bsca_block, cpu[0]) - 1;
>> +	if ((gpa & PAGE_MASK) != ((gpa + offset) & PAGE_MASK))
>> +		return set_validity_icpt(scb, 0x003bU);
>> +	return false;
>> +}
>> +
>>  /* mark the prefix as unmapped, this will block the VSIE */
>>  static void prefix_unmapped(struct vsie_page *vsie_page)
>>  {
>> @@ -791,13 +810,7 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
>>  
>>  	gpa = read_scao(vcpu->kvm, scb_o);
>>  	if (gpa) {
>> -		if (gpa < 2 * PAGE_SIZE)
>> -			rc = set_validity_icpt(scb_s, 0x0038U);
>> -		else if ((gpa & ~0x1fffUL) == kvm_s390_get_prefix(vcpu))
>> -			rc = set_validity_icpt(scb_s, 0x0011U);
>> -		else if ((gpa & PAGE_MASK) !=
>> -			 ((gpa + sizeof(struct bsca_block) - 1) & PAGE_MASK))
>> -			rc = set_validity_icpt(scb_s, 0x003bU);
>> +		rc = validate_scao(vcpu, scb_o, gpa);
>>  		if (!rc) {
>>  			rc = pin_guest_page(vcpu->kvm, gpa, &hpa);
>>  			if (rc)


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

* Re: [PATCH RFC v2 02/11] KVM: s390: Remove double 64bscao feature check
  2025-11-10 17:16 ` [PATCH RFC v2 02/11] KVM: s390: Remove double 64bscao feature check Christoph Schlameuss
  2025-11-10 21:32   ` Eric Farman
  2025-11-11  8:13   ` Hendrik Brueckner
@ 2025-11-11 13:20   ` Janosch Frank
  2 siblings, 0 replies; 23+ messages in thread
From: Janosch Frank @ 2025-11-11 13:20 UTC (permalink / raw)
  To: Christoph Schlameuss, kvm
  Cc: linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Claudio Imbrenda, Nico Boehr,
	David Hildenbrand, Sven Schnelle, Paolo Bonzini, Shuah Khan

On 11/10/25 18:16, Christoph Schlameuss wrote:
> sclp.has_64bscao is already verified in the guard clause a few lines
> above this. So we cannot reach this code if it is not true.
> 
> Signed-off-by: Christoph Schlameuss <schlameuss@linux.ibm.com>

Indeed

Reviewed-by: Janosch Frank <frankja@de.ibm.com>

> ---
>   arch/s390/kvm/kvm-s390.c | 3 +--
>   1 file changed, 1 insertion(+), 2 deletions(-)
> 
> diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
> index 769820e3a2431c16c7ec85dbf313f61f7ba1a3cc..984baa5f5ded1e05e389abc485c63c0bf35eee4c 100644
> --- a/arch/s390/kvm/kvm-s390.c
> +++ b/arch/s390/kvm/kvm-s390.c
> @@ -455,8 +455,7 @@ static void __init kvm_s390_cpu_feat_init(void)
>   	    !test_facility(3) || !nested)
>   		return;
>   	allow_cpu_feat(KVM_S390_VM_CPU_FEAT_SIEF2);
> -	if (sclp.has_64bscao)
> -		allow_cpu_feat(KVM_S390_VM_CPU_FEAT_64BSCAO);
> +	allow_cpu_feat(KVM_S390_VM_CPU_FEAT_64BSCAO);
>   	if (sclp.has_siif)
>   		allow_cpu_feat(KVM_S390_VM_CPU_FEAT_SIIF);
>   	if (sclp.has_gpere)
> 


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

* Re: [PATCH RFC v2 01/11] KVM: s390: Add SCAO read and write helpers
  2025-11-10 17:16 ` [PATCH RFC v2 01/11] KVM: s390: Add SCAO read and write helpers Christoph Schlameuss
@ 2025-11-11 13:45   ` Claudio Imbrenda
  2025-11-11 14:37     ` Christoph Schlameuss
  0 siblings, 1 reply; 23+ messages in thread
From: Claudio Imbrenda @ 2025-11-11 13:45 UTC (permalink / raw)
  To: Christoph Schlameuss
  Cc: kvm, linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Janosch Frank, Nico Boehr,
	David Hildenbrand, Sven Schnelle, Paolo Bonzini, Shuah Khan

On Mon, 10 Nov 2025 18:16:41 +0100
Christoph Schlameuss <schlameuss@linux.ibm.com> wrote:

> Introduce some small helper functions to get and set the system control
> area origin address from the SIE control block.
> 
> Signed-off-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
> ---
>  arch/s390/kvm/vsie.c | 29 +++++++++++++++++++++--------
>  1 file changed, 21 insertions(+), 8 deletions(-)
> 
> diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c
> index 347268f89f2f186bea623a3adff7376cabc305b2..ced2ca4ce5b584403d900ed11cb064919feda8e9 100644
> --- a/arch/s390/kvm/vsie.c
> +++ b/arch/s390/kvm/vsie.c
> @@ -123,6 +123,23 @@ static int prefix_is_mapped(struct vsie_page *vsie_page)
>  	return !(atomic_read(&vsie_page->scb_s.prog20) & PROG_REQUEST);
>  }
>  
> +static gpa_t read_scao(struct kvm *kvm, struct kvm_s390_sie_block *scb)
> +{
> +	gpa_t sca;

is it, though?

> +
> +	sca = READ_ONCE(scb->scaol) & ~0xfUL;
> +	if (test_kvm_cpu_feat(kvm, KVM_S390_VM_CPU_FEAT_64BSCAO))
> +		sca |= (u64)READ_ONCE(scb->scaoh) << 32;

this feels more like an hpa_t, which is what you also use in the
function below

> +
> +	return sca;
> +}
> +
> +static void write_scao(struct kvm_s390_sie_block *scb, hpa_t hpa)
> +{
> +	scb->scaoh = (u32)((u64)hpa >> 32);
> +	scb->scaol = (u32)(u64)hpa;
> +}
> +
>  /* copy the updated intervention request bits into the shadow scb */
>  static void update_intervention_requests(struct vsie_page *vsie_page)
>  {
> @@ -714,12 +731,11 @@ static void unpin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
>  	struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
>  	hpa_t hpa;
>  
> -	hpa = (u64) scb_s->scaoh << 32 | scb_s->scaol;
> +	hpa = read_scao(vcpu->kvm, scb_s);
>  	if (hpa) {
>  		unpin_guest_page(vcpu->kvm, vsie_page->sca_gpa, hpa);
>  		vsie_page->sca_gpa = 0;
> -		scb_s->scaol = 0;
> -		scb_s->scaoh = 0;
> +		write_scao(scb_s, 0);
>  	}
>  
>  	hpa = scb_s->itdba;
> @@ -773,9 +789,7 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
>  	gpa_t gpa;
>  	int rc = 0;
>  
> -	gpa = READ_ONCE(scb_o->scaol) & ~0xfUL;
> -	if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_64BSCAO))
> -		gpa |= (u64) READ_ONCE(scb_o->scaoh) << 32;
> +	gpa = read_scao(vcpu->kvm, scb_o);
>  	if (gpa) {
>  		if (gpa < 2 * PAGE_SIZE)
>  			rc = set_validity_icpt(scb_s, 0x0038U);
> @@ -792,8 +806,7 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
>  		if (rc)
>  			goto unpin;
>  		vsie_page->sca_gpa = gpa;
> -		scb_s->scaoh = (u32)((u64)hpa >> 32);
> -		scb_s->scaol = (u32)(u64)hpa;
> +		write_scao(scb_s, hpa);
>  	}
>  
>  	gpa = READ_ONCE(scb_o->itdba) & ~0xffUL;
> 


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

* Re: [PATCH RFC v2 09/11] KVM: s390: Allow guest-3 switch to extended sca with vsie sigpif
  2025-11-10 17:16 ` [PATCH RFC v2 09/11] KVM: s390: Allow guest-3 switch to extended sca " Christoph Schlameuss
@ 2025-11-11 14:18   ` Janosch Frank
  0 siblings, 0 replies; 23+ messages in thread
From: Janosch Frank @ 2025-11-11 14:18 UTC (permalink / raw)
  To: Christoph Schlameuss, kvm
  Cc: linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Claudio Imbrenda, Nico Boehr,
	David Hildenbrand, Sven Schnelle, Paolo Bonzini, Shuah Khan

On 11/10/25 18:16, Christoph Schlameuss wrote:
> If a guest wants to use more than 64 and use sigp interpretation it
> needs to use the extended system control area. When the ESCA is not
> already used and the 65th cpu is added the VM host will kick all cpus
> destroy the old basic system control area (BSCA) and create a new ESCA
> for the guest configuration.
> 
> In VSIE execution using vsie sigpif this also means the SSCA need to be
> updated. The structure of the SSCA remains the same but the pointers to
> the original SCA as well as its entries will have changed.
> 
> In guest-1 we can detect this change relatively simple as the original
> SCA address changes.

Be careful with this assumption.

The architecture doesn't specify that a hypervisor needs to use a fresh 
page when changing SCA formats AFAIK.

Additionally the hypervisor could move the SCA without changing the format.

Just because KVM does things this way doesn't mean that it won't change 
in the future or other hypervisors do things differently.

> 
> Signed-off-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
> ---
>   arch/s390/kvm/vsie.c | 10 +++++++++-
>   1 file changed, 9 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c
> index 1e15220e1f1ecfd83b10aa0620ca84ff0ff3c1ac..b69ef763b55296875522f2e63169446b5e2d5053 100644
> --- a/arch/s390/kvm/vsie.c
> +++ b/arch/s390/kvm/vsie.c
> @@ -932,8 +932,16 @@ static struct vsie_sca *get_vsie_sca(struct kvm_vcpu *vcpu, struct vsie_page *vs
>   	if (sca)
>   		goto out;
>   
> +	if (vsie_page->sca) {
> +		/* switch to extended system control area (esca) */
> +		sca = vsie_page->sca;
> +		WARN_ON_ONCE(atomic_read(&sca->ref_count));
> +		unpin_sca(kvm, sca);
> +		/* trigger init_ssca() later */
> +		if (sca->ssca)
> +			sca->ssca->osca = 0;
>   	/* check again under write lock if we are still under our sca_count limit */
> -	if (sca_new && kvm->arch.vsie.sca_count < max_sca) {
> +	} else if (sca_new && kvm->arch.vsie.sca_count < max_sca) {
>   		/* make use of vsie_sca just created */
>   		sca = sca_new;
>   		sca_new = NULL;
> 


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

* Re: [PATCH RFC v2 01/11] KVM: s390: Add SCAO read and write helpers
  2025-11-11 13:45   ` Claudio Imbrenda
@ 2025-11-11 14:37     ` Christoph Schlameuss
  2025-11-11 14:55       ` Claudio Imbrenda
  0 siblings, 1 reply; 23+ messages in thread
From: Christoph Schlameuss @ 2025-11-11 14:37 UTC (permalink / raw)
  To: Claudio Imbrenda
  Cc: kvm, linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Janosch Frank, Nico Boehr,
	David Hildenbrand, Sven Schnelle, Paolo Bonzini, Shuah Khan

On Tue Nov 11, 2025 at 2:45 PM CET, Claudio Imbrenda wrote:
> On Mon, 10 Nov 2025 18:16:41 +0100
> Christoph Schlameuss <schlameuss@linux.ibm.com> wrote:
>
>> Introduce some small helper functions to get and set the system control
>> area origin address from the SIE control block.
>> 
>> Signed-off-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
>> ---
>>  arch/s390/kvm/vsie.c | 29 +++++++++++++++++++++--------
>>  1 file changed, 21 insertions(+), 8 deletions(-)
>> 
>> diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c
>> index 347268f89f2f186bea623a3adff7376cabc305b2..ced2ca4ce5b584403d900ed11cb064919feda8e9 100644
>> --- a/arch/s390/kvm/vsie.c
>> +++ b/arch/s390/kvm/vsie.c
>> @@ -123,6 +123,23 @@ static int prefix_is_mapped(struct vsie_page *vsie_page)
>>  	return !(atomic_read(&vsie_page->scb_s.prog20) & PROG_REQUEST);
>>  }
>>  
>> +static gpa_t read_scao(struct kvm *kvm, struct kvm_s390_sie_block *scb)
>> +{
>> +	gpa_t sca;
>
> is it, though?
>
>> +
>> +	sca = READ_ONCE(scb->scaol) & ~0xfUL;
>> +	if (test_kvm_cpu_feat(kvm, KVM_S390_VM_CPU_FEAT_64BSCAO))
>> +		sca |= (u64)READ_ONCE(scb->scaoh) << 32;
>
> this feels more like an hpa_t, which is what you also use in the
> function below
>

It actually can be either. Without vsie sigp this is a gpa for reading and
writing. With vsie sigp this is a gpa when reading and a hpa when writing
it. It might be best to not imply anything here but just use "unsigned long"
for these functions.

>> +
>> +	return sca;
>> +}
>> +
>> +static void write_scao(struct kvm_s390_sie_block *scb, hpa_t hpa)
>> +{
>> +	scb->scaoh = (u32)((u64)hpa >> 32);
>> +	scb->scaol = (u32)(u64)hpa;
>> +}
>> +
>>  /* copy the updated intervention request bits into the shadow scb */
>>  static void update_intervention_requests(struct vsie_page *vsie_page)
>>  {
>> @@ -714,12 +731,11 @@ static void unpin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
>>  	struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
>>  	hpa_t hpa;
>>  
>> -	hpa = (u64) scb_s->scaoh << 32 | scb_s->scaol;
>> +	hpa = read_scao(vcpu->kvm, scb_s);
>>  	if (hpa) {
>>  		unpin_guest_page(vcpu->kvm, vsie_page->sca_gpa, hpa);
>>  		vsie_page->sca_gpa = 0;
>> -		scb_s->scaol = 0;
>> -		scb_s->scaoh = 0;
>> +		write_scao(scb_s, 0);
>>  	}
>>  
>>  	hpa = scb_s->itdba;
>> @@ -773,9 +789,7 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
>>  	gpa_t gpa;
>>  	int rc = 0;
>>  
>> -	gpa = READ_ONCE(scb_o->scaol) & ~0xfUL;
>> -	if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_64BSCAO))
>> -		gpa |= (u64) READ_ONCE(scb_o->scaoh) << 32;
>> +	gpa = read_scao(vcpu->kvm, scb_o);
>>  	if (gpa) {
>>  		if (gpa < 2 * PAGE_SIZE)
>>  			rc = set_validity_icpt(scb_s, 0x0038U);
>> @@ -792,8 +806,7 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
>>  		if (rc)
>>  			goto unpin;
>>  		vsie_page->sca_gpa = gpa;
>> -		scb_s->scaoh = (u32)((u64)hpa >> 32);
>> -		scb_s->scaol = (u32)(u64)hpa;
>> +		write_scao(scb_s, hpa);
>>  	}
>>  
>>  	gpa = READ_ONCE(scb_o->itdba) & ~0xffUL;
>> 


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

* Re: [PATCH RFC v2 01/11] KVM: s390: Add SCAO read and write helpers
  2025-11-11 14:37     ` Christoph Schlameuss
@ 2025-11-11 14:55       ` Claudio Imbrenda
  0 siblings, 0 replies; 23+ messages in thread
From: Claudio Imbrenda @ 2025-11-11 14:55 UTC (permalink / raw)
  To: Christoph Schlameuss
  Cc: kvm, linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Janosch Frank, Nico Boehr,
	David Hildenbrand, Sven Schnelle, Paolo Bonzini, Shuah Khan

On Tue, 11 Nov 2025 15:37:44 +0100
"Christoph Schlameuss" <schlameuss@linux.ibm.com> wrote:

> On Tue Nov 11, 2025 at 2:45 PM CET, Claudio Imbrenda wrote:
> > On Mon, 10 Nov 2025 18:16:41 +0100
> > Christoph Schlameuss <schlameuss@linux.ibm.com> wrote:
> >  
> >> Introduce some small helper functions to get and set the system control
> >> area origin address from the SIE control block.
> >> 
> >> Signed-off-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
> >> ---
> >>  arch/s390/kvm/vsie.c | 29 +++++++++++++++++++++--------
> >>  1 file changed, 21 insertions(+), 8 deletions(-)
> >> 
> >> diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c
> >> index 347268f89f2f186bea623a3adff7376cabc305b2..ced2ca4ce5b584403d900ed11cb064919feda8e9 100644
> >> --- a/arch/s390/kvm/vsie.c
> >> +++ b/arch/s390/kvm/vsie.c
> >> @@ -123,6 +123,23 @@ static int prefix_is_mapped(struct vsie_page *vsie_page)
> >>  	return !(atomic_read(&vsie_page->scb_s.prog20) & PROG_REQUEST);
> >>  }
> >>  
> >> +static gpa_t read_scao(struct kvm *kvm, struct kvm_s390_sie_block *scb)
> >> +{
> >> +	gpa_t sca;  
> >
> > is it, though?
> >  
> >> +
> >> +	sca = READ_ONCE(scb->scaol) & ~0xfUL;
> >> +	if (test_kvm_cpu_feat(kvm, KVM_S390_VM_CPU_FEAT_64BSCAO))
> >> +		sca |= (u64)READ_ONCE(scb->scaoh) << 32;  
> >
> > this feels more like an hpa_t, which is what you also use in the
> > function below
> >  
> 
> It actually can be either. Without vsie sigp this is a gpa for reading and
> writing. With vsie sigp this is a gpa when reading and a hpa when writing

this is a little confusing, maybe add an explanation

> it. It might be best to not imply anything here but just use "unsigned long"
> for these functions.

yes

> 
> >> +
> >> +	return sca;
> >> +}
> >> +
> >> +static void write_scao(struct kvm_s390_sie_block *scb, hpa_t hpa)
> >> +{
> >> +	scb->scaoh = (u32)((u64)hpa >> 32);
> >> +	scb->scaol = (u32)(u64)hpa;
> >> +}
> >> +
> >>  /* copy the updated intervention request bits into the shadow scb */
> >>  static void update_intervention_requests(struct vsie_page *vsie_page)
> >>  {
> >> @@ -714,12 +731,11 @@ static void unpin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
> >>  	struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
> >>  	hpa_t hpa;
> >>  
> >> -	hpa = (u64) scb_s->scaoh << 32 | scb_s->scaol;
> >> +	hpa = read_scao(vcpu->kvm, scb_s);
> >>  	if (hpa) {
> >>  		unpin_guest_page(vcpu->kvm, vsie_page->sca_gpa, hpa);
> >>  		vsie_page->sca_gpa = 0;
> >> -		scb_s->scaol = 0;
> >> -		scb_s->scaoh = 0;
> >> +		write_scao(scb_s, 0);
> >>  	}
> >>  
> >>  	hpa = scb_s->itdba;
> >> @@ -773,9 +789,7 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
> >>  	gpa_t gpa;
> >>  	int rc = 0;
> >>  
> >> -	gpa = READ_ONCE(scb_o->scaol) & ~0xfUL;
> >> -	if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_64BSCAO))
> >> -		gpa |= (u64) READ_ONCE(scb_o->scaoh) << 32;
> >> +	gpa = read_scao(vcpu->kvm, scb_o);
> >>  	if (gpa) {
> >>  		if (gpa < 2 * PAGE_SIZE)
> >>  			rc = set_validity_icpt(scb_s, 0x0038U);
> >> @@ -792,8 +806,7 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
> >>  		if (rc)
> >>  			goto unpin;
> >>  		vsie_page->sca_gpa = gpa;
> >> -		scb_s->scaoh = (u32)((u64)hpa >> 32);
> >> -		scb_s->scaol = (u32)(u64)hpa;
> >> +		write_scao(scb_s, hpa);
> >>  	}
> >>  
> >>  	gpa = READ_ONCE(scb_o->itdba) & ~0xffUL;
> >>   
> 


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

* Re: [PATCH RFC v2 08/11] KVM: s390: Allow guest-3 cpu add and remove with vsie sigpif
  2025-11-10 17:16 ` [PATCH RFC v2 08/11] KVM: s390: Allow guest-3 cpu add and remove with vsie sigpif Christoph Schlameuss
@ 2025-11-11 15:47   ` Janosch Frank
  2025-11-11 16:34     ` Christoph Schlameuss
  0 siblings, 1 reply; 23+ messages in thread
From: Janosch Frank @ 2025-11-11 15:47 UTC (permalink / raw)
  To: Christoph Schlameuss, kvm
  Cc: linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Claudio Imbrenda, Nico Boehr,
	David Hildenbrand, Sven Schnelle, Paolo Bonzini, Shuah Khan

On 11/10/25 18:16, Christoph Schlameuss wrote:
> As we are shadowing the SCA we need to add and remove the pointers to
> the shadowed control blocks and sca entries whenever the mcn changes.
> 
> It is not expected that the mcn changes frequently for a already running
> guest-3 configuration. So we can simply re-init the ssca whenever the
> mcn changes.
> To detect the mcn change we store the expected mcn in the struct
> vsie_sca when running the ssca init.
> 
> Signed-off-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
> ---
>   arch/s390/kvm/vsie.c | 20 ++++++++++++++++++--
>   1 file changed, 18 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c
> index 72c794945be916cc107aba74e1609d3b4780d4b9..1e15220e1f1ecfd83b10aa0620ca84ff0ff3c1ac 100644
> --- a/arch/s390/kvm/vsie.c
> +++ b/arch/s390/kvm/vsie.c
> @@ -1926,12 +1926,27 @@ static int init_ssca(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page, struct
>   	return PTR_ERR(vsie_page_n);
>   }
>   
> +static bool sca_mcn_equals(struct vsie_sca *sca, u64 *mcn)
> +{
> +	bool is_esca = test_bit(VSIE_SCA_ESCA, &sca->flags);
> +	int i;
> +
> +	if (!is_esca)
> +		return ((struct bsca_block *)phys_to_virt(sca->ssca->osca))->mcn == *mcn;
> +
> +	for (i = 0; i < 4; i++)
> +		if (((struct esca_block *)phys_to_virt(sca->ssca->osca))->mcn[i] != sca->mcn[i])
> +			return false;

You're reimplementing memcmp(), no?
Instead of casting which makes the comparison really messy you could use 
offsetof.

Something like this (+- errors):

void *osca = phys_to_virt(sca->ssca->osca);
int offset = offsetof(struct bsca_block, mcn);
int size = 8;

if (test_bit(VSIE_SCA_ESCA, &sca->flags)) {
	size = 8 * 4;
	offset = offsetof(struct esca_block, mcn);
}

return !memcmp(osca + offset, mcn, size);


> +	return true;
> +}
> +
>   /*
>    * Shadow the sca on vsie enter.
>    */
>   static int shadow_sca(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page, struct vsie_sca *sca)
>   {
>   	struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
> +	bool do_init_ssca;
>   	int rc;
>   
>   	vsie_page->sca = sca;
> @@ -1947,8 +1962,9 @@ static int shadow_sca(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page, struct
>   	if (!use_vsie_sigpif_for(vcpu->kvm, vsie_page))
>   		return false;
>   
> -	/* skip if the guest does not have an usable sca */
> -	if (!sca->ssca->osca) {
> +	do_init_ssca = !sca->ssca->osca;
> +	do_init_ssca = do_init_ssca || !sca_mcn_equals(sca, sca->mcn);
> +	if (do_init_ssca) {
>   		rc = init_ssca(vcpu, vsie_page, sca);
>   		if (rc)
>   			return rc;
> 


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

* Re: [PATCH RFC v2 08/11] KVM: s390: Allow guest-3 cpu add and remove with vsie sigpif
  2025-11-11 15:47   ` Janosch Frank
@ 2025-11-11 16:34     ` Christoph Schlameuss
  0 siblings, 0 replies; 23+ messages in thread
From: Christoph Schlameuss @ 2025-11-11 16:34 UTC (permalink / raw)
  To: Janosch Frank, kvm
  Cc: linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Claudio Imbrenda, Nico Boehr,
	David Hildenbrand, Sven Schnelle, Paolo Bonzini, Shuah Khan

On Tue Nov 11, 2025 at 4:47 PM CET, Janosch Frank wrote:
> On 11/10/25 18:16, Christoph Schlameuss wrote:
>> As we are shadowing the SCA we need to add and remove the pointers to
>> the shadowed control blocks and sca entries whenever the mcn changes.
>> 
>> It is not expected that the mcn changes frequently for a already running
>> guest-3 configuration. So we can simply re-init the ssca whenever the
>> mcn changes.
>> To detect the mcn change we store the expected mcn in the struct
>> vsie_sca when running the ssca init.
>> 
>> Signed-off-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
>> ---
>>   arch/s390/kvm/vsie.c | 20 ++++++++++++++++++--
>>   1 file changed, 18 insertions(+), 2 deletions(-)
>> 
>> diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c
>> index 72c794945be916cc107aba74e1609d3b4780d4b9..1e15220e1f1ecfd83b10aa0620ca84ff0ff3c1ac 100644
>> --- a/arch/s390/kvm/vsie.c
>> +++ b/arch/s390/kvm/vsie.c
>> @@ -1926,12 +1926,27 @@ static int init_ssca(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page, struct
>>   	return PTR_ERR(vsie_page_n);
>>   }
>>   
>> +static bool sca_mcn_equals(struct vsie_sca *sca, u64 *mcn)
>> +{
>> +	bool is_esca = test_bit(VSIE_SCA_ESCA, &sca->flags);
>> +	int i;
>> +
>> +	if (!is_esca)
>> +		return ((struct bsca_block *)phys_to_virt(sca->ssca->osca))->mcn == *mcn;
>> +
>> +	for (i = 0; i < 4; i++)
>> +		if (((struct esca_block *)phys_to_virt(sca->ssca->osca))->mcn[i] != sca->mcn[i])
>> +			return false;
>
> You're reimplementing memcmp(), no?
> Instead of casting which makes the comparison really messy you could use 
> offsetof.
>
> Something like this (+- errors):
>
> void *osca = phys_to_virt(sca->ssca->osca);
> int offset = offsetof(struct bsca_block, mcn);
> int size = 8;
>
> if (test_bit(VSIE_SCA_ESCA, &sca->flags)) {
> 	size = 8 * 4;
> 	offset = offsetof(struct esca_block, mcn);
> }
>
> return !memcmp(osca + offset, mcn, size);
>
>

Yes, that is exactly what it is. Will use your proposal instead.

>> +	return true;
>> +}
>> +
>>   /*
>>    * Shadow the sca on vsie enter.
>>    */
>>   static int shadow_sca(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page, struct vsie_sca *sca)
>>   {
>>   	struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
>> +	bool do_init_ssca;
>>   	int rc;
>>   
>>   	vsie_page->sca = sca;
>> @@ -1947,8 +1962,9 @@ static int shadow_sca(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page, struct
>>   	if (!use_vsie_sigpif_for(vcpu->kvm, vsie_page))
>>   		return false;
>>   
>> -	/* skip if the guest does not have an usable sca */
>> -	if (!sca->ssca->osca) {
>> +	do_init_ssca = !sca->ssca->osca;
>> +	do_init_ssca = do_init_ssca || !sca_mcn_equals(sca, sca->mcn);
>> +	if (do_init_ssca) {
>>   		rc = init_ssca(vcpu, vsie_page, sca);
>>   		if (rc)
>>   			return rc;
>> 


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

end of thread, other threads:[~2025-11-11 16:34 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-10 17:16 [PATCH RFC v2 00/11] KVM: s390: Add VSIE SIGP Interpretation (vsie_sigpif) Christoph Schlameuss
2025-11-10 17:16 ` [PATCH RFC v2 01/11] KVM: s390: Add SCAO read and write helpers Christoph Schlameuss
2025-11-11 13:45   ` Claudio Imbrenda
2025-11-11 14:37     ` Christoph Schlameuss
2025-11-11 14:55       ` Claudio Imbrenda
2025-11-10 17:16 ` [PATCH RFC v2 02/11] KVM: s390: Remove double 64bscao feature check Christoph Schlameuss
2025-11-10 21:32   ` Eric Farman
2025-11-11  8:13   ` Hendrik Brueckner
2025-11-11 13:20   ` Janosch Frank
2025-11-10 17:16 ` [PATCH RFC v2 03/11] KVM: s390: Move scao validation into a function Christoph Schlameuss
2025-11-10 21:30   ` Eric Farman
2025-11-11  8:48     ` Christoph Schlameuss
2025-11-10 17:16 ` [PATCH RFC v2 04/11] KVM: s390: Add vsie_sigpif detection Christoph Schlameuss
2025-11-10 17:16 ` [PATCH RFC v2 05/11] KVM: s390: Add ssca_block and ssca_entry structs for vsie_ie Christoph Schlameuss
2025-11-10 17:16 ` [PATCH RFC v2 06/11] KVM: s390: Add helper to pin multiple guest pages Christoph Schlameuss
2025-11-10 17:16 ` [PATCH RFC v2 07/11] KVM: s390: Shadow VSIE SCA in guest-1 Christoph Schlameuss
2025-11-10 17:16 ` [PATCH RFC v2 08/11] KVM: s390: Allow guest-3 cpu add and remove with vsie sigpif Christoph Schlameuss
2025-11-11 15:47   ` Janosch Frank
2025-11-11 16:34     ` Christoph Schlameuss
2025-11-10 17:16 ` [PATCH RFC v2 09/11] KVM: s390: Allow guest-3 switch to extended sca " Christoph Schlameuss
2025-11-11 14:18   ` Janosch Frank
2025-11-10 17:16 ` [PATCH RFC v2 10/11] KVM: s390: Add VSIE shadow configuration Christoph Schlameuss
2025-11-10 17:16 ` [PATCH RFC v2 11/11] KVM: s390: Add VSIE shadow stat counters Christoph Schlameuss

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).