aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2013-05-17 08:41:37 -0400
committerGleb Natapov <gleb@redhat.com>2013-05-21 04:55:26 -0400
commit7c470539c95630c1f2a10f109e96f249730b75eb (patch)
treeb3d518e9d6d92eb157ace9aa864dd3515c4e216b /arch/s390
parent2c70fe4416d5f6d092b20ebf7d7654835e09c109 (diff)
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>
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/kernel/entry64.S76
-rw-r--r--arch/s390/kvm/kvm-s390.c4
2 files changed, 36 insertions, 44 deletions
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index c7daeefb9864..51d99acc16fd 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -47,7 +47,6 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
47 _TIF_MCCK_PENDING) 47 _TIF_MCCK_PENDING)
48_TIF_TRACE = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \ 48_TIF_TRACE = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
49 _TIF_SYSCALL_TRACEPOINT) 49 _TIF_SYSCALL_TRACEPOINT)
50_TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
51 50
52#define BASED(name) name-system_call(%r13) 51#define BASED(name) name-system_call(%r13)
53 52
@@ -81,25 +80,27 @@ _TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
81#endif 80#endif
82 .endm 81 .endm
83 82
84 .macro HANDLE_SIE_INTERCEPT scratch,pgmcheck 83 .macro HANDLE_SIE_INTERCEPT scratch,reason
85#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) 84#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
86 tmhh %r8,0x0001 # interrupting from user ? 85 tmhh %r8,0x0001 # interrupting from user ?
87 jnz .+52 86 jnz .+62
88 lgr \scratch,%r9 87 lgr \scratch,%r9
89 slg \scratch,BASED(.Lsie_loop) 88 slg \scratch,BASED(.Lsie_critical)
90 clg \scratch,BASED(.Lsie_length) 89 clg \scratch,BASED(.Lsie_critical_length)
91 .if \pgmcheck 90 .if \reason==1
92 # Some program interrupts are suppressing (e.g. protection). 91 # Some program interrupts are suppressing (e.g. protection).
93 # We must also check the instruction after SIE in that case. 92 # We must also check the instruction after SIE in that case.
94 # do_protection_exception will rewind to rewind_pad 93 # do_protection_exception will rewind to rewind_pad
95 jh .+32 94 jh .+42
96 .else 95 .else
97 jhe .+32 96 jhe .+42
98 .endif 97 .endif
99 lg %r9,BASED(.Lsie_loop) 98 lg %r14,__SF_EMPTY(%r15) # get control block pointer
100 LPP BASED(.Lhost_id) # set host id 99 LPP __SF_EMPTY+16(%r15) # set host id
101 lg %r14,__SF_EMPTY(%r15) # get control block pointer
102 ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE 100 ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE
101 lctlg %c1,%c1,__LC_USER_ASCE # load primary asce
102 larl %r9,sie_exit # skip forward to sie_exit
103 mvi __SF_EMPTY+31(%r15),\reason # set exit reason
103#endif 104#endif
104 .endm 105 .endm
105 106
@@ -452,7 +453,7 @@ ENTRY(io_int_handler)
452 lg %r12,__LC_THREAD_INFO 453 lg %r12,__LC_THREAD_INFO
453 larl %r13,system_call 454 larl %r13,system_call
454 lmg %r8,%r9,__LC_IO_OLD_PSW 455 lmg %r8,%r9,__LC_IO_OLD_PSW
455 HANDLE_SIE_INTERCEPT %r14,0 456 HANDLE_SIE_INTERCEPT %r14,2
456 SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT 457 SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT
457 tmhh %r8,0x0001 # interrupting from user? 458 tmhh %r8,0x0001 # interrupting from user?
458 jz io_skip 459 jz io_skip
@@ -597,7 +598,7 @@ ENTRY(ext_int_handler)
597 lg %r12,__LC_THREAD_INFO 598 lg %r12,__LC_THREAD_INFO
598 larl %r13,system_call 599 larl %r13,system_call
599 lmg %r8,%r9,__LC_EXT_OLD_PSW 600 lmg %r8,%r9,__LC_EXT_OLD_PSW
600 HANDLE_SIE_INTERCEPT %r14,0 601 HANDLE_SIE_INTERCEPT %r14,3
601 SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT 602 SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT
602 tmhh %r8,0x0001 # interrupting from user ? 603 tmhh %r8,0x0001 # interrupting from user ?
603 jz ext_skip 604 jz ext_skip
@@ -645,7 +646,7 @@ ENTRY(mcck_int_handler)
645 lg %r12,__LC_THREAD_INFO 646 lg %r12,__LC_THREAD_INFO
646 larl %r13,system_call 647 larl %r13,system_call
647 lmg %r8,%r9,__LC_MCK_OLD_PSW 648 lmg %r8,%r9,__LC_MCK_OLD_PSW
648 HANDLE_SIE_INTERCEPT %r14,0 649 HANDLE_SIE_INTERCEPT %r14,4
649 tm __LC_MCCK_CODE,0x80 # system damage? 650 tm __LC_MCCK_CODE,0x80 # system damage?
650 jo mcck_panic # yes -> rest of mcck code invalid 651 jo mcck_panic # yes -> rest of mcck code invalid
651 lghi %r14,__LC_CPU_TIMER_SAVE_AREA 652 lghi %r14,__LC_CPU_TIMER_SAVE_AREA
@@ -939,19 +940,8 @@ ENTRY(sie64a)
939 stmg %r6,%r14,__SF_GPRS(%r15) # save kernel registers 940 stmg %r6,%r14,__SF_GPRS(%r15) # save kernel registers
940 stg %r2,__SF_EMPTY(%r15) # save control block pointer 941 stg %r2,__SF_EMPTY(%r15) # save control block pointer
941 stg %r3,__SF_EMPTY+8(%r15) # save guest register save area 942 stg %r3,__SF_EMPTY+8(%r15) # save guest register save area
942 xc __SF_EMPTY+16(8,%r15),__SF_EMPTY+16(%r15) # host id == 0 943 xc __SF_EMPTY+16(16,%r15),__SF_EMPTY+16(%r15) # host id & reason
943 lmg %r0,%r13,0(%r3) # load guest gprs 0-13 944 lmg %r0,%r13,0(%r3) # load guest gprs 0-13
944# some program checks are suppressing. C code (e.g. do_protection_exception)
945# will rewind the PSW by the ILC, which is 4 bytes in case of SIE. Other
946# instructions in the sie_loop should not cause program interrupts. So
947# lets use a nop (47 00 00 00) as a landing pad.
948# See also HANDLE_SIE_INTERCEPT
949rewind_pad:
950 nop 0
951sie_loop:
952 lg %r14,__LC_THREAD_INFO # pointer thread_info struct
953 tm __TI_flags+7(%r14),_TIF_EXIT_SIE
954 jnz sie_exit
955 lg %r14,__LC_GMAP # get gmap pointer 945 lg %r14,__LC_GMAP # get gmap pointer
956 ltgr %r14,%r14 946 ltgr %r14,%r14
957 jz sie_gmap 947 jz sie_gmap
@@ -966,33 +956,33 @@ sie_gmap:
966sie_done: 956sie_done:
967 LPP __SF_EMPTY+16(%r15) # set host id 957 LPP __SF_EMPTY+16(%r15) # set host id
968 ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE 958 ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE
969 lg %r14,__LC_THREAD_INFO # pointer thread_info struct
970sie_exit:
971 lctlg %c1,%c1,__LC_USER_ASCE # load primary asce 959 lctlg %c1,%c1,__LC_USER_ASCE # load primary asce
960# some program checks are suppressing. C code (e.g. do_protection_exception)
961# will rewind the PSW by the ILC, which is 4 bytes in case of SIE. Other
962# instructions beween sie64a and sie_done should not cause program
963# interrupts. So lets use a nop (47 00 00 00) as a landing pad.
964# See also HANDLE_SIE_INTERCEPT
965rewind_pad:
966 nop 0
967sie_exit:
972 lg %r14,__SF_EMPTY+8(%r15) # load guest register save area 968 lg %r14,__SF_EMPTY+8(%r15) # load guest register save area
973 stmg %r0,%r13,0(%r14) # save guest gprs 0-13 969 stmg %r0,%r13,0(%r14) # save guest gprs 0-13
974 lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers 970 lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers
975 lghi %r2,0 971 lg %r2,__SF_EMPTY+24(%r15) # return exit reason code
976 br %r14 972 br %r14
977sie_fault: 973sie_fault:
978 lctlg %c1,%c1,__LC_USER_ASCE # load primary asce 974 lghi %r14,-EFAULT
979 lg %r14,__LC_THREAD_INFO # pointer thread_info struct 975 stg %r14,__SF_EMPTY+24(%r15) # set exit reason code
980 lg %r14,__SF_EMPTY+8(%r15) # load guest register save area 976 j sie_exit
981 stmg %r0,%r13,0(%r14) # save guest gprs 0-13
982 lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers
983 lghi %r2,-EFAULT
984 br %r14
985 977
986 .align 8 978 .align 8
987.Lsie_loop: 979.Lsie_critical:
988 .quad sie_loop 980 .quad sie_gmap
989.Lsie_length: 981.Lsie_critical_length:
990 .quad sie_done - sie_loop 982 .quad sie_done - sie_gmap
991.Lhost_id:
992 .quad 0
993 983
994 EX_TABLE(rewind_pad,sie_fault) 984 EX_TABLE(rewind_pad,sie_fault)
995 EX_TABLE(sie_loop,sie_fault) 985 EX_TABLE(sie_exit,sie_fault)
996#endif 986#endif
997 987
998 .section .rodata, "a" 988 .section .rodata, "a"
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 08227c1e816f..93444c4dae5a 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -707,7 +707,9 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
707 trace_kvm_s390_sie_enter(vcpu, 707 trace_kvm_s390_sie_enter(vcpu,
708 atomic_read(&vcpu->arch.sie_block->cpuflags)); 708 atomic_read(&vcpu->arch.sie_block->cpuflags));
709 rc = sie64a(vcpu->arch.sie_block, vcpu->run->s.regs.gprs); 709 rc = sie64a(vcpu->arch.sie_block, vcpu->run->s.regs.gprs);
710 if (rc) { 710 if (rc > 0)
711 rc = 0;
712 if (rc < 0) {
711 if (kvm_is_ucontrol(vcpu->kvm)) { 713 if (kvm_is_ucontrol(vcpu->kvm)) {
712 rc = SIE_INTERCEPT_UCONTROL; 714 rc = SIE_INTERCEPT_UCONTROL;
713 } else { 715 } else {