mirror of
https://github.com/torvalds/linux.git
synced 2024-11-29 07:31:29 +00:00
s390/kvm: avoid automatic sie reentry
Do not automatically restart the sie instruction in entry64.S after an interrupt, return to the caller with a reason code instead. That allows to deal with RCU and other conditions in C code. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> Signed-off-by: Gleb Natapov <gleb@redhat.com>
This commit is contained in:
parent
2c70fe4416
commit
7c470539c9
@ -47,7 +47,6 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
|
||||
_TIF_MCCK_PENDING)
|
||||
_TIF_TRACE = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
|
||||
_TIF_SYSCALL_TRACEPOINT)
|
||||
_TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
|
||||
|
||||
#define BASED(name) name-system_call(%r13)
|
||||
|
||||
@ -81,25 +80,27 @@ _TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
|
||||
#endif
|
||||
.endm
|
||||
|
||||
.macro HANDLE_SIE_INTERCEPT scratch,pgmcheck
|
||||
.macro HANDLE_SIE_INTERCEPT scratch,reason
|
||||
#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
|
||||
tmhh %r8,0x0001 # interrupting from user ?
|
||||
jnz .+52
|
||||
jnz .+62
|
||||
lgr \scratch,%r9
|
||||
slg \scratch,BASED(.Lsie_loop)
|
||||
clg \scratch,BASED(.Lsie_length)
|
||||
.if \pgmcheck
|
||||
slg \scratch,BASED(.Lsie_critical)
|
||||
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 rewind_pad
|
||||
jh .+32
|
||||
jh .+42
|
||||
.else
|
||||
jhe .+32
|
||||
jhe .+42
|
||||
.endif
|
||||
lg %r9,BASED(.Lsie_loop)
|
||||
LPP BASED(.Lhost_id) # set host id
|
||||
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
|
||||
ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE
|
||||
lctlg %c1,%c1,__LC_USER_ASCE # load primary asce
|
||||
larl %r9,sie_exit # skip forward to sie_exit
|
||||
mvi __SF_EMPTY+31(%r15),\reason # set exit reason
|
||||
#endif
|
||||
.endm
|
||||
|
||||
@ -452,7 +453,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,0
|
||||
HANDLE_SIE_INTERCEPT %r14,2
|
||||
SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT
|
||||
tmhh %r8,0x0001 # interrupting from user?
|
||||
jz io_skip
|
||||
@ -597,7 +598,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,0
|
||||
HANDLE_SIE_INTERCEPT %r14,3
|
||||
SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT
|
||||
tmhh %r8,0x0001 # interrupting from user ?
|
||||
jz ext_skip
|
||||
@ -645,7 +646,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,0
|
||||
HANDLE_SIE_INTERCEPT %r14,4
|
||||
tm __LC_MCCK_CODE,0x80 # system damage?
|
||||
jo mcck_panic # yes -> rest of mcck code invalid
|
||||
lghi %r14,__LC_CPU_TIMER_SAVE_AREA
|
||||
@ -939,19 +940,8 @@ ENTRY(sie64a)
|
||||
stmg %r6,%r14,__SF_GPRS(%r15) # save kernel registers
|
||||
stg %r2,__SF_EMPTY(%r15) # save control block pointer
|
||||
stg %r3,__SF_EMPTY+8(%r15) # save guest register save area
|
||||
xc __SF_EMPTY+16(8,%r15),__SF_EMPTY+16(%r15) # host id == 0
|
||||
xc __SF_EMPTY+16(16,%r15),__SF_EMPTY+16(%r15) # host id & reason
|
||||
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
|
||||
jnz sie_exit
|
||||
lg %r14,__LC_GMAP # get gmap pointer
|
||||
ltgr %r14,%r14
|
||||
jz sie_gmap
|
||||
@ -966,33 +956,33 @@ sie_gmap:
|
||||
sie_done:
|
||||
LPP __SF_EMPTY+16(%r15) # set host id
|
||||
ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE
|
||||
lg %r14,__LC_THREAD_INFO # pointer thread_info struct
|
||||
sie_exit:
|
||||
lctlg %c1,%c1,__LC_USER_ASCE # load primary asce
|
||||
# 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 beween sie64a and sie_done 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_exit:
|
||||
lg %r14,__SF_EMPTY+8(%r15) # load guest register save area
|
||||
stmg %r0,%r13,0(%r14) # save guest gprs 0-13
|
||||
lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers
|
||||
lghi %r2,0
|
||||
lg %r2,__SF_EMPTY+24(%r15) # return exit reason code
|
||||
br %r14
|
||||
sie_fault:
|
||||
lctlg %c1,%c1,__LC_USER_ASCE # load primary asce
|
||||
lg %r14,__LC_THREAD_INFO # pointer thread_info struct
|
||||
lg %r14,__SF_EMPTY+8(%r15) # load guest register save area
|
||||
stmg %r0,%r13,0(%r14) # save guest gprs 0-13
|
||||
lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers
|
||||
lghi %r2,-EFAULT
|
||||
br %r14
|
||||
lghi %r14,-EFAULT
|
||||
stg %r14,__SF_EMPTY+24(%r15) # set exit reason code
|
||||
j sie_exit
|
||||
|
||||
.align 8
|
||||
.Lsie_loop:
|
||||
.quad sie_loop
|
||||
.Lsie_length:
|
||||
.quad sie_done - sie_loop
|
||||
.Lhost_id:
|
||||
.quad 0
|
||||
.Lsie_critical:
|
||||
.quad sie_gmap
|
||||
.Lsie_critical_length:
|
||||
.quad sie_done - sie_gmap
|
||||
|
||||
EX_TABLE(rewind_pad,sie_fault)
|
||||
EX_TABLE(sie_loop,sie_fault)
|
||||
EX_TABLE(sie_exit,sie_fault)
|
||||
#endif
|
||||
|
||||
.section .rodata, "a"
|
||||
|
@ -707,7 +707,9 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
|
||||
trace_kvm_s390_sie_enter(vcpu,
|
||||
atomic_read(&vcpu->arch.sie_block->cpuflags));
|
||||
rc = sie64a(vcpu->arch.sie_block, vcpu->run->s.regs.gprs);
|
||||
if (rc) {
|
||||
if (rc > 0)
|
||||
rc = 0;
|
||||
if (rc < 0) {
|
||||
if (kvm_is_ucontrol(vcpu->kvm)) {
|
||||
rc = SIE_INTERCEPT_UCONTROL;
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user