mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-22 07:27:12 +08:00
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:
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user