From: Michael Holzheu <[email-masked]>

With this patch on s390 a program check interrupt is emitted if purgatory
checksums are not valid. This establishes a error handling mechanism where
the caller of crash_kexec/purgatory can catch the error by installing a
program check handler function. On s390 this will be used by our stand-alone
dump tools. The tools first get control and install a program check handler.
Then if kdump is pre-loaded, the dump tools jump into the old kernel where
crash_kexec->purgatory is executed. If kdump fails on this code path, a
program check is emitted and then control is passed back to the stand-alone
dump tools that will then create a full-blown dump as backup mechanism.

Signed-off-by: Michael Holzheu <[email-masked]>
---
 purgatory/arch/i386/purgatory-x86.c      |    7 +++++++
 purgatory/arch/ia64/purgatory-ia64.c     |    7 +++++++
 purgatory/arch/ppc/purgatory-ppc.c       |    7 +++++++
 purgatory/arch/ppc64/purgatory-ppc64.c   |    7 +++++++
 purgatory/arch/s390/purgatory-s390.c     |   11 +++++++++++
 purgatory/arch/x86_64/purgatory-x86_64.c |    7 +++++++
 purgatory/include/purgatory.h            |    1 +
 purgatory/purgatory.c                    |    4 +---
 8 files changed, 48 insertions(+), 3 deletions(-)

--- a/purgatory/arch/i386/purgatory-x86.c
+++ b/purgatory/arch/i386/purgatory-x86.c
@@ -55,3 +55,10 @@ void post_verification_setup_arch(void)
 	if (panic_kernel)    crashdump_backup_memory();
 	if (jump_back_entry) x86_setup_jump_back_entry();
 }
+
+void sha256_digest_failed(void)
+{
+	for(;;) {
+		/* loop forever */
+	}
+}
--- a/purgatory/arch/ia64/purgatory-ia64.c
+++ b/purgatory/arch/ia64/purgatory-ia64.c
@@ -305,3 +305,10 @@ void post_verification_setup_arch(void)
 {
 	/* Nothing for now */
 }
+
+void sha256_digest_failed(void)
+{
+	for(;;) {
+		/* loop forever */
+	}
+}
--- a/purgatory/arch/ppc/purgatory-ppc.c
+++ b/purgatory/arch/ppc/purgatory-ppc.c
@@ -44,3 +44,10 @@ void crashdump_backup_memory(void)
 {
 	return;
 }
+
+void sha256_digest_failed(void)
+{
+	for(;;) {
+		/* loop forever */
+	}
+}
--- a/purgatory/arch/ppc64/purgatory-ppc64.c
+++ b/purgatory/arch/ppc64/purgatory-ppc64.c
@@ -40,3 +40,10 @@ void post_verification_setup_arch(void)
 	if (panic_kernel)
 		crashdump_backup_memory();
 }
+
+void sha256_digest_failed(void)
+{
+	for(;;) {
+		/* loop forever */
+	}
+}
--- a/purgatory/arch/s390/purgatory-s390.c
+++ b/purgatory/arch/s390/purgatory-s390.c
@@ -6,6 +6,12 @@
  * Author(s): Michael Holzheu <[email-masked]>
  */
 
+#define EMIT_PGM_CHECK() do {			\
+	asm volatile(			\
+		"0:     j       0b+2\n"	\
+	: :);				\
+} while (0)
+
 unsigned long kdump_psw_addr = 0;
 
 void setup_arch(void)
@@ -15,3 +21,8 @@ void setup_arch(void)
 void post_verification_setup_arch(void)
 {
 }
+
+void sha256_digest_failed(void)
+{
+	EMIT_PGM_CHECK();
+}
--- a/purgatory/arch/x86_64/purgatory-x86_64.c
+++ b/purgatory/arch/x86_64/purgatory-x86_64.c
@@ -28,3 +28,10 @@ void post_verification_setup_arch(void)
 	if (panic_kernel)    crashdump_backup_memory();
 	if (jump_back_entry) x86_setup_jump_back_entry();
 }
+
+void sha256_digest_failed(void)
+{
+	for(;;) {
+		/* loop forever */
+	}
+}
--- a/purgatory/include/purgatory.h
+++ b/purgatory/include/purgatory.h
@@ -6,5 +6,6 @@ void sprintf(char *buffer, const char *f
 void printf(const char *fmt, ...);
 void setup_arch(void);
 void post_verification_setup_arch(void);
+void sha256_digest_failed(void);
 
 #endif /* PURGATORY_H */
--- a/purgatory/purgatory.c
+++ b/purgatory/purgatory.c
@@ -34,9 +34,7 @@ void verify_sha256_digest(void)
 			printf("%hhx ", sha256_digest[i]);
 		}
 		printf("\n");
-		for(;;) {
-			/* loop forever */
-		}
+		sha256_digest_failed();
 	}
 }