Commit d29a29a9 authored by Claudio Imbrenda's avatar Claudio Imbrenda
Browse files

KVM: s390: Storage key functions refactoring



Refactor some storage key functions to improve readability.

Introduce helper functions that will be used in the next patches.

Acked-by: default avatarHeiko Carstens <hca@linux.ibm.com>
Signed-off-by: default avatarClaudio Imbrenda <imbrenda@linux.ibm.com>
parent cc50f105
Loading
Loading
Loading
Loading
+19 −19
Original line number Diff line number Diff line
@@ -961,7 +961,7 @@ int access_guest_real(struct kvm_vcpu *vcpu, unsigned long gra,
 *            *@old_addr contains the value at @gpa before the attempt to
 *            exchange the value.
 * @new: The value to place at @gpa.
 * @access_key: The access key to use for the guest access.
 * @acc: The access key to use for the guest access.
 * @success: output value indicating if an exchange occurred.
 *
 * Atomically exchange the value at @gpa by @new, if it contains *@old.
@@ -974,9 +974,8 @@ int access_guest_real(struct kvm_vcpu *vcpu, unsigned long gra,
 *         * -EAGAIN: transient failure (len 1 or 2)
 *         * -EOPNOTSUPP: read-only memslot (should never occur)
 */
int cmpxchg_guest_abs_with_key(struct kvm *kvm, gpa_t gpa, int len,
			       __uint128_t *old_addr, __uint128_t new,
			       u8 access_key, bool *success)
int cmpxchg_guest_abs_with_key(struct kvm *kvm, gpa_t gpa, int len, union kvm_s390_quad *old_addr,
			       union kvm_s390_quad new, u8 acc, bool *success)
{
	gfn_t gfn = gpa_to_gfn(gpa);
	struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn);
@@ -1008,41 +1007,42 @@ int cmpxchg_guest_abs_with_key(struct kvm *kvm, gpa_t gpa, int len,
	case 1: {
		u8 old;

		ret = cmpxchg_user_key((u8 __user *)hva, &old, *old_addr, new, access_key);
		*success = !ret && old == *old_addr;
		*old_addr = old;
		ret = cmpxchg_user_key((u8 __user *)hva, &old, old_addr->one, new.one, acc);
		*success = !ret && old == old_addr->one;
		old_addr->one = old;
		break;
	}
	case 2: {
		u16 old;

		ret = cmpxchg_user_key((u16 __user *)hva, &old, *old_addr, new, access_key);
		*success = !ret && old == *old_addr;
		*old_addr = old;
		ret = cmpxchg_user_key((u16 __user *)hva, &old, old_addr->two, new.two, acc);
		*success = !ret && old == old_addr->two;
		old_addr->two = old;
		break;
	}
	case 4: {
		u32 old;

		ret = cmpxchg_user_key((u32 __user *)hva, &old, *old_addr, new, access_key);
		*success = !ret && old == *old_addr;
		*old_addr = old;
		ret = cmpxchg_user_key((u32 __user *)hva, &old, old_addr->four, new.four, acc);
		*success = !ret && old == old_addr->four;
		old_addr->four = old;
		break;
	}
	case 8: {
		u64 old;

		ret = cmpxchg_user_key((u64 __user *)hva, &old, *old_addr, new, access_key);
		*success = !ret && old == *old_addr;
		*old_addr = old;
		ret = cmpxchg_user_key((u64 __user *)hva, &old, old_addr->eight, new.eight, acc);
		*success = !ret && old == old_addr->eight;
		old_addr->eight = old;
		break;
	}
	case 16: {
		__uint128_t old;

		ret = cmpxchg_user_key((__uint128_t __user *)hva, &old, *old_addr, new, access_key);
		*success = !ret && old == *old_addr;
		*old_addr = old;
		ret = cmpxchg_user_key((__uint128_t __user *)hva, &old, old_addr->sixteen,
				       new.sixteen, acc);
		*success = !ret && old == old_addr->sixteen;
		old_addr->sixteen = old;
		break;
	}
	default:
+2 −2
Original line number Diff line number Diff line
@@ -206,8 +206,8 @@ int access_guest_with_key(struct kvm_vcpu *vcpu, unsigned long ga, u8 ar,
int access_guest_real(struct kvm_vcpu *vcpu, unsigned long gra,
		      void *data, unsigned long len, enum gacc_mode mode);

int cmpxchg_guest_abs_with_key(struct kvm *kvm, gpa_t gpa, int len, __uint128_t *old,
			       __uint128_t new, u8 access_key, bool *success);
int cmpxchg_guest_abs_with_key(struct kvm *kvm, gpa_t gpa, int len, union kvm_s390_quad *old_addr,
			       union kvm_s390_quad new, u8 access_key, bool *success);

/**
 * write_guest_with_key - copy data from kernel space to guest space
+30 −50
Original line number Diff line number Diff line
@@ -2900,9 +2900,9 @@ static int mem_op_validate_common(struct kvm_s390_mem_op *mop, u64 supported_fla
static int kvm_s390_vm_mem_op_abs(struct kvm *kvm, struct kvm_s390_mem_op *mop)
{
	void __user *uaddr = (void __user *)mop->buf;
	void *tmpbuf __free(kvfree) = NULL;
	enum gacc_mode acc_mode;
	void *tmpbuf = NULL;
	int r, srcu_idx;
	int r;

	r = mem_op_validate_common(mop, KVM_S390_MEMOP_F_SKEY_PROTECTION |
					KVM_S390_MEMOP_F_CHECK_ONLY);
@@ -2915,52 +2915,36 @@ static int kvm_s390_vm_mem_op_abs(struct kvm *kvm, struct kvm_s390_mem_op *mop)
			return -ENOMEM;
	}

	srcu_idx = srcu_read_lock(&kvm->srcu);
	acc_mode = mop->op == KVM_S390_MEMOP_ABSOLUTE_READ ? GACC_FETCH : GACC_STORE;

	if (!kvm_is_gpa_in_memslot(kvm, mop->gaddr)) {
		r = PGM_ADDRESSING;
		goto out_unlock;
	}
	scoped_guard(srcu, &kvm->srcu) {
		if (!kvm_is_gpa_in_memslot(kvm, mop->gaddr))
			return PGM_ADDRESSING;

	acc_mode = mop->op == KVM_S390_MEMOP_ABSOLUTE_READ ? GACC_FETCH : GACC_STORE;
	if (mop->flags & KVM_S390_MEMOP_F_CHECK_ONLY) {
		r = check_gpa_range(kvm, mop->gaddr, mop->size, acc_mode, mop->key);
		goto out_unlock;
	}
	if (acc_mode == GACC_FETCH) {
		if (mop->flags & KVM_S390_MEMOP_F_CHECK_ONLY)
			return check_gpa_range(kvm, mop->gaddr, mop->size, acc_mode, mop->key);

		if (acc_mode == GACC_STORE && copy_from_user(tmpbuf, uaddr, mop->size))
			return -EFAULT;
		r = access_guest_abs_with_key(kvm, mop->gaddr, tmpbuf,
					      mop->size, GACC_FETCH, mop->key);
					      mop->size, acc_mode, mop->key);
		if (r)
			goto out_unlock;
		if (copy_to_user(uaddr, tmpbuf, mop->size))
			r = -EFAULT;
	} else {
		if (copy_from_user(tmpbuf, uaddr, mop->size)) {
			r = -EFAULT;
			goto out_unlock;
		}
		r = access_guest_abs_with_key(kvm, mop->gaddr, tmpbuf,
					      mop->size, GACC_STORE, mop->key);
			return r;
		if (acc_mode != GACC_STORE && copy_to_user(uaddr, tmpbuf, mop->size))
			return -EFAULT;
	}

out_unlock:
	srcu_read_unlock(&kvm->srcu, srcu_idx);

	vfree(tmpbuf);
	return r;
	return 0;
}

static int kvm_s390_vm_mem_op_cmpxchg(struct kvm *kvm, struct kvm_s390_mem_op *mop)
{
	void __user *uaddr = (void __user *)mop->buf;
	void __user *old_addr = (void __user *)mop->old_addr;
	union {
		__uint128_t quad;
		char raw[sizeof(__uint128_t)];
	} old = { .quad = 0}, new = { .quad = 0 };
	unsigned int off_in_quad = sizeof(new) - mop->size;
	int r, srcu_idx;
	bool success;
	union kvm_s390_quad old = { .sixteen = 0 };
	union kvm_s390_quad new = { .sixteen = 0 };
	bool success = false;
	int r;

	r = mem_op_validate_common(mop, KVM_S390_MEMOP_F_SKEY_PROTECTION);
	if (r)
@@ -2972,25 +2956,21 @@ static int kvm_s390_vm_mem_op_cmpxchg(struct kvm *kvm, struct kvm_s390_mem_op *m
	 */
	if (mop->size > sizeof(new))
		return -EINVAL;
	if (copy_from_user(&new.raw[off_in_quad], uaddr, mop->size))
	if (copy_from_user(&new, uaddr, mop->size))
		return -EFAULT;
	if (copy_from_user(&old.raw[off_in_quad], old_addr, mop->size))
	if (copy_from_user(&old, old_addr, mop->size))
		return -EFAULT;

	srcu_idx = srcu_read_lock(&kvm->srcu);

	if (!kvm_is_gpa_in_memslot(kvm, mop->gaddr)) {
		r = PGM_ADDRESSING;
		goto out_unlock;
	}
	scoped_guard(srcu, &kvm->srcu) {
		if (!kvm_is_gpa_in_memslot(kvm, mop->gaddr))
			return PGM_ADDRESSING;

	r = cmpxchg_guest_abs_with_key(kvm, mop->gaddr, mop->size, &old.quad,
				       new.quad, mop->key, &success);
	if (!success && copy_to_user(old_addr, &old.raw[off_in_quad], mop->size))
		r = -EFAULT;
		r = cmpxchg_guest_abs_with_key(kvm, mop->gaddr, mop->size, &old, new,
					       mop->key, &success);

out_unlock:
	srcu_read_unlock(&kvm->srcu, srcu_idx);
		if (!success && copy_to_user(old_addr, &old, mop->size))
			return -EFAULT;
	}
	return r;
}

+8 −0
Original line number Diff line number Diff line
@@ -22,6 +22,14 @@

#define KVM_S390_UCONTROL_MEMSLOT (KVM_USER_MEM_SLOTS + 0)

union kvm_s390_quad {
	__uint128_t sixteen;
	unsigned long eight;
	unsigned int four;
	unsigned short two;
	unsigned char one;
};

static inline void kvm_s390_fpu_store(struct kvm_run *run)
{
	fpu_stfpc(&run->s.regs.fpc);