xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2.2 07/15] xen: generate hypercall interface related code
@ 2021-11-03 10:20 Juergen Gross
  2021-11-03 15:08 ` Jan Beulich
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Juergen Gross @ 2021-11-03 10:20 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, Andrew Cooper, George Dunlap, Ian Jackson,
	Jan Beulich, Julien Grall, Stefano Stabellini, Wei Liu

Instead of repeating similar data multiple times use a single source
file and a generator script for producing prototypes and call sequences
of the hypercalls.

As the script already knows the number of parameters used add generating
a macro for populating an array with the number of parameters per
hypercall.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
V2:
- split platform_op for doe and compat prefixes (Jan Beulich)
- add "addline:" directive
- add priorities to handlers (Jan Beulich)
V2.1:
- add missing "delete" statement in awk script
- optimize case of 2 hypercalls with same priority
V2.2:
- avoid asort() function (Michal Orzel)

Signed-off-by: Juergen Gross <jgross@suse.com>
---
 .gitignore                    |   1 +
 xen/Makefile                  |  10 ++
 xen/include/hypercall-defs.c  | 285 ++++++++++++++++++++++++++++++
 xen/scripts/gen_hypercall.awk | 323 ++++++++++++++++++++++++++++++++++
 4 files changed, 619 insertions(+)
 create mode 100644 xen/include/hypercall-defs.c
 create mode 100644 xen/scripts/gen_hypercall.awk

diff --git a/.gitignore b/.gitignore
index 9513506dd9..753a602e29 100644
--- a/.gitignore
+++ b/.gitignore
@@ -336,6 +336,7 @@ xen/include/public/public
 xen/include/xen/*.new
 xen/include/xen/acm_policy.h
 xen/include/xen/compile.h
+xen/include/xen/hypercall-defs.h
 xen/include/xen/lib/x86/cpuid-autogen.h
 xen/test/livepatch/config.h
 xen/test/livepatch/expect_config.h
diff --git a/xen/Makefile b/xen/Makefile
index a3189eb47c..dfdae47e74 100644
--- a/xen/Makefile
+++ b/xen/Makefile
@@ -383,6 +383,7 @@ _clean: delete-unfresh-files
 		-o -name "*.gcno" -o -name ".*.cmd" -o -name "lib.a" \) -exec rm -f {} \;
 	rm -f include/asm $(TARGET) $(TARGET).gz $(TARGET).efi $(TARGET).efi.map $(TARGET)-syms $(TARGET)-syms.map *~ core
 	rm -f asm-offsets.s include/asm-*/asm-offsets.h
+	rm -f include/xen/hypercall-defs.h include/hypercall-defs.i
 	rm -f .banner .allconfig.tmp
 
 .PHONY: _distclean
@@ -405,6 +406,7 @@ $(TARGET): delete-unfresh-files
 	$(MAKE) -f $(BASEDIR)/Rules.mk -C include
 	$(MAKE) -f $(BASEDIR)/Rules.mk -C arch/$(TARGET_ARCH) include
 	$(MAKE) -f $(BASEDIR)/Rules.mk include/asm-$(TARGET_ARCH)/asm-offsets.h
+	$(MAKE) -f $(BASEDIR)/Rules.mk include/xen/hypercall-defs.h
 	$(MAKE) -f $(BASEDIR)/Rules.mk -C arch/$(TARGET_ARCH) $@
 
 # drivers/char/console.o contains static banner/compile info. Blow it away.
@@ -466,6 +468,14 @@ include/asm-$(TARGET_ARCH)/asm-offsets.h: asm-offsets.s
 	  echo ""; \
 	  echo "#endif") <$< >$@
 
+quiet_cmd_genhyp = GEN     $@
+define cmd_genhyp
+    awk -f scripts/gen_hypercall.awk <$< >$@
+endef
+
+include/xen/hypercall-defs.h: include/hypercall-defs.i scripts/gen_hypercall.awk FORCE
+	$(call if_changed,genhyp)
+
 SUBDIRS = xsm arch/$(TARGET_ARCH) common drivers lib test
 define all_sources
     ( find include/asm-$(TARGET_ARCH) -name '*.h' -print; \
diff --git a/xen/include/hypercall-defs.c b/xen/include/hypercall-defs.c
new file mode 100644
index 0000000000..c31a4a302c
--- /dev/null
+++ b/xen/include/hypercall-defs.c
@@ -0,0 +1,285 @@
+/*
+ * Hypercall interface description:
+ * Used by scripts/gen_hypercall.awk to generate hypercall prototypes and call
+ * sequences.
+ *
+ * Syntax is like a prototype, but without return type and without the ";" at
+ * the end. Pointer types will be automatically converted to use the
+ * XEN_GUEST_HANDLE_PARAM() macro. Handlers with no parameters just use a
+ * definition like "fn()".
+ * Hypercall/function names are without the leading "__HYPERVISOR_"/"do_"
+ * strings.
+ *
+ * The return type of a class of prototypes using the same prefix is set via:
+ * rettype: <prefix> <type>
+ * Default return type is "long". A return type for a prefix can be set only
+ * once and it needs to be set before that prefix is being used via the
+ * "prefix:" directive.
+ *
+ * The prefix of the prototypes is set via a line:
+ * prefix: <prefix> ...
+ * Multiple prefixes are possible (restriction see below). Prefixes are without
+ * a trailing "_". The current prefix settings are active until a new "prefix:"
+ * line.
+ *
+ * Caller macros are suffixed with a selectable name via lines like:
+ * caller: <suffix>
+ * When a caller suffix is active, there is only one active prefix allowed.
+ *
+ * With a "defhandle:" line it is possible to add a DEFINE_XEN_GUEST_HANDLE()
+ * to the generated header:
+ * defhandle: <handle-type> [<type>]
+ * Without specifying <type> only a DEFINE_XEN_GUEST_HANDLE(<handle-type>)
+ * will be generated, otherwise it will be a
+ * __DEFINE_XEN_GUEST_HANDLE(<handle-type>, <type>) being generated. Note that
+ * the latter will include the related "const" handle "const_<handle-type>".
+ *
+ * In order to support using coding style compliant pointers in the
+ * prototypes it is possible to add translation entries to generate the correct
+ * handle types:
+ * handle: <handle-type> <type>
+ * This will result in the prototype translation from "<type> *" to
+ * "XEN_GUEST_HANDLE_PARAM(<handle-type>)".
+ *
+ * A verbatim line can be added via:
+ * addline: <line-contents>
+ * Its position is kept in regard of other "handle:" and "defhandle:" lines.
+ *
+ * The hypercall handler calling code will be generated from a final table in
+ * the source file, which is started via the line:
+ * table: <caller> <caller> ...
+ * with the <caller>s specifying the designated caller macro of each column of
+ * the table. Any column of a <caller> not having been set via a "caller:"
+ * line will be ignored.
+ * The first column of the table contains the hypercall/prototype, each
+ * <caller> column contains the prefix for the function to use for that caller.
+ * A function prefix can be annotated with a priority by adding ":<prio>" to it
+ * ("1" being the highest priority, higher numbers mean lower priority, no
+ * priority specified is the lowest priority). The generated code will try to
+ * achieve better performance for calling high priority handlers.
+ * A column not being supported by a <caller> is marked with "-". Lines with all
+ * entries being "-" after removal of inactive <caller> columns are ignored.
+ *
+ * This file is being preprocessed using $(CPP), so #ifdef CONFIG_* conditionals
+ * are possible.
+ */
+
+#ifdef CONFIG_HVM
+#define PREFIX_hvm hvm
+#else
+#define PREFIX_hvm
+#endif
+
+#ifdef CONFIG_COMPAT
+#define PREFIX_compat compat
+rettype: compat int
+#else
+#define PREFIX_compat
+#endif
+
+#ifdef CONFIG_ARM
+#define PREFIX_dep dep
+#else
+#define PREFIX_dep
+#endif
+
+handle: uint unsigned int
+handle: const_void const void
+handle: const_char const char
+
+#ifdef CONFIG_COMPAT
+defhandle: multicall_entry_compat_t
+#ifndef CONFIG_PV_SHIM_EXCLUSIVE
+addline: typedef struct compat_platform_op compat_platform_op_t;
+defhandle: compat_platform_op_t
+#endif
+#endif
+#ifdef CONFIG_PV32
+defhandle: trap_info_compat_t
+defhandle: physdev_op_compat_t
+#endif
+
+prefix: do PREFIX_hvm PREFIX_compat
+physdev_op(int cmd, void *arg)
+#if defined(CONFIG_GRANT_TABLE) || defined(CONFIG_PV_SHIM)
+grant_table_op(unsigned int cmd, void *uop, unsigned int count)
+#endif
+
+prefix: do PREFIX_hvm
+memory_op(unsigned long cmd, void *arg)
+
+prefix: do PREFIX_compat
+xen_version(int cmd, void *arg)
+vcpu_op(int cmd, unsigned int vcpuid, void *arg)
+sched_op(int cmd, void *arg)
+xsm_op(void *op)
+callback_op(int cmd, const void *arg)
+#ifdef CONFIG_ARGO
+argo_op(unsigned int cmd, void *arg1, void *arg2, unsigned long arg3, unsigned long arg4)
+#endif
+#ifdef CONFIG_KEXEC
+kexec_op(unsigned int op, void *uarg)
+#endif
+#ifdef CONFIG_PV
+iret()
+nmi_op(unsigned int cmd, void *arg)
+#ifdef CONFIG_XENOPROF
+xenoprof_op(int op, void *arg)
+#endif
+#endif /* CONFIG_PV */
+
+#ifdef CONFIG_COMPAT
+prefix: compat
+set_timer_op(uint32_t lo, int32_t hi)
+multicall(multicall_entry_compat_t *call_list, uint32_t nr_calls)
+memory_op(unsigned int cmd, void *arg)
+#ifdef CONFIG_IOREQ_SERVER
+dm_op(domid_t domid, unsigned int nr_bufs, void *bufs)
+#endif
+mmuext_op(void *arg, unsigned int count, uint *pdone, unsigned int foreigndom)
+#ifdef CONFIG_PV32
+set_trap_table(trap_info_compat_t *traps)
+set_gdt(unsigned int *frame_list, unsigned int entries)
+set_callbacks(unsigned long event_selector, unsigned long event_address, unsigned long failsafe_selector, unsigned long failsafe_address)
+update_descriptor(uint32_t pa_lo, uint32_t pa_hi, uint32_t desc_lo, uint32_t desc_hi)
+update_va_mapping(unsigned int va, uint32_t lo, uint32_t hi, unsigned int flags)
+physdev_op_compat(physdev_op_compat_t *uop)
+update_va_mapping_otherdomain(unsigned int va, uint32_t lo, uint32_t hi, unsigned int flags, domid_t domid)
+#endif
+#ifndef CONFIG_PV_SHIM_EXCLUSIVE
+platform_op(compat_platform_op_t *u_xenpf_op)
+#endif
+#endif /* CONFIG_COMPAT */
+
+#if defined(CONFIG_PV) || defined(CONFIG_ARM)
+prefix: do PREFIX_dep
+event_channel_op_compat(evtchn_op_t *uop)
+physdev_op_compat(physdev_op_t *uop)
+/* Legacy hypercall (as of 0x00030101). */
+sched_op_compat(int cmd, unsigned long arg)
+#endif
+
+prefix: do
+set_timer_op(s_time_t timeout)
+console_io(unsigned int cmd, unsigned int count, char *buffer)
+vm_assist(unsigned int cmd, unsigned int type)
+event_channel_op(int cmd, void *arg)
+mmuext_op(mmuext_op_t *uops, unsigned int count, unsigned int *pdone, unsigned int foreigndom)
+multicall(multicall_entry_t *call_list, unsigned int nr_calls)
+#ifdef CONFIG_PV
+mmu_update(mmu_update_t *ureqs, unsigned int count, unsigned int *pdone, unsigned int foreigndom)
+stack_switch(unsigned long ss, unsigned long esp)
+fpu_taskswitch(int set)
+set_debugreg(int reg, unsigned long value)
+get_debugreg(int reg)
+set_segment_base(unsigned int which, unsigned long base)
+mca(xen_mc_t *u_xen_mc)
+set_trap_table(const_trap_info_t *traps)
+set_gdt(xen_ulong_t *frame_list, unsigned int entries)
+set_callbacks(unsigned long event_address, unsigned long failsafe_address, unsigned long syscall_address)
+update_descriptor(uint64_t gaddr, seg_desc_t desc)
+update_va_mapping(unsigned long va, uint64_t val64, unsigned long flags)
+update_va_mapping_otherdomain(unsigned long va, uint64_t val64, unsigned long flags, domid_t domid)
+#endif
+#ifdef CONFIG_IOREQ_SERVER
+dm_op(domid_t domid, unsigned int nr_bufs, xen_dm_op_buf_t *bufs)
+#endif
+#ifndef CONFIG_PV_SHIM_EXCLUSIVE
+sysctl(xen_sysctl_t *u_sysctl)
+domctl(xen_domctl_t *u_domctl)
+paging_domctl_cont(xen_domctl_t *u_domctl)
+platform_op(xen_platform_op_t *u_xenpf_op)
+#endif
+#ifdef CONFIG_HVM
+hvm_op(unsigned long op, void *arg)
+#endif
+#ifdef CONFIG_HYPFS
+hypfs_op(unsigned int cmd, const char *arg1, unsigned long arg2, void *arg3, unsigned long arg4)
+#endif
+#ifdef CONFIG_X86
+xenpmu_op(unsigned int op, xen_pmu_params_t *arg)
+#endif
+
+#ifdef CONFIG_PV
+caller: pv64
+#ifdef CONFIG_PV32
+caller: pv32
+#endif
+#endif
+#if defined(CONFIG_HVM) && defined(CONFIG_X86)
+caller: hvm64
+#ifdef CONFIG_COMPAT
+caller: hvm32
+#endif
+#endif
+#ifdef CONFIG_ARM
+caller: arm
+#endif
+
+table:                             pv32     pv64     hvm32    hvm64    arm
+set_trap_table                     compat   do       -        -        -
+mmu_update                         do:1     do:1     -        -        -
+set_gdt                            compat   do       -        -        -
+stack_switch                       do:2     do:2     -        -        -
+set_callbacks                      compat   do       -        -        -
+fpu_taskswitch                     do       do       -        -        -
+sched_op_compat                    do       do       -        -        dep
+#ifndef CONFIG_PV_SHIM_EXCLUSIVE
+platform_op                        compat   do       compat   do       do
+#endif
+set_debugreg                       do       do       -        -        -
+get_debugreg                       do       do       -        -        -
+update_descriptor                  compat   do       -        -        -
+memory_op                          compat   do       hvm      hvm      do
+multicall                          compat:2 do:2     compat   do       do
+update_va_mapping                  compat   do       -        -        -
+set_timer_op                       compat   do       compat   do       -
+event_channel_op_compat            do       do       -        -        dep
+xen_version                        compat   do       compat   do       do
+console_io                         do       do       do       do       do
+physdev_op_compat                  compat   do       -        -        dep
+#if defined(CONFIG_GRANT_TABLE) || defined(CONFIG_PV_SHIM)
+grant_table_op                     compat   do       hvm      hvm      do
+#endif
+vm_assist                          do       do       do       do       do
+update_va_mapping_otherdomain      compat   do       -        -        -
+iret                               compat:1 do:1     -        -        -
+vcpu_op                            compat   do       compat:1 do:1     do
+set_segment_base                   do:2     do:2     -        -        -
+#ifdef CONFIG_PV
+mmuext_op                          compat:2 do:2     compat   do       -
+#endif
+xsm_op                             compat   do       compat   do       do
+nmi_op                             compat   do       -        -        -
+sched_op                           compat   do       compat   do       do
+callback_op                        compat   do       -        -        -
+#ifdef CONFIG_XENOPROF
+xenoprof_op                        compat   do       -        -        -
+#endif
+event_channel_op                   do       do       do:1     do:1     do
+physdev_op                         compat   do       hvm      hvm      do
+#ifdef CONFIG_HVM
+hvm_op                             do       do       do       do       do
+#endif
+#ifndef CONFIG_PV_SHIM_EXCLUSIVE
+sysctl                             do       do       do       do       do
+domctl                             do       do       do       do       do
+#endif
+#ifdef CONFIG_KEXEC
+kexec_op                           compat   do       -        -        -
+#endif
+tmem_op                            -        -        -        -        -
+#ifdef CONFIG_ARGO
+argo_op                            compat   do       compat   do       do
+#endif
+xenpmu_op                          do       do       do       do       -
+#ifdef CONFIG_IOREQ_SERVER
+dm_op                              compat   do       compat   do       do
+#endif
+#ifdef CONFIG_HYPFS
+hypfs_op                           do       do       do       do       do
+#endif
+mca                                do       do       -        -        -
+#ifndef CONFIG_PV_SHIM_EXCLUSIVE
+paging_domctl_cont                 do       do       do       do       -
+#endif
diff --git a/xen/scripts/gen_hypercall.awk b/xen/scripts/gen_hypercall.awk
new file mode 100644
index 0000000000..1484217201
--- /dev/null
+++ b/xen/scripts/gen_hypercall.awk
@@ -0,0 +1,323 @@
+# awk script to generate hypercall handler prototypes and a macro for doing
+# the calls of the handlers inside a switch() statement.
+
+BEGIN {
+    printf("/* Generated file, do not edit! */\n\n");
+    e = 0;
+    n = 0;
+    p = 0;
+    nc = 0;
+}
+
+# Issue error to stderr
+function do_err(msg) {
+    print "Error: "msg": "$0 >"/dev/stderr";
+    exit 1;
+}
+
+# Generate handler call
+function do_call(f, p,    i) {
+    printf("            ret = %s_%s(", pre[f, p], fn[f]);
+    for (i = 1; i <= n_args[f]; i++) {
+        if (i > 1)
+            printf(", ");
+        if (ptr[f, i])
+            printf("(XEN_GUEST_HANDLE_PARAM(%s)){ _p(a%d) }", typ[f, i], i);
+        else
+            printf("(%s)(a%d)", typ[f, i], i);
+    }
+    printf("); \\\n");
+}
+
+# Generate case statement for call
+function do_case(f, p) {
+    printf("        case __HYPERVISOR_%s: \\\n", fn[f]);
+    do_call(f, p);
+    printf("            break; \\\n");
+}
+
+# Generate switch statement for calling handlers
+function do_switch(ca, p,    i) {
+    printf("        switch ( num ) \\\n");
+    printf("        { \\\n");
+    for (i = 1; i <= nc; i++)
+        if (call[i] == ca && call_prio[i] == p)
+            do_case(call_fn[i], call_p[i]);
+    printf("        default: \\\n");
+    printf("            ret = -ENOSYS; \\\n");
+    printf("            break; \\\n");
+    printf("        } \\\n");
+}
+
+function rest_of_line(par,    i, val) {
+    val = $(par);
+    for (i = par + 1; i <= NF; i++)
+        val = val " " $(i);
+    return val;
+}
+
+# Handle comments (multi- and single line)
+$1 == "/*" {
+    comment = 1;
+}
+comment == 1 {
+    if ($(NF) == "*/") comment = 0;
+    next;
+}
+
+# Skip preprocessing artefacts
+$1 == "extern" {
+    next;
+}
+/^#/ {
+    next;
+}
+
+# Drop empty lines
+NF == 0 {
+    next;
+}
+
+# Handle "handle:" line
+$1 == "handle:" {
+    if (NF < 3)
+        do_err("\"handle:\" requires at least two parameters");
+    val = rest_of_line(3);
+    xlate[val] = $2;
+    next;
+}
+
+# Handle "defhandle:" line
+$1 == "defhandle:" {
+    if (NF < 2)
+        do_err("\"defhandle:\" requires at least one parameter");
+    e++;
+    if (NF == 2) {
+        emit[e] = sprintf("DEFINE_XEN_GUEST_HANDLE(%s);", $2);
+    } else {
+        val = rest_of_line(3);
+        emit[e] = sprintf("__DEFINE_XEN_GUEST_HANDLE(%s, %s);", $2, val);
+        xlate[val] = $2;
+    }
+    next;
+}
+
+# Handle "addline:" line
+$1 == "addline:" {
+    if (NF < 2)
+        do_err("\"addline:\" requires at least one parameter");
+    e++;
+    emit[e] = rest_of_line(2);
+    next;
+}
+
+# Handle "rettype:" line
+$1 == "rettype:" {
+    if (NF < 3)
+        do_err("\"rettype:\" requires at least two parameters");
+    if ($2 in rettype)
+        do_err("rettype can be set only once for each prefix");
+    rettype[$2] = rest_of_line(3);
+    next;
+}
+
+# Handle "caller:" line
+$1 == "caller:" {
+    caller[$2] = 1;
+    next;
+}
+
+# Handle "prefix:" line
+$1 == "prefix:" {
+    p = NF - 1;
+    for (i = 2; i <= NF; i++) {
+        prefix[i - 1] = $(i);
+        if (!(prefix[i - 1] in rettype))
+            rettype[prefix[i - 1]] = "long";
+    }
+    next;
+}
+
+# Handle "table:" line
+$1 == "table:" {
+    table = 1;
+    for (i = 2; i <= NF; i++)
+        col[i - 1] = $(i);
+    n_cols = NF - 1;
+    next;
+}
+
+# Handle table definition line
+table == 1 {
+    if (NF != n_cols + 1)
+        do_err("Table definition line has wrong number of fields");
+    for (c = 1; c <= n_cols; c++) {
+        if (caller[col[c]] != 1)
+            continue;
+        if ($(c + 1) == "-")
+            continue;
+        pref = $(c + 1);
+        idx = index(pref, ":");
+        if (idx == 0)
+            prio = 100;
+        else {
+            prio = substr(pref, idx + 1) + 0;
+            pref = substr(pref, 1, idx - 1);
+            if (prio >= 100 || prio < 1)
+                do_err("Priority must be in the range 1..99");
+        }
+        fnd = 0;
+        for (i = 1; i <= n; i++) {
+            if (fn[i] != $1)
+                continue;
+            for (j = 1; j <= n_pre[i]; j++) {
+                if (pre[i, j] == pref) {
+                    prios[col[c], prio]++;
+                    if (prios[col[c], prio] == 1) {
+                        n_prios[col[c]]++;
+                        prio_list[col[c], n_prios[col[c]]] = prio;
+                        prio_mask[col[c], prio] = "(1ULL << __HYPERVISOR_"$1")";
+                    } else
+                        prio_mask[col[c], prio] = prio_mask[col[c], prio] " | (1ULL << __HYPERVISOR_"$1")";
+                    nc++;
+                    call[nc] = col[c];
+                    call_fn[nc] = i;
+                    call_p[nc] = j;
+                    call_prio[nc] = prio;
+                    fnd = 1;
+                }
+            }
+        }
+        if (fnd == 0)
+            do_err("No prototype for prefix/hypercall combination");
+    }
+    next;
+}
+
+# Prototype line
+{
+    bro = index($0, "(");
+    brc = index($0, ")");
+    if (bro < 2 || brc < bro)
+        do_err("No valid prototype line");
+    n++;
+    fn[n] = substr($0, 1, bro - 1);
+    n_pre[n] = p;
+    for (i = 1; i <= p; i++)
+        pre[n, i] = prefix[i];
+    args = substr($0, bro + 1, brc - bro - 1);
+    n_args[n] = split(args, a, ",");
+    if (n_args[n] > 5)
+        do_err("Too many parameters");
+    for (i = 1; i <= n_args[n]; i++) {
+        sub("^ *", "", a[i]);         # Remove leading white space
+        sub(" +", " ", a[i]);         # Replace multiple spaces with single ones
+        sub(" *$", "", a[i]);         # Remove trailing white space
+        ptr[n, i] = index(a[i], "*"); # Is it a pointer type?
+        sub("[*]", "", a[i]);         # Remove "*"
+        if (index(a[i], " ") == 0)
+            do_err("Parameter with no type or no name");
+        typ[n, i] = a[i];
+        sub(" [^ ]+$", "", typ[n, i]);    # Remove parameter name
+        if (ptr[n, i] && (typ[n, i] in xlate))
+            typ[n, i] = xlate[typ[n, i]];
+        arg[n, i] = a[i];
+        sub("^([^ ]+ )+", "", arg[n, i]); # Remove parameter type
+    }
+}
+
+# Generate the output
+END {
+    # Verbatim generated lines
+    for (i = 1; i <= e; i++)
+        printf("%s\n", emit[i]);
+    printf("\n");
+    # Generate prototypes
+    for (i = 1; i <= n; i++) {
+        for (p = 1; p <= n_pre[i]; p++) {
+            printf("%s %s_%s(", rettype[pre[i, p]], pre[i, p], fn[i]);
+            if (n_args[i] == 0)
+                printf("void");
+            else
+                for (j = 1; j <= n_args[i]; j++) {
+                    if (j > 1)
+                        printf(", ");
+                    if (ptr[i, j])
+                        printf("XEN_GUEST_HANDLE_PARAM(%s)", typ[i, j]);
+                    else
+                        printf("%s", typ[i, j]);
+                    printf(" %s", arg[i, j]);
+                }
+            printf(");\n");
+        }
+    }
+    # Generate call sequences and args array contents
+    for (ca in caller) {
+        if (caller[ca] != 1)
+            continue;
+        need_mask = 0;
+        for (pl = 1; pl <= n_prios[ca]; pl++) {
+            for (pll = pl; pll > 1; pll--) {
+                if (prio_list[ca, pl] > p_list[pll - 1])
+                    break;
+                else
+                    p_list[pll] = p_list[pll - 1];
+            }
+            p_list[pll] = prio_list[ca, pl];
+            # If any prio but the default one has more than 1 entry we need "mask"
+            if (p_list[pll] != 100 && prios[ca, p_list[pll]] > 1)
+                need_mask = 1;
+        }
+        printf("\n");
+        printf("#define call_handlers_%s(num, ret, a1, a2, a3, a4, a5) \\\n", ca);
+        printf("{ \\\n");
+        if (need_mask)
+            printf("    uint64_t mask = 1ULL << num; \\\n");
+        printf("    ");
+        for (pl = 1; pl <= n_prios[ca]; pl++) {
+            if (prios[ca, p_list[pl]] > 1) {
+                if (pl < n_prios[ca]) {
+                    printf("if ( likely(mask & (%s)) ) \\\n", prio_mask[ca, p_list[pl]]);
+                    printf("    { \\\n");
+                }
+                if (prios[ca, p_list[pl]] == 2) {
+                    fnd = 0;
+                    for (i = 1; i <= nc; i++)
+                        if (call[i] == ca && call_prio[i] == p_list[pl]) {
+                            fnd++;
+                            if (fnd == 1)
+                                printf("        if ( num == __HYPERVISOR_%s ) \\\n", fn[call_fn[i]]);
+                            else
+                                printf("        else \\\n");
+                            do_call(call_fn[i], call_p[i]);
+                        }
+                } else {
+                    do_switch(ca, p_list[pl]);
+                }
+                if (pl < n_prios[ca])
+                    printf("    } \\\n");
+            } else {
+                for (i = 1; i <= nc; i++)
+                    if (call[i] == ca && call_prio[i] == p_list[pl]) {
+                        printf("if ( likely(num == __HYPERVISOR_%s) ) \\\n", fn[call_fn[i]]);
+                        do_call(call_fn[i], call_p[i]);
+                    }
+            }
+            if (pl < n_prios[ca] || prios[ca, p_list[pl]] <= 2)
+                printf("    else ");
+        }
+        if (prios[ca, p_list[n_prios[ca]]] <= 2) {
+            printf("\\\n");
+            printf("        ret = -ENOSYS; \\\n");
+        }
+        printf("}\n");
+        delete p_list;
+        printf("\n");
+        printf("#define hypercall_args_%s \\\n", ca);
+        printf("{ \\\n");
+        for (i = 1; i <= nc; i++)
+            if (call[i] == ca)
+                printf("[__HYPERVISOR_%s] = %d, \\\n", fn[call_fn[i]], n_args[call_fn[i]]);
+        printf("}\n");
+    }
+}
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH v2.2 07/15] xen: generate hypercall interface related code
  2021-11-03 10:20 [PATCH v2.2 07/15] xen: generate hypercall interface related code Juergen Gross
@ 2021-11-03 15:08 ` Jan Beulich
  2021-11-03 15:12   ` Juergen Gross
  2021-11-03 15:42 ` Jan Beulich
  2021-11-11 16:04 ` Anthony PERARD
  2 siblings, 1 reply; 7+ messages in thread
From: Jan Beulich @ 2021-11-03 15:08 UTC (permalink / raw)
  To: Juergen Gross
  Cc: Andrew Cooper, George Dunlap, Ian Jackson, Julien Grall,
	Stefano Stabellini, Wei Liu, xen-devel

On 03.11.2021 11:20, Juergen Gross wrote:
> +# Generate the output
> +END {
> +    # Verbatim generated lines
> +    for (i = 1; i <= e; i++)
> +        printf("%s\n", emit[i]);
> +    printf("\n");
> +    # Generate prototypes
> +    for (i = 1; i <= n; i++) {
> +        for (p = 1; p <= n_pre[i]; p++) {
> +            printf("%s %s_%s(", rettype[pre[i, p]], pre[i, p], fn[i]);
> +            if (n_args[i] == 0)
> +                printf("void");
> +            else
> +                for (j = 1; j <= n_args[i]; j++) {
> +                    if (j > 1)
> +                        printf(", ");
> +                    if (ptr[i, j])
> +                        printf("XEN_GUEST_HANDLE_PARAM(%s)", typ[i, j]);
> +                    else
> +                        printf("%s", typ[i, j]);
> +                    printf(" %s", arg[i, j]);
> +                }
> +            printf(");\n");
> +        }
> +    }
> +    # Generate call sequences and args array contents
> +    for (ca in caller) {
> +        if (caller[ca] != 1)
> +            continue;
> +        need_mask = 0;
> +        for (pl = 1; pl <= n_prios[ca]; pl++) {
> +            for (pll = pl; pll > 1; pll--) {
> +                if (prio_list[ca, pl] > p_list[pll - 1])
> +                    break;
> +                else
> +                    p_list[pll] = p_list[pll - 1];
> +            }
> +            p_list[pll] = prio_list[ca, pl];
> +            # If any prio but the default one has more than 1 entry we need "mask"
> +            if (p_list[pll] != 100 && prios[ca, p_list[pll]] > 1)
> +                need_mask = 1;
> +        }
> +        printf("\n");
> +        printf("#define call_handlers_%s(num, ret, a1, a2, a3, a4, a5) \\\n", ca);
> +        printf("{ \\\n");

In order to require a semicolon at the use site(s) of the macro I think
you want "({ \\\n" here. Everything else looks good to me so far, but
I'd really like to take a look at the generated output: Would you happen
to have available an instance, to supply in reply?

Thanks, Jan



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2.2 07/15] xen: generate hypercall interface related code
  2021-11-03 15:08 ` Jan Beulich
@ 2021-11-03 15:12   ` Juergen Gross
  0 siblings, 0 replies; 7+ messages in thread
From: Juergen Gross @ 2021-11-03 15:12 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Andrew Cooper, George Dunlap, Ian Jackson, Julien Grall,
	Stefano Stabellini, Wei Liu, xen-devel


[-- Attachment #1.1.1: Type: text/plain, Size: 2230 bytes --]

On 03.11.21 16:08, Jan Beulich wrote:
> On 03.11.2021 11:20, Juergen Gross wrote:
>> +# Generate the output
>> +END {
>> +    # Verbatim generated lines
>> +    for (i = 1; i <= e; i++)
>> +        printf("%s\n", emit[i]);
>> +    printf("\n");
>> +    # Generate prototypes
>> +    for (i = 1; i <= n; i++) {
>> +        for (p = 1; p <= n_pre[i]; p++) {
>> +            printf("%s %s_%s(", rettype[pre[i, p]], pre[i, p], fn[i]);
>> +            if (n_args[i] == 0)
>> +                printf("void");
>> +            else
>> +                for (j = 1; j <= n_args[i]; j++) {
>> +                    if (j > 1)
>> +                        printf(", ");
>> +                    if (ptr[i, j])
>> +                        printf("XEN_GUEST_HANDLE_PARAM(%s)", typ[i, j]);
>> +                    else
>> +                        printf("%s", typ[i, j]);
>> +                    printf(" %s", arg[i, j]);
>> +                }
>> +            printf(");\n");
>> +        }
>> +    }
>> +    # Generate call sequences and args array contents
>> +    for (ca in caller) {
>> +        if (caller[ca] != 1)
>> +            continue;
>> +        need_mask = 0;
>> +        for (pl = 1; pl <= n_prios[ca]; pl++) {
>> +            for (pll = pl; pll > 1; pll--) {
>> +                if (prio_list[ca, pl] > p_list[pll - 1])
>> +                    break;
>> +                else
>> +                    p_list[pll] = p_list[pll - 1];
>> +            }
>> +            p_list[pll] = prio_list[ca, pl];
>> +            # If any prio but the default one has more than 1 entry we need "mask"
>> +            if (p_list[pll] != 100 && prios[ca, p_list[pll]] > 1)
>> +                need_mask = 1;
>> +        }
>> +        printf("\n");
>> +        printf("#define call_handlers_%s(num, ret, a1, a2, a3, a4, a5) \\\n", ca);
>> +        printf("{ \\\n");
> 
> In order to require a semicolon at the use site(s) of the macro I think
> you want "({ \\\n" here. Everything else looks good to me so far, but
> I'd really like to take a look at the generated output: Would you happen
> to have available an instance, to supply in reply?

Okay.

The generated file is attached.


Juergen

[-- Attachment #1.1.2: hypercall-defs.h --]
[-- Type: text/x-chdr, Size: 32559 bytes --]

/* Generated file, do not edit! */

DEFINE_XEN_GUEST_HANDLE(multicall_entry_compat_t);
typedef struct compat_platform_op compat_platform_op_t;
DEFINE_XEN_GUEST_HANDLE(compat_platform_op_t);
DEFINE_XEN_GUEST_HANDLE(trap_info_compat_t);
DEFINE_XEN_GUEST_HANDLE(physdev_op_compat_t);

long do_physdev_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg);
long hvm_physdev_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg);
int compat_physdev_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg);
long do_grant_table_op(unsigned int cmd, XEN_GUEST_HANDLE_PARAM(void) uop, unsigned int count);
long hvm_grant_table_op(unsigned int cmd, XEN_GUEST_HANDLE_PARAM(void) uop, unsigned int count);
int compat_grant_table_op(unsigned int cmd, XEN_GUEST_HANDLE_PARAM(void) uop, unsigned int count);
long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE_PARAM(void) arg);
long hvm_memory_op(unsigned long cmd, XEN_GUEST_HANDLE_PARAM(void) arg);
long do_xen_version(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg);
int compat_xen_version(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg);
long do_vcpu_op(int cmd, unsigned int vcpuid, XEN_GUEST_HANDLE_PARAM(void) arg);
int compat_vcpu_op(int cmd, unsigned int vcpuid, XEN_GUEST_HANDLE_PARAM(void) arg);
long do_sched_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg);
int compat_sched_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg);
long do_xsm_op(XEN_GUEST_HANDLE_PARAM(void) op);
int compat_xsm_op(XEN_GUEST_HANDLE_PARAM(void) op);
long do_callback_op(int cmd, XEN_GUEST_HANDLE_PARAM(const_void) arg);
int compat_callback_op(int cmd, XEN_GUEST_HANDLE_PARAM(const_void) arg);
long do_kexec_op(unsigned int op, XEN_GUEST_HANDLE_PARAM(void) uarg);
int compat_kexec_op(unsigned int op, XEN_GUEST_HANDLE_PARAM(void) uarg);
long do_iret(void);
int compat_iret(void);
long do_nmi_op(unsigned int cmd, XEN_GUEST_HANDLE_PARAM(void) arg);
int compat_nmi_op(unsigned int cmd, XEN_GUEST_HANDLE_PARAM(void) arg);
long do_xenoprof_op(int op, XEN_GUEST_HANDLE_PARAM(void) arg);
int compat_xenoprof_op(int op, XEN_GUEST_HANDLE_PARAM(void) arg);
int compat_set_timer_op(uint32_t lo, int32_t hi);
int compat_multicall(XEN_GUEST_HANDLE_PARAM(multicall_entry_compat_t) call_list, uint32_t nr_calls);
int compat_memory_op(unsigned int cmd, XEN_GUEST_HANDLE_PARAM(void) arg);
int compat_dm_op(domid_t domid, unsigned int nr_bufs, XEN_GUEST_HANDLE_PARAM(void) bufs);
int compat_mmuext_op(XEN_GUEST_HANDLE_PARAM(void) arg, unsigned int count, XEN_GUEST_HANDLE_PARAM(uint) pdone, unsigned int foreigndom);
int compat_set_trap_table(XEN_GUEST_HANDLE_PARAM(trap_info_compat_t) traps);
int compat_set_gdt(XEN_GUEST_HANDLE_PARAM(uint) frame_list, unsigned int entries);
int compat_set_callbacks(unsigned long event_selector, unsigned long event_address, unsigned long failsafe_selector, unsigned long failsafe_address);
int compat_update_descriptor(uint32_t pa_lo, uint32_t pa_hi, uint32_t desc_lo, uint32_t desc_hi);
int compat_update_va_mapping(unsigned int va, uint32_t lo, uint32_t hi, unsigned int flags);
int compat_physdev_op_compat(XEN_GUEST_HANDLE_PARAM(physdev_op_compat_t) uop);
int compat_update_va_mapping_otherdomain(unsigned int va, uint32_t lo, uint32_t hi, unsigned int flags, domid_t domid);
int compat_platform_op(XEN_GUEST_HANDLE_PARAM(compat_platform_op_t) u_xenpf_op);
long do_event_channel_op_compat(XEN_GUEST_HANDLE_PARAM(evtchn_op_t) uop);
long do_physdev_op_compat(XEN_GUEST_HANDLE_PARAM(physdev_op_t) uop);
long do_sched_op_compat(int cmd, unsigned long arg);
long do_set_timer_op(s_time_t timeout);
long do_console_io(unsigned int cmd, unsigned int count, XEN_GUEST_HANDLE_PARAM(char) buffer);
long do_vm_assist(unsigned int cmd, unsigned int type);
long do_event_channel_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg);
long do_mmuext_op(XEN_GUEST_HANDLE_PARAM(mmuext_op_t) uops, unsigned int count, XEN_GUEST_HANDLE_PARAM(uint) pdone, unsigned int foreigndom);
long do_multicall(XEN_GUEST_HANDLE_PARAM(multicall_entry_t) call_list, unsigned int nr_calls);
long do_mmu_update(XEN_GUEST_HANDLE_PARAM(mmu_update_t) ureqs, unsigned int count, XEN_GUEST_HANDLE_PARAM(uint) pdone, unsigned int foreigndom);
long do_stack_switch(unsigned long ss, unsigned long esp);
long do_fpu_taskswitch(int set);
long do_set_debugreg(int reg, unsigned long value);
long do_get_debugreg(int reg);
long do_set_segment_base(unsigned int which, unsigned long base);
long do_mca(XEN_GUEST_HANDLE_PARAM(xen_mc_t) u_xen_mc);
long do_set_trap_table(XEN_GUEST_HANDLE_PARAM(const_trap_info_t) traps);
long do_set_gdt(XEN_GUEST_HANDLE_PARAM(xen_ulong_t) frame_list, unsigned int entries);
long do_set_callbacks(unsigned long event_address, unsigned long failsafe_address, unsigned long syscall_address);
long do_update_descriptor(uint64_t gaddr, seg_desc_t desc);
long do_update_va_mapping(unsigned long va, uint64_t val64, unsigned long flags);
long do_update_va_mapping_otherdomain(unsigned long va, uint64_t val64, unsigned long flags, domid_t domid);
long do_dm_op(domid_t domid, unsigned int nr_bufs, XEN_GUEST_HANDLE_PARAM(xen_dm_op_buf_t) bufs);
long do_sysctl(XEN_GUEST_HANDLE_PARAM(xen_sysctl_t) u_sysctl);
long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl);
long do_paging_domctl_cont(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl);
long do_platform_op(XEN_GUEST_HANDLE_PARAM(xen_platform_op_t) u_xenpf_op);
long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg);
long do_hypfs_op(unsigned int cmd, XEN_GUEST_HANDLE_PARAM(const_char) arg1, unsigned long arg2, XEN_GUEST_HANDLE_PARAM(void) arg3, unsigned long arg4);
long do_xenpmu_op(unsigned int op, XEN_GUEST_HANDLE_PARAM(xen_pmu_params_t) arg);

#define call_handlers_hvm64(num, ret, a1, a2, a3, a4, a5) \
{ \
    uint64_t mask = 1ULL << num; \
    if ( likely(mask & ((1ULL << __HYPERVISOR_vcpu_op) | (1ULL << __HYPERVISOR_event_channel_op))) ) \
    { \
        if ( num == __HYPERVISOR_vcpu_op ) \
            ret = do_vcpu_op((int)(a1), (unsigned int)(a2), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a3) }); \
        else \
            ret = do_event_channel_op((int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
    } \
    else         switch ( num ) \
        { \
        case __HYPERVISOR_platform_op: \
            ret = do_platform_op((XEN_GUEST_HANDLE_PARAM(xen_platform_op_t)){ _p(a1) }); \
            break; \
        case __HYPERVISOR_memory_op: \
            ret = hvm_memory_op((unsigned long)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_multicall: \
            ret = do_multicall((XEN_GUEST_HANDLE_PARAM(multicall_entry_t)){ _p(a1) }, (unsigned int)(a2)); \
            break; \
        case __HYPERVISOR_set_timer_op: \
            ret = do_set_timer_op((s_time_t)(a1)); \
            break; \
        case __HYPERVISOR_xen_version: \
            ret = do_xen_version((int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_console_io: \
            ret = do_console_io((unsigned int)(a1), (unsigned int)(a2), (XEN_GUEST_HANDLE_PARAM(char)){ _p(a3) }); \
            break; \
        case __HYPERVISOR_grant_table_op: \
            ret = hvm_grant_table_op((unsigned int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }, (unsigned int)(a3)); \
            break; \
        case __HYPERVISOR_vm_assist: \
            ret = do_vm_assist((unsigned int)(a1), (unsigned int)(a2)); \
            break; \
        case __HYPERVISOR_mmuext_op: \
            ret = do_mmuext_op((XEN_GUEST_HANDLE_PARAM(mmuext_op_t)){ _p(a1) }, (unsigned int)(a2), (XEN_GUEST_HANDLE_PARAM(uint)){ _p(a3) }, (unsigned int)(a4)); \
            break; \
        case __HYPERVISOR_xsm_op: \
            ret = do_xsm_op((XEN_GUEST_HANDLE_PARAM(void)){ _p(a1) }); \
            break; \
        case __HYPERVISOR_sched_op: \
            ret = do_sched_op((int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_physdev_op: \
            ret = hvm_physdev_op((int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_hvm_op: \
            ret = do_hvm_op((unsigned long)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_sysctl: \
            ret = do_sysctl((XEN_GUEST_HANDLE_PARAM(xen_sysctl_t)){ _p(a1) }); \
            break; \
        case __HYPERVISOR_domctl: \
            ret = do_domctl((XEN_GUEST_HANDLE_PARAM(xen_domctl_t)){ _p(a1) }); \
            break; \
        case __HYPERVISOR_xenpmu_op: \
            ret = do_xenpmu_op((unsigned int)(a1), (XEN_GUEST_HANDLE_PARAM(xen_pmu_params_t)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_dm_op: \
            ret = do_dm_op((domid_t)(a1), (unsigned int)(a2), (XEN_GUEST_HANDLE_PARAM(xen_dm_op_buf_t)){ _p(a3) }); \
            break; \
        case __HYPERVISOR_hypfs_op: \
            ret = do_hypfs_op((unsigned int)(a1), (XEN_GUEST_HANDLE_PARAM(const_char)){ _p(a2) }, (unsigned long)(a3), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a4) }, (unsigned long)(a5)); \
            break; \
        case __HYPERVISOR_paging_domctl_cont: \
            ret = do_paging_domctl_cont((XEN_GUEST_HANDLE_PARAM(xen_domctl_t)){ _p(a1) }); \
            break; \
        default: \
            ret = -ENOSYS; \
            break; \
        } \
}

#define hypercall_args_hvm64 \
{ \
[__HYPERVISOR_platform_op] = 1, \
[__HYPERVISOR_memory_op] = 2, \
[__HYPERVISOR_multicall] = 2, \
[__HYPERVISOR_set_timer_op] = 1, \
[__HYPERVISOR_xen_version] = 2, \
[__HYPERVISOR_console_io] = 3, \
[__HYPERVISOR_grant_table_op] = 3, \
[__HYPERVISOR_vm_assist] = 2, \
[__HYPERVISOR_vcpu_op] = 3, \
[__HYPERVISOR_mmuext_op] = 4, \
[__HYPERVISOR_xsm_op] = 1, \
[__HYPERVISOR_sched_op] = 2, \
[__HYPERVISOR_event_channel_op] = 2, \
[__HYPERVISOR_physdev_op] = 2, \
[__HYPERVISOR_hvm_op] = 2, \
[__HYPERVISOR_sysctl] = 1, \
[__HYPERVISOR_domctl] = 1, \
[__HYPERVISOR_xenpmu_op] = 2, \
[__HYPERVISOR_dm_op] = 3, \
[__HYPERVISOR_hypfs_op] = 5, \
[__HYPERVISOR_paging_domctl_cont] = 1, \
}

#define call_handlers_pv32(num, ret, a1, a2, a3, a4, a5) \
{ \
    uint64_t mask = 1ULL << num; \
    if ( likely(mask & ((1ULL << __HYPERVISOR_mmu_update) | (1ULL << __HYPERVISOR_iret))) ) \
    { \
        if ( num == __HYPERVISOR_mmu_update ) \
            ret = do_mmu_update((XEN_GUEST_HANDLE_PARAM(mmu_update_t)){ _p(a1) }, (unsigned int)(a2), (XEN_GUEST_HANDLE_PARAM(uint)){ _p(a3) }, (unsigned int)(a4)); \
        else \
            ret = compat_iret(); \
    } \
    else if ( likely(mask & ((1ULL << __HYPERVISOR_stack_switch) | (1ULL << __HYPERVISOR_multicall) | (1ULL << __HYPERVISOR_set_segment_base) | (1ULL << __HYPERVISOR_mmuext_op))) ) \
    { \
        switch ( num ) \
        { \
        case __HYPERVISOR_stack_switch: \
            ret = do_stack_switch((unsigned long)(a1), (unsigned long)(a2)); \
            break; \
        case __HYPERVISOR_multicall: \
            ret = compat_multicall((XEN_GUEST_HANDLE_PARAM(multicall_entry_compat_t)){ _p(a1) }, (uint32_t)(a2)); \
            break; \
        case __HYPERVISOR_set_segment_base: \
            ret = do_set_segment_base((unsigned int)(a1), (unsigned long)(a2)); \
            break; \
        case __HYPERVISOR_mmuext_op: \
            ret = compat_mmuext_op((XEN_GUEST_HANDLE_PARAM(void)){ _p(a1) }, (unsigned int)(a2), (XEN_GUEST_HANDLE_PARAM(uint)){ _p(a3) }, (unsigned int)(a4)); \
            break; \
        default: \
            ret = -ENOSYS; \
            break; \
        } \
    } \
    else         switch ( num ) \
        { \
        case __HYPERVISOR_set_trap_table: \
            ret = compat_set_trap_table((XEN_GUEST_HANDLE_PARAM(trap_info_compat_t)){ _p(a1) }); \
            break; \
        case __HYPERVISOR_set_gdt: \
            ret = compat_set_gdt((XEN_GUEST_HANDLE_PARAM(uint)){ _p(a1) }, (unsigned int)(a2)); \
            break; \
        case __HYPERVISOR_set_callbacks: \
            ret = compat_set_callbacks((unsigned long)(a1), (unsigned long)(a2), (unsigned long)(a3), (unsigned long)(a4)); \
            break; \
        case __HYPERVISOR_fpu_taskswitch: \
            ret = do_fpu_taskswitch((int)(a1)); \
            break; \
        case __HYPERVISOR_sched_op_compat: \
            ret = do_sched_op_compat((int)(a1), (unsigned long)(a2)); \
            break; \
        case __HYPERVISOR_platform_op: \
            ret = compat_platform_op((XEN_GUEST_HANDLE_PARAM(compat_platform_op_t)){ _p(a1) }); \
            break; \
        case __HYPERVISOR_set_debugreg: \
            ret = do_set_debugreg((int)(a1), (unsigned long)(a2)); \
            break; \
        case __HYPERVISOR_get_debugreg: \
            ret = do_get_debugreg((int)(a1)); \
            break; \
        case __HYPERVISOR_update_descriptor: \
            ret = compat_update_descriptor((uint32_t)(a1), (uint32_t)(a2), (uint32_t)(a3), (uint32_t)(a4)); \
            break; \
        case __HYPERVISOR_memory_op: \
            ret = compat_memory_op((unsigned int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_update_va_mapping: \
            ret = compat_update_va_mapping((unsigned int)(a1), (uint32_t)(a2), (uint32_t)(a3), (unsigned int)(a4)); \
            break; \
        case __HYPERVISOR_set_timer_op: \
            ret = compat_set_timer_op((uint32_t)(a1), (int32_t)(a2)); \
            break; \
        case __HYPERVISOR_event_channel_op_compat: \
            ret = do_event_channel_op_compat((XEN_GUEST_HANDLE_PARAM(evtchn_op_t)){ _p(a1) }); \
            break; \
        case __HYPERVISOR_xen_version: \
            ret = compat_xen_version((int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_console_io: \
            ret = do_console_io((unsigned int)(a1), (unsigned int)(a2), (XEN_GUEST_HANDLE_PARAM(char)){ _p(a3) }); \
            break; \
        case __HYPERVISOR_physdev_op_compat: \
            ret = compat_physdev_op_compat((XEN_GUEST_HANDLE_PARAM(physdev_op_compat_t)){ _p(a1) }); \
            break; \
        case __HYPERVISOR_grant_table_op: \
            ret = compat_grant_table_op((unsigned int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }, (unsigned int)(a3)); \
            break; \
        case __HYPERVISOR_vm_assist: \
            ret = do_vm_assist((unsigned int)(a1), (unsigned int)(a2)); \
            break; \
        case __HYPERVISOR_update_va_mapping_otherdomain: \
            ret = compat_update_va_mapping_otherdomain((unsigned int)(a1), (uint32_t)(a2), (uint32_t)(a3), (unsigned int)(a4), (domid_t)(a5)); \
            break; \
        case __HYPERVISOR_vcpu_op: \
            ret = compat_vcpu_op((int)(a1), (unsigned int)(a2), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a3) }); \
            break; \
        case __HYPERVISOR_xsm_op: \
            ret = compat_xsm_op((XEN_GUEST_HANDLE_PARAM(void)){ _p(a1) }); \
            break; \
        case __HYPERVISOR_nmi_op: \
            ret = compat_nmi_op((unsigned int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_sched_op: \
            ret = compat_sched_op((int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_callback_op: \
            ret = compat_callback_op((int)(a1), (XEN_GUEST_HANDLE_PARAM(const_void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_xenoprof_op: \
            ret = compat_xenoprof_op((int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_event_channel_op: \
            ret = do_event_channel_op((int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_physdev_op: \
            ret = compat_physdev_op((int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_hvm_op: \
            ret = do_hvm_op((unsigned long)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_sysctl: \
            ret = do_sysctl((XEN_GUEST_HANDLE_PARAM(xen_sysctl_t)){ _p(a1) }); \
            break; \
        case __HYPERVISOR_domctl: \
            ret = do_domctl((XEN_GUEST_HANDLE_PARAM(xen_domctl_t)){ _p(a1) }); \
            break; \
        case __HYPERVISOR_kexec_op: \
            ret = compat_kexec_op((unsigned int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_xenpmu_op: \
            ret = do_xenpmu_op((unsigned int)(a1), (XEN_GUEST_HANDLE_PARAM(xen_pmu_params_t)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_dm_op: \
            ret = compat_dm_op((domid_t)(a1), (unsigned int)(a2), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a3) }); \
            break; \
        case __HYPERVISOR_hypfs_op: \
            ret = do_hypfs_op((unsigned int)(a1), (XEN_GUEST_HANDLE_PARAM(const_char)){ _p(a2) }, (unsigned long)(a3), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a4) }, (unsigned long)(a5)); \
            break; \
        case __HYPERVISOR_mca: \
            ret = do_mca((XEN_GUEST_HANDLE_PARAM(xen_mc_t)){ _p(a1) }); \
            break; \
        case __HYPERVISOR_paging_domctl_cont: \
            ret = do_paging_domctl_cont((XEN_GUEST_HANDLE_PARAM(xen_domctl_t)){ _p(a1) }); \
            break; \
        default: \
            ret = -ENOSYS; \
            break; \
        } \
}

#define hypercall_args_pv32 \
{ \
[__HYPERVISOR_set_trap_table] = 1, \
[__HYPERVISOR_mmu_update] = 4, \
[__HYPERVISOR_set_gdt] = 2, \
[__HYPERVISOR_stack_switch] = 2, \
[__HYPERVISOR_set_callbacks] = 4, \
[__HYPERVISOR_fpu_taskswitch] = 1, \
[__HYPERVISOR_sched_op_compat] = 2, \
[__HYPERVISOR_platform_op] = 1, \
[__HYPERVISOR_set_debugreg] = 2, \
[__HYPERVISOR_get_debugreg] = 1, \
[__HYPERVISOR_update_descriptor] = 4, \
[__HYPERVISOR_memory_op] = 2, \
[__HYPERVISOR_multicall] = 2, \
[__HYPERVISOR_update_va_mapping] = 4, \
[__HYPERVISOR_set_timer_op] = 2, \
[__HYPERVISOR_event_channel_op_compat] = 1, \
[__HYPERVISOR_xen_version] = 2, \
[__HYPERVISOR_console_io] = 3, \
[__HYPERVISOR_physdev_op_compat] = 1, \
[__HYPERVISOR_grant_table_op] = 3, \
[__HYPERVISOR_vm_assist] = 2, \
[__HYPERVISOR_update_va_mapping_otherdomain] = 5, \
[__HYPERVISOR_iret] = 0, \
[__HYPERVISOR_vcpu_op] = 3, \
[__HYPERVISOR_set_segment_base] = 2, \
[__HYPERVISOR_mmuext_op] = 4, \
[__HYPERVISOR_xsm_op] = 1, \
[__HYPERVISOR_nmi_op] = 2, \
[__HYPERVISOR_sched_op] = 2, \
[__HYPERVISOR_callback_op] = 2, \
[__HYPERVISOR_xenoprof_op] = 2, \
[__HYPERVISOR_event_channel_op] = 2, \
[__HYPERVISOR_physdev_op] = 2, \
[__HYPERVISOR_hvm_op] = 2, \
[__HYPERVISOR_sysctl] = 1, \
[__HYPERVISOR_domctl] = 1, \
[__HYPERVISOR_kexec_op] = 2, \
[__HYPERVISOR_xenpmu_op] = 2, \
[__HYPERVISOR_dm_op] = 3, \
[__HYPERVISOR_hypfs_op] = 5, \
[__HYPERVISOR_mca] = 1, \
[__HYPERVISOR_paging_domctl_cont] = 1, \
}

#define call_handlers_hvm32(num, ret, a1, a2, a3, a4, a5) \
{ \
    uint64_t mask = 1ULL << num; \
    if ( likely(mask & ((1ULL << __HYPERVISOR_vcpu_op) | (1ULL << __HYPERVISOR_event_channel_op))) ) \
    { \
        if ( num == __HYPERVISOR_vcpu_op ) \
            ret = compat_vcpu_op((int)(a1), (unsigned int)(a2), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a3) }); \
        else \
            ret = do_event_channel_op((int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
    } \
    else         switch ( num ) \
        { \
        case __HYPERVISOR_platform_op: \
            ret = compat_platform_op((XEN_GUEST_HANDLE_PARAM(compat_platform_op_t)){ _p(a1) }); \
            break; \
        case __HYPERVISOR_memory_op: \
            ret = hvm_memory_op((unsigned long)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_multicall: \
            ret = compat_multicall((XEN_GUEST_HANDLE_PARAM(multicall_entry_compat_t)){ _p(a1) }, (uint32_t)(a2)); \
            break; \
        case __HYPERVISOR_set_timer_op: \
            ret = compat_set_timer_op((uint32_t)(a1), (int32_t)(a2)); \
            break; \
        case __HYPERVISOR_xen_version: \
            ret = compat_xen_version((int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_console_io: \
            ret = do_console_io((unsigned int)(a1), (unsigned int)(a2), (XEN_GUEST_HANDLE_PARAM(char)){ _p(a3) }); \
            break; \
        case __HYPERVISOR_grant_table_op: \
            ret = hvm_grant_table_op((unsigned int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }, (unsigned int)(a3)); \
            break; \
        case __HYPERVISOR_vm_assist: \
            ret = do_vm_assist((unsigned int)(a1), (unsigned int)(a2)); \
            break; \
        case __HYPERVISOR_mmuext_op: \
            ret = compat_mmuext_op((XEN_GUEST_HANDLE_PARAM(void)){ _p(a1) }, (unsigned int)(a2), (XEN_GUEST_HANDLE_PARAM(uint)){ _p(a3) }, (unsigned int)(a4)); \
            break; \
        case __HYPERVISOR_xsm_op: \
            ret = compat_xsm_op((XEN_GUEST_HANDLE_PARAM(void)){ _p(a1) }); \
            break; \
        case __HYPERVISOR_sched_op: \
            ret = compat_sched_op((int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_physdev_op: \
            ret = hvm_physdev_op((int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_hvm_op: \
            ret = do_hvm_op((unsigned long)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_sysctl: \
            ret = do_sysctl((XEN_GUEST_HANDLE_PARAM(xen_sysctl_t)){ _p(a1) }); \
            break; \
        case __HYPERVISOR_domctl: \
            ret = do_domctl((XEN_GUEST_HANDLE_PARAM(xen_domctl_t)){ _p(a1) }); \
            break; \
        case __HYPERVISOR_xenpmu_op: \
            ret = do_xenpmu_op((unsigned int)(a1), (XEN_GUEST_HANDLE_PARAM(xen_pmu_params_t)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_dm_op: \
            ret = compat_dm_op((domid_t)(a1), (unsigned int)(a2), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a3) }); \
            break; \
        case __HYPERVISOR_hypfs_op: \
            ret = do_hypfs_op((unsigned int)(a1), (XEN_GUEST_HANDLE_PARAM(const_char)){ _p(a2) }, (unsigned long)(a3), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a4) }, (unsigned long)(a5)); \
            break; \
        case __HYPERVISOR_paging_domctl_cont: \
            ret = do_paging_domctl_cont((XEN_GUEST_HANDLE_PARAM(xen_domctl_t)){ _p(a1) }); \
            break; \
        default: \
            ret = -ENOSYS; \
            break; \
        } \
}

#define hypercall_args_hvm32 \
{ \
[__HYPERVISOR_platform_op] = 1, \
[__HYPERVISOR_memory_op] = 2, \
[__HYPERVISOR_multicall] = 2, \
[__HYPERVISOR_set_timer_op] = 2, \
[__HYPERVISOR_xen_version] = 2, \
[__HYPERVISOR_console_io] = 3, \
[__HYPERVISOR_grant_table_op] = 3, \
[__HYPERVISOR_vm_assist] = 2, \
[__HYPERVISOR_vcpu_op] = 3, \
[__HYPERVISOR_mmuext_op] = 4, \
[__HYPERVISOR_xsm_op] = 1, \
[__HYPERVISOR_sched_op] = 2, \
[__HYPERVISOR_event_channel_op] = 2, \
[__HYPERVISOR_physdev_op] = 2, \
[__HYPERVISOR_hvm_op] = 2, \
[__HYPERVISOR_sysctl] = 1, \
[__HYPERVISOR_domctl] = 1, \
[__HYPERVISOR_xenpmu_op] = 2, \
[__HYPERVISOR_dm_op] = 3, \
[__HYPERVISOR_hypfs_op] = 5, \
[__HYPERVISOR_paging_domctl_cont] = 1, \
}

#define call_handlers_pv64(num, ret, a1, a2, a3, a4, a5) \
{ \
    uint64_t mask = 1ULL << num; \
    if ( likely(mask & ((1ULL << __HYPERVISOR_mmu_update) | (1ULL << __HYPERVISOR_iret))) ) \
    { \
        if ( num == __HYPERVISOR_mmu_update ) \
            ret = do_mmu_update((XEN_GUEST_HANDLE_PARAM(mmu_update_t)){ _p(a1) }, (unsigned int)(a2), (XEN_GUEST_HANDLE_PARAM(uint)){ _p(a3) }, (unsigned int)(a4)); \
        else \
            ret = do_iret(); \
    } \
    else if ( likely(mask & ((1ULL << __HYPERVISOR_stack_switch) | (1ULL << __HYPERVISOR_multicall) | (1ULL << __HYPERVISOR_set_segment_base) | (1ULL << __HYPERVISOR_mmuext_op))) ) \
    { \
        switch ( num ) \
        { \
        case __HYPERVISOR_stack_switch: \
            ret = do_stack_switch((unsigned long)(a1), (unsigned long)(a2)); \
            break; \
        case __HYPERVISOR_multicall: \
            ret = do_multicall((XEN_GUEST_HANDLE_PARAM(multicall_entry_t)){ _p(a1) }, (unsigned int)(a2)); \
            break; \
        case __HYPERVISOR_set_segment_base: \
            ret = do_set_segment_base((unsigned int)(a1), (unsigned long)(a2)); \
            break; \
        case __HYPERVISOR_mmuext_op: \
            ret = do_mmuext_op((XEN_GUEST_HANDLE_PARAM(mmuext_op_t)){ _p(a1) }, (unsigned int)(a2), (XEN_GUEST_HANDLE_PARAM(uint)){ _p(a3) }, (unsigned int)(a4)); \
            break; \
        default: \
            ret = -ENOSYS; \
            break; \
        } \
    } \
    else         switch ( num ) \
        { \
        case __HYPERVISOR_set_trap_table: \
            ret = do_set_trap_table((XEN_GUEST_HANDLE_PARAM(const_trap_info_t)){ _p(a1) }); \
            break; \
        case __HYPERVISOR_set_gdt: \
            ret = do_set_gdt((XEN_GUEST_HANDLE_PARAM(xen_ulong_t)){ _p(a1) }, (unsigned int)(a2)); \
            break; \
        case __HYPERVISOR_set_callbacks: \
            ret = do_set_callbacks((unsigned long)(a1), (unsigned long)(a2), (unsigned long)(a3)); \
            break; \
        case __HYPERVISOR_fpu_taskswitch: \
            ret = do_fpu_taskswitch((int)(a1)); \
            break; \
        case __HYPERVISOR_sched_op_compat: \
            ret = do_sched_op_compat((int)(a1), (unsigned long)(a2)); \
            break; \
        case __HYPERVISOR_platform_op: \
            ret = do_platform_op((XEN_GUEST_HANDLE_PARAM(xen_platform_op_t)){ _p(a1) }); \
            break; \
        case __HYPERVISOR_set_debugreg: \
            ret = do_set_debugreg((int)(a1), (unsigned long)(a2)); \
            break; \
        case __HYPERVISOR_get_debugreg: \
            ret = do_get_debugreg((int)(a1)); \
            break; \
        case __HYPERVISOR_update_descriptor: \
            ret = do_update_descriptor((uint64_t)(a1), (seg_desc_t)(a2)); \
            break; \
        case __HYPERVISOR_memory_op: \
            ret = do_memory_op((unsigned long)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_update_va_mapping: \
            ret = do_update_va_mapping((unsigned long)(a1), (uint64_t)(a2), (unsigned long)(a3)); \
            break; \
        case __HYPERVISOR_set_timer_op: \
            ret = do_set_timer_op((s_time_t)(a1)); \
            break; \
        case __HYPERVISOR_event_channel_op_compat: \
            ret = do_event_channel_op_compat((XEN_GUEST_HANDLE_PARAM(evtchn_op_t)){ _p(a1) }); \
            break; \
        case __HYPERVISOR_xen_version: \
            ret = do_xen_version((int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_console_io: \
            ret = do_console_io((unsigned int)(a1), (unsigned int)(a2), (XEN_GUEST_HANDLE_PARAM(char)){ _p(a3) }); \
            break; \
        case __HYPERVISOR_physdev_op_compat: \
            ret = do_physdev_op_compat((XEN_GUEST_HANDLE_PARAM(physdev_op_t)){ _p(a1) }); \
            break; \
        case __HYPERVISOR_grant_table_op: \
            ret = do_grant_table_op((unsigned int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }, (unsigned int)(a3)); \
            break; \
        case __HYPERVISOR_vm_assist: \
            ret = do_vm_assist((unsigned int)(a1), (unsigned int)(a2)); \
            break; \
        case __HYPERVISOR_update_va_mapping_otherdomain: \
            ret = do_update_va_mapping_otherdomain((unsigned long)(a1), (uint64_t)(a2), (unsigned long)(a3), (domid_t)(a4)); \
            break; \
        case __HYPERVISOR_vcpu_op: \
            ret = do_vcpu_op((int)(a1), (unsigned int)(a2), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a3) }); \
            break; \
        case __HYPERVISOR_xsm_op: \
            ret = do_xsm_op((XEN_GUEST_HANDLE_PARAM(void)){ _p(a1) }); \
            break; \
        case __HYPERVISOR_nmi_op: \
            ret = do_nmi_op((unsigned int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_sched_op: \
            ret = do_sched_op((int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_callback_op: \
            ret = do_callback_op((int)(a1), (XEN_GUEST_HANDLE_PARAM(const_void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_xenoprof_op: \
            ret = do_xenoprof_op((int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_event_channel_op: \
            ret = do_event_channel_op((int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_physdev_op: \
            ret = do_physdev_op((int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_hvm_op: \
            ret = do_hvm_op((unsigned long)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_sysctl: \
            ret = do_sysctl((XEN_GUEST_HANDLE_PARAM(xen_sysctl_t)){ _p(a1) }); \
            break; \
        case __HYPERVISOR_domctl: \
            ret = do_domctl((XEN_GUEST_HANDLE_PARAM(xen_domctl_t)){ _p(a1) }); \
            break; \
        case __HYPERVISOR_kexec_op: \
            ret = do_kexec_op((unsigned int)(a1), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_xenpmu_op: \
            ret = do_xenpmu_op((unsigned int)(a1), (XEN_GUEST_HANDLE_PARAM(xen_pmu_params_t)){ _p(a2) }); \
            break; \
        case __HYPERVISOR_dm_op: \
            ret = do_dm_op((domid_t)(a1), (unsigned int)(a2), (XEN_GUEST_HANDLE_PARAM(xen_dm_op_buf_t)){ _p(a3) }); \
            break; \
        case __HYPERVISOR_hypfs_op: \
            ret = do_hypfs_op((unsigned int)(a1), (XEN_GUEST_HANDLE_PARAM(const_char)){ _p(a2) }, (unsigned long)(a3), (XEN_GUEST_HANDLE_PARAM(void)){ _p(a4) }, (unsigned long)(a5)); \
            break; \
        case __HYPERVISOR_mca: \
            ret = do_mca((XEN_GUEST_HANDLE_PARAM(xen_mc_t)){ _p(a1) }); \
            break; \
        case __HYPERVISOR_paging_domctl_cont: \
            ret = do_paging_domctl_cont((XEN_GUEST_HANDLE_PARAM(xen_domctl_t)){ _p(a1) }); \
            break; \
        default: \
            ret = -ENOSYS; \
            break; \
        } \
}

#define hypercall_args_pv64 \
{ \
[__HYPERVISOR_set_trap_table] = 1, \
[__HYPERVISOR_mmu_update] = 4, \
[__HYPERVISOR_set_gdt] = 2, \
[__HYPERVISOR_stack_switch] = 2, \
[__HYPERVISOR_set_callbacks] = 3, \
[__HYPERVISOR_fpu_taskswitch] = 1, \
[__HYPERVISOR_sched_op_compat] = 2, \
[__HYPERVISOR_platform_op] = 1, \
[__HYPERVISOR_set_debugreg] = 2, \
[__HYPERVISOR_get_debugreg] = 1, \
[__HYPERVISOR_update_descriptor] = 2, \
[__HYPERVISOR_memory_op] = 2, \
[__HYPERVISOR_multicall] = 2, \
[__HYPERVISOR_update_va_mapping] = 3, \
[__HYPERVISOR_set_timer_op] = 1, \
[__HYPERVISOR_event_channel_op_compat] = 1, \
[__HYPERVISOR_xen_version] = 2, \
[__HYPERVISOR_console_io] = 3, \
[__HYPERVISOR_physdev_op_compat] = 1, \
[__HYPERVISOR_grant_table_op] = 3, \
[__HYPERVISOR_vm_assist] = 2, \
[__HYPERVISOR_update_va_mapping_otherdomain] = 4, \
[__HYPERVISOR_iret] = 0, \
[__HYPERVISOR_vcpu_op] = 3, \
[__HYPERVISOR_set_segment_base] = 2, \
[__HYPERVISOR_mmuext_op] = 4, \
[__HYPERVISOR_xsm_op] = 1, \
[__HYPERVISOR_nmi_op] = 2, \
[__HYPERVISOR_sched_op] = 2, \
[__HYPERVISOR_callback_op] = 2, \
[__HYPERVISOR_xenoprof_op] = 2, \
[__HYPERVISOR_event_channel_op] = 2, \
[__HYPERVISOR_physdev_op] = 2, \
[__HYPERVISOR_hvm_op] = 2, \
[__HYPERVISOR_sysctl] = 1, \
[__HYPERVISOR_domctl] = 1, \
[__HYPERVISOR_kexec_op] = 2, \
[__HYPERVISOR_xenpmu_op] = 2, \
[__HYPERVISOR_dm_op] = 3, \
[__HYPERVISOR_hypfs_op] = 5, \
[__HYPERVISOR_mca] = 1, \
[__HYPERVISOR_paging_domctl_cont] = 1, \
}

[-- Attachment #1.1.3: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3135 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2.2 07/15] xen: generate hypercall interface related code
  2021-11-03 10:20 [PATCH v2.2 07/15] xen: generate hypercall interface related code Juergen Gross
  2021-11-03 15:08 ` Jan Beulich
@ 2021-11-03 15:42 ` Jan Beulich
  2021-11-08 14:42   ` Juergen Gross
  2021-11-11 16:04 ` Anthony PERARD
  2 siblings, 1 reply; 7+ messages in thread
From: Jan Beulich @ 2021-11-03 15:42 UTC (permalink / raw)
  To: Juergen Gross
  Cc: Andrew Cooper, George Dunlap, Ian Jackson, Julien Grall,
	Stefano Stabellini, Wei Liu, xen-devel

On 03.11.2021 11:20, Juergen Gross wrote:
> Instead of repeating similar data multiple times use a single source
> file and a generator script for producing prototypes and call sequences
> of the hypercalls.
> 
> As the script already knows the number of parameters used add generating
> a macro for populating an array with the number of parameters per
> hypercall.
> 
> Signed-off-by: Juergen Gross <jgross@suse.com>

What's missing here now that you have introduced priorities is how you
did arrive at the chosen values. That's a pretty important aspect,
especially if someone would later want to adjust these.

Just one further remark from looking at the output of the script (thanks
for making that available):

> +# Generate the output
> +END {
> +    # Verbatim generated lines
> +    for (i = 1; i <= e; i++)
> +        printf("%s\n", emit[i]);
> +    printf("\n");
> +    # Generate prototypes
> +    for (i = 1; i <= n; i++) {
> +        for (p = 1; p <= n_pre[i]; p++) {
> +            printf("%s %s_%s(", rettype[pre[i, p]], pre[i, p], fn[i]);
> +            if (n_args[i] == 0)
> +                printf("void");
> +            else
> +                for (j = 1; j <= n_args[i]; j++) {
> +                    if (j > 1)
> +                        printf(", ");
> +                    if (ptr[i, j])
> +                        printf("XEN_GUEST_HANDLE_PARAM(%s)", typ[i, j]);
> +                    else
> +                        printf("%s", typ[i, j]);
> +                    printf(" %s", arg[i, j]);
> +                }
> +            printf(");\n");
> +        }
> +    }
> +    # Generate call sequences and args array contents
> +    for (ca in caller) {
> +        if (caller[ca] != 1)
> +            continue;
> +        need_mask = 0;
> +        for (pl = 1; pl <= n_prios[ca]; pl++) {
> +            for (pll = pl; pll > 1; pll--) {
> +                if (prio_list[ca, pl] > p_list[pll - 1])
> +                    break;
> +                else
> +                    p_list[pll] = p_list[pll - 1];
> +            }
> +            p_list[pll] = prio_list[ca, pl];
> +            # If any prio but the default one has more than 1 entry we need "mask"
> +            if (p_list[pll] != 100 && prios[ca, p_list[pll]] > 1)
> +                need_mask = 1;
> +        }
> +        printf("\n");
> +        printf("#define call_handlers_%s(num, ret, a1, a2, a3, a4, a5) \\\n", ca);
> +        printf("{ \\\n");
> +        if (need_mask)
> +            printf("    uint64_t mask = 1ULL << num; \\\n");
> +        printf("    ");
> +        for (pl = 1; pl <= n_prios[ca]; pl++) {
> +            if (prios[ca, p_list[pl]] > 1) {
> +                if (pl < n_prios[ca]) {
> +                    printf("if ( likely(mask & (%s)) ) \\\n", prio_mask[ca, p_list[pl]]);
> +                    printf("    { \\\n");
> +                }
> +                if (prios[ca, p_list[pl]] == 2) {
> +                    fnd = 0;
> +                    for (i = 1; i <= nc; i++)
> +                        if (call[i] == ca && call_prio[i] == p_list[pl]) {
> +                            fnd++;
> +                            if (fnd == 1)
> +                                printf("        if ( num == __HYPERVISOR_%s ) \\\n", fn[call_fn[i]]);
> +                            else
> +                                printf("        else \\\n");
> +                            do_call(call_fn[i], call_p[i]);
> +                        }
> +                } else {
> +                    do_switch(ca, p_list[pl]);
> +                }
> +                if (pl < n_prios[ca])
> +                    printf("    } \\\n");
> +            } else {
> +                for (i = 1; i <= nc; i++)
> +                    if (call[i] == ca && call_prio[i] == p_list[pl]) {
> +                        printf("if ( likely(num == __HYPERVISOR_%s) ) \\\n", fn[call_fn[i]]);
> +                        do_call(call_fn[i], call_p[i]);
> +                    }
> +            }
> +            if (pl < n_prios[ca] || prios[ca, p_list[pl]] <= 2)
> +                printf("    else ");

I think there's a line continuation escape + newline missing here.

Jan



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2.2 07/15] xen: generate hypercall interface related code
  2021-11-03 15:42 ` Jan Beulich
@ 2021-11-08 14:42   ` Juergen Gross
  2021-11-08 14:54     ` Jan Beulich
  0 siblings, 1 reply; 7+ messages in thread
From: Juergen Gross @ 2021-11-08 14:42 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Andrew Cooper, George Dunlap, Ian Jackson, Julien Grall,
	Stefano Stabellini, Wei Liu, xen-devel


[-- Attachment #1.1.1: Type: text/plain, Size: 4859 bytes --]

On 03.11.21 16:42, Jan Beulich wrote:
> On 03.11.2021 11:20, Juergen Gross wrote:
>> Instead of repeating similar data multiple times use a single source
>> file and a generator script for producing prototypes and call sequences
>> of the hypercalls.
>>
>> As the script already knows the number of parameters used add generating
>> a macro for populating an array with the number of parameters per
>> hypercall.
>>
>> Signed-off-by: Juergen Gross <jgross@suse.com>
> 
> What's missing here now that you have introduced priorities is how you
> did arrive at the chosen values. That's a pretty important aspect,
> especially if someone would later want to adjust these.

Will include the measured data in next version's commit message.

> Just one further remark from looking at the output of the script (thanks
> for making that available):
> 
>> +# Generate the output
>> +END {
>> +    # Verbatim generated lines
>> +    for (i = 1; i <= e; i++)
>> +        printf("%s\n", emit[i]);
>> +    printf("\n");
>> +    # Generate prototypes
>> +    for (i = 1; i <= n; i++) {
>> +        for (p = 1; p <= n_pre[i]; p++) {
>> +            printf("%s %s_%s(", rettype[pre[i, p]], pre[i, p], fn[i]);
>> +            if (n_args[i] == 0)
>> +                printf("void");
>> +            else
>> +                for (j = 1; j <= n_args[i]; j++) {
>> +                    if (j > 1)
>> +                        printf(", ");
>> +                    if (ptr[i, j])
>> +                        printf("XEN_GUEST_HANDLE_PARAM(%s)", typ[i, j]);
>> +                    else
>> +                        printf("%s", typ[i, j]);
>> +                    printf(" %s", arg[i, j]);
>> +                }
>> +            printf(");\n");
>> +        }
>> +    }
>> +    # Generate call sequences and args array contents
>> +    for (ca in caller) {
>> +        if (caller[ca] != 1)
>> +            continue;
>> +        need_mask = 0;
>> +        for (pl = 1; pl <= n_prios[ca]; pl++) {
>> +            for (pll = pl; pll > 1; pll--) {
>> +                if (prio_list[ca, pl] > p_list[pll - 1])
>> +                    break;
>> +                else
>> +                    p_list[pll] = p_list[pll - 1];
>> +            }
>> +            p_list[pll] = prio_list[ca, pl];
>> +            # If any prio but the default one has more than 1 entry we need "mask"
>> +            if (p_list[pll] != 100 && prios[ca, p_list[pll]] > 1)
>> +                need_mask = 1;
>> +        }
>> +        printf("\n");
>> +        printf("#define call_handlers_%s(num, ret, a1, a2, a3, a4, a5) \\\n", ca);
>> +        printf("{ \\\n");
>> +        if (need_mask)
>> +            printf("    uint64_t mask = 1ULL << num; \\\n");
>> +        printf("    ");
>> +        for (pl = 1; pl <= n_prios[ca]; pl++) {
>> +            if (prios[ca, p_list[pl]] > 1) {
>> +                if (pl < n_prios[ca]) {
>> +                    printf("if ( likely(mask & (%s)) ) \\\n", prio_mask[ca, p_list[pl]]);
>> +                    printf("    { \\\n");
>> +                }
>> +                if (prios[ca, p_list[pl]] == 2) {
>> +                    fnd = 0;
>> +                    for (i = 1; i <= nc; i++)
>> +                        if (call[i] == ca && call_prio[i] == p_list[pl]) {
>> +                            fnd++;
>> +                            if (fnd == 1)
>> +                                printf("        if ( num == __HYPERVISOR_%s ) \\\n", fn[call_fn[i]]);
>> +                            else
>> +                                printf("        else \\\n");
>> +                            do_call(call_fn[i], call_p[i]);
>> +                        }
>> +                } else {
>> +                    do_switch(ca, p_list[pl]);
>> +                }
>> +                if (pl < n_prios[ca])
>> +                    printf("    } \\\n");
>> +            } else {
>> +                for (i = 1; i <= nc; i++)
>> +                    if (call[i] == ca && call_prio[i] == p_list[pl]) {
>> +                        printf("if ( likely(num == __HYPERVISOR_%s) ) \\\n", fn[call_fn[i]]);
>> +                        do_call(call_fn[i], call_p[i]);
>> +                    }
>> +            }
>> +            if (pl < n_prios[ca] || prios[ca, p_list[pl]] <= 2)
>> +                printf("    else ");
> 
> I think there's a line continuation escape + newline missing here.

Yes and no.

This can either continue with another "if" clause not wanting a new
line or with a final ending statement (either a "switch" or a
"ret = -ENOSYS"), which probably would want the new line. Adding
code for handling both cases is possible, but I'm not sure it is
worth it. In case you are preferring an unconditional new line,
this would be easy to arrange, of course.


Juergen

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3135 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2.2 07/15] xen: generate hypercall interface related code
  2021-11-08 14:42   ` Juergen Gross
@ 2021-11-08 14:54     ` Jan Beulich
  0 siblings, 0 replies; 7+ messages in thread
From: Jan Beulich @ 2021-11-08 14:54 UTC (permalink / raw)
  To: Juergen Gross
  Cc: Andrew Cooper, George Dunlap, Ian Jackson, Julien Grall,
	Stefano Stabellini, Wei Liu, xen-devel

On 08.11.2021 15:42, Juergen Gross wrote:
> On 03.11.21 16:42, Jan Beulich wrote:
>> On 03.11.2021 11:20, Juergen Gross wrote:
>>> +# Generate the output
>>> +END {
>>> +    # Verbatim generated lines
>>> +    for (i = 1; i <= e; i++)
>>> +        printf("%s\n", emit[i]);
>>> +    printf("\n");
>>> +    # Generate prototypes
>>> +    for (i = 1; i <= n; i++) {
>>> +        for (p = 1; p <= n_pre[i]; p++) {
>>> +            printf("%s %s_%s(", rettype[pre[i, p]], pre[i, p], fn[i]);
>>> +            if (n_args[i] == 0)
>>> +                printf("void");
>>> +            else
>>> +                for (j = 1; j <= n_args[i]; j++) {
>>> +                    if (j > 1)
>>> +                        printf(", ");
>>> +                    if (ptr[i, j])
>>> +                        printf("XEN_GUEST_HANDLE_PARAM(%s)", typ[i, j]);
>>> +                    else
>>> +                        printf("%s", typ[i, j]);
>>> +                    printf(" %s", arg[i, j]);
>>> +                }
>>> +            printf(");\n");
>>> +        }
>>> +    }
>>> +    # Generate call sequences and args array contents
>>> +    for (ca in caller) {
>>> +        if (caller[ca] != 1)
>>> +            continue;
>>> +        need_mask = 0;
>>> +        for (pl = 1; pl <= n_prios[ca]; pl++) {
>>> +            for (pll = pl; pll > 1; pll--) {
>>> +                if (prio_list[ca, pl] > p_list[pll - 1])
>>> +                    break;
>>> +                else
>>> +                    p_list[pll] = p_list[pll - 1];
>>> +            }
>>> +            p_list[pll] = prio_list[ca, pl];
>>> +            # If any prio but the default one has more than 1 entry we need "mask"
>>> +            if (p_list[pll] != 100 && prios[ca, p_list[pll]] > 1)
>>> +                need_mask = 1;
>>> +        }
>>> +        printf("\n");
>>> +        printf("#define call_handlers_%s(num, ret, a1, a2, a3, a4, a5) \\\n", ca);
>>> +        printf("{ \\\n");
>>> +        if (need_mask)
>>> +            printf("    uint64_t mask = 1ULL << num; \\\n");
>>> +        printf("    ");
>>> +        for (pl = 1; pl <= n_prios[ca]; pl++) {
>>> +            if (prios[ca, p_list[pl]] > 1) {
>>> +                if (pl < n_prios[ca]) {
>>> +                    printf("if ( likely(mask & (%s)) ) \\\n", prio_mask[ca, p_list[pl]]);
>>> +                    printf("    { \\\n");
>>> +                }
>>> +                if (prios[ca, p_list[pl]] == 2) {
>>> +                    fnd = 0;
>>> +                    for (i = 1; i <= nc; i++)
>>> +                        if (call[i] == ca && call_prio[i] == p_list[pl]) {
>>> +                            fnd++;
>>> +                            if (fnd == 1)
>>> +                                printf("        if ( num == __HYPERVISOR_%s ) \\\n", fn[call_fn[i]]);
>>> +                            else
>>> +                                printf("        else \\\n");
>>> +                            do_call(call_fn[i], call_p[i]);
>>> +                        }
>>> +                } else {
>>> +                    do_switch(ca, p_list[pl]);
>>> +                }
>>> +                if (pl < n_prios[ca])
>>> +                    printf("    } \\\n");
>>> +            } else {
>>> +                for (i = 1; i <= nc; i++)
>>> +                    if (call[i] == ca && call_prio[i] == p_list[pl]) {
>>> +                        printf("if ( likely(num == __HYPERVISOR_%s) ) \\\n", fn[call_fn[i]]);
>>> +                        do_call(call_fn[i], call_p[i]);
>>> +                    }
>>> +            }
>>> +            if (pl < n_prios[ca] || prios[ca, p_list[pl]] <= 2)
>>> +                printf("    else ");
>>
>> I think there's a line continuation escape + newline missing here.
> 
> Yes and no.
> 
> This can either continue with another "if" clause not wanting a new
> line or with a final ending statement (either a "switch" or a
> "ret = -ENOSYS"), which probably would want the new line. Adding
> code for handling both cases is possible, but I'm not sure it is
> worth it. In case you are preferring an unconditional new line,
> this would be easy to arrange, of course.

I'm not going to insist; it merely looked odd to me, and I was
thinking that the alternative would overall look less odd.

Jan



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2.2 07/15] xen: generate hypercall interface related code
  2021-11-03 10:20 [PATCH v2.2 07/15] xen: generate hypercall interface related code Juergen Gross
  2021-11-03 15:08 ` Jan Beulich
  2021-11-03 15:42 ` Jan Beulich
@ 2021-11-11 16:04 ` Anthony PERARD
  2 siblings, 0 replies; 7+ messages in thread
From: Anthony PERARD @ 2021-11-11 16:04 UTC (permalink / raw)
  To: Juergen Gross
  Cc: xen-devel, Andrew Cooper, George Dunlap, Ian Jackson,
	Jan Beulich, Julien Grall, Stefano Stabellini, Wei Liu

On Wed, Nov 03, 2021 at 11:20:59AM +0100, Juergen Gross wrote:
> diff --git a/xen/Makefile b/xen/Makefile
> index a3189eb47c..dfdae47e74 100644
> --- a/xen/Makefile
> +++ b/xen/Makefile
> @@ -405,6 +406,7 @@ $(TARGET): delete-unfresh-files
>  	$(MAKE) -f $(BASEDIR)/Rules.mk -C include
>  	$(MAKE) -f $(BASEDIR)/Rules.mk -C arch/$(TARGET_ARCH) include
>  	$(MAKE) -f $(BASEDIR)/Rules.mk include/asm-$(TARGET_ARCH)/asm-offsets.h
> +	$(MAKE) -f $(BASEDIR)/Rules.mk include/xen/hypercall-defs.h
>  	$(MAKE) -f $(BASEDIR)/Rules.mk -C arch/$(TARGET_ARCH) $@
>  
>  # drivers/char/console.o contains static banner/compile info. Blow it away.
> @@ -466,6 +468,14 @@ include/asm-$(TARGET_ARCH)/asm-offsets.h: asm-offsets.s
>  	  echo ""; \
>  	  echo "#endif") <$< >$@
>  
> +quiet_cmd_genhyp = GEN     $@
> +define cmd_genhyp
> +    awk -f scripts/gen_hypercall.awk <$< >$@
> +endef
> +
> +include/xen/hypercall-defs.h: include/hypercall-defs.i scripts/gen_hypercall.awk FORCE
> +	$(call if_changed,genhyp)
> +

Is there a reason to generate "hypercall-defs.h" here? Could this be
moved to include/Makefile instead?

Then, when moved to include/Makefile, I think you would need to add both
"xen/hypercall-def.h" and "hypercall-defs.i" to $(targets) to avoid them
been rebuilt needlessly.

Thanks,

-- 
Anthony PERARD


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2021-11-11 16:05 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-03 10:20 [PATCH v2.2 07/15] xen: generate hypercall interface related code Juergen Gross
2021-11-03 15:08 ` Jan Beulich
2021-11-03 15:12   ` Juergen Gross
2021-11-03 15:42 ` Jan Beulich
2021-11-08 14:42   ` Juergen Gross
2021-11-08 14:54     ` Jan Beulich
2021-11-11 16:04 ` Anthony PERARD

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).