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: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
This commit is contained in:
Claudio Imbrenda
2026-02-04 16:02:52 +01:00
parent cc50f105fd
commit d29a29a9e1
4 changed files with 60 additions and 72 deletions

View File

@@ -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:

View File

@@ -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

View File

@@ -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);
if (!kvm_is_gpa_in_memslot(kvm, mop->gaddr)) {
r = PGM_ADDRESSING;
goto out_unlock;
}
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) {
scoped_guard(srcu, &kvm->srcu) {
if (!kvm_is_gpa_in_memslot(kvm, mop->gaddr))
return PGM_ADDRESSING;
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);
scoped_guard(srcu, &kvm->srcu) {
if (!kvm_is_gpa_in_memslot(kvm, mop->gaddr))
return PGM_ADDRESSING;
if (!kvm_is_gpa_in_memslot(kvm, mop->gaddr)) {
r = PGM_ADDRESSING;
goto out_unlock;
r = cmpxchg_guest_abs_with_key(kvm, mop->gaddr, mop->size, &old, new,
mop->key, &success);
if (!success && copy_to_user(old_addr, &old, mop->size))
return -EFAULT;
}
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;
out_unlock:
srcu_read_unlock(&kvm->srcu, srcu_idx);
return r;
}

View File

@@ -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);