aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel
diff options
context:
space:
mode:
authorChristian Borntraeger <borntraeger@de.ibm.com>2012-11-15 03:35:16 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2012-11-23 05:14:34 -0500
commitce6a04ac1b759beafc88dbc443ae5da867579eeb (patch)
treed291f9d71b8d6ab6ef1d8e3783eac4acc667f2cd /arch/s390/kernel
parent39efd4ec9a2967e9720be7b66d9a4b31a58dbf61 (diff)
s390/kvm: Fix address space mixup
I was chasing down a bug of random validity intercepts on s390. (guest prefix page not mapped in the host virtual aspace). Turns out that the problem was a wrong address space control element. The cause was quite complex: During paging activity a DAT protection during SIE caused a program interrupt. Normally, the sie retry loop tries to catch all interrupts during and shortly before sie to rerun the setup. The problem is now that protection causes a suppressing program interrupt, causing the PSW to point to the instruction AFTER SIE in case of DAT protection. This confused the logic of the retry loop to not trigger, instead we jumped directly back to SIE after return from the program interrupt. (the protection fault handler itself did a rewind of the psw). This usually works quite well, but: If now the protection fault handler has to wait, another program might be scheduled in. Later on the sie process will be schedules in again. In that case the content of CR1 (primary address space) will be wrong because switch_to will put the user space ASCE into CR1 and not the guest ASCE. In addition the program parameter is also wrong for every protection fault of a guest, since we dont issue the SPP instruction. So lets also check for PSW == instruction after SIE in the program check handler. Instead of expensively checking all program interruption codes that might be suppressing we assume that a program interrupt pointing after SIE was always a program interrupt in SIE. (Otherwise we have a kernel bug anyway). We also have to compensate the rewinding, since the C-level handlers will do that. Therefore we need to add a nop with the same length as SIE before the sie_loop. Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> CC: stable@vger.kernel.org CC: Heiko Carstens <heiko.carstens@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r--arch/s390/kernel/entry64.S25
1 files changed, 20 insertions, 5 deletions
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 7a2d22dda9ef..14eec6a9577e 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -80,14 +80,21 @@ _TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
80#endif 80#endif
81 .endm 81 .endm
82 82
83 .macro HANDLE_SIE_INTERCEPT scratch 83 .macro HANDLE_SIE_INTERCEPT scratch,pgmcheck
84#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) 84#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
85 tmhh %r8,0x0001 # interrupting from user ? 85 tmhh %r8,0x0001 # interrupting from user ?
86 jnz .+42 86 jnz .+42
87 lgr \scratch,%r9 87 lgr \scratch,%r9
88 slg \scratch,BASED(.Lsie_loop) 88 slg \scratch,BASED(.Lsie_loop)
89 clg \scratch,BASED(.Lsie_length) 89 clg \scratch,BASED(.Lsie_length)
90 .if \pgmcheck
91 # Some program interrupts are suppressing (e.g. protection).
92 # We must also check the instruction after SIE in that case.
93 # do_protection_exception will rewind to rewind_pad
94 jh .+22
95 .else
90 jhe .+22 96 jhe .+22
97 .endif
91 lg %r9,BASED(.Lsie_loop) 98 lg %r9,BASED(.Lsie_loop)
92 SPP BASED(.Lhost_id) # set host id 99 SPP BASED(.Lhost_id) # set host id
93#endif 100#endif
@@ -390,7 +397,7 @@ ENTRY(pgm_check_handler)
390 lg %r12,__LC_THREAD_INFO 397 lg %r12,__LC_THREAD_INFO
391 larl %r13,system_call 398 larl %r13,system_call
392 lmg %r8,%r9,__LC_PGM_OLD_PSW 399 lmg %r8,%r9,__LC_PGM_OLD_PSW
393 HANDLE_SIE_INTERCEPT %r14 400 HANDLE_SIE_INTERCEPT %r14,1
394 tmhh %r8,0x0001 # test problem state bit 401 tmhh %r8,0x0001 # test problem state bit
395 jnz 1f # -> fault in user space 402 jnz 1f # -> fault in user space
396 tmhh %r8,0x4000 # PER bit set in old PSW ? 403 tmhh %r8,0x4000 # PER bit set in old PSW ?
@@ -466,7 +473,7 @@ ENTRY(io_int_handler)
466 lg %r12,__LC_THREAD_INFO 473 lg %r12,__LC_THREAD_INFO
467 larl %r13,system_call 474 larl %r13,system_call
468 lmg %r8,%r9,__LC_IO_OLD_PSW 475 lmg %r8,%r9,__LC_IO_OLD_PSW
469 HANDLE_SIE_INTERCEPT %r14 476 HANDLE_SIE_INTERCEPT %r14,0
470 SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT 477 SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT
471 tmhh %r8,0x0001 # interrupting from user? 478 tmhh %r8,0x0001 # interrupting from user?
472 jz io_skip 479 jz io_skip
@@ -612,7 +619,7 @@ ENTRY(ext_int_handler)
612 lg %r12,__LC_THREAD_INFO 619 lg %r12,__LC_THREAD_INFO
613 larl %r13,system_call 620 larl %r13,system_call
614 lmg %r8,%r9,__LC_EXT_OLD_PSW 621 lmg %r8,%r9,__LC_EXT_OLD_PSW
615 HANDLE_SIE_INTERCEPT %r14 622 HANDLE_SIE_INTERCEPT %r14,0
616 SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT 623 SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT
617 tmhh %r8,0x0001 # interrupting from user ? 624 tmhh %r8,0x0001 # interrupting from user ?
618 jz ext_skip 625 jz ext_skip
@@ -660,7 +667,7 @@ ENTRY(mcck_int_handler)
660 lg %r12,__LC_THREAD_INFO 667 lg %r12,__LC_THREAD_INFO
661 larl %r13,system_call 668 larl %r13,system_call
662 lmg %r8,%r9,__LC_MCK_OLD_PSW 669 lmg %r8,%r9,__LC_MCK_OLD_PSW
663 HANDLE_SIE_INTERCEPT %r14 670 HANDLE_SIE_INTERCEPT %r14,0
664 tm __LC_MCCK_CODE,0x80 # system damage? 671 tm __LC_MCCK_CODE,0x80 # system damage?
665 jo mcck_panic # yes -> rest of mcck code invalid 672 jo mcck_panic # yes -> rest of mcck code invalid
666 lghi %r14,__LC_CPU_TIMER_SAVE_AREA 673 lghi %r14,__LC_CPU_TIMER_SAVE_AREA
@@ -959,6 +966,13 @@ ENTRY(sie64a)
959 stg %r3,__SF_EMPTY+8(%r15) # save guest register save area 966 stg %r3,__SF_EMPTY+8(%r15) # save guest register save area
960 xc __SF_EMPTY+16(8,%r15),__SF_EMPTY+16(%r15) # host id == 0 967 xc __SF_EMPTY+16(8,%r15),__SF_EMPTY+16(%r15) # host id == 0
961 lmg %r0,%r13,0(%r3) # load guest gprs 0-13 968 lmg %r0,%r13,0(%r3) # load guest gprs 0-13
969# some program checks are suppressing. C code (e.g. do_protection_exception)
970# will rewind the PSW by the ILC, which is 4 bytes in case of SIE. Other
971# instructions in the sie_loop should not cause program interrupts. So
972# lets use a nop (47 00 00 00) as a landing pad.
973# See also HANDLE_SIE_INTERCEPT
974rewind_pad:
975 nop 0
962sie_loop: 976sie_loop:
963 lg %r14,__LC_THREAD_INFO # pointer thread_info struct 977 lg %r14,__LC_THREAD_INFO # pointer thread_info struct
964 tm __TI_flags+7(%r14),_TIF_EXIT_SIE 978 tm __TI_flags+7(%r14),_TIF_EXIT_SIE
@@ -998,6 +1012,7 @@ sie_fault:
998.Lhost_id: 1012.Lhost_id:
999 .quad 0 1013 .quad 0
1000 1014
1015 EX_TABLE(rewind_pad,sie_fault)
1001 EX_TABLE(sie_loop,sie_fault) 1016 EX_TABLE(sie_loop,sie_fault)
1002#endif 1017#endif
1003 1018