KVM: PPC: RTAS: Do byte swaps explicitly
In commit b59d9d26b
we introduced implicit byte swaps for RTAS calls.
Unfortunately we messed up and didn't swizzle return values properly.
Also the old approach wasn't "sparse" compatible - we were randomly
reading __be32 values on an LE system.
Let's just do all of the swizzling explicitly with byte swaps right
where values get used. That way we can at least catch bugs using sparse.
This patch fixes XICS RTAS emulation on little endian hosts for me.
Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
parent
55ab169b7b
commit
19a44ecff5
|
@ -23,20 +23,20 @@ static void kvm_rtas_set_xive(struct kvm_vcpu *vcpu, struct rtas_args *args)
|
||||||
u32 irq, server, priority;
|
u32 irq, server, priority;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (args->nargs != 3 || args->nret != 1) {
|
if (be32_to_cpu(args->nargs) != 3 || be32_to_cpu(args->nret) != 1) {
|
||||||
rc = -3;
|
rc = -3;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
irq = args->args[0];
|
irq = be32_to_cpu(args->args[0]);
|
||||||
server = args->args[1];
|
server = be32_to_cpu(args->args[1]);
|
||||||
priority = args->args[2];
|
priority = be32_to_cpu(args->args[2]);
|
||||||
|
|
||||||
rc = kvmppc_xics_set_xive(vcpu->kvm, irq, server, priority);
|
rc = kvmppc_xics_set_xive(vcpu->kvm, irq, server, priority);
|
||||||
if (rc)
|
if (rc)
|
||||||
rc = -3;
|
rc = -3;
|
||||||
out:
|
out:
|
||||||
args->rets[0] = rc;
|
args->rets[0] = cpu_to_be32(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kvm_rtas_get_xive(struct kvm_vcpu *vcpu, struct rtas_args *args)
|
static void kvm_rtas_get_xive(struct kvm_vcpu *vcpu, struct rtas_args *args)
|
||||||
|
@ -44,12 +44,12 @@ static void kvm_rtas_get_xive(struct kvm_vcpu *vcpu, struct rtas_args *args)
|
||||||
u32 irq, server, priority;
|
u32 irq, server, priority;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (args->nargs != 1 || args->nret != 3) {
|
if (be32_to_cpu(args->nargs) != 1 || be32_to_cpu(args->nret) != 3) {
|
||||||
rc = -3;
|
rc = -3;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
irq = args->args[0];
|
irq = be32_to_cpu(args->args[0]);
|
||||||
|
|
||||||
server = priority = 0;
|
server = priority = 0;
|
||||||
rc = kvmppc_xics_get_xive(vcpu->kvm, irq, &server, &priority);
|
rc = kvmppc_xics_get_xive(vcpu->kvm, irq, &server, &priority);
|
||||||
|
@ -58,10 +58,10 @@ static void kvm_rtas_get_xive(struct kvm_vcpu *vcpu, struct rtas_args *args)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
args->rets[1] = server;
|
args->rets[1] = cpu_to_be32(server);
|
||||||
args->rets[2] = priority;
|
args->rets[2] = cpu_to_be32(priority);
|
||||||
out:
|
out:
|
||||||
args->rets[0] = rc;
|
args->rets[0] = cpu_to_be32(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kvm_rtas_int_off(struct kvm_vcpu *vcpu, struct rtas_args *args)
|
static void kvm_rtas_int_off(struct kvm_vcpu *vcpu, struct rtas_args *args)
|
||||||
|
@ -69,18 +69,18 @@ static void kvm_rtas_int_off(struct kvm_vcpu *vcpu, struct rtas_args *args)
|
||||||
u32 irq;
|
u32 irq;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (args->nargs != 1 || args->nret != 1) {
|
if (be32_to_cpu(args->nargs) != 1 || be32_to_cpu(args->nret) != 1) {
|
||||||
rc = -3;
|
rc = -3;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
irq = args->args[0];
|
irq = be32_to_cpu(args->args[0]);
|
||||||
|
|
||||||
rc = kvmppc_xics_int_off(vcpu->kvm, irq);
|
rc = kvmppc_xics_int_off(vcpu->kvm, irq);
|
||||||
if (rc)
|
if (rc)
|
||||||
rc = -3;
|
rc = -3;
|
||||||
out:
|
out:
|
||||||
args->rets[0] = rc;
|
args->rets[0] = cpu_to_be32(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kvm_rtas_int_on(struct kvm_vcpu *vcpu, struct rtas_args *args)
|
static void kvm_rtas_int_on(struct kvm_vcpu *vcpu, struct rtas_args *args)
|
||||||
|
@ -88,18 +88,18 @@ static void kvm_rtas_int_on(struct kvm_vcpu *vcpu, struct rtas_args *args)
|
||||||
u32 irq;
|
u32 irq;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (args->nargs != 1 || args->nret != 1) {
|
if (be32_to_cpu(args->nargs) != 1 || be32_to_cpu(args->nret) != 1) {
|
||||||
rc = -3;
|
rc = -3;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
irq = args->args[0];
|
irq = be32_to_cpu(args->args[0]);
|
||||||
|
|
||||||
rc = kvmppc_xics_int_on(vcpu->kvm, irq);
|
rc = kvmppc_xics_int_on(vcpu->kvm, irq);
|
||||||
if (rc)
|
if (rc)
|
||||||
rc = -3;
|
rc = -3;
|
||||||
out:
|
out:
|
||||||
args->rets[0] = rc;
|
args->rets[0] = cpu_to_be32(rc);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_KVM_XICS */
|
#endif /* CONFIG_KVM_XICS */
|
||||||
|
|
||||||
|
@ -205,32 +205,6 @@ int kvm_vm_ioctl_rtas_define_token(struct kvm *kvm, void __user *argp)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kvmppc_rtas_swap_endian_in(struct rtas_args *args)
|
|
||||||
{
|
|
||||||
#ifdef __LITTLE_ENDIAN__
|
|
||||||
int i;
|
|
||||||
|
|
||||||
args->token = be32_to_cpu(args->token);
|
|
||||||
args->nargs = be32_to_cpu(args->nargs);
|
|
||||||
args->nret = be32_to_cpu(args->nret);
|
|
||||||
for (i = 0; i < args->nargs; i++)
|
|
||||||
args->args[i] = be32_to_cpu(args->args[i]);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void kvmppc_rtas_swap_endian_out(struct rtas_args *args)
|
|
||||||
{
|
|
||||||
#ifdef __LITTLE_ENDIAN__
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < args->nret; i++)
|
|
||||||
args->args[i] = cpu_to_be32(args->args[i]);
|
|
||||||
args->token = cpu_to_be32(args->token);
|
|
||||||
args->nargs = cpu_to_be32(args->nargs);
|
|
||||||
args->nret = cpu_to_be32(args->nret);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu)
|
int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
struct rtas_token_definition *d;
|
struct rtas_token_definition *d;
|
||||||
|
@ -249,8 +223,6 @@ int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu)
|
||||||
if (rc)
|
if (rc)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
kvmppc_rtas_swap_endian_in(&args);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* args->rets is a pointer into args->args. Now that we've
|
* args->rets is a pointer into args->args. Now that we've
|
||||||
* copied args we need to fix it up to point into our copy,
|
* copied args we need to fix it up to point into our copy,
|
||||||
|
@ -258,13 +230,13 @@ int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu)
|
||||||
* value so we can restore it on the way out.
|
* value so we can restore it on the way out.
|
||||||
*/
|
*/
|
||||||
orig_rets = args.rets;
|
orig_rets = args.rets;
|
||||||
args.rets = &args.args[args.nargs];
|
args.rets = &args.args[be32_to_cpu(args.nargs)];
|
||||||
|
|
||||||
mutex_lock(&vcpu->kvm->lock);
|
mutex_lock(&vcpu->kvm->lock);
|
||||||
|
|
||||||
rc = -ENOENT;
|
rc = -ENOENT;
|
||||||
list_for_each_entry(d, &vcpu->kvm->arch.rtas_tokens, list) {
|
list_for_each_entry(d, &vcpu->kvm->arch.rtas_tokens, list) {
|
||||||
if (d->token == args.token) {
|
if (d->token == be32_to_cpu(args.token)) {
|
||||||
d->handler->handler(vcpu, &args);
|
d->handler->handler(vcpu, &args);
|
||||||
rc = 0;
|
rc = 0;
|
||||||
break;
|
break;
|
||||||
|
@ -275,7 +247,6 @@ int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu)
|
||||||
|
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
args.rets = orig_rets;
|
args.rets = orig_rets;
|
||||||
kvmppc_rtas_swap_endian_out(&args);
|
|
||||||
rc = kvm_write_guest(vcpu->kvm, args_phys, &args, sizeof(args));
|
rc = kvm_write_guest(vcpu->kvm, args_phys, &args, sizeof(args));
|
||||||
if (rc)
|
if (rc)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
Loading…
Reference in New Issue