Commit 61380a7a authored by Janis Schoetterl-Glausch's avatar Janis Schoetterl-Glausch Committed by Christian Borntraeger
Browse files

KVM: s390: handle_tprot: Honor storage keys



Use the access key operand to check for key protection when
translating guest addresses.
Since the translation code checks for accessing exceptions/error hvas,
we can remove the check here and simplify the control flow.
Keep checking if the memory is read-only even if such memslots are
currently not supported.

handle_tprot was the last user of guest_translate_address,
so remove it.

Signed-off-by: default avatarJanis Schoetterl-Glausch <scgl@linux.ibm.com>
Reviewed-by: default avatarJanosch Frank <frankja@linux.ibm.com>
Reviewed-by: default avatarClaudio Imbrenda <imbrenda@linux.ibm.com>
Link: https://lore.kernel.org/r/20220211182215.2730017-4-scgl@linux.ibm.com


Signed-off-by: default avatarChristian Borntraeger <borntraeger@linux.ibm.com>
parent e613d834
Loading
Loading
Loading
Loading
+0 −9
Original line number Diff line number Diff line
@@ -1118,15 +1118,6 @@ int guest_translate_address_with_key(struct kvm_vcpu *vcpu, unsigned long gva, u
				   access_key);
}

int guest_translate_address(struct kvm_vcpu *vcpu, unsigned long gva, u8 ar,
			    unsigned long *gpa, enum gacc_mode mode)
{
	u8 access_key = psw_bits(vcpu->arch.sie_block->gpsw).key;

	return guest_translate_address_with_key(vcpu, gva, ar, gpa, mode,
						access_key);
}

/**
 * check_gva_range - test a range of guest virtual addresses for accessibility
 * @vcpu: virtual cpu
+0 −3
Original line number Diff line number Diff line
@@ -190,9 +190,6 @@ int guest_translate_address_with_key(struct kvm_vcpu *vcpu, unsigned long gva, u
				     unsigned long *gpa, enum gacc_mode mode,
				     u8 access_key);

int guest_translate_address(struct kvm_vcpu *vcpu, unsigned long gva,
			    u8 ar, unsigned long *gpa, enum gacc_mode mode);

int check_gva_range(struct kvm_vcpu *vcpu, unsigned long gva, u8 ar,
		    unsigned long length, enum gacc_mode mode, u8 access_key);

+35 −31
Original line number Diff line number Diff line
@@ -1443,10 +1443,11 @@ int kvm_s390_handle_eb(struct kvm_vcpu *vcpu)

static int handle_tprot(struct kvm_vcpu *vcpu)
{
	u64 address1, address2;
	unsigned long hva, gpa;
	int ret = 0, cc = 0;
	u64 address, operand2;
	unsigned long gpa;
	u8 access_key;
	bool writable;
	int ret, cc;
	u8 ar;

	vcpu->stat.instruction_tprot++;
@@ -1454,43 +1455,46 @@ static int handle_tprot(struct kvm_vcpu *vcpu)
	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);

	kvm_s390_get_base_disp_sse(vcpu, &address1, &address2, &ar, NULL);
	kvm_s390_get_base_disp_sse(vcpu, &address, &operand2, &ar, NULL);
	access_key = (operand2 & 0xf0) >> 4;

	/* we only handle the Linux memory detection case:
	 * access key == 0
	 * everything else goes to userspace. */
	if (address2 & 0xf0)
		return -EOPNOTSUPP;
	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_DAT)
		ipte_lock(vcpu);
	ret = guest_translate_address(vcpu, address1, ar, &gpa, GACC_STORE);
	if (ret == PGM_PROTECTION) {

	ret = guest_translate_address_with_key(vcpu, address, ar, &gpa,
					       GACC_STORE, access_key);
	if (ret == 0) {
		gfn_to_hva_prot(vcpu->kvm, gpa_to_gfn(gpa), &writable);
	} else if (ret == PGM_PROTECTION) {
		writable = false;
		/* Write protected? Try again with read-only... */
		cc = 1;
		ret = guest_translate_address(vcpu, address1, ar, &gpa,
					      GACC_FETCH);
		ret = guest_translate_address_with_key(vcpu, address, ar, &gpa,
						       GACC_FETCH, access_key);
	}
	if (ret) {
		if (ret == PGM_ADDRESSING || ret == PGM_TRANSLATION_SPEC) {
			ret = kvm_s390_inject_program_int(vcpu, ret);
		} else if (ret > 0) {
	if (ret >= 0) {
		cc = -1;

		/* Fetching permitted; storing permitted */
		if (ret == 0 && writable)
			cc = 0;
		/* Fetching permitted; storing not permitted */
		else if (ret == 0 && !writable)
			cc = 1;
		/* Fetching not permitted; storing not permitted */
		else if (ret == PGM_PROTECTION)
			cc = 2;
		/* Translation not available */
			kvm_s390_set_psw_cc(vcpu, 3);
		else if (ret != PGM_ADDRESSING && ret != PGM_TRANSLATION_SPEC)
			cc = 3;

		if (cc != -1) {
			kvm_s390_set_psw_cc(vcpu, cc);
			ret = 0;
		} else {
			ret = kvm_s390_inject_program_int(vcpu, ret);
		}
		goto out_unlock;
	}

	hva = gfn_to_hva_prot(vcpu->kvm, gpa_to_gfn(gpa), &writable);
	if (kvm_is_error_hva(hva)) {
		ret = kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
	} else {
		if (!writable)
			cc = 1;		/* Write not permitted ==> read-only */
		kvm_s390_set_psw_cc(vcpu, cc);
		/* Note: CC2 only occurs for storage keys (not supported yet) */
	}
out_unlock:
	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_DAT)
		ipte_unlock(vcpu);
	return ret;