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

Commit 49b99e1e authored by Christian Borntraeger's avatar Christian Borntraeger Committed by Gleb Natapov
Browse files

s390/kvm: Provide a way to prevent reentering SIE



Lets provide functions to prevent KVM from reentering SIE and
to kick cpus out of SIE. We cannot use the common kvm_vcpu_kick code,
since we need to kick out guests in places that hold architecture
specific locks (e.g. pgste lock) which might be necessary on the
other cpus - so no waiting possible.

So lets provide a bit in a private field of the sie control block
that acts as a gate keeper, after we claimed we are in SIE.
Please note that we do not reuse prog0c, since we want to access
that bit without atomic ops.

Signed-off-by: default avatarChristian Borntraeger <borntraeger@de.ibm.com>
Acked-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarGleb Natapov <gleb@redhat.com>
parent 95d38fd0
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -71,7 +71,10 @@ struct kvm_s390_sie_block {
	__u8	reserved08[4];		/* 0x0008 */
#define PROG_IN_SIE (1<<0)
	__u32	prog0c;			/* 0x000c */
	__u8	reserved10[24];		/* 0x0010 */
	__u8	reserved10[16];		/* 0x0010 */
#define PROG_BLOCK_SIE 0x00000001
	atomic_t prog20;		/* 0x0020 */
	__u8	reserved24[4];		/* 0x0024 */
	__u64	cputm;			/* 0x0028 */
	__u64	ckc;			/* 0x0030 */
	__u64	epoch;			/* 0x0038 */
+1 −0
Original line number Diff line number Diff line
@@ -163,6 +163,7 @@ int main(void)
	DEFINE(__THREAD_trap_tdb, offsetof(struct task_struct, thread.trap_tdb));
	DEFINE(__GMAP_ASCE, offsetof(struct gmap, asce));
	DEFINE(__SIE_PROG0C, offsetof(struct kvm_s390_sie_block, prog0c));
	DEFINE(__SIE_PROG20, offsetof(struct kvm_s390_sie_block, prog20));
#endif /* CONFIG_32BIT */
	return 0;
}
+3 −1
Original line number Diff line number Diff line
@@ -958,7 +958,9 @@ sie_loop:
	lctlg	%c1,%c1,__GMAP_ASCE(%r14)	# load primary asce
sie_gmap:
	lg	%r14,__SF_EMPTY(%r15)		# get control block pointer
	oi	__SIE_PROG0C+3(%r14),1		# we are in SIE now
	oi	__SIE_PROG0C+3(%r14),1		# we are going into SIE now
	tm	__SIE_PROG20+3(%r14),1		# last exit...
	jnz	sie_done
	LPP	__SF_EMPTY(%r15)		# set guest id
	sie	0(%r14)
sie_done:
+28 −0
Original line number Diff line number Diff line
@@ -454,6 +454,34 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
	return 0;
}

void s390_vcpu_block(struct kvm_vcpu *vcpu)
{
	atomic_set_mask(PROG_BLOCK_SIE, &vcpu->arch.sie_block->prog20);
}

void s390_vcpu_unblock(struct kvm_vcpu *vcpu)
{
	atomic_clear_mask(PROG_BLOCK_SIE, &vcpu->arch.sie_block->prog20);
}

/*
 * Kick a guest cpu out of SIE and wait until SIE is not running.
 * If the CPU is not running (e.g. waiting as idle) the function will
 * return immediately. */
void exit_sie(struct kvm_vcpu *vcpu)
{
	atomic_set_mask(CPUSTAT_STOP_INT, &vcpu->arch.sie_block->cpuflags);
	while (vcpu->arch.sie_block->prog0c & PROG_IN_SIE)
		cpu_relax();
}

/* Kick a guest cpu out of SIE and prevent SIE-reentry */
void exit_sie_sync(struct kvm_vcpu *vcpu)
{
	s390_vcpu_block(vcpu);
	exit_sie(vcpu);
}

int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
{
	/* kvm common code refers to this, but never calls it */
+4 −0
Original line number Diff line number Diff line
@@ -133,6 +133,10 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
/* implemented in kvm-s390.c */
int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu,
				 unsigned long addr);
void s390_vcpu_block(struct kvm_vcpu *vcpu);
void s390_vcpu_unblock(struct kvm_vcpu *vcpu);
void exit_sie(struct kvm_vcpu *vcpu);
void exit_sie_sync(struct kvm_vcpu *vcpu);
/* implemented in diag.c */
int kvm_s390_handle_diag(struct kvm_vcpu *vcpu);