Skip to content

Commit

Permalink
KVM: PPC: RTAS: Do byte swaps explicitly
Browse files Browse the repository at this point in the history
In commit b59d9d2 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>
  • Loading branch information
Alexander Graf committed Jul 7, 2014
1 parent 55ab169 commit 19a44ec
Showing 1 changed file with 18 additions and 47 deletions.
65 changes: 18 additions & 47 deletions arch/powerpc/kvm/book3s_rtas.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,33 +23,33 @@ static void kvm_rtas_set_xive(struct kvm_vcpu *vcpu, struct rtas_args *args)
u32 irq, server, priority;
int rc;

if (args->nargs != 3 || args->nret != 1) {
if (be32_to_cpu(args->nargs) != 3 || be32_to_cpu(args->nret) != 1) {
rc = -3;
goto out;
}

irq = args->args[0];
server = args->args[1];
priority = args->args[2];
irq = be32_to_cpu(args->args[0]);
server = be32_to_cpu(args->args[1]);
priority = be32_to_cpu(args->args[2]);

rc = kvmppc_xics_set_xive(vcpu->kvm, irq, server, priority);
if (rc)
rc = -3;
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)
{
u32 irq, server, priority;
int rc;

if (args->nargs != 1 || args->nret != 3) {
if (be32_to_cpu(args->nargs) != 1 || be32_to_cpu(args->nret) != 3) {
rc = -3;
goto out;
}

irq = args->args[0];
irq = be32_to_cpu(args->args[0]);

server = priority = 0;
rc = kvmppc_xics_get_xive(vcpu->kvm, irq, &server, &priority);
Expand All @@ -58,48 +58,48 @@ static void kvm_rtas_get_xive(struct kvm_vcpu *vcpu, struct rtas_args *args)
goto out;
}

args->rets[1] = server;
args->rets[2] = priority;
args->rets[1] = cpu_to_be32(server);
args->rets[2] = cpu_to_be32(priority);
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)
{
u32 irq;
int rc;

if (args->nargs != 1 || args->nret != 1) {
if (be32_to_cpu(args->nargs) != 1 || be32_to_cpu(args->nret) != 1) {
rc = -3;
goto out;
}

irq = args->args[0];
irq = be32_to_cpu(args->args[0]);

rc = kvmppc_xics_int_off(vcpu->kvm, irq);
if (rc)
rc = -3;
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)
{
u32 irq;
int rc;

if (args->nargs != 1 || args->nret != 1) {
if (be32_to_cpu(args->nargs) != 1 || be32_to_cpu(args->nret) != 1) {
rc = -3;
goto out;
}

irq = args->args[0];
irq = be32_to_cpu(args->args[0]);

rc = kvmppc_xics_int_on(vcpu->kvm, irq);
if (rc)
rc = -3;
out:
args->rets[0] = rc;
args->rets[0] = cpu_to_be32(rc);
}
#endif /* CONFIG_KVM_XICS */

Expand Down Expand Up @@ -205,32 +205,6 @@ int kvm_vm_ioctl_rtas_define_token(struct kvm *kvm, void __user *argp)
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)
{
struct rtas_token_definition *d;
Expand All @@ -249,22 +223,20 @@ int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu)
if (rc)
goto fail;

kvmppc_rtas_swap_endian_in(&args);

/*
* 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,
* not the guest args. We also need to save the original
* value so we can restore it on the way out.
*/
orig_rets = args.rets;
args.rets = &args.args[args.nargs];
args.rets = &args.args[be32_to_cpu(args.nargs)];

mutex_lock(&vcpu->kvm->lock);

rc = -ENOENT;
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);
rc = 0;
break;
Expand All @@ -275,7 +247,6 @@ int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu)

if (rc == 0) {
args.rets = orig_rets;
kvmppc_rtas_swap_endian_out(&args);
rc = kvm_write_guest(vcpu->kvm, args_phys, &args, sizeof(args));
if (rc)
goto fail;
Expand Down

0 comments on commit 19a44ec

Please sign in to comment.