syswrap-xen.c revision 0ab84fe82d1e25c2e0544d08826df42caa44ded1
1
2/*--------------------------------------------------------------------*/
3/*--- Xen Hypercalls                                 syswrap-xen.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7   This file is part of Valgrind, a dynamic binary instrumentation
8   framework.
9
10   Copyright (C) 2012 Citrix Systems
11      ian.campbell@citrix.com
12
13   This program is free software; you can redistribute it and/or
14   modify it under the terms of the GNU General Public License as
15   published by the Free Software Foundation; either version 2 of the
16   License, or (at your option) any later version.
17
18   This program is distributed in the hope that it will be useful, but
19   WITHOUT ANY WARRANTY; without even the implied warranty of
20   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21   General Public License for more details.
22
23   You should have received a copy of the GNU General Public License
24   along with this program; if not, write to the Free Software
25   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26   02111-1307, USA.
27
28   The GNU General Public License is contained in the file COPYING.
29*/
30
31#include "pub_core_basics.h"
32#include "pub_core_vki.h"
33#include "pub_core_vkiscnums.h"
34#include "pub_core_libcsetjmp.h"   // to keep _threadstate.h happy
35#include "pub_core_threadstate.h"
36#include "pub_core_aspacemgr.h"
37#include "pub_core_debuginfo.h"    // VG_(di_notify_*)
38#include "pub_core_transtab.h"     // VG_(discard_translations)
39#include "pub_core_xarray.h"
40#include "pub_core_clientstate.h"
41#include "pub_core_debuglog.h"
42#include "pub_core_libcbase.h"
43#include "pub_core_libcassert.h"
44#include "pub_core_libcfile.h"
45#include "pub_core_libcprint.h"
46#include "pub_core_libcproc.h"
47#include "pub_core_libcsignal.h"
48#include "pub_core_mallocfree.h"
49#include "pub_core_tooliface.h"
50#include "pub_core_options.h"
51#include "pub_core_scheduler.h"
52#include "pub_core_signals.h"
53#include "pub_core_syscall.h"
54#include "pub_core_syswrap.h"
55#include "pub_core_stacktrace.h"    // For VG_(get_and_pp_StackTrace)()
56
57#include "priv_types_n_macros.h"
58#include "priv_syswrap-generic.h"
59#include "priv_syswrap-xen.h"
60
61#include <stdint.h>
62
63#define __XEN_TOOLS__
64
65#include <xen/xen.h>
66#include <xen/sysctl.h>
67#include <xen/domctl.h>
68#include <xen/memory.h>
69#include <xen/event_channel.h>
70#include <xen/version.h>
71
72#include <xen/hvm/hvm_op.h>
73
74#define PRE(name) static DEFN_PRE_TEMPLATE(xen, name)
75#define POST(name) static DEFN_POST_TEMPLATE(xen, name)
76
77static void bad_subop ( ThreadId              tid,
78                        SyscallArgLayout*     layout,
79                        /*MOD*/SyscallArgs*   args,
80                        /*OUT*/SyscallStatus* status,
81                        /*OUT*/UWord*         flags,
82                        const char*           hypercall,
83                        UWord                 subop)
84{
85   VG_(dmsg)("WARNING: unhandled %s subop: %ld\n",
86             hypercall, subop);
87   if (VG_(clo_verbosity) > 1) {
88      VG_(get_and_pp_StackTrace)(tid, VG_(clo_backtrace_size));
89   }
90   VG_(dmsg)("You may be able to write your own handler.\n");
91   VG_(dmsg)("Read the file README_MISSING_SYSCALL_OR_IOCTL.\n");
92   VG_(dmsg)("Nevertheless we consider this a bug.  Please report\n");
93   VG_(dmsg)("it at http://valgrind.org/support/bug_reports.html &\n");
94   VG_(dmsg)("http://wiki.xen.org/wiki/Reporting_Bugs_against_Xen.\n");
95
96   SET_STATUS_Failure(VKI_ENOSYS);
97}
98
99PRE(memory_op)
100{
101   PRINT("__HYPERVISOR_memory_op ( %ld, %lx )", ARG1, ARG2);
102
103   switch (ARG1) {
104   case XENMEM_set_memory_map: {
105      xen_foreign_memory_map_t *arg =
106         (xen_foreign_memory_map_t *)(unsigned int)ARG2;
107      PRE_MEM_READ("XENMEM_set_memory_map",
108                   (Addr)&arg->domid, sizeof(arg->domid));
109      PRE_MEM_READ("XENMEM_set_memory_map",
110                   (Addr)&arg->map, sizeof(arg->map));
111      break;
112   }
113   case XENMEM_increase_reservation:
114   case XENMEM_decrease_reservation:
115   case XENMEM_populate_physmap: {
116      struct xen_memory_reservation *memory_reservation =
117         (struct xen_memory_reservation *)(unsigned int)ARG2;
118      char *which;
119
120      switch (ARG1) {
121      case XENMEM_increase_reservation:
122         which = "XENMEM_increase_reservation";
123         break;
124      case XENMEM_decrease_reservation:
125         which = "XENMEM_decrease_reservation";
126         PRE_MEM_READ(which,
127                      (Addr)memory_reservation->extent_start.p,
128                      sizeof(xen_pfn_t) * memory_reservation->nr_extents);
129      case XENMEM_populate_physmap:
130         which = "XENMEM_populate_physmap";
131         PRE_MEM_READ(which,
132                      (Addr)memory_reservation->extent_start.p,
133                      sizeof(xen_pfn_t) * memory_reservation->nr_extents);
134         break;
135      default:
136         which = "XENMEM_unknown";
137         break;
138      }
139
140      PRE_MEM_READ(which,
141                   (Addr)&memory_reservation->extent_start,
142                   sizeof(memory_reservation->extent_start));
143      PRE_MEM_READ(which,
144                   (Addr)&memory_reservation->nr_extents,
145                   sizeof(memory_reservation->nr_extents));
146      PRE_MEM_READ(which,
147                   (Addr)&memory_reservation->extent_order,
148                   sizeof(memory_reservation->extent_order));
149      PRE_MEM_READ(which,
150                   (Addr)&memory_reservation->mem_flags,
151                   sizeof(memory_reservation->mem_flags));
152      PRE_MEM_READ(which,
153                   (Addr)&memory_reservation->domid,
154                   sizeof(memory_reservation->domid));
155      break;
156   }
157
158   default:
159      bad_subop(tid, layout, arrghs, status, flags,
160                "__HYPERVISOR_memory_op", ARG1);
161      break;
162   }
163}
164
165PRE(mmuext_op)
166{
167   mmuext_op_t *ops = (void *)(unsigned int)ARG1;
168   unsigned int i, nr = ARG2;
169
170
171   for (i=0; i<nr; i++) {
172      mmuext_op_t *op = ops + i;
173      PRE_MEM_READ("__HYPERVISOR_MMUEXT_OP",
174                   (Addr)&op->cmd, sizeof(op->cmd));
175      switch(op->cmd) {
176      case MMUEXT_PIN_L1_TABLE:
177      case MMUEXT_PIN_L2_TABLE:
178      case MMUEXT_PIN_L3_TABLE:
179      case MMUEXT_PIN_L4_TABLE:
180      case MMUEXT_UNPIN_TABLE:
181      case MMUEXT_NEW_BASEPTR:
182      case MMUEXT_CLEAR_PAGE:
183      case MMUEXT_COPY_PAGE:
184      case MMUEXT_MARK_SUPER:
185      case MMUEXT_UNMARK_SUPER:
186         PRE_MEM_READ("__HYPERVISOR_MMUEXT_OP arg1.mfn",
187                      (Addr)&op->arg1.mfn,
188                      sizeof(op->arg1.mfn));
189         break;
190
191      case MMUEXT_INVLPG_LOCAL:
192      case MMUEXT_INVLPG_ALL:
193      case MMUEXT_SET_LDT:
194         PRE_MEM_READ("__HYPERVISOR_MMUEXT_OP arg1.mfn",
195                      (Addr)&op->arg1.linear_addr,
196                      sizeof(op->arg1.linear_addr));
197         break;
198
199      case MMUEXT_TLB_FLUSH_LOCAL:
200      case MMUEXT_TLB_FLUSH_MULTI:
201      case MMUEXT_INVLPG_MULTI:
202      case MMUEXT_TLB_FLUSH_ALL:
203      case MMUEXT_FLUSH_CACHE:
204      case MMUEXT_NEW_USER_BASEPTR:
205      case MMUEXT_FLUSH_CACHE_GLOBAL:
206         /* None */
207         break;
208      }
209
210      switch(op->cmd) {
211      case MMUEXT_SET_LDT:
212         PRE_MEM_READ("__HYPERVISOR_MMUEXT_OP arg2.nr_ents",
213                      (Addr)&op->arg2.nr_ents,
214                      sizeof(op->arg2.nr_ents));
215         break;
216
217      case MMUEXT_TLB_FLUSH_MULTI:
218      case MMUEXT_INVLPG_MULTI:
219         /* How many??? */
220         PRE_MEM_READ("__HYPERVISOR_MMUEXT_OP arg2.vcpumask",
221                      (Addr)&op->arg2.vcpumask,
222                      sizeof(op->arg2.vcpumask));
223         break;
224
225      case MMUEXT_COPY_PAGE:
226         PRE_MEM_READ("__HYPERVISOR_MMUEXT_OP arg2.src_mfn",
227                      (Addr)&op->arg2.src_mfn,
228                      sizeof(op->arg2.src_mfn));
229         break;
230
231      case MMUEXT_PIN_L1_TABLE:
232      case MMUEXT_PIN_L2_TABLE:
233      case MMUEXT_PIN_L3_TABLE:
234      case MMUEXT_PIN_L4_TABLE:
235      case MMUEXT_UNPIN_TABLE:
236      case MMUEXT_NEW_BASEPTR:
237      case MMUEXT_TLB_FLUSH_LOCAL:
238      case MMUEXT_INVLPG_LOCAL:
239      case MMUEXT_TLB_FLUSH_ALL:
240      case MMUEXT_INVLPG_ALL:
241      case MMUEXT_FLUSH_CACHE:
242      case MMUEXT_NEW_USER_BASEPTR:
243      case MMUEXT_CLEAR_PAGE:
244      case MMUEXT_FLUSH_CACHE_GLOBAL:
245      case MMUEXT_MARK_SUPER:
246      case MMUEXT_UNMARK_SUPER:
247         /* None */
248         break;
249      }
250   }
251}
252
253static void pre_evtchn_op(ThreadId tid,
254                          SyscallArgLayout*     layout,
255                          /*MOD*/SyscallArgs*   arrghs,
256                          /*OUT*/SyscallStatus* status,
257                          /*OUT*/UWord*         flags,
258                          __vki_u32 cmd, void *arg, int compat)
259{
260   PRINT("__HYPERVISOR_event_channel_op%s ( %d, %p )",
261         compat ? "_compat" : "", cmd, arg);
262
263   switch (cmd) {
264   case EVTCHNOP_alloc_unbound: {
265      struct evtchn_alloc_unbound *alloc_unbound = arg;
266      PRE_MEM_READ("EVTCHNOP_alloc_unbound",
267                   (Addr)&alloc_unbound->dom, sizeof(alloc_unbound->dom));
268      PRE_MEM_READ("EVTCHNOP_alloc_unbound",
269                   (Addr)&alloc_unbound->remote_dom,
270                   sizeof(alloc_unbound->remote_dom));
271      break;
272   }
273   default:
274      if ( compat )
275         bad_subop(tid, layout, arrghs, status, flags,
276                   "__HYPERVISOR_event_channel_op_compat", cmd);
277      else
278         bad_subop(tid, layout, arrghs, status, flags,
279                   "__HYPERVISOR_event_channel_op", cmd);
280      break;
281   }
282}
283
284PRE(evtchn_op)
285{
286   pre_evtchn_op(tid, layout, arrghs, status, flags,
287                 ARG1, (void *)(unsigned int)ARG2, 0);
288}
289
290PRE(evtchn_op_compat)
291{
292   struct evtchn_op *evtchn = (struct evtchn_op *)(unsigned int)ARG1;
293   PRE_MEM_READ("__HYPERVISOR_event_channel_op_compat",
294                ARG1, sizeof(*evtchn));
295
296   pre_evtchn_op(tid, layout, arrghs, status, flags,
297                 evtchn->cmd, &evtchn->u, 1);
298}
299
300PRE(xen_version)
301{
302   PRINT("__HYPERVISOR_xen_version ( %ld, %lx )", ARG1, ARG2);
303
304   switch (ARG1) {
305   case XENVER_version:
306   case XENVER_extraversion:
307   case XENVER_compile_info:
308   case XENVER_capabilities:
309   case XENVER_changeset:
310   case XENVER_platform_parameters:
311   case XENVER_get_features:
312   case XENVER_pagesize:
313   case XENVER_guest_handle:
314   case XENVER_commandline:
315      /* No inputs */
316      break;
317
318   default:
319      bad_subop(tid, layout, arrghs, status, flags,
320                "__HYPERVISOR_xen_version", ARG1);
321      break;
322   }
323}
324
325PRE(grant_table_op)
326{
327   PRINT("__HYPERVISOR_grant_table_op ( %ld, 0x%lx, %ld )", ARG1, ARG2, ARG3);
328   switch (ARG1) {
329   case GNTTABOP_setup_table: {
330      struct gnttab_setup_table *gst = (void *)(intptr_t)ARG2;
331      PRE_MEM_READ("GNTTABOP_setup_table", (Addr)&gst->dom, sizeof(gst->dom));
332      PRE_MEM_READ("GNTTABOP_setup_table",
333                   (Addr)&gst->nr_frames, sizeof(gst->nr_frames));
334      break;
335   }
336   default:
337      bad_subop(tid, layout, arrghs, status, flags,
338                "__HYPERVISOR_grant_table_op", ARG1);
339      break;
340   }
341}
342
343PRE(sysctl) {
344   struct xen_sysctl *sysctl = (struct xen_sysctl *)(unsigned int)ARG1;
345
346   PRINT("__HYPERVISOR_sysctl ( %d )", sysctl->cmd);
347
348   /*
349    * Common part of xen_sysctl:
350    *    uint32_t cmd;
351    *    uint32_t interface_version;
352    */
353   PRE_MEM_READ("__HYPERVISOR_sysctl", ARG1,
354                sizeof(uint32_t) + sizeof(uint32_t));
355
356   if (!sysctl || sysctl->interface_version != XEN_SYSCTL_INTERFACE_VERSION)
357      /* BUG ? */
358      return;
359
360#define __PRE_XEN_SYSCTL_READ(_sysctl, _union, _field)  \
361      PRE_MEM_READ("XEN_SYSCTL_" # _sysctl,             \
362                   (Addr)&sysctl->u._union._field,      \
363                   sizeof(sysctl->u._union._field))
364#define PRE_XEN_SYSCTL_READ(_sysctl, _field) \
365      __PRE_XEN_SYSCTL_READ(_sysctl, _sysctl, _field)
366
367   switch (sysctl->cmd) {
368   case XEN_SYSCTL_getdomaininfolist:
369      PRE_XEN_SYSCTL_READ(getdomaininfolist, first_domain);
370      PRE_XEN_SYSCTL_READ(getdomaininfolist, max_domains);
371      PRE_XEN_SYSCTL_READ(getdomaininfolist, buffer);
372      break;
373
374   case XEN_SYSCTL_cpupool_op:
375      PRE_XEN_SYSCTL_READ(cpupool_op, op);
376
377      switch(sysctl->u.cpupool_op.op) {
378      case XEN_SYSCTL_CPUPOOL_OP_CREATE:
379      case XEN_SYSCTL_CPUPOOL_OP_DESTROY:
380      case XEN_SYSCTL_CPUPOOL_OP_INFO:
381      case XEN_SYSCTL_CPUPOOL_OP_ADDCPU:
382      case XEN_SYSCTL_CPUPOOL_OP_RMCPU:
383      case XEN_SYSCTL_CPUPOOL_OP_MOVEDOMAIN:
384         PRE_XEN_SYSCTL_READ(cpupool_op, cpupool_id);
385      }
386
387      if (sysctl->u.cpupool_op.op == XEN_SYSCTL_CPUPOOL_OP_CREATE)
388         PRE_XEN_SYSCTL_READ(cpupool_op, sched_id);
389
390      if (sysctl->u.cpupool_op.op == XEN_SYSCTL_CPUPOOL_OP_MOVEDOMAIN)
391         PRE_XEN_SYSCTL_READ(cpupool_op, domid);
392
393      if (sysctl->u.cpupool_op.op == XEN_SYSCTL_CPUPOOL_OP_ADDCPU ||
394          sysctl->u.cpupool_op.op == XEN_SYSCTL_CPUPOOL_OP_RMCPU)
395         PRE_XEN_SYSCTL_READ(cpupool_op, cpu);
396
397      break;
398
399   case XEN_SYSCTL_physinfo:
400      /* No input params */
401      break;
402
403   case XEN_SYSCTL_topologyinfo:
404      PRE_XEN_SYSCTL_READ(topologyinfo, max_cpu_index);
405      PRE_XEN_SYSCTL_READ(topologyinfo, cpu_to_core);
406      PRE_XEN_SYSCTL_READ(topologyinfo, cpu_to_socket);
407      PRE_XEN_SYSCTL_READ(topologyinfo, cpu_to_node);
408      break;
409
410   case XEN_SYSCTL_numainfo:
411      PRE_XEN_SYSCTL_READ(numainfo, max_node_index);
412      PRE_XEN_SYSCTL_READ(numainfo, node_to_memsize);
413      PRE_XEN_SYSCTL_READ(numainfo, node_to_memfree);
414      PRE_XEN_SYSCTL_READ(numainfo, node_to_node_distance);
415      break;
416
417   default:
418      bad_subop(tid, layout, arrghs, status, flags,
419                "__HYPERVISOR_sysctl", sysctl->cmd);
420      break;
421   }
422#undef PRE_XEN_SYSCTL_READ
423#undef __PRE_XEN_SYSCTL_READ
424}
425
426PRE(domctl)
427{
428   struct xen_domctl *domctl = (struct xen_domctl *)(unsigned int)ARG1;
429
430   PRINT("__HYPERVISOR_domctl ( %d ) on dom%d", domctl->cmd, domctl->domain);
431
432   /*
433    * Common part of xen_domctl:
434    *    uint32_t cmd;
435    *    uint32_t interface_version;
436    *    domid_t  domain;
437    */
438   PRE_MEM_READ("__HYPERVISOR_domctl", ARG1,
439                sizeof(uint32_t) + sizeof(uint32_t) + sizeof(domid_t));
440
441   if (!domctl || domctl->interface_version != XEN_DOMCTL_INTERFACE_VERSION)
442      /* BUG ? */
443      return;
444
445#define __PRE_XEN_DOMCTL_READ(_domctl, _union, _field)  \
446      PRE_MEM_READ("XEN_DOMCTL_" # _domctl,             \
447                   (Addr)&domctl->u._union._field,      \
448                   sizeof(domctl->u._union._field))
449#define PRE_XEN_DOMCTL_READ(_domctl, _field) \
450      __PRE_XEN_DOMCTL_READ(_domctl, _domctl, _field)
451
452   switch (domctl->cmd) {
453   case XEN_DOMCTL_destroydomain:
454   case XEN_DOMCTL_pausedomain:
455   case XEN_DOMCTL_max_vcpus:
456   case XEN_DOMCTL_get_address_size:
457   case XEN_DOMCTL_gettscinfo:
458   case XEN_DOMCTL_getdomaininfo:
459   case XEN_DOMCTL_unpausedomain:
460      /* No input fields. */
461      break;
462
463   case XEN_DOMCTL_createdomain:
464      PRE_XEN_DOMCTL_READ(createdomain, ssidref);
465      PRE_XEN_DOMCTL_READ(createdomain, handle);
466      PRE_XEN_DOMCTL_READ(createdomain, flags);
467      break;
468
469   case XEN_DOMCTL_max_mem:
470      PRE_XEN_DOMCTL_READ(max_mem, max_memkb);
471      break;
472
473   case XEN_DOMCTL_set_address_size:
474      __PRE_XEN_DOMCTL_READ(set_address_size, address_size, size);
475      break;
476
477   case XEN_DOMCTL_settscinfo:
478      __PRE_XEN_DOMCTL_READ(settscinfo, tsc_info, info.tsc_mode);
479      __PRE_XEN_DOMCTL_READ(settscinfo, tsc_info, info.gtsc_khz);
480      __PRE_XEN_DOMCTL_READ(settscinfo, tsc_info, info.incarnation);
481      __PRE_XEN_DOMCTL_READ(settscinfo, tsc_info, info.elapsed_nsec);
482      break;
483
484   case XEN_DOMCTL_hypercall_init:
485      PRE_XEN_DOMCTL_READ(hypercall_init, gmfn);
486      break;
487
488   case XEN_DOMCTL_getvcpuinfo:
489      PRE_XEN_DOMCTL_READ(getvcpuinfo, vcpu);
490      break;
491
492   case XEN_DOMCTL_scheduler_op:
493      PRE_XEN_DOMCTL_READ(scheduler_op, sched_id);
494      PRE_XEN_DOMCTL_READ(scheduler_op, cmd);
495      if ( domctl->u.scheduler_op.cmd == XEN_DOMCTL_SCHEDOP_putinfo ) {
496         switch(domctl->u.scheduler_op.sched_id) {
497         case XEN_SCHEDULER_SEDF:
498            PRE_XEN_DOMCTL_READ(scheduler_op, u.sedf.period);
499            PRE_XEN_DOMCTL_READ(scheduler_op, u.sedf.slice);
500            PRE_XEN_DOMCTL_READ(scheduler_op, u.sedf.latency);
501            PRE_XEN_DOMCTL_READ(scheduler_op, u.sedf.extratime);
502            PRE_XEN_DOMCTL_READ(scheduler_op, u.sedf.weight);
503            break;
504         case XEN_SCHEDULER_CREDIT:
505            PRE_XEN_DOMCTL_READ(scheduler_op, u.credit.weight);
506            PRE_XEN_DOMCTL_READ(scheduler_op, u.credit.cap);
507            break;
508         case XEN_SCHEDULER_CREDIT2:
509            PRE_XEN_DOMCTL_READ(scheduler_op, u.credit2.weight);
510            break;
511         case XEN_SCHEDULER_ARINC653:
512            break;
513         }
514      }
515      break;
516
517   case XEN_DOMCTL_getvcpuaffinity:
518      __PRE_XEN_DOMCTL_READ(getvcpuaffinity, vcpuaffinity, vcpu);
519      break;
520
521   case XEN_DOMCTL_setvcpuaffinity:
522      __PRE_XEN_DOMCTL_READ(setvcpuaffinity, vcpuaffinity, vcpu);
523      PRE_MEM_READ("XEN_DOMCTL_setvcpuaffinity",
524                   (Addr)domctl->u.vcpuaffinity.cpumap.bitmap.p,
525                   domctl->u.vcpuaffinity.cpumap.nr_cpus / 8);
526      break;
527
528   case XEN_DOMCTL_getvcpucontext:
529      __PRE_XEN_DOMCTL_READ(getvcpucontext, vcpucontext, vcpu);
530      break;
531
532   case XEN_DOMCTL_setvcpucontext:
533      __PRE_XEN_DOMCTL_READ(setvcpucontext, vcpucontext, vcpu);
534      __PRE_XEN_DOMCTL_READ(setvcpucontext, vcpucontext, ctxt.p);
535      break;
536
537   case XEN_DOMCTL_set_cpuid:
538      PRE_MEM_READ("XEN_DOMCTL_set_cpuid",
539                   (Addr)&domctl->u.cpuid, sizeof(domctl->u.cpuid));
540      break;
541
542   case XEN_DOMCTL_getvcpuextstate:
543      __PRE_XEN_DOMCTL_READ(getvcpuextstate, vcpuextstate, vcpu);
544      __PRE_XEN_DOMCTL_READ(getvcpuextstate, vcpuextstate, xfeature_mask);
545      __PRE_XEN_DOMCTL_READ(getvcpuextstate, vcpuextstate, size);
546      __PRE_XEN_DOMCTL_READ(getvcpuextstate, vcpuextstate, buffer);
547      break;
548
549   default:
550      bad_subop(tid, layout, arrghs, status, flags,
551                "__HYPERVISOR_domctl", domctl->cmd);
552      break;
553   }
554#undef PRE_XEN_DOMCTL_READ
555#undef __PRE_XEN_DOMCTL_READ
556}
557
558PRE(hvm_op)
559{
560   unsigned long op = ARG1;
561   void *arg = (void *)(unsigned long)ARG2;
562
563   PRINT("__HYPERVISOR_hvm_op ( %ld, %p )", op, arg);
564
565#define __PRE_XEN_HVMOP_READ(_hvm_op, _type, _field)    \
566   PRE_MEM_READ("XEN_HVMOP_" # _hvm_op,                 \
567                (Addr)&((_type*)arg)->_field,           \
568                sizeof(((_type*)arg)->_field))
569#define PRE_XEN_HVMOP_READ(_hvm_op, _field)                             \
570   __PRE_XEN_HVMOP_READ(_hvm_op, "xen_hvm_" # _hvm_op "_t", _field)
571
572   switch (op) {
573   case HVMOP_set_param:
574      __PRE_XEN_HVMOP_READ(set_param, xen_hvm_param_t, domid);
575      __PRE_XEN_HVMOP_READ(set_param, xen_hvm_param_t, index);
576      __PRE_XEN_HVMOP_READ(set_param, xen_hvm_param_t, value);
577      break;
578
579   case HVMOP_get_param:
580      __PRE_XEN_HVMOP_READ(get_param, xen_hvm_param_t, domid);
581      __PRE_XEN_HVMOP_READ(get_param, xen_hvm_param_t, index);
582      break;
583
584   default:
585      bad_subop(tid, layout, arrghs, status, flags,
586                "__HYPERVISOR_hvm_op", op);
587      break;
588   }
589#undef __PRE_XEN_HVMOP_READ
590#undef PRE_XEN_HVMOP_READ
591}
592
593POST(memory_op)
594{
595   switch (ARG1) {
596   case XENMEM_set_memory_map:
597   case XENMEM_decrease_reservation:
598      /* No outputs */
599      break;
600   case XENMEM_increase_reservation:
601   case XENMEM_populate_physmap: {
602      struct xen_memory_reservation *memory_reservation =
603         (struct xen_memory_reservation *)(unsigned int)ARG2;
604
605      POST_MEM_WRITE((Addr)memory_reservation->extent_start.p,
606                     sizeof(xen_pfn_t) * memory_reservation->nr_extents);
607      break;
608   }
609   }
610}
611
612POST(mmuext_op)
613{
614   unsigned int *pdone = (void *)(unsigned int)ARG3;
615   /* simplistic */
616   POST_MEM_WRITE((Addr)pdone, sizeof(*pdone));
617}
618
619static void post_evtchn_op(ThreadId tid, __vki_u32 cmd, void *arg, int compat)
620{
621   switch (cmd) {
622   case EVTCHNOP_alloc_unbound: {
623      struct evtchn_alloc_unbound *alloc_unbound = arg;
624      POST_MEM_WRITE((Addr)&alloc_unbound->port, sizeof(alloc_unbound->port));
625      break;
626   }
627   }
628}
629
630POST(evtchn_op)
631{
632   post_evtchn_op(tid, ARG1, (void *)(unsigned int)ARG2, 0);
633}
634
635POST(evtchn_op_compat)
636{
637   struct evtchn_op *evtchn = (struct evtchn_op *)(unsigned int)ARG1;
638   post_evtchn_op(tid, evtchn->cmd, &evtchn->u, 1);
639}
640
641POST(xen_version)
642{
643   switch (ARG1) {
644   case XENVER_version:
645      /* No outputs */
646      break;
647   case XENVER_extraversion:
648      POST_MEM_WRITE((Addr)ARG2, sizeof(xen_extraversion_t));
649      break;
650   case XENVER_compile_info:
651      POST_MEM_WRITE((Addr)ARG2, sizeof(xen_compile_info_t));
652      break;
653   case XENVER_capabilities:
654      POST_MEM_WRITE((Addr)ARG2, sizeof(xen_capabilities_info_t));
655      break;
656   case XENVER_changeset:
657      POST_MEM_WRITE((Addr)ARG2, sizeof(xen_changeset_info_t));
658      break;
659   case XENVER_platform_parameters:
660      POST_MEM_WRITE((Addr)ARG2, sizeof(xen_platform_parameters_t));
661      break;
662   case XENVER_get_features:
663      POST_MEM_WRITE((Addr)ARG2, sizeof(xen_feature_info_t));
664      break;
665   case XENVER_pagesize:
666      /* No outputs */
667      break;
668   case XENVER_guest_handle:
669      POST_MEM_WRITE((Addr)ARG2, sizeof(xen_domain_handle_t));
670      break;
671   case XENVER_commandline:
672      POST_MEM_WRITE((Addr)ARG2, sizeof(xen_commandline_t));
673      break;
674   }
675}
676
677POST(grant_table_op)
678{
679   switch (ARG1) {
680   case GNTTABOP_setup_table: {
681      struct gnttab_setup_table *gst = (void *)(uintptr_t)ARG2;
682      PRE_MEM_WRITE("GNTTABOP_setup_table",
683                    (Addr)&gst->status, sizeof(gst->status));
684      PRE_MEM_WRITE("GNTTABOP_setup_table",
685                    (Addr)gst->frame_list.p,
686                    sizeof(*gst->frame_list.p) & gst->nr_frames);
687      break;
688   }
689   }
690}
691
692POST(sysctl)
693{
694   struct xen_sysctl *sysctl = (struct xen_sysctl *)(unsigned int)ARG1;
695
696   if (!sysctl || sysctl->interface_version != XEN_SYSCTL_INTERFACE_VERSION)
697      return;
698
699#define __POST_XEN_SYSCTL_WRITE(_sysctl, _union, _field)        \
700      POST_MEM_WRITE((Addr)&sysctl->u._union._field,            \
701                     sizeof(sysctl->u._union._field))
702#define POST_XEN_SYSCTL_WRITE(_sysctl, _field) \
703      __POST_XEN_SYSCTL_WRITE(_sysctl, _sysctl, _field)
704
705   switch (sysctl->cmd) {
706   case XEN_SYSCTL_getdomaininfolist:
707      POST_XEN_SYSCTL_WRITE(getdomaininfolist, num_domains);
708      POST_MEM_WRITE((Addr)sysctl->u.getdomaininfolist.buffer.p,
709                     sizeof(xen_domctl_getdomaininfo_t)
710                     * sysctl->u.getdomaininfolist.num_domains);
711      break;
712
713   case XEN_SYSCTL_cpupool_op:
714      if (sysctl->u.cpupool_op.op == XEN_SYSCTL_CPUPOOL_OP_CREATE ||
715          sysctl->u.cpupool_op.op == XEN_SYSCTL_CPUPOOL_OP_INFO)
716         POST_XEN_SYSCTL_WRITE(cpupool_op, cpupool_id);
717      if (sysctl->u.cpupool_op.op == XEN_SYSCTL_CPUPOOL_OP_INFO) {
718         POST_XEN_SYSCTL_WRITE(cpupool_op, sched_id);
719         POST_XEN_SYSCTL_WRITE(cpupool_op, n_dom);
720      }
721      if (sysctl->u.cpupool_op.op == XEN_SYSCTL_CPUPOOL_OP_INFO ||
722          sysctl->u.cpupool_op.op == XEN_SYSCTL_CPUPOOL_OP_FREEINFO)
723         POST_XEN_SYSCTL_WRITE(cpupool_op, cpumap);
724      break;
725
726   case XEN_SYSCTL_physinfo:
727      POST_XEN_SYSCTL_WRITE(physinfo, threads_per_core);
728      POST_XEN_SYSCTL_WRITE(physinfo, cores_per_socket);
729      POST_XEN_SYSCTL_WRITE(physinfo, nr_cpus);
730      POST_XEN_SYSCTL_WRITE(physinfo, max_cpu_id);
731      POST_XEN_SYSCTL_WRITE(physinfo, nr_nodes);
732      POST_XEN_SYSCTL_WRITE(physinfo, max_node_id);
733      POST_XEN_SYSCTL_WRITE(physinfo, cpu_khz);
734      POST_XEN_SYSCTL_WRITE(physinfo, total_pages);
735      POST_XEN_SYSCTL_WRITE(physinfo, free_pages);
736      POST_XEN_SYSCTL_WRITE(physinfo, scrub_pages);
737      POST_XEN_SYSCTL_WRITE(physinfo, hw_cap[8]);
738      POST_XEN_SYSCTL_WRITE(physinfo, capabilities);
739      break;
740
741   case XEN_SYSCTL_topologyinfo:
742      POST_XEN_SYSCTL_WRITE(topologyinfo, max_cpu_index);
743      POST_MEM_WRITE((Addr)sysctl->u.topologyinfo.cpu_to_core.p,
744                     sizeof(uint32_t) * sysctl->u.topologyinfo.max_cpu_index);
745      POST_MEM_WRITE((Addr)sysctl->u.topologyinfo.cpu_to_socket.p,
746                     sizeof(uint32_t) * sysctl->u.topologyinfo.max_cpu_index);
747      POST_MEM_WRITE((Addr)sysctl->u.topologyinfo.cpu_to_node.p,
748                     sizeof(uint32_t) * sysctl->u.topologyinfo.max_cpu_index);
749      break;
750
751   case XEN_SYSCTL_numainfo:
752      POST_XEN_SYSCTL_WRITE(numainfo, max_node_index);
753      POST_MEM_WRITE((Addr)sysctl->u.numainfo.node_to_memsize.p,
754                     sizeof(uint64_t) * sysctl->u.numainfo.max_node_index);
755      POST_MEM_WRITE((Addr)sysctl->u.numainfo.node_to_memfree.p,
756                     sizeof(uint64_t) * sysctl->u.numainfo.max_node_index);
757      POST_MEM_WRITE((Addr)sysctl->u.numainfo.node_to_node_distance.p,
758                     sizeof(uint32_t) * sysctl->u.numainfo.max_node_index);
759   }
760#undef POST_XEN_SYSCTL_WRITE
761#undef __POST_XEN_SYSCTL_WRITE
762}
763
764POST(domctl){
765   struct xen_domctl *domctl = (struct xen_domctl *)(unsigned int)ARG1;
766
767   if (!domctl || domctl->interface_version != XEN_DOMCTL_INTERFACE_VERSION)
768      return;
769
770#define __POST_XEN_DOMCTL_WRITE(_domctl, _union, _field)        \
771   POST_MEM_WRITE((Addr)&domctl->u._union._field,               \
772                  sizeof(domctl->u._union._field));
773#define POST_XEN_DOMCTL_WRITE(_domctl, _field)          \
774   __POST_XEN_DOMCTL_WRITE(_domctl, _domctl, _field)
775
776   switch (domctl->cmd) {
777   case XEN_DOMCTL_createdomain:
778   case XEN_DOMCTL_destroydomain:
779   case XEN_DOMCTL_pausedomain:
780   case XEN_DOMCTL_max_mem:
781   case XEN_DOMCTL_set_address_size:
782   case XEN_DOMCTL_settscinfo:
783   case XEN_DOMCTL_hypercall_init:
784   case XEN_DOMCTL_setvcpuaffinity:
785   case XEN_DOMCTL_setvcpucontext:
786   case XEN_DOMCTL_set_cpuid:
787   case XEN_DOMCTL_unpausedomain:
788      /* No output fields */
789      break;
790
791   case XEN_DOMCTL_max_vcpus:
792      POST_XEN_DOMCTL_WRITE(max_vcpus, max);
793
794   case XEN_DOMCTL_get_address_size:
795      __POST_XEN_DOMCTL_WRITE(get_address_size, address_size, size);
796      break;
797
798   case XEN_DOMCTL_gettscinfo:
799      __POST_XEN_DOMCTL_WRITE(settscinfo, tsc_info, info.tsc_mode);
800      __POST_XEN_DOMCTL_WRITE(settscinfo, tsc_info, info.gtsc_khz);
801      __POST_XEN_DOMCTL_WRITE(settscinfo, tsc_info, info.incarnation);
802      __POST_XEN_DOMCTL_WRITE(settscinfo, tsc_info, info.elapsed_nsec);
803      break;
804
805   case XEN_DOMCTL_getvcpuinfo:
806      POST_XEN_DOMCTL_WRITE(getvcpuinfo, online);
807      POST_XEN_DOMCTL_WRITE(getvcpuinfo, blocked);
808      POST_XEN_DOMCTL_WRITE(getvcpuinfo, running);
809      POST_XEN_DOMCTL_WRITE(getvcpuinfo, cpu_time);
810      POST_XEN_DOMCTL_WRITE(getvcpuinfo, cpu);
811      break;
812
813   case XEN_DOMCTL_scheduler_op:
814      if ( domctl->u.scheduler_op.cmd == XEN_DOMCTL_SCHEDOP_getinfo ) {
815         switch(domctl->u.scheduler_op.sched_id) {
816         case XEN_SCHEDULER_SEDF:
817            POST_XEN_DOMCTL_WRITE(scheduler_op, u.sedf.period);
818            POST_XEN_DOMCTL_WRITE(scheduler_op, u.sedf.slice);
819            POST_XEN_DOMCTL_WRITE(scheduler_op, u.sedf.latency);
820            POST_XEN_DOMCTL_WRITE(scheduler_op, u.sedf.extratime);
821            POST_XEN_DOMCTL_WRITE(scheduler_op, u.sedf.weight);
822            break;
823         case XEN_SCHEDULER_CREDIT:
824            POST_XEN_DOMCTL_WRITE(scheduler_op, u.credit.weight);
825            POST_XEN_DOMCTL_WRITE(scheduler_op, u.credit.cap);
826            break;
827         case XEN_SCHEDULER_CREDIT2:
828            POST_XEN_DOMCTL_WRITE(scheduler_op, u.credit2.weight);
829            break;
830         case XEN_SCHEDULER_ARINC653:
831            break;
832         }
833      }
834      break;
835
836   case XEN_DOMCTL_getvcpuaffinity:
837      POST_MEM_WRITE((Addr)domctl->u.vcpuaffinity.cpumap.bitmap.p,
838                     domctl->u.vcpuaffinity.cpumap.nr_cpus / 8);
839      break;
840
841   case XEN_DOMCTL_getdomaininfo:
842      POST_XEN_DOMCTL_WRITE(getdomaininfo, domain);
843      POST_XEN_DOMCTL_WRITE(getdomaininfo, flags);
844      POST_XEN_DOMCTL_WRITE(getdomaininfo, tot_pages);
845      POST_XEN_DOMCTL_WRITE(getdomaininfo, max_pages);
846      POST_XEN_DOMCTL_WRITE(getdomaininfo, shr_pages);
847      POST_XEN_DOMCTL_WRITE(getdomaininfo, shared_info_frame);
848      POST_XEN_DOMCTL_WRITE(getdomaininfo, cpu_time);
849      POST_XEN_DOMCTL_WRITE(getdomaininfo, nr_online_vcpus);
850      POST_XEN_DOMCTL_WRITE(getdomaininfo, max_vcpu_id);
851      POST_XEN_DOMCTL_WRITE(getdomaininfo, ssidref);
852      POST_XEN_DOMCTL_WRITE(getdomaininfo, handle);
853      POST_XEN_DOMCTL_WRITE(getdomaininfo, cpupool);
854      break;
855
856   case XEN_DOMCTL_getvcpucontext:
857      __POST_XEN_DOMCTL_WRITE(getvcpucontext, vcpucontext, ctxt.p);
858      break;
859
860   case XEN_DOMCTL_getvcpuextstate:
861      __POST_XEN_DOMCTL_WRITE(getvcpuextstate, vcpuextstate, xfeature_mask);
862      __POST_XEN_DOMCTL_WRITE(getvcpuextstate, vcpuextstate, size);
863      POST_MEM_WRITE((Addr)domctl->u.vcpuextstate.buffer.p,
864                     domctl->u.vcpuextstate.size);
865      break;
866
867   }
868#undef POST_XEN_DOMCTL_WRITE
869#undef __POST_XEN_DOMCTL_WRITE
870}
871
872POST(hvm_op)
873{
874   unsigned long op = ARG1;
875   void *arg = (void *)(unsigned long)ARG2;
876
877#define __POST_XEN_HVMOP_WRITE(_hvm_op, _type, _field)  \
878      POST_MEM_WRITE((Addr)&((_type*)arg)->_field,      \
879                     sizeof(((_type*)arg)->_field))
880#define POST_XEN_HVMOP_WRITE(_hvm_op, _field) \
881      __PRE_XEN_HVMOP_READ(_hvm_op, "xen_hvm_" # _hvm_op "_t", _field)
882
883   switch (op) {
884   case HVMOP_set_param:
885      /* No output paramters */
886      break;
887
888   case HVMOP_get_param:
889      __POST_XEN_HVMOP_WRITE(get_param, xen_hvm_param_t, value);
890      break;
891   }
892#undef __POST_XEN_HVMOP_WRITE
893#undef POST_XEN_HVMOP_WRITE
894}
895
896typedef
897   struct {
898      SyscallTableEntry entry;
899      int nr_args;
900   }
901   XenHypercallTableEntry;
902
903#define HYPX_(const, name, nr_args) \
904   [const] = { { vgSysWrap_xen_##name##_before, NULL }, nr_args }
905#define HYPXY(const, name, nr_args)                     \
906   [const] = { { vgSysWrap_xen_##name##_before,         \
907                 vgSysWrap_xen_##name##_after },        \
908               nr_args }
909
910static XenHypercallTableEntry hypercall_table[] = {
911   //    __HYPERVISOR_set_trap_table                                  // 0
912   //    __HYPERVISOR_mmu_update                                      // 1
913   //    __HYPERVISOR_set_gdt                                         // 2
914   //    __HYPERVISOR_stack_switch                                    // 3
915   //    __HYPERVISOR_set_callbacks                                   // 4
916
917   //    __HYPERVISOR_fpu_taskswitch                                  // 5
918   //    __HYPERVISOR_sched_op_compat                                 // 6
919   //    __HYPERVISOR_platform_op                                     // 7
920   //    __HYPERVISOR_set_debugreg                                    // 8
921   //    __HYPERVISOR_get_debugreg                                    // 9
922
923   //    __HYPERVISOR_update_descriptor                               // 10
924   //                                                                 // 11
925   HYPXY(__HYPERVISOR_memory_op,               memory_op,         2), // 12
926   //    __HYPERVISOR_multicall                                       // 13
927   //    __HYPERVISOR_update_va_mapping                               // 14
928
929   //    __HYPERVISOR_set_timer_op                                    // 15
930   HYPXY(__HYPERVISOR_event_channel_op_compat, evtchn_op_compat,  1), // 16
931   HYPXY(__HYPERVISOR_xen_version,             xen_version,       2), // 17
932   //    __HYPERVISOR_console_io                                      // 18
933   //    __HYPERVISOR_physdev_op_compat                               // 19
934
935   HYPXY(__HYPERVISOR_grant_table_op,          grant_table_op,    3), // 20
936   //    __HYPERVISOR_vm_assist                                       // 21
937   //    __HYPERVISOR_update_va_mapping_otherdomain                   // 22
938   //    __HYPERVISOR_iret,                    iret                   // 23
939   //    __HYPERVISOR_vcpu_op,                 vcpu_op                // 24
940
941   //    __HYPERVISOR_set_segment_base                                // 25
942   HYPXY(__HYPERVISOR_mmuext_op,               mmuext_op,         2), // 26
943   //    __HYPERVISOR_xsm_op                                          // 27
944   //    __HYPERVISOR_nmi_op                                          // 28
945   //    __HYPERVISOR_sched_op                                        // 29
946
947   //    __HYPERVISOR_callback_op                                     // 30
948   //    __HYPERVISOR_xenoprof_op                                     // 31
949   HYPXY(__HYPERVISOR_event_channel_op,        evtchn_op,         2), // 32
950   //    __HYPERVISOR_physdev_op                                      // 33
951   HYPXY(__HYPERVISOR_hvm_op,                  hvm_op,            2), // 34
952
953   HYPXY(__HYPERVISOR_sysctl,                  sysctl,            1), // 35
954   HYPXY(__HYPERVISOR_domctl,                  domctl,            1), // 36
955   //    __HYPERVISOR_kexec_op                                        // 37
956   //    __HYPERVISOR_tmem_op                                         // 38
957};
958
959static void bad_before ( ThreadId              tid,
960                         SyscallArgLayout*     layout,
961                         /*MOD*/SyscallArgs*   args,
962                         /*OUT*/SyscallStatus* status,
963                         /*OUT*/UWord*         flags )
964{
965   VG_(dmsg)("WARNING: unhandled hypercall: %s\n",
966      VG_SYSNUM_STRING_EXTRA(args->sysno));
967   if (VG_(clo_verbosity) > 1) {
968      VG_(get_and_pp_StackTrace)(tid, VG_(clo_backtrace_size));
969   }
970   VG_(dmsg)("You may be able to write your own handler.\n");
971   VG_(dmsg)("Read the file README_MISSING_SYSCALL_OR_IOCTL.\n");
972   VG_(dmsg)("Nevertheless we consider this a bug.  Please report\n");
973   VG_(dmsg)("it at http://valgrind.org/support/bug_reports.html &\n");
974   VG_(dmsg)("http://wiki.xen.org/wiki/Reporting_Bugs_against_Xen.\n");
975
976   SET_STATUS_Failure(VKI_ENOSYS);
977}
978
979static XenHypercallTableEntry bad_hyper =
980{ { bad_before, NULL }, 0 };
981
982static XenHypercallTableEntry* ML_(get_xen_hypercall_entry) ( UInt sysno )
983{
984   XenHypercallTableEntry *ret = &bad_hyper;
985
986   const UInt hypercall_table_size
987      = sizeof(hypercall_table) / sizeof(hypercall_table[0]);
988
989   /* Is it in the contiguous initial section of the table? */
990   if (sysno < hypercall_table_size) {
991      XenHypercallTableEntry* ent = &hypercall_table[sysno];
992      if (ent->entry.before != NULL)
993         ret = ent;
994   }
995
996   /* Can't find a wrapper */
997   return ret;
998}
999
1000DEFN_PRE_TEMPLATE(xen, hypercall)
1001{
1002   XenHypercallTableEntry *ent = ML_(get_xen_hypercall_entry)(SYSNO);
1003
1004   /* Return number of arguments consumed */
1005   ARG8 = ent->nr_args;
1006
1007   vg_assert(ent);
1008   vg_assert(ent->entry.before);
1009   (ent->entry.before)( tid, layout, arrghs, status, flags );
1010
1011}
1012
1013DEFN_POST_TEMPLATE(xen, hypercall)
1014{
1015   XenHypercallTableEntry *ent = ML_(get_xen_hypercall_entry)(SYSNO);
1016
1017   /* Return number of arguments consumed */
1018   ARG8 = ent->nr_args;
1019
1020   vg_assert(ent);
1021   if (ent->entry.after)
1022      (ent->entry.after)( tid, arrghs, status );
1023}
1024