~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/powerpc/kvm/book3s_rtas.c

Version: ~ [ linux-5.14-rc3 ] ~ [ linux-5.13.5 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.53 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.135 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.198 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.240 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.276 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.276 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * Copyright 2012 Michael Ellerman, IBM Corporation.
  3  *
  4  * This program is free software; you can redistribute it and/or modify
  5  * it under the terms of the GNU General Public License, version 2, as
  6  * published by the Free Software Foundation.
  7  */
  8 
  9 #include <linux/kernel.h>
 10 #include <linux/kvm_host.h>
 11 #include <linux/kvm.h>
 12 #include <linux/err.h>
 13 
 14 #include <linux/uaccess.h>
 15 #include <asm/kvm_book3s.h>
 16 #include <asm/kvm_ppc.h>
 17 #include <asm/hvcall.h>
 18 #include <asm/rtas.h>
 19 #include <asm/xive.h>
 20 
 21 #ifdef CONFIG_KVM_XICS
 22 static void kvm_rtas_set_xive(struct kvm_vcpu *vcpu, struct rtas_args *args)
 23 {
 24         u32 irq, server, priority;
 25         int rc;
 26 
 27         if (be32_to_cpu(args->nargs) != 3 || be32_to_cpu(args->nret) != 1) {
 28                 rc = -3;
 29                 goto out;
 30         }
 31 
 32         irq = be32_to_cpu(args->args[0]);
 33         server = be32_to_cpu(args->args[1]);
 34         priority = be32_to_cpu(args->args[2]);
 35 
 36         if (xive_enabled())
 37                 rc = kvmppc_xive_set_xive(vcpu->kvm, irq, server, priority);
 38         else
 39                 rc = kvmppc_xics_set_xive(vcpu->kvm, irq, server, priority);
 40         if (rc)
 41                 rc = -3;
 42 out:
 43         args->rets[0] = cpu_to_be32(rc);
 44 }
 45 
 46 static void kvm_rtas_get_xive(struct kvm_vcpu *vcpu, struct rtas_args *args)
 47 {
 48         u32 irq, server, priority;
 49         int rc;
 50 
 51         if (be32_to_cpu(args->nargs) != 1 || be32_to_cpu(args->nret) != 3) {
 52                 rc = -3;
 53                 goto out;
 54         }
 55 
 56         irq = be32_to_cpu(args->args[0]);
 57 
 58         server = priority = 0;
 59         if (xive_enabled())
 60                 rc = kvmppc_xive_get_xive(vcpu->kvm, irq, &server, &priority);
 61         else
 62                 rc = kvmppc_xics_get_xive(vcpu->kvm, irq, &server, &priority);
 63         if (rc) {
 64                 rc = -3;
 65                 goto out;
 66         }
 67 
 68         args->rets[1] = cpu_to_be32(server);
 69         args->rets[2] = cpu_to_be32(priority);
 70 out:
 71         args->rets[0] = cpu_to_be32(rc);
 72 }
 73 
 74 static void kvm_rtas_int_off(struct kvm_vcpu *vcpu, struct rtas_args *args)
 75 {
 76         u32 irq;
 77         int rc;
 78 
 79         if (be32_to_cpu(args->nargs) != 1 || be32_to_cpu(args->nret) != 1) {
 80                 rc = -3;
 81                 goto out;
 82         }
 83 
 84         irq = be32_to_cpu(args->args[0]);
 85 
 86         if (xive_enabled())
 87                 rc = kvmppc_xive_int_off(vcpu->kvm, irq);
 88         else
 89                 rc = kvmppc_xics_int_off(vcpu->kvm, irq);
 90         if (rc)
 91                 rc = -3;
 92 out:
 93         args->rets[0] = cpu_to_be32(rc);
 94 }
 95 
 96 static void kvm_rtas_int_on(struct kvm_vcpu *vcpu, struct rtas_args *args)
 97 {
 98         u32 irq;
 99         int rc;
100 
101         if (be32_to_cpu(args->nargs) != 1 || be32_to_cpu(args->nret) != 1) {
102                 rc = -3;
103                 goto out;
104         }
105 
106         irq = be32_to_cpu(args->args[0]);
107 
108         if (xive_enabled())
109                 rc = kvmppc_xive_int_on(vcpu->kvm, irq);
110         else
111                 rc = kvmppc_xics_int_on(vcpu->kvm, irq);
112         if (rc)
113                 rc = -3;
114 out:
115         args->rets[0] = cpu_to_be32(rc);
116 }
117 #endif /* CONFIG_KVM_XICS */
118 
119 struct rtas_handler {
120         void (*handler)(struct kvm_vcpu *vcpu, struct rtas_args *args);
121         char *name;
122 };
123 
124 static struct rtas_handler rtas_handlers[] = {
125 #ifdef CONFIG_KVM_XICS
126         { .name = "ibm,set-xive", .handler = kvm_rtas_set_xive },
127         { .name = "ibm,get-xive", .handler = kvm_rtas_get_xive },
128         { .name = "ibm,int-off",  .handler = kvm_rtas_int_off },
129         { .name = "ibm,int-on",   .handler = kvm_rtas_int_on },
130 #endif
131 };
132 
133 struct rtas_token_definition {
134         struct list_head list;
135         struct rtas_handler *handler;
136         u64 token;
137 };
138 
139 static int rtas_name_matches(char *s1, char *s2)
140 {
141         struct kvm_rtas_token_args args;
142         return !strncmp(s1, s2, sizeof(args.name));
143 }
144 
145 static int rtas_token_undefine(struct kvm *kvm, char *name)
146 {
147         struct rtas_token_definition *d, *tmp;
148 
149         lockdep_assert_held(&kvm->lock);
150 
151         list_for_each_entry_safe(d, tmp, &kvm->arch.rtas_tokens, list) {
152                 if (rtas_name_matches(d->handler->name, name)) {
153                         list_del(&d->list);
154                         kfree(d);
155                         return 0;
156                 }
157         }
158 
159         /* It's not an error to undefine an undefined token */
160         return 0;
161 }
162 
163 static int rtas_token_define(struct kvm *kvm, char *name, u64 token)
164 {
165         struct rtas_token_definition *d;
166         struct rtas_handler *h = NULL;
167         bool found;
168         int i;
169 
170         lockdep_assert_held(&kvm->lock);
171 
172         list_for_each_entry(d, &kvm->arch.rtas_tokens, list) {
173                 if (d->token == token)
174                         return -EEXIST;
175         }
176 
177         found = false;
178         for (i = 0; i < ARRAY_SIZE(rtas_handlers); i++) {
179                 h = &rtas_handlers[i];
180                 if (rtas_name_matches(h->name, name)) {
181                         found = true;
182                         break;
183                 }
184         }
185 
186         if (!found)
187                 return -ENOENT;
188 
189         d = kzalloc(sizeof(*d), GFP_KERNEL);
190         if (!d)
191                 return -ENOMEM;
192 
193         d->handler = h;
194         d->token = token;
195 
196         list_add_tail(&d->list, &kvm->arch.rtas_tokens);
197 
198         return 0;
199 }
200 
201 int kvm_vm_ioctl_rtas_define_token(struct kvm *kvm, void __user *argp)
202 {
203         struct kvm_rtas_token_args args;
204         int rc;
205 
206         if (copy_from_user(&args, argp, sizeof(args)))
207                 return -EFAULT;
208 
209         mutex_lock(&kvm->lock);
210 
211         if (args.token)
212                 rc = rtas_token_define(kvm, args.name, args.token);
213         else
214                 rc = rtas_token_undefine(kvm, args.name);
215 
216         mutex_unlock(&kvm->lock);
217 
218         return rc;
219 }
220 
221 int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu)
222 {
223         struct rtas_token_definition *d;
224         struct rtas_args args;
225         rtas_arg_t *orig_rets;
226         gpa_t args_phys;
227         int rc;
228 
229         /*
230          * r4 contains the guest physical address of the RTAS args
231          * Mask off the top 4 bits since this is a guest real address
232          */
233         args_phys = kvmppc_get_gpr(vcpu, 4) & KVM_PAM;
234 
235         rc = kvm_read_guest(vcpu->kvm, args_phys, &args, sizeof(args));
236         if (rc)
237                 goto fail;
238 
239         /*
240          * args->rets is a pointer into args->args. Now that we've
241          * copied args we need to fix it up to point into our copy,
242          * not the guest args. We also need to save the original
243          * value so we can restore it on the way out.
244          */
245         orig_rets = args.rets;
246         args.rets = &args.args[be32_to_cpu(args.nargs)];
247 
248         mutex_lock(&vcpu->kvm->lock);
249 
250         rc = -ENOENT;
251         list_for_each_entry(d, &vcpu->kvm->arch.rtas_tokens, list) {
252                 if (d->token == be32_to_cpu(args.token)) {
253                         d->handler->handler(vcpu, &args);
254                         rc = 0;
255                         break;
256                 }
257         }
258 
259         mutex_unlock(&vcpu->kvm->lock);
260 
261         if (rc == 0) {
262                 args.rets = orig_rets;
263                 rc = kvm_write_guest(vcpu->kvm, args_phys, &args, sizeof(args));
264                 if (rc)
265                         goto fail;
266         }
267 
268         return rc;
269 
270 fail:
271         /*
272          * We only get here if the guest has called RTAS with a bogus
273          * args pointer. That means we can't get to the args, and so we
274          * can't fail the RTAS call. So fail right out to userspace,
275          * which should kill the guest.
276          */
277         return rc;
278 }
279 EXPORT_SYMBOL_GPL(kvmppc_rtas_hcall);
280 
281 void kvmppc_rtas_tokens_free(struct kvm *kvm)
282 {
283         struct rtas_token_definition *d, *tmp;
284 
285         lockdep_assert_held(&kvm->lock);
286 
287         list_for_each_entry_safe(d, tmp, &kvm->arch.rtas_tokens, list) {
288                 list_del(&d->list);
289                 kfree(d);
290         }
291 }
292 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp