Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
xcom_hcall.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * Tristan Gingold <[email protected]>
17  *
18  * Copyright (c) 2007
19  * Isaku Yamahata <yamahata at valinux co jp>
20  * VA Linux Systems Japan K.K.
21  * consolidate mini and inline version.
22  */
23 
24 #include <linux/module.h>
25 #include <xen/interface/xen.h>
26 #include <xen/interface/memory.h>
28 #include <xen/interface/callback.h>
29 #include <xen/interface/vcpu.h>
30 #include <asm/xen/hypervisor.h>
31 #include <asm/xen/xencomm.h>
32 
33 /* Xencomm notes:
34  * This file defines hypercalls to be used by xencomm. The hypercalls simply
35  * create inlines or mini descriptors for pointers and then call the raw arch
36  * hypercall xencomm_arch_hypercall_XXX
37  *
38  * If the arch wants to directly use these hypercalls, simply define macros
39  * in asm/xen/hypercall.h, eg:
40  * #define HYPERVISOR_sched_op xencomm_hypercall_sched_op
41  *
42  * The arch may also define HYPERVISOR_xxx as a function and do more operations
43  * before/after doing the hypercall.
44  *
45  * Note: because only inline or mini descriptors are created these functions
46  * must only be called with in kernel memory parameters.
47  */
48 
49 int
51 {
52  /* xen early printk uses console io hypercall before
53  * xencomm initialization. In that case, we just ignore it.
54  */
56  return 0;
57 
58  return xencomm_arch_hypercall_console_io
59  (cmd, count, xencomm_map_no_alloc(str, count));
60 }
62 
63 int
65 {
66  struct xencomm_handle *desc;
67  desc = xencomm_map_no_alloc(op, sizeof(struct evtchn_op));
68  if (desc == NULL)
69  return -EINVAL;
70 
71  return xencomm_arch_hypercall_event_channel_op(cmd, desc);
72 }
74 
75 int
77 {
78  struct xencomm_handle *desc;
79  unsigned int argsize;
80 
81  switch (cmd) {
82  case XENVER_version:
83  /* do not actually pass an argument */
84  return xencomm_arch_hypercall_xen_version(cmd, 0);
86  argsize = sizeof(struct xen_extraversion);
87  break;
89  argsize = sizeof(struct xen_compile_info);
90  break;
92  argsize = sizeof(struct xen_capabilities_info);
93  break;
94  case XENVER_changeset:
95  argsize = sizeof(struct xen_changeset_info);
96  break;
98  argsize = sizeof(struct xen_platform_parameters);
99  break;
100  case XENVER_get_features:
101  argsize = (arg == NULL) ? 0 : sizeof(struct xen_feature_info);
102  break;
103 
104  default:
106  "%s: unknown version op %d\n", __func__, cmd);
107  return -ENOSYS;
108  }
109 
110  desc = xencomm_map_no_alloc(arg, argsize);
111  if (desc == NULL)
112  return -EINVAL;
113 
114  return xencomm_arch_hypercall_xen_version(cmd, desc);
115 }
117 
118 int
120 {
121  unsigned int argsize;
122 
123  switch (cmd) {
124  case PHYSDEVOP_apic_read:
126  argsize = sizeof(struct physdev_apic);
127  break;
130  argsize = sizeof(struct physdev_irq);
131  break;
133  argsize = sizeof(struct physdev_irq_status_query);
134  break;
135 
136  default:
138  "%s: unknown physdev op %d\n", __func__, cmd);
139  return -ENOSYS;
140  }
141 
142  return xencomm_arch_hypercall_physdev_op
143  (cmd, xencomm_map_no_alloc(op, argsize));
144 }
145 
146 static int
147 xencommize_grant_table_op(struct xencomm_mini **xc_area,
148  unsigned int cmd, void *op, unsigned int count,
149  struct xencomm_handle **desc)
150 {
151  struct xencomm_handle *desc1;
152  unsigned int argsize;
153 
154  switch (cmd) {
156  argsize = sizeof(struct gnttab_map_grant_ref);
157  break;
159  argsize = sizeof(struct gnttab_unmap_grant_ref);
160  break;
162  {
163  struct gnttab_setup_table *setup = op;
164 
165  argsize = sizeof(*setup);
166 
167  if (count != 1)
168  return -EINVAL;
169  desc1 = __xencomm_map_no_alloc
170  (xen_guest_handle(setup->frame_list),
171  setup->nr_frames *
172  sizeof(*xen_guest_handle(setup->frame_list)),
173  *xc_area);
174  if (desc1 == NULL)
175  return -EINVAL;
176  (*xc_area)++;
177  set_xen_guest_handle(setup->frame_list, (void *)desc1);
178  break;
179  }
180  case GNTTABOP_dump_table:
181  argsize = sizeof(struct gnttab_dump_table);
182  break;
183  case GNTTABOP_transfer:
184  argsize = sizeof(struct gnttab_transfer);
185  break;
186  case GNTTABOP_copy:
187  argsize = sizeof(struct gnttab_copy);
188  break;
189  case GNTTABOP_query_size:
190  argsize = sizeof(struct gnttab_query_size);
191  break;
192  default:
193  printk(KERN_DEBUG "%s: unknown hypercall grant table op %d\n",
194  __func__, cmd);
195  BUG();
196  }
197 
198  *desc = __xencomm_map_no_alloc(op, count * argsize, *xc_area);
199  if (*desc == NULL)
200  return -EINVAL;
201  (*xc_area)++;
202 
203  return 0;
204 }
205 
206 int
207 xencomm_hypercall_grant_table_op(unsigned int cmd, void *op,
208  unsigned int count)
209 {
210  int rc;
211  struct xencomm_handle *desc;
212  XENCOMM_MINI_ALIGNED(xc_area, 2);
213 
214  rc = xencommize_grant_table_op(&xc_area, cmd, op, count, &desc);
215  if (rc)
216  return rc;
217 
218  return xencomm_arch_hypercall_grant_table_op(cmd, desc, count);
219 }
221 
222 int
224 {
225  struct xencomm_handle *desc;
226  unsigned int argsize;
227 
228  switch (cmd) {
229  case SCHEDOP_yield:
230  case SCHEDOP_block:
231  argsize = 0;
232  break;
233  case SCHEDOP_shutdown:
234  argsize = sizeof(struct sched_shutdown);
235  break;
236  case SCHEDOP_poll:
237  {
238  struct sched_poll *poll = arg;
239  struct xencomm_handle *ports;
240 
241  argsize = sizeof(struct sched_poll);
242  ports = xencomm_map_no_alloc(xen_guest_handle(poll->ports),
243  sizeof(*xen_guest_handle(poll->ports)));
244 
245  set_xen_guest_handle(poll->ports, (void *)ports);
246  break;
247  }
248  default:
249  printk(KERN_DEBUG "%s: unknown sched op %d\n", __func__, cmd);
250  return -ENOSYS;
251  }
252 
253  desc = xencomm_map_no_alloc(arg, argsize);
254  if (desc == NULL)
255  return -EINVAL;
256 
257  return xencomm_arch_hypercall_sched_op(cmd, desc);
258 }
260 
261 int
262 xencomm_hypercall_multicall(void *call_list, int nr_calls)
263 {
264  int rc;
265  int i;
266  struct multicall_entry *mce;
267  struct xencomm_handle *desc;
268  XENCOMM_MINI_ALIGNED(xc_area, nr_calls * 2);
269 
270  for (i = 0; i < nr_calls; i++) {
271  mce = (struct multicall_entry *)call_list + i;
272 
273  switch (mce->op) {
276  /* No-op on ia64. */
277  break;
279  rc = xencommize_grant_table_op
280  (&xc_area,
281  mce->args[0], (void *)mce->args[1],
282  mce->args[2], &desc);
283  if (rc)
284  return rc;
285  mce->args[1] = (unsigned long)desc;
286  break;
288  default:
290  "%s: unhandled multicall op entry op %lu\n",
291  __func__, mce->op);
292  return -ENOSYS;
293  }
294  }
295 
296  desc = xencomm_map_no_alloc(call_list,
297  nr_calls * sizeof(struct multicall_entry));
298  if (desc == NULL)
299  return -EINVAL;
300 
301  return xencomm_arch_hypercall_multicall(desc, nr_calls);
302 }
304 
305 int
307 {
308  unsigned int argsize;
309  switch (cmd) {
310  case CALLBACKOP_register:
311  argsize = sizeof(struct callback_register);
312  break;
314  argsize = sizeof(struct callback_unregister);
315  break;
316  default:
318  "%s: unknown callback op %d\n", __func__, cmd);
319  return -ENOSYS;
320  }
321 
322  return xencomm_arch_hypercall_callback_op
323  (cmd, xencomm_map_no_alloc(arg, argsize));
324 }
325 
326 static int
327 xencommize_memory_reservation(struct xencomm_mini *xc_area,
328  struct xen_memory_reservation *mop)
329 {
330  struct xencomm_handle *desc;
331 
332  desc = __xencomm_map_no_alloc(xen_guest_handle(mop->extent_start),
333  mop->nr_extents *
334  sizeof(*xen_guest_handle(mop->extent_start)),
335  xc_area);
336  if (desc == NULL)
337  return -EINVAL;
338 
339  set_xen_guest_handle(mop->extent_start, (void *)desc);
340  return 0;
341 }
342 
343 int
344 xencomm_hypercall_memory_op(unsigned int cmd, void *arg)
345 {
346  GUEST_HANDLE(xen_pfn_t) extent_start_va[2] = { {NULL}, {NULL} };
347  struct xen_memory_reservation *xmr = NULL;
348  int rc;
349  struct xencomm_handle *desc;
350  unsigned int argsize;
351  XENCOMM_MINI_ALIGNED(xc_area, 2);
352 
353  switch (cmd) {
357  xmr = (struct xen_memory_reservation *)arg;
358  set_xen_guest_handle(extent_start_va[0],
359  xen_guest_handle(xmr->extent_start));
360 
361  argsize = sizeof(*xmr);
362  rc = xencommize_memory_reservation(xc_area, xmr);
363  if (rc)
364  return rc;
365  xc_area++;
366  break;
367 
369  argsize = 0;
370  break;
371 
373  argsize = sizeof(struct xen_add_to_physmap);
374  break;
375 
376  default:
377  printk(KERN_DEBUG "%s: unknown memory op %d\n", __func__, cmd);
378  return -ENOSYS;
379  }
380 
381  desc = xencomm_map_no_alloc(arg, argsize);
382  if (desc == NULL)
383  return -EINVAL;
384 
385  rc = xencomm_arch_hypercall_memory_op(cmd, desc);
386 
387  switch (cmd) {
391  set_xen_guest_handle(xmr->extent_start,
392  xen_guest_handle(extent_start_va[0]));
393  break;
394  }
395 
396  return rc;
397 }
399 
400 int
401 xencomm_hypercall_suspend(unsigned long srec)
402 {
403  struct sched_shutdown arg;
404 
405  arg.reason = SHUTDOWN_suspend;
406 
407  return xencomm_arch_hypercall_sched_op(
408  SCHEDOP_shutdown, xencomm_map_no_alloc(&arg, sizeof(arg)));
409 }
410 
411 long
412 xencomm_hypercall_vcpu_op(int cmd, int cpu, void *arg)
413 {
414  unsigned int argsize;
415  switch (cmd) {
419  argsize = sizeof(*arg);
420  set_xen_guest_handle(area->addr.h,
421  (void *)xencomm_map_no_alloc(area->addr.v,
422  sizeof(area->addr.v)));
423  break;
424  }
425 
426  default:
427  printk(KERN_DEBUG "%s: unknown vcpu op %d\n", __func__, cmd);
428  return -ENOSYS;
429  }
430 
431  return xencomm_arch_hypercall_vcpu_op(cmd, cpu,
432  xencomm_map_no_alloc(arg, argsize));
433 }
434 
435 long
437 {
438  return xencomm_arch_hypercall_opt_feature(
440  sizeof(struct xen_ia64_opt_feature)));
441 }