s390/nmi: consistently enable machine checks in trap_init()
authorHeiko Carstens <hca@linux.ibm.com>
Fri, 1 Dec 2023 13:09:30 +0000 (14:09 +0100)
committerAlexander Gordeev <agordeev@linux.ibm.com>
Mon, 11 Dec 2023 13:33:05 +0000 (14:33 +0100)
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>
arch/s390/kernel/setup.c
arch/s390/kernel/traps.c

index 5701356f4f330200093148866d7e676fc8a33a08..c0e7cfdd7747697d9fccd391c0f1b3d779c38bab 100644 (file)
@@ -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;
index 1d2aa448d1031ce516bcf5afdec778e7a911d660..8cb3832a162110dabc96978407ae1963c62f81b4 100644 (file)
@@ -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();
 }