Commit dcd2a9aa authored by Martin Schwidefsky's avatar Martin Schwidefsky

s390/kvm: fix interrupt race with HANDLE_SIE_INTERCEPT

The HANDLE_SIE_INTERCEPT macro is used in the interrupt handlers
and the program check handler to undo a few changes done by sie64a.
Among them are guest vs host LPP, the gmap ASCE vs kernel ASCE and
the bit that indicates that SIE is currently running on the CPU.

There is a race of a voluntary SIE exit vs asynchronous interrupts.
If the CPU completed the SIE instruction and the TM instruction of
the LPP macro at the time it receives an interrupt, the interrupt
handler will run while the LPP, the ASCE and the SIE bit are still
set up for guest execution. This might result in wrong sampling data,
but it will not cause data corruption or lockups.

The critical section in sie64a needs to be enlarged to include all
instructions that undo the changes required for guest execution.
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent d05377c1
...@@ -90,14 +90,7 @@ _PIF_WORK = (_PIF_PER_TRAP) ...@@ -90,14 +90,7 @@ _PIF_WORK = (_PIF_PER_TRAP)
lgr \scratch,%r9 lgr \scratch,%r9
slg \scratch,BASED(.Lsie_critical) slg \scratch,BASED(.Lsie_critical)
clg \scratch,BASED(.Lsie_critical_length) clg \scratch,BASED(.Lsie_critical_length)
.if \reason==1
# 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 .Lrewind_pad
jh .+42
.else
jhe .+42 jhe .+42
.endif
lg %r14,__SF_EMPTY(%r15) # get control block pointer lg %r14,__SF_EMPTY(%r15) # get control block pointer
LPP __SF_EMPTY+16(%r15) # set host id LPP __SF_EMPTY+16(%r15) # set host id
ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE
...@@ -1308,15 +1301,16 @@ ENTRY(sie64a) ...@@ -1308,15 +1301,16 @@ ENTRY(sie64a)
lg %r14,__SF_EMPTY(%r15) # get control block pointer lg %r14,__SF_EMPTY(%r15) # get control block pointer
oi __SIE_PROG0C+3(%r14),1 # we are going into SIE now oi __SIE_PROG0C+3(%r14),1 # we are going into SIE now
tm __SIE_PROG20+3(%r14),3 # last exit... tm __SIE_PROG20+3(%r14),3 # last exit...
jnz .Lsie_done jnz .Lsie_skip
tm __LC_CPU_FLAGS+7,_CIF_FPU tm __LC_CPU_FLAGS+7,_CIF_FPU
jo .Lsie_done # exit if fp/vx regs changed jo .Lsie_skip # exit if fp/vx regs changed
LPP __SF_EMPTY(%r15) # set guest id LPP __SF_EMPTY(%r15) # set guest id
sie 0(%r14) sie 0(%r14)
.Lsie_done:
LPP __SF_EMPTY+16(%r15) # set host id LPP __SF_EMPTY+16(%r15) # set host id
.Lsie_skip:
ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE
lctlg %c1,%c1,__LC_USER_ASCE # load primary asce lctlg %c1,%c1,__LC_USER_ASCE # load primary asce
.Lsie_done:
# some program checks are suppressing. C code (e.g. do_protection_exception) # 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 # will rewind the PSW by the ILC, which is 4 bytes in case of SIE. Other
# instructions between sie64a and .Lsie_done should not cause program # instructions between sie64a and .Lsie_done should not cause program
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment