Commit 7c470539 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Gleb Natapov

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: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarChristian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: default avatarGleb Natapov <gleb@redhat.com>
parent 2c70fe44
...@@ -47,7 +47,6 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ ...@@ -47,7 +47,6 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
_TIF_MCCK_PENDING) _TIF_MCCK_PENDING)
_TIF_TRACE = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \ _TIF_TRACE = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
_TIF_SYSCALL_TRACEPOINT) _TIF_SYSCALL_TRACEPOINT)
_TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
#define BASED(name) name-system_call(%r13) #define BASED(name) name-system_call(%r13)
...@@ -81,25 +80,27 @@ _TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING) ...@@ -81,25 +80,27 @@ _TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
#endif #endif
.endm .endm
.macro HANDLE_SIE_INTERCEPT scratch,pgmcheck .macro HANDLE_SIE_INTERCEPT scratch,reason
#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
tmhh %r8,0x0001 # interrupting from user ? tmhh %r8,0x0001 # interrupting from user ?
jnz .+52 jnz .+62
lgr \scratch,%r9 lgr \scratch,%r9
slg \scratch,BASED(.Lsie_loop) slg \scratch,BASED(.Lsie_critical)
clg \scratch,BASED(.Lsie_length) clg \scratch,BASED(.Lsie_critical_length)
.if \pgmcheck .if \reason==1
# Some program interrupts are suppressing (e.g. protection). # Some program interrupts are suppressing (e.g. protection).
# We must also check the instruction after SIE in that case. # We must also check the instruction after SIE in that case.
# do_protection_exception will rewind to rewind_pad # do_protection_exception will rewind to rewind_pad
jh .+32 jh .+42
.else .else
jhe .+32 jhe .+42
.endif .endif
lg %r9,BASED(.Lsie_loop) lg %r14,__SF_EMPTY(%r15) # get control block pointer
LPP BASED(.Lhost_id) # set host id LPP __SF_EMPTY+16(%r15) # set host id
lg %r14,__SF_EMPTY(%r15) # get control block pointer
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
larl %r9,sie_exit # skip forward to sie_exit
mvi __SF_EMPTY+31(%r15),\reason # set exit reason
#endif #endif
.endm .endm
...@@ -452,7 +453,7 @@ ENTRY(io_int_handler) ...@@ -452,7 +453,7 @@ ENTRY(io_int_handler)
lg %r12,__LC_THREAD_INFO lg %r12,__LC_THREAD_INFO
larl %r13,system_call larl %r13,system_call
lmg %r8,%r9,__LC_IO_OLD_PSW 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 SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT
tmhh %r8,0x0001 # interrupting from user? tmhh %r8,0x0001 # interrupting from user?
jz io_skip jz io_skip
...@@ -597,7 +598,7 @@ ENTRY(ext_int_handler) ...@@ -597,7 +598,7 @@ ENTRY(ext_int_handler)
lg %r12,__LC_THREAD_INFO lg %r12,__LC_THREAD_INFO
larl %r13,system_call larl %r13,system_call
lmg %r8,%r9,__LC_EXT_OLD_PSW 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 SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT
tmhh %r8,0x0001 # interrupting from user ? tmhh %r8,0x0001 # interrupting from user ?
jz ext_skip jz ext_skip
...@@ -645,7 +646,7 @@ ENTRY(mcck_int_handler) ...@@ -645,7 +646,7 @@ ENTRY(mcck_int_handler)
lg %r12,__LC_THREAD_INFO lg %r12,__LC_THREAD_INFO
larl %r13,system_call larl %r13,system_call
lmg %r8,%r9,__LC_MCK_OLD_PSW lmg %r8,%r9,__LC_MCK_OLD_PSW
HANDLE_SIE_INTERCEPT %r14,0 HANDLE_SIE_INTERCEPT %r14,4
tm __LC_MCCK_CODE,0x80 # system damage? tm __LC_MCCK_CODE,0x80 # system damage?
jo mcck_panic # yes -> rest of mcck code invalid jo mcck_panic # yes -> rest of mcck code invalid
lghi %r14,__LC_CPU_TIMER_SAVE_AREA lghi %r14,__LC_CPU_TIMER_SAVE_AREA
...@@ -939,19 +940,8 @@ ENTRY(sie64a) ...@@ -939,19 +940,8 @@ ENTRY(sie64a)
stmg %r6,%r14,__SF_GPRS(%r15) # save kernel registers stmg %r6,%r14,__SF_GPRS(%r15) # save kernel registers
stg %r2,__SF_EMPTY(%r15) # save control block pointer stg %r2,__SF_EMPTY(%r15) # save control block pointer
stg %r3,__SF_EMPTY+8(%r15) # save guest register save area 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 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 lg %r14,__LC_GMAP # get gmap pointer
ltgr %r14,%r14 ltgr %r14,%r14
jz sie_gmap jz sie_gmap
...@@ -966,33 +956,33 @@ sie_gmap: ...@@ -966,33 +956,33 @@ sie_gmap:
sie_done: sie_done:
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
lg %r14,__LC_THREAD_INFO # pointer thread_info struct
sie_exit:
lctlg %c1,%c1,__LC_USER_ASCE # load primary asce 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 lg %r14,__SF_EMPTY+8(%r15) # load guest register save area
stmg %r0,%r13,0(%r14) # save guest gprs 0-13 stmg %r0,%r13,0(%r14) # save guest gprs 0-13
lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers
lghi %r2,0 lg %r2,__SF_EMPTY+24(%r15) # return exit reason code
br %r14 br %r14
sie_fault: sie_fault:
lctlg %c1,%c1,__LC_USER_ASCE # load primary asce lghi %r14,-EFAULT
lg %r14,__LC_THREAD_INFO # pointer thread_info struct stg %r14,__SF_EMPTY+24(%r15) # set exit reason code
lg %r14,__SF_EMPTY+8(%r15) # load guest register save area j sie_exit
stmg %r0,%r13,0(%r14) # save guest gprs 0-13
lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers
lghi %r2,-EFAULT
br %r14
.align 8 .align 8
.Lsie_loop: .Lsie_critical:
.quad sie_loop .quad sie_gmap
.Lsie_length: .Lsie_critical_length:
.quad sie_done - sie_loop .quad sie_done - sie_gmap
.Lhost_id:
.quad 0
EX_TABLE(rewind_pad,sie_fault) EX_TABLE(rewind_pad,sie_fault)
EX_TABLE(sie_loop,sie_fault) EX_TABLE(sie_exit,sie_fault)
#endif #endif
.section .rodata, "a" .section .rodata, "a"
......
...@@ -707,7 +707,9 @@ static int __vcpu_run(struct kvm_vcpu *vcpu) ...@@ -707,7 +707,9 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
trace_kvm_s390_sie_enter(vcpu, trace_kvm_s390_sie_enter(vcpu,
atomic_read(&vcpu->arch.sie_block->cpuflags)); atomic_read(&vcpu->arch.sie_block->cpuflags));
rc = sie64a(vcpu->arch.sie_block, vcpu->run->s.regs.gprs); 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)) { if (kvm_is_ucontrol(vcpu->kvm)) {
rc = SIE_INTERCEPT_UCONTROL; rc = SIE_INTERCEPT_UCONTROL;
} else { } else {
......
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