Commit 4c6abb7f authored by Christian Borntraeger's avatar Christian Borntraeger
Browse files

KVM: s390: fix LPSWEY handling



in rare cases, e.g. for injecting a machine check we do intercept all
load PSW instructions via ICTL_LPSW. With facility 193 a new variant
LPSWEY was added. KVM needs to handle that as well.

Fixes: a3efa842 ("KVM: s390: gen_facilities: allow facilities 165, 193, 194 and 196")
Reported-by: default avatarMarc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: default avatarSven Schnelle <svens@linux.ibm.com>
Reviewed-by: default avatarClaudio Imbrenda <imbrenda@linux.ibm.com>
Signed-off-by: default avatarChristian Borntraeger <borntraeger@linux.ibm.com>
Message-ID: <20240628163547.2314-1-borntraeger@linux.ibm.com>
parent dee67a94
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -427,6 +427,7 @@ struct kvm_vcpu_stat {
	u64 instruction_io_other;
	u64 instruction_lpsw;
	u64 instruction_lpswe;
	u64 instruction_lpswey;
	u64 instruction_pfmf;
	u64 instruction_ptff;
	u64 instruction_sck;
+1 −0
Original line number Diff line number Diff line
@@ -132,6 +132,7 @@ const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
	STATS_DESC_COUNTER(VCPU, instruction_io_other),
	STATS_DESC_COUNTER(VCPU, instruction_lpsw),
	STATS_DESC_COUNTER(VCPU, instruction_lpswe),
	STATS_DESC_COUNTER(VCPU, instruction_lpswey),
	STATS_DESC_COUNTER(VCPU, instruction_pfmf),
	STATS_DESC_COUNTER(VCPU, instruction_ptff),
	STATS_DESC_COUNTER(VCPU, instruction_sck),
+15 −0
Original line number Diff line number Diff line
@@ -138,6 +138,21 @@ static inline u64 kvm_s390_get_base_disp_s(struct kvm_vcpu *vcpu, u8 *ar)
	return (base2 ? vcpu->run->s.regs.gprs[base2] : 0) + disp2;
}

static inline u64 kvm_s390_get_base_disp_siy(struct kvm_vcpu *vcpu, u8 *ar)
{
	u32 base1 = vcpu->arch.sie_block->ipb >> 28;
	s64 disp1;

	/* The displacement is a 20bit _SIGNED_ value */
	disp1 = sign_extend64(((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16) +
			      ((vcpu->arch.sie_block->ipb & 0xff00) << 4), 19);

	if (ar)
		*ar = base1;

	return (base1 ? vcpu->run->s.regs.gprs[base1] : 0) + disp1;
}

static inline void kvm_s390_get_base_disp_sse(struct kvm_vcpu *vcpu,
					      u64 *address1, u64 *address2,
					      u8 *ar_b1, u8 *ar_b2)
+32 −0
Original line number Diff line number Diff line
@@ -797,6 +797,36 @@ static int handle_lpswe(struct kvm_vcpu *vcpu)
	return 0;
}

static int handle_lpswey(struct kvm_vcpu *vcpu)
{
	psw_t new_psw;
	u64 addr;
	int rc;
	u8 ar;

	vcpu->stat.instruction_lpswey++;

	if (!test_kvm_facility(vcpu->kvm, 193))
		return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);

	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);

	addr = kvm_s390_get_base_disp_siy(vcpu, &ar);
	if (addr & 7)
		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);

	rc = read_guest(vcpu, addr, ar, &new_psw, sizeof(new_psw));
	if (rc)
		return kvm_s390_inject_prog_cond(vcpu, rc);

	vcpu->arch.sie_block->gpsw = new_psw;
	if (!is_valid_psw(&vcpu->arch.sie_block->gpsw))
		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);

	return 0;
}

static int handle_stidp(struct kvm_vcpu *vcpu)
{
	u64 stidp_data = vcpu->kvm->arch.model.cpuid;
@@ -1462,6 +1492,8 @@ int kvm_s390_handle_eb(struct kvm_vcpu *vcpu)
	case 0x61:
	case 0x62:
		return handle_ri(vcpu);
	case 0x71:
		return handle_lpswey(vcpu);
	default:
		return -EOPNOTSUPP;
	}