s390/sclp: make early sclp irq handler more robust
authorHeiko Carstens <heiko.carstens@de.ibm.com>
Wed, 11 Jan 2017 08:14:45 +0000 (09:14 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 16 Jan 2017 06:27:55 +0000 (07:27 +0100)
Make the early sclp interrupt handler more robust:

- disable all interrupt sub classes except for the service signal subclass
- extend ctlreg0 union so it is easily possible to set the service signal
  subclass mask bit without using a magic number
- disable lowcore protection before writing to it
- make sure that all write accesses are done before the original content
  of control register 0 is restored, which could enable lowcore protection

Reviewed-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/include/asm/ctl_reg.h
arch/s390/kernel/sclp.c

index 8e136b88cdf4f13460b960f8db9d02e1ae88324f..cf4c9a106049f98ba9caa6d70f5a96ecfcc66033 100644 (file)
@@ -62,7 +62,9 @@ union ctlreg0 {
                unsigned long      : 4;
                unsigned long afp  : 1; /* AFP-register control */
                unsigned long vx   : 1; /* Vector enablement control */
-               unsigned long      : 17;
+               unsigned long      : 7;
+               unsigned long sssm : 1; /* Service signal subclass mask */
+               unsigned long      : 9;
        };
 };
 
index f08af675f36f5371ce52e219cde59e176fee8c10..745324349a7b8d7efc6a730dfa5a283a973f4070 100644 (file)
@@ -18,12 +18,16 @@ static bool have_linemode __section(data);
 
 static void _sclp_wait_int(void)
 {
-       unsigned long cr0, cr0_new, psw_mask, addr;
+       unsigned long psw_mask, addr, flags;
        psw_t psw_ext_save, psw_wait;
+       union ctlreg0 cr0, cr0_new;
 
-       __ctl_store(cr0, 0, 0);
-       cr0_new = cr0 | 0x200;
-       __ctl_load(cr0_new, 0, 0);
+       raw_local_irq_save(flags);
+       __ctl_store(cr0.val, 0, 0);
+       cr0_new.val = cr0.val & ~CR0_IRQ_SUBCLASS_MASK;
+       cr0_new.lap = 0;
+       cr0_new.sssm = 1;
+       __ctl_load(cr0_new.val, 0, 0);
 
        psw_ext_save = S390_lowcore.external_new_psw;
        psw_mask = __extract_psw();
@@ -45,8 +49,9 @@ static void _sclp_wait_int(void)
                        : "cc", "memory");
        } while (S390_lowcore.ext_int_code != EXT_IRQ_SERVICE_SIG);
 
-       __ctl_load(cr0, 0, 0);
        S390_lowcore.external_new_psw = psw_ext_save;
+       __ctl_load(cr0.val, 0, 0);
+       raw_local_irq_restore(flags);
 }
 
 static int _sclp_servc(unsigned int cmd, char *sccb)