Skip to content

Commit 19a44ec

Browse files
committed
KVM: PPC: RTAS: Do byte swaps explicitly
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 <[email protected]>
1 parent 55ab169 commit 19a44ec

File tree

1 file changed

+18
-47
lines changed

1 file changed

+18
-47
lines changed

arch/powerpc/kvm/book3s_rtas.c

Lines changed: 18 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -23,33 +23,33 @@ static void kvm_rtas_set_xive(struct kvm_vcpu *vcpu, struct rtas_args *args)
2323
u32 irq, server, priority;
2424
int rc;
2525

26-
if (args->nargs != 3 || args->nret != 1) {
26+
if (be32_to_cpu(args->nargs) != 3 || be32_to_cpu(args->nret) != 1) {
2727
rc = -3;
2828
goto out;
2929
}
3030

31-
irq = args->args[0];
32-
server = args->args[1];
33-
priority = args->args[2];
31+
irq = be32_to_cpu(args->args[0]);
32+
server = be32_to_cpu(args->args[1]);
33+
priority = be32_to_cpu(args->args[2]);
3434

3535
rc = kvmppc_xics_set_xive(vcpu->kvm, irq, server, priority);
3636
if (rc)
3737
rc = -3;
3838
out:
39-
args->rets[0] = rc;
39+
args->rets[0] = cpu_to_be32(rc);
4040
}
4141

4242
static void kvm_rtas_get_xive(struct kvm_vcpu *vcpu, struct rtas_args *args)
4343
{
4444
u32 irq, server, priority;
4545
int rc;
4646

47-
if (args->nargs != 1 || args->nret != 3) {
47+
if (be32_to_cpu(args->nargs) != 1 || be32_to_cpu(args->nret) != 3) {
4848
rc = -3;
4949
goto out;
5050
}
5151

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

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

61-
args->rets[1] = server;
62-
args->rets[2] = priority;
61+
args->rets[1] = cpu_to_be32(server);
62+
args->rets[2] = cpu_to_be32(priority);
6363
out:
64-
args->rets[0] = rc;
64+
args->rets[0] = cpu_to_be32(rc);
6565
}
6666

6767
static void kvm_rtas_int_off(struct kvm_vcpu *vcpu, struct rtas_args *args)
6868
{
6969
u32 irq;
7070
int rc;
7171

72-
if (args->nargs != 1 || args->nret != 1) {
72+
if (be32_to_cpu(args->nargs) != 1 || be32_to_cpu(args->nret) != 1) {
7373
rc = -3;
7474
goto out;
7575
}
7676

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

7979
rc = kvmppc_xics_int_off(vcpu->kvm, irq);
8080
if (rc)
8181
rc = -3;
8282
out:
83-
args->rets[0] = rc;
83+
args->rets[0] = cpu_to_be32(rc);
8484
}
8585

8686
static void kvm_rtas_int_on(struct kvm_vcpu *vcpu, struct rtas_args *args)
8787
{
8888
u32 irq;
8989
int rc;
9090

91-
if (args->nargs != 1 || args->nret != 1) {
91+
if (be32_to_cpu(args->nargs) != 1 || be32_to_cpu(args->nret) != 1) {
9292
rc = -3;
9393
goto out;
9494
}
9595

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

9898
rc = kvmppc_xics_int_on(vcpu->kvm, irq);
9999
if (rc)
100100
rc = -3;
101101
out:
102-
args->rets[0] = rc;
102+
args->rets[0] = cpu_to_be32(rc);
103103
}
104104
#endif /* CONFIG_KVM_XICS */
105105

@@ -205,32 +205,6 @@ int kvm_vm_ioctl_rtas_define_token(struct kvm *kvm, void __user *argp)
205205
return rc;
206206
}
207207

208-
static void kvmppc_rtas_swap_endian_in(struct rtas_args *args)
209-
{
210-
#ifdef __LITTLE_ENDIAN__
211-
int i;
212-
213-
args->token = be32_to_cpu(args->token);
214-
args->nargs = be32_to_cpu(args->nargs);
215-
args->nret = be32_to_cpu(args->nret);
216-
for (i = 0; i < args->nargs; i++)
217-
args->args[i] = be32_to_cpu(args->args[i]);
218-
#endif
219-
}
220-
221-
static void kvmppc_rtas_swap_endian_out(struct rtas_args *args)
222-
{
223-
#ifdef __LITTLE_ENDIAN__
224-
int i;
225-
226-
for (i = 0; i < args->nret; i++)
227-
args->args[i] = cpu_to_be32(args->args[i]);
228-
args->token = cpu_to_be32(args->token);
229-
args->nargs = cpu_to_be32(args->nargs);
230-
args->nret = cpu_to_be32(args->nret);
231-
#endif
232-
}
233-
234208
int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu)
235209
{
236210
struct rtas_token_definition *d;
@@ -249,22 +223,20 @@ int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu)
249223
if (rc)
250224
goto fail;
251225

252-
kvmppc_rtas_swap_endian_in(&args);
253-
254226
/*
255227
* args->rets is a pointer into args->args. Now that we've
256228
* copied args we need to fix it up to point into our copy,
257229
* not the guest args. We also need to save the original
258230
* value so we can restore it on the way out.
259231
*/
260232
orig_rets = args.rets;
261-
args.rets = &args.args[args.nargs];
233+
args.rets = &args.args[be32_to_cpu(args.nargs)];
262234

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

265237
rc = -ENOENT;
266238
list_for_each_entry(d, &vcpu->kvm->arch.rtas_tokens, list) {
267-
if (d->token == args.token) {
239+
if (d->token == be32_to_cpu(args.token)) {
268240
d->handler->handler(vcpu, &args);
269241
rc = 0;
270242
break;
@@ -275,7 +247,6 @@ int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu)
275247

276248
if (rc == 0) {
277249
args.rets = orig_rets;
278-
kvmppc_rtas_swap_endian_out(&args);
279250
rc = kvm_write_guest(vcpu->kvm, args_phys, &args, sizeof(args));
280251
if (rc)
281252
goto fail;

0 commit comments

Comments
 (0)