1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
28e591cb7SMichael Ellerman /*
38e591cb7SMichael Ellerman * Copyright 2012 Michael Ellerman, IBM Corporation.
48e591cb7SMichael Ellerman */
58e591cb7SMichael Ellerman
68e591cb7SMichael Ellerman #include <linux/kernel.h>
78e591cb7SMichael Ellerman #include <linux/kvm_host.h>
88e591cb7SMichael Ellerman #include <linux/kvm.h>
98e591cb7SMichael Ellerman #include <linux/err.h>
108e591cb7SMichael Ellerman
117c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
128e591cb7SMichael Ellerman #include <asm/kvm_book3s.h>
138e591cb7SMichael Ellerman #include <asm/kvm_ppc.h>
148e591cb7SMichael Ellerman #include <asm/hvcall.h>
158e591cb7SMichael Ellerman #include <asm/rtas.h>
165af50993SBenjamin Herrenschmidt #include <asm/xive.h>
178e591cb7SMichael Ellerman
18bc5ad3f3SBenjamin Herrenschmidt #ifdef CONFIG_KVM_XICS
kvm_rtas_set_xive(struct kvm_vcpu * vcpu,struct rtas_args * args)19bc5ad3f3SBenjamin Herrenschmidt static void kvm_rtas_set_xive(struct kvm_vcpu *vcpu, struct rtas_args *args)
20bc5ad3f3SBenjamin Herrenschmidt {
21bc5ad3f3SBenjamin Herrenschmidt u32 irq, server, priority;
22bc5ad3f3SBenjamin Herrenschmidt int rc;
23bc5ad3f3SBenjamin Herrenschmidt
2419a44ecfSAlexander Graf if (be32_to_cpu(args->nargs) != 3 || be32_to_cpu(args->nret) != 1) {
25bc5ad3f3SBenjamin Herrenschmidt rc = -3;
26bc5ad3f3SBenjamin Herrenschmidt goto out;
27bc5ad3f3SBenjamin Herrenschmidt }
28bc5ad3f3SBenjamin Herrenschmidt
2919a44ecfSAlexander Graf irq = be32_to_cpu(args->args[0]);
3019a44ecfSAlexander Graf server = be32_to_cpu(args->args[1]);
3119a44ecfSAlexander Graf priority = be32_to_cpu(args->args[2]);
32bc5ad3f3SBenjamin Herrenschmidt
3303f95332SPaul Mackerras if (xics_on_xive())
345af50993SBenjamin Herrenschmidt rc = kvmppc_xive_set_xive(vcpu->kvm, irq, server, priority);
355af50993SBenjamin Herrenschmidt else
36bc5ad3f3SBenjamin Herrenschmidt rc = kvmppc_xics_set_xive(vcpu->kvm, irq, server, priority);
37bc5ad3f3SBenjamin Herrenschmidt if (rc)
38bc5ad3f3SBenjamin Herrenschmidt rc = -3;
39bc5ad3f3SBenjamin Herrenschmidt out:
4019a44ecfSAlexander Graf args->rets[0] = cpu_to_be32(rc);
41bc5ad3f3SBenjamin Herrenschmidt }
42bc5ad3f3SBenjamin Herrenschmidt
kvm_rtas_get_xive(struct kvm_vcpu * vcpu,struct rtas_args * args)43bc5ad3f3SBenjamin Herrenschmidt static void kvm_rtas_get_xive(struct kvm_vcpu *vcpu, struct rtas_args *args)
44bc5ad3f3SBenjamin Herrenschmidt {
45bc5ad3f3SBenjamin Herrenschmidt u32 irq, server, priority;
46bc5ad3f3SBenjamin Herrenschmidt int rc;
47bc5ad3f3SBenjamin Herrenschmidt
4819a44ecfSAlexander Graf if (be32_to_cpu(args->nargs) != 1 || be32_to_cpu(args->nret) != 3) {
49bc5ad3f3SBenjamin Herrenschmidt rc = -3;
50bc5ad3f3SBenjamin Herrenschmidt goto out;
51bc5ad3f3SBenjamin Herrenschmidt }
52bc5ad3f3SBenjamin Herrenschmidt
5319a44ecfSAlexander Graf irq = be32_to_cpu(args->args[0]);
54bc5ad3f3SBenjamin Herrenschmidt
55bc5ad3f3SBenjamin Herrenschmidt server = priority = 0;
5603f95332SPaul Mackerras if (xics_on_xive())
575af50993SBenjamin Herrenschmidt rc = kvmppc_xive_get_xive(vcpu->kvm, irq, &server, &priority);
585af50993SBenjamin Herrenschmidt else
59bc5ad3f3SBenjamin Herrenschmidt rc = kvmppc_xics_get_xive(vcpu->kvm, irq, &server, &priority);
60bc5ad3f3SBenjamin Herrenschmidt if (rc) {
61bc5ad3f3SBenjamin Herrenschmidt rc = -3;
62bc5ad3f3SBenjamin Herrenschmidt goto out;
63bc5ad3f3SBenjamin Herrenschmidt }
64bc5ad3f3SBenjamin Herrenschmidt
6519a44ecfSAlexander Graf args->rets[1] = cpu_to_be32(server);
6619a44ecfSAlexander Graf args->rets[2] = cpu_to_be32(priority);
67bc5ad3f3SBenjamin Herrenschmidt out:
6819a44ecfSAlexander Graf args->rets[0] = cpu_to_be32(rc);
69bc5ad3f3SBenjamin Herrenschmidt }
70d19bd862SPaul Mackerras
kvm_rtas_int_off(struct kvm_vcpu * vcpu,struct rtas_args * args)71d19bd862SPaul Mackerras static void kvm_rtas_int_off(struct kvm_vcpu *vcpu, struct rtas_args *args)
72d19bd862SPaul Mackerras {
73d19bd862SPaul Mackerras u32 irq;
74d19bd862SPaul Mackerras int rc;
75d19bd862SPaul Mackerras
7619a44ecfSAlexander Graf if (be32_to_cpu(args->nargs) != 1 || be32_to_cpu(args->nret) != 1) {
77d19bd862SPaul Mackerras rc = -3;
78d19bd862SPaul Mackerras goto out;
79d19bd862SPaul Mackerras }
80d19bd862SPaul Mackerras
8119a44ecfSAlexander Graf irq = be32_to_cpu(args->args[0]);
82d19bd862SPaul Mackerras
8303f95332SPaul Mackerras if (xics_on_xive())
845af50993SBenjamin Herrenschmidt rc = kvmppc_xive_int_off(vcpu->kvm, irq);
855af50993SBenjamin Herrenschmidt else
86d19bd862SPaul Mackerras rc = kvmppc_xics_int_off(vcpu->kvm, irq);
87d19bd862SPaul Mackerras if (rc)
88d19bd862SPaul Mackerras rc = -3;
89d19bd862SPaul Mackerras out:
9019a44ecfSAlexander Graf args->rets[0] = cpu_to_be32(rc);
91d19bd862SPaul Mackerras }
92d19bd862SPaul Mackerras
kvm_rtas_int_on(struct kvm_vcpu * vcpu,struct rtas_args * args)93d19bd862SPaul Mackerras static void kvm_rtas_int_on(struct kvm_vcpu *vcpu, struct rtas_args *args)
94d19bd862SPaul Mackerras {
95d19bd862SPaul Mackerras u32 irq;
96d19bd862SPaul Mackerras int rc;
97d19bd862SPaul Mackerras
9819a44ecfSAlexander Graf if (be32_to_cpu(args->nargs) != 1 || be32_to_cpu(args->nret) != 1) {
99d19bd862SPaul Mackerras rc = -3;
100d19bd862SPaul Mackerras goto out;
101d19bd862SPaul Mackerras }
102d19bd862SPaul Mackerras
10319a44ecfSAlexander Graf irq = be32_to_cpu(args->args[0]);
104d19bd862SPaul Mackerras
10503f95332SPaul Mackerras if (xics_on_xive())
1065af50993SBenjamin Herrenschmidt rc = kvmppc_xive_int_on(vcpu->kvm, irq);
1075af50993SBenjamin Herrenschmidt else
108d19bd862SPaul Mackerras rc = kvmppc_xics_int_on(vcpu->kvm, irq);
109d19bd862SPaul Mackerras if (rc)
110d19bd862SPaul Mackerras rc = -3;
111d19bd862SPaul Mackerras out:
11219a44ecfSAlexander Graf args->rets[0] = cpu_to_be32(rc);
113d19bd862SPaul Mackerras }
114bc5ad3f3SBenjamin Herrenschmidt #endif /* CONFIG_KVM_XICS */
1158e591cb7SMichael Ellerman
1168e591cb7SMichael Ellerman struct rtas_handler {
1178e591cb7SMichael Ellerman void (*handler)(struct kvm_vcpu *vcpu, struct rtas_args *args);
1188e591cb7SMichael Ellerman char *name;
1198e591cb7SMichael Ellerman };
1208e591cb7SMichael Ellerman
121bc5ad3f3SBenjamin Herrenschmidt static struct rtas_handler rtas_handlers[] = {
122bc5ad3f3SBenjamin Herrenschmidt #ifdef CONFIG_KVM_XICS
123bc5ad3f3SBenjamin Herrenschmidt { .name = "ibm,set-xive", .handler = kvm_rtas_set_xive },
124bc5ad3f3SBenjamin Herrenschmidt { .name = "ibm,get-xive", .handler = kvm_rtas_get_xive },
125d19bd862SPaul Mackerras { .name = "ibm,int-off", .handler = kvm_rtas_int_off },
126d19bd862SPaul Mackerras { .name = "ibm,int-on", .handler = kvm_rtas_int_on },
127bc5ad3f3SBenjamin Herrenschmidt #endif
128bc5ad3f3SBenjamin Herrenschmidt };
1298e591cb7SMichael Ellerman
1308e591cb7SMichael Ellerman struct rtas_token_definition {
1318e591cb7SMichael Ellerman struct list_head list;
1328e591cb7SMichael Ellerman struct rtas_handler *handler;
1338e591cb7SMichael Ellerman u64 token;
1348e591cb7SMichael Ellerman };
1358e591cb7SMichael Ellerman
rtas_name_matches(char * s1,char * s2)1368e591cb7SMichael Ellerman static int rtas_name_matches(char *s1, char *s2)
1378e591cb7SMichael Ellerman {
1388e591cb7SMichael Ellerman struct kvm_rtas_token_args args;
1398e591cb7SMichael Ellerman return !strncmp(s1, s2, sizeof(args.name));
1408e591cb7SMichael Ellerman }
1418e591cb7SMichael Ellerman
rtas_token_undefine(struct kvm * kvm,char * name)1428e591cb7SMichael Ellerman static int rtas_token_undefine(struct kvm *kvm, char *name)
1438e591cb7SMichael Ellerman {
1448e591cb7SMichael Ellerman struct rtas_token_definition *d, *tmp;
1458e591cb7SMichael Ellerman
1461659e27dSPaul Mackerras lockdep_assert_held(&kvm->arch.rtas_token_lock);
1478e591cb7SMichael Ellerman
1488e591cb7SMichael Ellerman list_for_each_entry_safe(d, tmp, &kvm->arch.rtas_tokens, list) {
1498e591cb7SMichael Ellerman if (rtas_name_matches(d->handler->name, name)) {
1508e591cb7SMichael Ellerman list_del(&d->list);
1518e591cb7SMichael Ellerman kfree(d);
1528e591cb7SMichael Ellerman return 0;
1538e591cb7SMichael Ellerman }
1548e591cb7SMichael Ellerman }
1558e591cb7SMichael Ellerman
1568e591cb7SMichael Ellerman /* It's not an error to undefine an undefined token */
1578e591cb7SMichael Ellerman return 0;
1588e591cb7SMichael Ellerman }
1598e591cb7SMichael Ellerman
rtas_token_define(struct kvm * kvm,char * name,u64 token)1608e591cb7SMichael Ellerman static int rtas_token_define(struct kvm *kvm, char *name, u64 token)
1618e591cb7SMichael Ellerman {
1628e591cb7SMichael Ellerman struct rtas_token_definition *d;
1638e591cb7SMichael Ellerman struct rtas_handler *h = NULL;
1648e591cb7SMichael Ellerman bool found;
1658e591cb7SMichael Ellerman int i;
1668e591cb7SMichael Ellerman
1671659e27dSPaul Mackerras lockdep_assert_held(&kvm->arch.rtas_token_lock);
1688e591cb7SMichael Ellerman
1698e591cb7SMichael Ellerman list_for_each_entry(d, &kvm->arch.rtas_tokens, list) {
1708e591cb7SMichael Ellerman if (d->token == token)
1718e591cb7SMichael Ellerman return -EEXIST;
1728e591cb7SMichael Ellerman }
1738e591cb7SMichael Ellerman
1748e591cb7SMichael Ellerman found = false;
1758e591cb7SMichael Ellerman for (i = 0; i < ARRAY_SIZE(rtas_handlers); i++) {
1768e591cb7SMichael Ellerman h = &rtas_handlers[i];
1778e591cb7SMichael Ellerman if (rtas_name_matches(h->name, name)) {
1788e591cb7SMichael Ellerman found = true;
1798e591cb7SMichael Ellerman break;
1808e591cb7SMichael Ellerman }
1818e591cb7SMichael Ellerman }
1828e591cb7SMichael Ellerman
1838e591cb7SMichael Ellerman if (!found)
1848e591cb7SMichael Ellerman return -ENOENT;
1858e591cb7SMichael Ellerman
1868e591cb7SMichael Ellerman d = kzalloc(sizeof(*d), GFP_KERNEL);
1878e591cb7SMichael Ellerman if (!d)
1888e591cb7SMichael Ellerman return -ENOMEM;
1898e591cb7SMichael Ellerman
1908e591cb7SMichael Ellerman d->handler = h;
1918e591cb7SMichael Ellerman d->token = token;
1928e591cb7SMichael Ellerman
1938e591cb7SMichael Ellerman list_add_tail(&d->list, &kvm->arch.rtas_tokens);
1948e591cb7SMichael Ellerman
1958e591cb7SMichael Ellerman return 0;
1968e591cb7SMichael Ellerman }
1978e591cb7SMichael Ellerman
kvm_vm_ioctl_rtas_define_token(struct kvm * kvm,void __user * argp)1988e591cb7SMichael Ellerman int kvm_vm_ioctl_rtas_define_token(struct kvm *kvm, void __user *argp)
1998e591cb7SMichael Ellerman {
2008e591cb7SMichael Ellerman struct kvm_rtas_token_args args;
2018e591cb7SMichael Ellerman int rc;
2028e591cb7SMichael Ellerman
2038e591cb7SMichael Ellerman if (copy_from_user(&args, argp, sizeof(args)))
2048e591cb7SMichael Ellerman return -EFAULT;
2058e591cb7SMichael Ellerman
2061659e27dSPaul Mackerras mutex_lock(&kvm->arch.rtas_token_lock);
2078e591cb7SMichael Ellerman
2088e591cb7SMichael Ellerman if (args.token)
2098e591cb7SMichael Ellerman rc = rtas_token_define(kvm, args.name, args.token);
2108e591cb7SMichael Ellerman else
2118e591cb7SMichael Ellerman rc = rtas_token_undefine(kvm, args.name);
2128e591cb7SMichael Ellerman
2131659e27dSPaul Mackerras mutex_unlock(&kvm->arch.rtas_token_lock);
2148e591cb7SMichael Ellerman
2158e591cb7SMichael Ellerman return rc;
2168e591cb7SMichael Ellerman }
2178e591cb7SMichael Ellerman
kvmppc_rtas_hcall(struct kvm_vcpu * vcpu)2188e591cb7SMichael Ellerman int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu)
2198e591cb7SMichael Ellerman {
2208e591cb7SMichael Ellerman struct rtas_token_definition *d;
2218e591cb7SMichael Ellerman struct rtas_args args;
2228e591cb7SMichael Ellerman rtas_arg_t *orig_rets;
2238e591cb7SMichael Ellerman gpa_t args_phys;
2248e591cb7SMichael Ellerman int rc;
2258e591cb7SMichael Ellerman
226b24f36f3SPaul Mackerras /*
227b24f36f3SPaul Mackerras * r4 contains the guest physical address of the RTAS args
228b24f36f3SPaul Mackerras * Mask off the top 4 bits since this is a guest real address
229b24f36f3SPaul Mackerras */
230b24f36f3SPaul Mackerras args_phys = kvmppc_get_gpr(vcpu, 4) & KVM_PAM;
2318e591cb7SMichael Ellerman
232*2031f287SSean Christopherson kvm_vcpu_srcu_read_lock(vcpu);
2338e591cb7SMichael Ellerman rc = kvm_read_guest(vcpu->kvm, args_phys, &args, sizeof(args));
234*2031f287SSean Christopherson kvm_vcpu_srcu_read_unlock(vcpu);
2358e591cb7SMichael Ellerman if (rc)
2368e591cb7SMichael Ellerman goto fail;
2378e591cb7SMichael Ellerman
2388e591cb7SMichael Ellerman /*
2398e591cb7SMichael Ellerman * args->rets is a pointer into args->args. Now that we've
2408e591cb7SMichael Ellerman * copied args we need to fix it up to point into our copy,
2418e591cb7SMichael Ellerman * not the guest args. We also need to save the original
2428e591cb7SMichael Ellerman * value so we can restore it on the way out.
2438e591cb7SMichael Ellerman */
2448e591cb7SMichael Ellerman orig_rets = args.rets;
245f62f3c20SNicholas Piggin if (be32_to_cpu(args.nargs) >= ARRAY_SIZE(args.args)) {
246f62f3c20SNicholas Piggin /*
247f62f3c20SNicholas Piggin * Don't overflow our args array: ensure there is room for
248f62f3c20SNicholas Piggin * at least rets[0] (even if the call specifies 0 nret).
249f62f3c20SNicholas Piggin *
250f62f3c20SNicholas Piggin * Each handler must then check for the correct nargs and nret
251f62f3c20SNicholas Piggin * values, but they may always return failure in rets[0].
252f62f3c20SNicholas Piggin */
253f62f3c20SNicholas Piggin rc = -EINVAL;
254f62f3c20SNicholas Piggin goto fail;
255f62f3c20SNicholas Piggin }
25619a44ecfSAlexander Graf args.rets = &args.args[be32_to_cpu(args.nargs)];
2578e591cb7SMichael Ellerman
2581659e27dSPaul Mackerras mutex_lock(&vcpu->kvm->arch.rtas_token_lock);
2598e591cb7SMichael Ellerman
2608e591cb7SMichael Ellerman rc = -ENOENT;
2618e591cb7SMichael Ellerman list_for_each_entry(d, &vcpu->kvm->arch.rtas_tokens, list) {
26219a44ecfSAlexander Graf if (d->token == be32_to_cpu(args.token)) {
2638e591cb7SMichael Ellerman d->handler->handler(vcpu, &args);
2648e591cb7SMichael Ellerman rc = 0;
2658e591cb7SMichael Ellerman break;
2668e591cb7SMichael Ellerman }
2678e591cb7SMichael Ellerman }
2688e591cb7SMichael Ellerman
2691659e27dSPaul Mackerras mutex_unlock(&vcpu->kvm->arch.rtas_token_lock);
2708e591cb7SMichael Ellerman
2718e591cb7SMichael Ellerman if (rc == 0) {
2728e591cb7SMichael Ellerman args.rets = orig_rets;
2738e591cb7SMichael Ellerman rc = kvm_write_guest(vcpu->kvm, args_phys, &args, sizeof(args));
2748e591cb7SMichael Ellerman if (rc)
2758e591cb7SMichael Ellerman goto fail;
2768e591cb7SMichael Ellerman }
2778e591cb7SMichael Ellerman
2788e591cb7SMichael Ellerman return rc;
2798e591cb7SMichael Ellerman
2808e591cb7SMichael Ellerman fail:
2818e591cb7SMichael Ellerman /*
2828e591cb7SMichael Ellerman * We only get here if the guest has called RTAS with a bogus
283f62f3c20SNicholas Piggin * args pointer or nargs/nret values that would overflow the
284f62f3c20SNicholas Piggin * array. That means we can't get to the args, and so we can't
285f62f3c20SNicholas Piggin * fail the RTAS call. So fail right out to userspace, which
286f62f3c20SNicholas Piggin * should kill the guest.
287f62f3c20SNicholas Piggin *
288f62f3c20SNicholas Piggin * SLOF should actually pass the hcall return value from the
289f62f3c20SNicholas Piggin * rtas handler call in r3, so enter_rtas could be modified to
290f62f3c20SNicholas Piggin * return a failure indication in r3 and we could return such
291f62f3c20SNicholas Piggin * errors to the guest rather than failing to host userspace.
292f62f3c20SNicholas Piggin * However old guests that don't test for failure could then
293f62f3c20SNicholas Piggin * continue silently after errors, so for now we won't do this.
2948e591cb7SMichael Ellerman */
2958e591cb7SMichael Ellerman return rc;
2968e591cb7SMichael Ellerman }
2972ba9f0d8SAneesh Kumar K.V EXPORT_SYMBOL_GPL(kvmppc_rtas_hcall);
2988e591cb7SMichael Ellerman
kvmppc_rtas_tokens_free(struct kvm * kvm)2998e591cb7SMichael Ellerman void kvmppc_rtas_tokens_free(struct kvm *kvm)
3008e591cb7SMichael Ellerman {
3018e591cb7SMichael Ellerman struct rtas_token_definition *d, *tmp;
3028e591cb7SMichael Ellerman
3038e591cb7SMichael Ellerman list_for_each_entry_safe(d, tmp, &kvm->arch.rtas_tokens, list) {
3048e591cb7SMichael Ellerman list_del(&d->list);
3058e591cb7SMichael Ellerman kfree(d);
3068e591cb7SMichael Ellerman }
3078e591cb7SMichael Ellerman }
308