summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeiko Carstens <hca@linux.ibm.com>2023-12-01 14:09:30 +0100
committerAlexander Gordeev <agordeev@linux.ibm.com>2023-12-11 14:33:05 +0100
commit84e599e3adc78800f8517f22f65b7a181cbb824b (patch)
tree356505c15f461b25237f611c1d565205d7fe266e
parents390/ctlreg: return old register contents when changing bits (diff)
downloadlinux-84e599e3adc78800f8517f22f65b7a181cbb824b.tar.xz
linux-84e599e3adc78800f8517f22f65b7a181cbb824b.zip
s390/nmi: consistently enable machine checks in trap_init()
The kernel starts with machine checks disabled (machine check mask bit in the PSW is zero), and machine checks are enabled when trap_init() is called. The rationale is that this allows to assume that the system is initialized up to a certain point before the machine check handler may be invoked. However the implementation is incomplete: all new PSW masks in lowcore have the machine check mask bit. This means that e.g. for any early program check machine checks are enabled within the program check handler. This contradicts the whole point of enabling machine checks at a single place. Change this and initialize all new PSWs in lowcore so they have the machine check mask bit not set. Set the bit in all masks in trap_init(). This way machine check enabling is consistent. 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>
-rw-r--r--arch/s390/kernel/setup.c8
-rw-r--r--arch/s390/kernel/traps.c11
2 files changed, 15 insertions, 4 deletions
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 5701356f4f33..c0e7cfdd7747 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -408,15 +408,15 @@ static void __init setup_lowcore(void)
lc->restart_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_DAT;
lc->restart_psw.addr = __pa(restart_int_handler);
- lc->external_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK;
+ lc->external_new_psw.mask = PSW_KERNEL_BITS;
lc->external_new_psw.addr = (unsigned long) ext_int_handler;
- lc->svc_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK;
+ lc->svc_new_psw.mask = PSW_KERNEL_BITS;
lc->svc_new_psw.addr = (unsigned long) system_call;
- lc->program_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK;
+ lc->program_new_psw.mask = PSW_KERNEL_BITS;
lc->program_new_psw.addr = (unsigned long) pgm_check_handler;
lc->mcck_new_psw.mask = PSW_KERNEL_BITS;
lc->mcck_new_psw.addr = (unsigned long) mcck_int_handler;
- lc->io_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK;
+ lc->io_new_psw.mask = PSW_KERNEL_BITS;
lc->io_new_psw.addr = (unsigned long) io_int_handler;
lc->clock_comparator = clock_comparator_max;
lc->current_task = (unsigned long)&init_task;
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index 1d2aa448d103..8cb3832a1621 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -286,6 +286,17 @@ static void __init test_monitor_call(void)
void __init trap_init(void)
{
+ unsigned long flags;
+ struct ctlreg cr0;
+
+ local_irq_save(flags);
+ cr0 = local_ctl_clear_bit(0, CR0_LOW_ADDRESS_PROTECTION_BIT);
+ psw_bits(S390_lowcore.external_new_psw).mcheck = 1;
+ psw_bits(S390_lowcore.program_new_psw).mcheck = 1;
+ psw_bits(S390_lowcore.svc_new_psw).mcheck = 1;
+ psw_bits(S390_lowcore.io_new_psw).mcheck = 1;
+ local_ctl_load(0, &cr0);
+ local_irq_restore(flags);
local_mcck_enable();
test_monitor_call();
}