Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

s390/base: pass pt_regs to early program check handler

Pass pt_regs to early program check handler like it is done for every
other interrupt and exception handler.

Also the passed pt_regs can be changed by the called function and the
changes register contents and psw contents will be taken into account
when returning. In addition the return psw will not be copied to the
program check old psw in lowcore, but to the usual return psw
location, like it is also done by the regular program check handler.
This allows also to get rid of the code that disabled lowcore
protection when changing the return address.

Reviewed-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>

authored by

Heiko Carstens and committed by
Vasily Gorbik
cfa45c5e 0741ec11

+20 -18
+1 -1
arch/s390/include/asm/processor.h
··· 313 313 * Basic Program Check Handler. 314 314 */ 315 315 extern void s390_base_pgm_handler(void); 316 - extern void (*s390_base_pgm_handler_fn)(void); 316 + extern void (*s390_base_pgm_handler_fn)(struct pt_regs *regs); 317 317 318 318 #define ARCH_LOW_ADDRESS_LIMIT 0x7fffffffUL 319 319
+16 -6
arch/s390/kernel/base.S
··· 14 14 GEN_BR_THUNK %r9 15 15 GEN_BR_THUNK %r14 16 16 17 + __PT_R0 = __PT_GPRS 18 + __PT_R8 = __PT_GPRS + 64 19 + 17 20 ENTRY(s390_base_pgm_handler) 18 - stmg %r0,%r15,__LC_SAVE_AREA_SYNC 19 - basr %r13,0 20 - 0: aghi %r15,-STACK_FRAME_OVERHEAD 21 + stmg %r8,%r15,__LC_SAVE_AREA_SYNC 22 + aghi %r15,-(STACK_FRAME_OVERHEAD+__PT_SIZE) 23 + la %r11,STACK_FRAME_OVERHEAD(%r15) 24 + xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) 25 + stmg %r0,%r7,__PT_R0(%r11) 26 + mvc __PT_PSW(16,%r11),__LC_PGM_OLD_PSW 27 + mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC 28 + lgr %r2,%r11 21 29 larl %r1,s390_base_pgm_handler_fn 22 30 lg %r9,0(%r1) 23 31 ltgr %r9,%r9 24 32 jz 1f 25 33 BASR_EX %r14,%r9 26 - lmg %r0,%r15,__LC_SAVE_AREA_SYNC 27 - lpswe __LC_PGM_OLD_PSW 28 - 1: lpswe disabled_wait_psw-0b(%r13) 34 + mvc __LC_RETURN_PSW(16),STACK_FRAME_OVERHEAD+__PT_PSW(%r15) 35 + lmg %r0,%r15,STACK_FRAME_OVERHEAD+__PT_R0(%r15) 36 + lpswe __LC_RETURN_PSW 37 + 1: larl %r13,disabled_wait_psw 38 + lpswe 0(%r13) 29 39 ENDPROC(s390_base_pgm_handler) 30 40 31 41 .align 8
+3 -11
arch/s390/kernel/early.c
··· 149 149 topology_max_mnest = max_mnest; 150 150 } 151 151 152 - static void early_pgm_check_handler(void) 152 + static void early_pgm_check_handler(struct pt_regs *regs) 153 153 { 154 154 const struct exception_table_entry *fixup; 155 - unsigned long cr0, cr0_new; 156 - unsigned long addr; 157 155 158 - addr = S390_lowcore.program_old_psw.addr; 159 - fixup = s390_search_extables(addr); 156 + fixup = s390_search_extables(regs->psw.addr); 160 157 if (!fixup) 161 158 disabled_wait(); 162 - /* Disable low address protection before storing into lowcore. */ 163 - __ctl_store(cr0, 0, 0); 164 - cr0_new = cr0 & ~(1UL << 28); 165 - __ctl_load(cr0_new, 0, 0); 166 - S390_lowcore.program_old_psw.addr = extable_fixup(fixup); 167 - __ctl_load(cr0, 0, 0); 159 + regs->psw.addr = extable_fixup(fixup); 168 160 } 169 161 170 162 static noinline __init void setup_lowcore_early(void)