diff options
author | Heiko Carstens <hca@linux.ibm.com> | 2022-11-28 14:16:33 +0100 |
---|---|---|
committer | Alexander Gordeev <agordeev@linux.ibm.com> | 2022-12-06 16:18:25 +0100 |
commit | 506faa5b9b4f05e667b39252a28dace17a5017a1 (patch) | |
tree | 2d2267db461afe0ecd5324e02caa346dc978c9d7 /arch/s390/kernel | |
parent | b64d7254ffe8b11010150fa97a4b235ec36e7a90 (diff) | |
download | linux-stable-506faa5b9b4f05e667b39252a28dace17a5017a1.tar.gz linux-stable-506faa5b9b4f05e667b39252a28dace17a5017a1.tar.bz2 linux-stable-506faa5b9b4f05e667b39252a28dace17a5017a1.zip |
s390/nmi: print machine check interruption code before stopping system
In case a system will be stopped because of e.g. missing validity bits
print the machine check interruption code before the system is stopped.
This is helpful, since up to now no message was printed in such a
case. Only a disabled wait PSW was loaded, which doesn't give a hint of
what went wrong.
Improve this by printing a message with debug information.
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Reviewed-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r-- | arch/s390/kernel/nmi.c | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c index 3518ba638a85..b1579c85b869 100644 --- a/arch/s390/kernel/nmi.c +++ b/arch/s390/kernel/nmi.c @@ -114,9 +114,61 @@ void nmi_free_mcesa(u64 *mcesad) kmem_cache_free(mcesa_cache, __va(*mcesad & MCESA_ORIGIN_MASK)); } +static __always_inline char *nmi_puts(char *dest, const char *src) +{ + while (*src) + *dest++ = *src++; + *dest = 0; + return dest; +} + +static __always_inline char *u64_to_hex(char *dest, u64 val) +{ + int i, num; + + for (i = 1; i <= 16; i++) { + num = (val >> (64 - 4 * i)) & 0xf; + if (num >= 10) + *dest++ = 'A' + num - 10; + else + *dest++ = '0' + num; + } + *dest = 0; + return dest; +} + static notrace void s390_handle_damage(void) { + union ctlreg0 cr0, cr0_new; + char message[100]; + psw_t psw_save; + char *ptr; + smp_emergency_stop(); + diag_amode31_ops.diag308_reset(); + ptr = nmi_puts(message, "System stopped due to unrecoverable machine check, code: 0x"); + u64_to_hex(ptr, S390_lowcore.mcck_interruption_code); + + /* + * Disable low address protection and make machine check new PSW a + * disabled wait PSW. Any additional machine check cannot be handled. + */ + __ctl_store(cr0.val, 0, 0); + cr0_new = cr0; + cr0_new.lap = 0; + __ctl_load(cr0_new.val, 0, 0); + psw_save = S390_lowcore.mcck_new_psw; + psw_bits(S390_lowcore.mcck_new_psw).io = 0; + psw_bits(S390_lowcore.mcck_new_psw).ext = 0; + psw_bits(S390_lowcore.mcck_new_psw).wait = 1; + sclp_emergency_printk(message); + + /* + * Restore machine check new PSW and control register 0 to original + * values. This makes possible system dump analysis easier. + */ + S390_lowcore.mcck_new_psw = psw_save; + __ctl_load(cr0.val, 0, 0); disabled_wait(); while (1); } |