From 37e37c20ab2dbccdc7a7fa5922e182a51adf50f6 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Wed, 11 Apr 2012 14:28:11 +0200 Subject: [PATCH] [S390] Fix stfle() lowcore protection problem The stfle() function writes into lowcore memory when stfl_fac_list is initialized with "S390_lowcore.stfl_fac_list = 0". For older compilers this triggers a lowcore exception. With newer compilers and "-OXX" compile option the bug does not show up because the "S390_lowcore.stfl_fac_list" initialization is removed by the compiler. The reason for thatis the incorrect "=m" (S390_lowcore.stfl_fac_list) constraint in the stfl inline assembly. The following shows the disassembly of the stfle() optimized code that is inlined in the lgr_info_get() function: 000000000011325c : 11325c: eb 9f f0 60 00 24 stmg %r9,%r15,96(%r15) 113262: c0 d0 00 29 0e 47 larl %r13,634ef0 113268: a7 f1 3f c0 tml %r15,16320 11326c: b9 04 00 ef lgr %r14,%r15 113270: a7 84 00 01 je 113272 113274: a7 fb ff c0 aghi %r15,-64 113278: b9 04 00 c2 lgr %r12,%r2 11327c: a7 29 00 01 lghi %r2,1 113280: e3 e0 f0 98 00 24 stg %r14,152(%r15) 113286: d7 97 c0 00 c0 00 xc 0(152,%r12),0(%r12) 11328c: c0 e5 00 28 db 4c brasl %r14,62e924 113292: b2 b1 00 00 stfl 0 To fix the problem we now clear the S390_lowcore.stfl_fac_list at startup in "head.S" for all machine types before lowcore protection is enabled. In addition to that the "=m" constraint is replaced by "+m". Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/facility.h | 3 +-- arch/s390/kernel/head.S | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/s390/include/asm/facility.h b/arch/s390/include/asm/facility.h index 1e5b27edc0c9..2ee66a65f2d4 100644 --- a/arch/s390/include/asm/facility.h +++ b/arch/s390/include/asm/facility.h @@ -38,12 +38,11 @@ static inline void stfle(u64 *stfle_fac_list, int size) unsigned long nr; preempt_disable(); - S390_lowcore.stfl_fac_list = 0; asm volatile( " .insn s,0xb2b10000,0(0)\n" /* stfl */ "0:\n" EX_TABLE(0b, 0b) - : "=m" (S390_lowcore.stfl_fac_list)); + : "+m" (S390_lowcore.stfl_fac_list)); nr = 4; /* bytes stored by stfl */ memcpy(stfle_fac_list, &S390_lowcore.stfl_fac_list, 4); if (S390_lowcore.stfl_fac_list & 0x01000000) { diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index c27a0727f930..adccd908ebc7 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S @@ -474,9 +474,9 @@ ENTRY(startup_kdump) stck __LC_LAST_UPDATE_CLOCK spt 5f-.LPG0(%r13) mvc __LC_LAST_UPDATE_TIMER(8),5f-.LPG0(%r13) + xc __LC_STFL_FAC_LIST(8),__LC_STFL_FAC_LIST #ifndef CONFIG_MARCH_G5 # check capabilities against MARCH_{G5,Z900,Z990,Z9_109,Z10} - xc __LC_STFL_FAC_LIST(8),__LC_STFL_FAC_LIST .insn s,0xb2b10000,__LC_STFL_FAC_LIST # store facility list tm __LC_STFL_FAC_LIST,0x01 # stfle available ? jz 0f