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>
This commit is contained in:
Родитель
39efd4ec9a
Коммит
ce6a04ac1b
|
@ -80,14 +80,21 @@ _TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
|
|||
#endif
|
||||
.endm
|
||||
|
||||
.macro HANDLE_SIE_INTERCEPT scratch
|
||||
.macro HANDLE_SIE_INTERCEPT scratch,pgmcheck
|
||||
#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
|
||||
tmhh %r8,0x0001 # interrupting from user ?
|
||||
jnz .+42
|
||||
lgr \scratch,%r9
|
||||
slg \scratch,BASED(.Lsie_loop)
|
||||
clg \scratch,BASED(.Lsie_length)
|
||||
.if \pgmcheck
|
||||
# Some program interrupts are suppressing (e.g. protection).
|
||||
# We must also check the instruction after SIE in that case.
|
||||
# do_protection_exception will rewind to rewind_pad
|
||||
jh .+22
|
||||
.else
|
||||
jhe .+22
|
||||
.endif
|
||||
lg %r9,BASED(.Lsie_loop)
|
||||
SPP BASED(.Lhost_id) # set host id
|
||||
#endif
|
||||
|
@ -390,7 +397,7 @@ ENTRY(pgm_check_handler)
|
|||
lg %r12,__LC_THREAD_INFO
|
||||
larl %r13,system_call
|
||||
lmg %r8,%r9,__LC_PGM_OLD_PSW
|
||||
HANDLE_SIE_INTERCEPT %r14
|
||||
HANDLE_SIE_INTERCEPT %r14,1
|
||||
tmhh %r8,0x0001 # test problem state bit
|
||||
jnz 1f # -> fault in user space
|
||||
tmhh %r8,0x4000 # PER bit set in old PSW ?
|
||||
|
@ -466,7 +473,7 @@ ENTRY(io_int_handler)
|
|||
lg %r12,__LC_THREAD_INFO
|
||||
larl %r13,system_call
|
||||
lmg %r8,%r9,__LC_IO_OLD_PSW
|
||||
HANDLE_SIE_INTERCEPT %r14
|
||||
HANDLE_SIE_INTERCEPT %r14,0
|
||||
SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT
|
||||
tmhh %r8,0x0001 # interrupting from user?
|
||||
jz io_skip
|
||||
|
@ -612,7 +619,7 @@ ENTRY(ext_int_handler)
|
|||
lg %r12,__LC_THREAD_INFO
|
||||
larl %r13,system_call
|
||||
lmg %r8,%r9,__LC_EXT_OLD_PSW
|
||||
HANDLE_SIE_INTERCEPT %r14
|
||||
HANDLE_SIE_INTERCEPT %r14,0
|
||||
SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT
|
||||
tmhh %r8,0x0001 # interrupting from user ?
|
||||
jz ext_skip
|
||||
|
@ -660,7 +667,7 @@ ENTRY(mcck_int_handler)
|
|||
lg %r12,__LC_THREAD_INFO
|
||||
larl %r13,system_call
|
||||
lmg %r8,%r9,__LC_MCK_OLD_PSW
|
||||
HANDLE_SIE_INTERCEPT %r14
|
||||
HANDLE_SIE_INTERCEPT %r14,0
|
||||
tm __LC_MCCK_CODE,0x80 # system damage?
|
||||
jo mcck_panic # yes -> rest of mcck code invalid
|
||||
lghi %r14,__LC_CPU_TIMER_SAVE_AREA
|
||||
|
@ -959,6 +966,13 @@ ENTRY(sie64a)
|
|||
stg %r3,__SF_EMPTY+8(%r15) # save guest register save area
|
||||
xc __SF_EMPTY+16(8,%r15),__SF_EMPTY+16(%r15) # host id == 0
|
||||
lmg %r0,%r13,0(%r3) # load guest gprs 0-13
|
||||
# some program checks are suppressing. C code (e.g. do_protection_exception)
|
||||
# will rewind the PSW by the ILC, which is 4 bytes in case of SIE. Other
|
||||
# instructions in the sie_loop should not cause program interrupts. So
|
||||
# lets use a nop (47 00 00 00) as a landing pad.
|
||||
# See also HANDLE_SIE_INTERCEPT
|
||||
rewind_pad:
|
||||
nop 0
|
||||
sie_loop:
|
||||
lg %r14,__LC_THREAD_INFO # pointer thread_info struct
|
||||
tm __TI_flags+7(%r14),_TIF_EXIT_SIE
|
||||
|
@ -998,6 +1012,7 @@ sie_fault:
|
|||
.Lhost_id:
|
||||
.quad 0
|
||||
|
||||
EX_TABLE(rewind_pad,sie_fault)
|
||||
EX_TABLE(sie_loop,sie_fault)
|
||||
#endif
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче