Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+33 −43
Original line number Diff line number Diff line
@@ -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
	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"
+3 −1
Original line number Diff line number Diff line
@@ -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 {