Implement FastABI basing on docs/guest-guide/x86/fastabi.pandoc and defined ABI.

Signed-off-by: Teddy Astie <teddy.as...@vates.tech>
---
 xen/arch/x86/cpuid.c               |   3 +
 xen/arch/x86/domain.c              |  71 ++++++++++
 xen/arch/x86/hvm/hvm.c             |  81 +++++++++++-
 xen/arch/x86/hvm/hypercall.c       |  22 ++++
 xen/arch/x86/include/asm/fastabi.h |  17 +++
 xen/common/Kconfig                 |   6 +
 xen/common/Makefile                |   1 +
 xen/common/domain.c                | 179 ++++++++++++++++++++++++++
 xen/common/event_channel.c         | 199 +++++++++++++++++++++++++++++
 xen/common/fastabi.c               |  49 +++++++
 xen/common/grant_table.c           |  44 +++++++
 xen/common/kernel.c                |  33 +++++
 xen/common/memory.c                | 110 ++++++++++++++++
 xen/common/sched/core.c            | 109 +++++++++++++++-
 xen/include/public/event_channel.h |   7 +
 xen/include/public/fastabi.h       |  20 +++
 xen/include/xen/fastabi.h          |  21 +++
 17 files changed, 970 insertions(+), 2 deletions(-)
 create mode 100644 xen/arch/x86/include/asm/fastabi.h
 create mode 100644 xen/common/fastabi.c
 create mode 100644 xen/include/public/fastabi.h
 create mode 100644 xen/include/xen/fastabi.h

diff --git a/xen/arch/x86/cpuid.c b/xen/arch/x86/cpuid.c
index 8dc68945f7..b1f90c1d91 100644
--- a/xen/arch/x86/cpuid.c
+++ b/xen/arch/x86/cpuid.c
@@ -153,6 +153,9 @@ static void cpuid_hypervisor_leaves(const struct vcpu *v, 
uint32_t leaf,
          */
         res->a |= XEN_HVM_CPUID_UPCALL_VECTOR;
 
+        if ( IS_ENABLED(CONFIG_FASTABI) && is_hvm_vcpu(v) )
+            res->a |= XEN_HVM_CPUID_FASTABI;
+
         break;
 
     case 5: /* PV-specific parameters */
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index 56c3816187..44416869a3 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -71,6 +71,10 @@
 #include <public/sysctl.h>
 #include <public/hvm/hvm_vcpu.h>
 
+#ifdef CONFIG_FASTABI
+#include <xen/fastabi.h>
+#endif
+
 #ifdef CONFIG_COMPAT
 #include <compat/vcpu.h>
 #endif
@@ -1695,6 +1699,73 @@ long do_vcpu_op(int cmd, unsigned int vcpuid, 
XEN_GUEST_HANDLE_PARAM(void) arg)
     return rc;
 }
 
+#ifdef CONFIG_FASTABI
+void do_vcpu_fast_op(struct cpu_user_regs *regs)
+{
+    long rc = 0;
+    struct domain *d = current->domain;
+    struct vcpu *v;
+
+    unsigned long cmd = fastabi_value_n(regs, 1);
+    unsigned long vcpuid = fastabi_value_n(regs, 2);
+
+    if ( (v = domain_vcpu(d, vcpuid)) == NULL )
+    {
+        fastabi_value_n(regs, 0) = -ENOENT;
+        return;
+    }
+
+    switch ( cmd )
+    {
+    case VCPUOP_send_nmi:
+        if ( !test_and_set_bool(v->arch.nmi_pending) )
+            vcpu_kick(v);
+        break;
+
+
+    case VCPUOP_register_vcpu_time_phys_area:
+    {
+        struct vcpu_register_time_memory_area area = {
+            .addr.p = fastabi_value_n(regs, 3)
+        };
+
+        rc = -ENOSYS;
+        if ( 0 /* TODO: Dom's XENFEAT_vcpu_time_phys_area setting */ )
+            break;
+
+        rc = map_guest_area(v, area.addr.p,
+                            sizeof(vcpu_time_info_t),
+                            &v->arch.time_guest_area,
+                            time_area_populate);
+        break;
+    }
+
+    case VCPUOP_get_physid:
+    {
+        rc = -EINVAL;
+        if ( !is_hwdom_pinned_vcpu(v) )
+            break;
+
+        fastabi_value_n(regs, 3) =
+            (uint64_t)x86_cpu_to_apicid[v->vcpu_id] |
+            ((uint64_t)acpi_get_processor_id(v->vcpu_id) << 32);
+
+        rc = 0;
+        break;
+    }
+
+    default:
+        rc = common_vcpu_fast_op(regs, cmd, v);
+        break;
+    }
+
+    if ( rc == -ERESTART )
+        fastabi_make_continuation();
+    else
+        fastabi_value_n(regs, 0) = rc;
+}
+#endif
+
 /*
  * Notes on PV segment handling:
  *  - 32bit: All data from the GDT/LDT.
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 8bf59c63fe..eca052e109 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -68,6 +68,10 @@
 
 #include <compat/hvm/hvm_op.h>
 
+#ifdef CONFIG_FASTABI
+#include <xen/fastabi.h>
+#endif
+
 bool __read_mostly hvm_enabled;
 
 #ifdef DBG_LEVEL_0
@@ -4548,7 +4552,7 @@ static int hvmop_get_param(struct xen_hvm_param *op)
 
     rc = -EINVAL;
     if ( is_hvm_domain(d) && !(rc = hvm_get_param(d, op->index, &op->value)) )
-        HVM_DBG_LOG(DBG_LEVEL_HCALL, "get param %u = %"PRIx64, a.index, 
a.value);
+        HVM_DBG_LOG(DBG_LEVEL_HCALL, "get param %u = %"PRIx64, op->index, 
op->value);
 
     rcu_unlock_domain(d);
     return rc;
@@ -5224,6 +5228,81 @@ long do_hvm_op(unsigned long op, 
XEN_GUEST_HANDLE_PARAM(void) arg)
     return rc;
 }
 
+#ifdef CONFIG_FASTABI
+void do_hvm_fast_op(struct cpu_user_regs *regs)
+{
+    long rc = 0;
+    unsigned long op = fastabi_value_n(regs, 1);
+
+    switch ( op )
+    {
+    case HVMOP_set_evtchn_upcall_vector:
+    {
+        struct xen_hvm_evtchn_upcall_vector op = {
+            .vcpu = fastabi_value_n(regs, 2),
+            .vector = fastabi_value_n(regs, 3),
+        };
+
+        rc = hvmop_set_evtchn_upcall_vector(op);
+        break;
+    }
+
+    case HVMOP_set_param:
+    {
+        struct xen_hvm_param op = {
+            .domid = fastabi_value_n(regs, 2),
+            .index = fastabi_value_n(regs, 3),
+            .value = fastabi_value_n(regs, 4),
+        };
+
+        rc = hvmop_set_param(op);
+        break;
+    }
+
+    case HVMOP_get_param:
+    {
+        struct xen_hvm_param op = {
+            .domid = fastabi_value_n(regs, 2),
+            .index = fastabi_value_n(regs, 3),
+        };
+
+        rc = hvmop_get_param(&op);
+        if ( !rc )
+            fastabi_value_n(regs, 4) = op.value;
+        break;
+    }
+
+    case HVMOP_flush_tlbs:
+        rc = hvmop_flush_tlb_all();
+        break;
+
+    case HVMOP_get_time:
+        fastabi_value_n(regs, 2) = NOW();
+        break;
+    
+    case HVMOP_get_mem_type:
+    {
+        struct xen_hvm_get_mem_type op = {
+            .domid = fastabi_value_n(regs, 2),
+            .pfn = fastabi_value_n(regs, 3),
+        };
+
+        rc = hvmop_get_mem_type(&op);
+
+        if ( !rc )
+            fastabi_value_n(regs, 4) = op.mem_type;
+        break;
+    }
+
+    default:
+        rc = -ENOSYS;
+        break;
+    }
+
+    fastabi_value_n(regs, 0) = rc;
+}
+#endif
+
 int hvm_debug_op(struct vcpu *v, int32_t op)
 {
     int rc = 0;
diff --git a/xen/arch/x86/hvm/hypercall.c b/xen/arch/x86/hvm/hypercall.c
index 6f8dfdff4a..3759a1aa58 100644
--- a/xen/arch/x86/hvm/hypercall.c
+++ b/xen/arch/x86/hvm/hypercall.c
@@ -19,6 +19,10 @@
 #include <public/hvm/hvm_op.h>
 #include <public/hvm/params.h>
 
+#ifdef CONFIG_FASTABI
+#include <xen/fastabi.h>
+#endif
+
 long hvm_memory_op(unsigned long cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
 {
     long rc;
@@ -155,6 +159,24 @@ int hvm_hypercall(struct cpu_user_regs *regs)
 
     curr->hcall_preempted = false;
 
+    #ifdef CONFIG_FASTABI
+    if ( eax & 0x40000000U && is_hvm_domain(currd) && mode == X86_MODE_64BIT )
+    {
+        unsigned long index = eax & ~0x40000000U;
+        HVM_DBG_LOG(DBG_LEVEL_HCALL,
+                    "fasthcall%lu(%lx, %lx, %lx, %lx, %lx, %lx, %lx)",
+                    index, fastabi_value_n(regs, 1), fastabi_value_n(regs, 2),
+                    fastabi_value_n(regs, 3), fastabi_value_n(regs, 4),
+                    fastabi_value_n(regs, 5), fastabi_value_n(regs, 6),
+                    fastabi_value_n(regs, 7));
+
+        fastabi_dispatch(index, regs);
+
+        hvmemul_cache_restore(curr, token);
+        return HVM_HCALL_completed;
+    }
+    #endif
+
     if ( mode == 8 )
     {
         HVM_DBG_LOG(DBG_LEVEL_HCALL, "hcall%lu(%lx, %lx, %lx, %lx, %lx)",
diff --git a/xen/arch/x86/include/asm/fastabi.h 
b/xen/arch/x86/include/asm/fastabi.h
new file mode 100644
index 0000000000..914504c63d
--- /dev/null
+++ b/xen/arch/x86/include/asm/fastabi.h
@@ -0,0 +1,17 @@
+#ifndef XEN_ASM_FASTABI_H
+#define XEN_ASM_FASTABI_H
+
+#include <asm/current.h>
+
+#define fastabi_param_reg0 rax
+#define fastabi_param_reg1 rdi
+#define fastabi_param_reg2 rsi
+#define fastabi_param_reg3 r8
+#define fastabi_param_reg4 r9
+#define fastabi_param_reg5 r10
+#define fastabi_param_reg6 r11
+#define fastabi_param_reg7 r12
+
+#define fastabi_value_n(regs, n) (regs)->fastabi_param_reg##n
+
+#endif /* XEN_ASM_FASTABI_H */
\ No newline at end of file
diff --git a/xen/common/Kconfig b/xen/common/Kconfig
index 65f07289dd..71bb4e4f2d 100644
--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -636,4 +636,10 @@ config PM_STATS
          Enable collection of performance management statistics to aid in
          analyzing and tuning power/performance characteristics of the system
 
+config FASTABI
+       depends on X86 && HVM
+       bool "Fast HVM ABI (unsupported)"
+       help
+               Add support for a alternative fast HVM ABI.
+
 endmenu
diff --git a/xen/common/Makefile b/xen/common/Makefile
index 98f0873056..362e8f61d7 100644
--- a/xen/common/Makefile
+++ b/xen/common/Makefile
@@ -62,6 +62,7 @@ obj-y += wait.o
 obj-bin-y += warning.init.o
 obj-$(CONFIG_XENOPROF) += xenoprof.o
 obj-y += xmalloc_tlsf.o
+obj-$(CONFIG_FASTABI) += fastabi.o
 
 obj-bin-$(CONFIG_X86) += $(foreach n,decompress bunzip2 unxz unlzma lzo unlzo 
unlz4 unzstd earlycpio,$(n).init.o)
 
diff --git a/xen/common/domain.c b/xen/common/domain.c
index 303c338ef2..5a641403b9 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -45,6 +45,10 @@
 #include <xen/trace.h>
 #include <asm/setup.h>
 
+#ifdef CONFIG_FASTABI
+#include <xen/fastabi.h>
+#endif
+
 #ifdef CONFIG_X86
 #include <asm/guest.h>
 #endif
@@ -2266,6 +2270,181 @@ long common_vcpu_op(int cmd, struct vcpu *v, 
XEN_GUEST_HANDLE_PARAM(void) arg)
     return rc;
 }
 
+#ifdef CONFIG_FASTABI
+long common_vcpu_fast_op(struct cpu_user_regs *regs, int cmd, struct vcpu *v)
+{
+    long rc = 0;
+    struct domain *d = v->domain;
+    unsigned int vcpuid = v->vcpu_id;
+
+    switch ( cmd )
+    {
+    case VCPUOP_initialise:
+        rc = arch_initialise_vcpu(v, (XEN_GUEST_HANDLE(void)) { 
+            (void *)fastabi_value_n(regs, 2) });
+        break;
+
+    case VCPUOP_up:
+    {
+        bool wake = false;
+
+        domain_lock(d);
+        if ( !v->is_initialised )
+            rc = -EINVAL;
+        else
+            wake = test_and_clear_bit(_VPF_down, &v->pause_flags);
+        domain_unlock(d);
+        if ( wake )
+            vcpu_wake(v);
+    }
+
+        break;
+
+    case VCPUOP_down:
+        for_each_vcpu ( d, v )
+            if ( !test_bit(_VPF_down, &v->pause_flags) )
+            {
+               rc = 1;
+               break;
+            }
+
+        if ( !rc ) /* Last vcpu going down? */
+        {
+            domain_shutdown(d, SHUTDOWN_poweroff);
+            break;
+        }
+
+        rc = 0;
+        v = d->vcpu[vcpuid];
+
+        if ( !test_and_set_bit(_VPF_down, &v->pause_flags) )
+            vcpu_sleep_nosync(v);
+
+        break;
+
+    case VCPUOP_is_up:
+        rc = !(v->pause_flags & VPF_down);
+        break;
+
+    case VCPUOP_get_runstate_info:
+    {
+        struct vcpu_runstate_info runstate;
+        vcpu_runstate_get(v, &runstate);
+
+        fastabi_value_n(regs, 2) = runstate.state;
+        fastabi_value_n(regs, 3) = runstate.state_entry_time;
+        fastabi_value_n(regs, 4) = runstate.time[0];
+        fastabi_value_n(regs, 5) = runstate.time[1];
+        fastabi_value_n(regs, 6) = runstate.time[2];
+        fastabi_value_n(regs, 7) = runstate.time[3];
+        break;
+    }
+
+    case VCPUOP_set_periodic_timer:
+    {
+        uint64_t period_ns = fastabi_value_n(regs, 3);
+
+        if ( period_ns < MILLISECS(1) )
+            return -EINVAL;
+
+        if ( period_ns > STIME_DELTA_MAX )
+            return -EINVAL;
+
+        vcpu_set_periodic_timer(v, period_ns);
+
+        break;
+    }
+
+    case VCPUOP_stop_periodic_timer:
+        vcpu_set_periodic_timer(v, 0);
+        break;
+
+    case VCPUOP_set_singleshot_timer:
+    {
+        struct vcpu_set_singleshot_timer set = {
+            .timeout_abs_ns = fastabi_value_n(regs, 3),
+            .flags = fastabi_value_n(regs, 4),
+        };
+
+        if ( v != current )
+            return -EINVAL;
+
+        if ( set.timeout_abs_ns < NOW() )
+        {
+            /*
+             * Simplify the logic if the timeout has already expired and just
+             * inject the event.
+             */
+            stop_timer(&v->singleshot_timer);
+            send_timer_event(v);
+            break;
+        }
+
+        migrate_timer(&v->singleshot_timer, smp_processor_id());
+        set_timer(&v->singleshot_timer, set.timeout_abs_ns);
+
+        break;
+    }
+
+    case VCPUOP_stop_singleshot_timer:
+        if ( v != current )
+            return -EINVAL;
+
+        stop_timer(&v->singleshot_timer);
+
+        break;
+
+    case VCPUOP_register_vcpu_info:
+    {
+        struct vcpu_register_vcpu_info info = {
+            .mfn = fastabi_value_n(regs, 3),
+            .offset = fastabi_value_n(regs, 4)
+        };
+        paddr_t gaddr;
+
+        rc = -EINVAL;
+        gaddr = gfn_to_gaddr(_gfn(info.mfn)) + info.offset;
+        if ( !~gaddr ||
+             gfn_x(gaddr_to_gfn(gaddr)) != info.mfn )
+            break;
+
+        /* Preliminary check only; see map_guest_area(). */
+        rc = -EBUSY;
+        if ( v->vcpu_info_area.pg )
+            break;
+
+        /* See the BUILD_BUG_ON() in vcpu_info_populate(). */
+        rc = map_guest_area(v, gaddr, sizeof(vcpu_info_t),
+                            &v->vcpu_info_area, vcpu_info_populate);
+        break;
+    }
+
+    case VCPUOP_register_runstate_phys_area:
+    {
+        struct vcpu_register_runstate_memory_area area = {
+            .addr.p = fastabi_value_n(regs, 3)
+        };
+
+        rc = -ENOSYS;
+        if ( 0 /* TODO: Dom's XENFEAT_runstate_phys_area setting */ )
+            break;
+
+        rc = map_guest_area(v, area.addr.p,
+                            sizeof(struct vcpu_runstate_info),
+                            &v->runstate_guest_area,
+                            runstate_area_populate);
+        break;
+    }
+
+    default:
+        rc = -ENOSYS;
+        break;
+    }
+
+    return rc;
+}
+#endif
+
 #ifdef arch_vm_assist_valid_mask
 long do_vm_assist(unsigned int cmd, unsigned int type)
 {
diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c
index c8c1bfa615..9c8bc0f354 100644
--- a/xen/common/event_channel.c
+++ b/xen/common/event_channel.c
@@ -34,6 +34,10 @@
 #include <public/event_channel.h>
 #include <xsm/xsm.h>
 
+#ifdef CONFIG_FASTABI
+#include <xen/fastabi.h>
+#endif
+
 #ifdef CONFIG_PV_SHIM
 #include <asm/guest.h>
 #endif
@@ -1507,6 +1511,201 @@ long do_event_channel_op(int cmd, 
XEN_GUEST_HANDLE_PARAM(void) arg)
     return rc;
 }
 
+#ifdef CONFIG_FASTABI
+void do_event_channel_fast_op(struct cpu_user_regs *regs)
+{
+    long rc;
+    uint64_t cmd = fastabi_value_n(regs, 1);
+
+    switch ( cmd )
+    {
+    case EVTCHNOP_alloc_unbound: {
+        struct evtchn_alloc_unbound alloc_unbound = {
+            .dom = fastabi_value_n(regs, 2),
+            .remote_dom = fastabi_value_n(regs, 3),
+            .port = 0,
+        };
+        rc = evtchn_alloc_unbound(&alloc_unbound, 0);
+
+        if ( !rc )
+            fastabi_value_n(regs, 4) = alloc_unbound.port;
+        break;
+    }
+
+    case EVTCHNOP_bind_interdomain: {
+        struct evtchn_bind_interdomain bind_interdomain = {
+            .remote_dom = fastabi_value_n(regs, 2),
+            .remote_port = fastabi_value_n(regs, 3),
+            .local_port = 0,
+        };
+        rc = evtchn_bind_interdomain(&bind_interdomain, current->domain, 0);
+
+        if ( !rc )
+            fastabi_value_n(regs, 4) = bind_interdomain.local_port;
+        break;
+    }
+
+    case EVTCHNOP_bind_virq: {
+        struct evtchn_bind_virq bind_virq = {
+            .virq = fastabi_value_n(regs, 2),
+            .vcpu = fastabi_value_n(regs, 3),
+            .port = 0,
+        };
+        rc = evtchn_bind_virq(&bind_virq, 0);
+
+        if ( !rc )
+            fastabi_value_n(regs, 4) = bind_virq.port;
+        break;
+    }
+
+    case EVTCHNOP_bind_ipi: {
+        struct evtchn_bind_ipi bind_ipi = {
+            .vcpu = fastabi_value_n(regs, 2),
+            .port = 0,
+        };
+        rc = evtchn_bind_ipi(&bind_ipi);
+
+        if ( !rc )
+            fastabi_value_n(regs, 4) = bind_ipi.port;
+        break;
+    }
+
+    case EVTCHNOP_bind_pirq: {
+        struct evtchn_bind_pirq bind_pirq = {
+            .pirq = fastabi_value_n(regs, 2),
+            .flags = fastabi_value_n(regs, 3),
+        };
+        rc = evtchn_bind_pirq(&bind_pirq);
+
+        if ( !rc )
+            fastabi_value_n(regs, 4) = bind_pirq.port;
+        break;
+    }
+
+    case EVTCHNOP_close: {
+        struct evtchn_close close = { .port = fastabi_value_n(regs, 2) };
+        rc = evtchn_close(current->domain, close.port, 1);
+        break;
+    }
+
+    case EVTCHNOP_send: {
+        struct evtchn_send send = { .port = fastabi_value_n(regs, 2) };
+        rc = evtchn_send(current->domain, send.port);
+        break;
+    }
+
+    case EVTCHNOP_status: {
+        struct evtchn_status status = {
+            .dom = fastabi_value_n(regs, 2),
+            .port = fastabi_value_n(regs, 3),
+        };
+        rc = evtchn_status(&status);
+
+        if ( !rc )
+        {
+            fastabi_value_n(regs, 4) = status.status;
+            fastabi_value_n(regs, 5) = status.vcpu;
+
+            switch (status.status)
+            {
+            case EVTCHNSTAT_unbound:
+                fastabi_value_n(regs, 6) = status.u.unbound.dom;
+                break;
+            case EVTCHNSTAT_interdomain:
+                fastabi_value_n(regs, 6) = status.u.interdomain.dom;
+                fastabi_value_n(regs, 7) = status.u.interdomain.port;
+                break;
+            case EVTCHNSTAT_pirq:
+                fastabi_value_n(regs, 6) = status.u.pirq;
+                break;
+            case EVTCHNSTAT_virq:
+                fastabi_value_n(regs, 6) = status.u.virq;
+                break;
+            default:
+                break;
+            }
+        }
+        break;
+    }
+
+    case EVTCHNOP_bind_vcpu: {
+        struct evtchn_bind_vcpu bind_vcpu = {
+            .vcpu = fastabi_value_n(regs, 2),
+            .port = fastabi_value_n(regs, 3)
+        };
+        rc = evtchn_bind_vcpu(bind_vcpu.port, bind_vcpu.vcpu);
+        break;
+    }
+
+    case EVTCHNOP_unmask: {
+        struct evtchn_unmask unmask = { .port = fastabi_value_n(regs, 2) };
+        rc = evtchn_unmask(unmask.port);
+        break;
+    }
+
+    case EVTCHNOP_reset:
+    case EVTCHNOP_reset_cont: {
+        struct evtchn_reset reset = { .dom = fastabi_value_n(regs, 2) };
+        struct domain *d;
+
+        d = rcu_lock_domain_by_any_id(reset.dom);
+        if ( d == NULL )
+        {
+            rc = -ESRCH;
+            break;
+        }
+
+        rc = xsm_evtchn_reset(XSM_TARGET, current->domain, d);
+        if ( !rc )
+            rc = evtchn_reset(d, cmd == EVTCHNOP_reset_cont);
+
+        rcu_unlock_domain(d);
+
+        if ( rc == -ERESTART )
+        {
+            fastabi_value_n(regs, 1) = EVTCHNOP_reset_cont;
+            fastabi_make_continuation();
+            return;
+        }
+        break;
+    }
+
+    case EVTCHNOP_init_control: {
+        struct evtchn_init_control init_control = {
+            .control_gfn = fastabi_value_n(regs, 2),
+            .offset = fastabi_value_n(regs, 3),
+            .vcpu = fastabi_value_n(regs, 4)
+        };
+        rc = evtchn_fifo_init_control(&init_control);
+
+        if ( !rc )
+            fastabi_value_n(regs, 5) = init_control.link_bits;
+        break;
+    }
+
+    case EVTCHNOP_expand_array: {
+        struct evtchn_expand_array expand_array = { .array_gfn = 
fastabi_value_n(regs, 2) };
+        rc = evtchn_fifo_expand_array(&expand_array);
+        break;
+    }
+
+    case EVTCHNOP_set_priority: {
+        struct evtchn_set_priority set_priority = {
+            .port = fastabi_value_n(regs, 2),
+            .priority = fastabi_value_n(regs, 3),
+        };
+        rc = evtchn_set_priority(&set_priority);
+        break;
+    }
+
+    default:
+        rc = -ENOSYS;
+        break;
+    }
+
+    fastabi_value_n(regs, 0) = rc;
+}
+#endif
 
 int alloc_unbound_xen_event_channel(
     struct domain *ld, unsigned int lvcpu, domid_t remote_domid,
diff --git a/xen/common/fastabi.c b/xen/common/fastabi.c
new file mode 100644
index 0000000000..96a3b05ee7
--- /dev/null
+++ b/xen/common/fastabi.c
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <xen/errno.h>
+#include <xen/fastabi.h>
+#include <xen/sched.h>
+
+#include <public/xen.h>
+
+void fastabi_make_continuation(void)
+{
+    current->hcall_preempted = true;
+}
+
+void fastabi_dispatch(unsigned long index, struct cpu_user_regs *regs)
+{
+    switch (index) {
+    case __HYPERVISOR_memory_op:
+        do_memory_fast_op(regs);
+        break;
+
+    case __HYPERVISOR_xen_version:
+        do_xen_version_fast_op(regs);
+        break;
+    
+    case __HYPERVISOR_grant_table_op:
+        do_grant_table_fast_op(regs);
+        break;
+
+    case __HYPERVISOR_vcpu_op:
+        do_vcpu_fast_op(regs);
+        break;
+
+    case __HYPERVISOR_sched_op:
+        do_sched_fast_op(regs);
+        break;
+
+    case __HYPERVISOR_event_channel_op:
+        do_event_channel_fast_op(regs);
+        break;
+
+    case __HYPERVISOR_hvm_op:
+        do_hvm_fast_op(regs);
+        break;
+
+    default:
+        fastabi_value_n(regs, 0) = -ENOSYS;
+        break;
+    }
+}
\ No newline at end of file
diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index 3c3bbca2fc..1476e5e5ca 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -45,6 +45,10 @@
 #include <asm/flushtlb.h>
 #include <asm/guest_atomics.h>
 
+#ifdef CONFIG_FASTABI
+#include <xen/fastabi.h>
+#endif
+
 #ifdef CONFIG_PV_SHIM
 #include <asm/guest.h>
 #endif
@@ -3826,6 +3830,46 @@ long do_grant_table_op(
     return rc;
 }
 
+#ifdef CONFIG_FASTABI
+void do_grant_table_fast_op(struct cpu_user_regs *regs)
+{
+    long rc = 0;
+    unsigned int cmd = fastabi_value_n(regs, 1);
+
+    switch (cmd)
+    {
+    case GNTTABOP_query_size:
+    {
+        struct grant_table *gt = current->domain->grant_table;
+
+        grant_read_lock(gt);
+        fastabi_value_n(regs, 2) = nr_grant_frames(gt);
+        fastabi_value_n(regs, 3) = gt->max_grant_frames;
+        grant_read_unlock(gt);
+        break;
+    }
+    case GNTTABOP_get_version:
+    {
+        struct grant_table *gt = current->domain->grant_table;
+
+        fastabi_value_n(regs, 2) = gt->gt_version;
+        break;
+    }
+    case GNTTABOP_set_version:
+    {
+        gnttab_set_version_t op = { .version = fastabi_value_n(regs, 2) };
+        rc = gnttab_set_version(&op);
+        break;
+    }
+    default:
+        rc = -ENOSYS;
+        break;
+    }
+
+    fastabi_value_n(regs, 0) = rc;
+}
+#endif
+
 #ifdef CONFIG_COMPAT
 #include "compat/grant_table.c"
 #endif
diff --git a/xen/common/kernel.c b/xen/common/kernel.c
index eff6db6c8f..2230ccdcaf 100644
--- a/xen/common/kernel.c
+++ b/xen/common/kernel.c
@@ -18,6 +18,10 @@
 #include <asm/current.h>
 #include <public/version.h>
 
+#ifdef CONFIG_FASTABI
+#include <xen/fastabi.h>
+#endif
+
 #ifdef CONFIG_COMPAT
 #include <compat/version.h>
 
@@ -772,6 +776,35 @@ long do_xen_version(int cmd, XEN_GUEST_HANDLE_PARAM(void) 
arg)
     return -ENOSYS;
 }
 
+#ifdef CONFIG_FASTABI
+void do_xen_version_fast_op(struct cpu_user_regs *regs)
+{
+    long cmd = fastabi_value_n(regs, 1);
+    long rc = 0;
+
+    switch ( cmd ) {
+    case XENVER_version:
+        rc = (xen_major_version() << 16) | xen_minor_version();
+        break;
+    case XENVER_get_features:
+    {
+        uint32_t submap = 0, submap_idx = fastabi_value_n(regs, 2);
+
+        rc = xenver_get_features(current->domain, submap_idx, &submap);
+
+        if ( !rc )
+            fastabi_value_n(regs, 3) = submap;
+        break;
+    }
+    default:
+        rc = -ENOSYS;
+        break;
+    }
+
+    fastabi_value_n(regs, 0) = rc;
+}
+#endif
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/common/memory.c b/xen/common/memory.c
index 3688e6dd50..689218390e 100644
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -35,6 +35,10 @@
 #include <public/memory.h>
 #include <xsm/xsm.h>
 
+#ifdef CONFIG_FASTABI
+#include <xen/fastabi.h>
+#endif
+
 #ifdef CONFIG_X86
 #include <asm/guest.h>
 #endif
@@ -1864,6 +1868,112 @@ long do_memory_op(unsigned long cmd, 
XEN_GUEST_HANDLE_PARAM(void) arg)
     return rc;
 }
 
+#ifdef CONFIG_FASTABI
+void do_memory_fast_op(struct cpu_user_regs *regs)
+{
+    unsigned long cmd = fastabi_value_n(regs, 1);
+    unsigned long start_extent = cmd >> MEMOP_EXTENT_SHIFT;
+    long rc;
+    int op = cmd & MEMOP_CMD_MASK;
+
+    switch ( op ) {
+    case XENMEM_add_to_physmap:
+    {
+        struct xen_add_to_physmap xatp = {
+            .size = fastabi_value_n(regs, 2),
+            .space = fastabi_value_n(regs, 3),
+            .idx = fastabi_value_n(regs, 4),
+            .gpfn = fastabi_value_n(regs, 5)
+        };
+
+        BUILD_BUG_ON((typeof(xatp.size))-1 > (UINT_MAX >> MEMOP_EXTENT_SHIFT));
+
+        /* Check for malicious or buggy input. */
+        if ( start_extent != (typeof(xatp.size))start_extent )
+        {
+            rc = -EDOM;
+            break;
+        }
+
+        /* Foreign mapping is only possible via add_to_physmap_batch. */
+        if ( xatp.space == XENMAPSPACE_gmfn_foreign )
+        {
+            rc = -ENOSYS;
+            break;
+        }
+
+        rc = xatp_permission_check(current->domain, xatp.space);
+        if ( rc )
+            break;
+
+        rc = xenmem_add_to_physmap(current->domain, &xatp, start_extent);
+
+        if ( xatp.space == XENMAPSPACE_gmfn_range && rc > 0 )
+            panic("TODO");
+            //rc = hypercall_create_continuation(
+            //         __HYPERVISOR_memory_op, "lh",
+            //         op | (rc << MEMOP_EXTENT_SHIFT), arg);
+        break;
+    }
+    
+    case XENMEM_remove_from_physmap:
+    {
+        unsigned long gpfn = fastabi_value_n(regs, 5);
+        struct page_info *page;
+
+        if ( unlikely(start_extent) )
+        {
+            rc = -EINVAL;
+            break;
+        }
+
+        if ( !paging_mode_translate(current->domain) )
+        {
+            rc = -EACCES;
+            break;
+        }
+
+        page = get_page_from_gfn(current->domain, gpfn, NULL, P2M_ALLOC);
+        if ( page )
+        {
+            rc = guest_physmap_remove_page(current->domain, _gfn(gpfn),
+                                           page_to_mfn(page), 0);
+            put_page(page);
+        }
+        else
+            rc = -ENOENT;
+
+        break;
+    }
+    
+    case XENMEM_memory_map:
+    {
+        struct domain *d = current->domain;
+        unsigned long nr_entries = fastabi_value_n(regs, 2);
+        paddr_t buffer_addr = fastabi_value_n(regs, 3);
+
+        spin_lock(&d->arch.e820_lock);
+
+        if ( nr_entries > d->arch.nr_e820 )
+            nr_entries = d->arch.nr_e820;
+
+        if ( hvm_copy_to_guest_phys(buffer_addr, d->arch.e820,
+                                    nr_entries * sizeof(struct e820entry), 
current) )
+            rc = -EFAULT;
+
+        spin_unlock(&d->arch.e820_lock);
+        break;
+    }
+
+    default:
+        rc = -ENOSYS;
+        break;
+    }
+
+    fastabi_value_n(regs, 0) = rc;
+}
+#endif
+
 void clear_domain_page(mfn_t mfn)
 {
     void *ptr = map_domain_page(mfn);
diff --git a/xen/common/sched/core.c b/xen/common/sched/core.c
index b2c784c60e..51b2fbc00a 100644
--- a/xen/common/sched/core.c
+++ b/xen/common/sched/core.c
@@ -41,6 +41,10 @@
 
 #include "private.h"
 
+#ifdef CONFIG_FASTABI
+#include <xen/fastabi.h>
+#endif
+
 #ifdef CONFIG_XEN_GUEST
 #include <asm/guest.h>
 #else
@@ -1896,6 +1900,110 @@ void domain_update_node_aff(struct domain *d, struct 
affinity_masks *affinity)
 
 typedef long ret_t;
 
+#ifdef CONFIG_FASTABI
+void do_sched_fast_op(struct cpu_user_regs *regs)
+{
+    long ret = 0;
+    unsigned long cmd = fastabi_value_n(regs, 1);
+
+    switch ( cmd )
+    {
+    case SCHEDOP_yield:
+    {
+        ret = vcpu_yield();
+        break;
+    }
+
+    case SCHEDOP_block:
+    {
+        vcpu_block_enable_events();
+        break;
+    }
+
+    case SCHEDOP_shutdown:
+    {
+        struct sched_shutdown sched_shutdown = {
+            .reason = fastabi_value_n(regs, 2)
+        };
+
+        TRACE_TIME(TRC_SCHED_SHUTDOWN, current->domain->domain_id,
+                   current->vcpu_id, sched_shutdown.reason);
+        ret = domain_shutdown(current->domain, (u8)sched_shutdown.reason);
+
+        break;
+    }
+
+    case SCHEDOP_shutdown_code:
+    {
+        struct sched_shutdown sched_shutdown = {
+            .reason = fastabi_value_n(regs, 2)
+        };
+        struct domain *d = current->domain;
+
+        TRACE_TIME(TRC_SCHED_SHUTDOWN_CODE, d->domain_id, current->vcpu_id,
+                   sched_shutdown.reason);
+
+        spin_lock(&d->shutdown_lock);
+        if ( d->shutdown_code == SHUTDOWN_CODE_INVALID )
+            d->shutdown_code = (u8)sched_shutdown.reason;
+        spin_unlock(&d->shutdown_lock);
+
+        ret = 0;
+        break;
+    }
+
+    case SCHEDOP_poll:
+    {
+        uint64_t timeout = fastabi_value_n(regs, 2);
+        evtchn_port_t port = fastabi_value_n(regs, 3);
+
+        ret = vcpu_poll(1, timeout, &port);
+
+        break;
+    }
+
+    case SCHEDOP_watchdog:
+    {
+        struct sched_watchdog sched_watchdog = {
+            .id = fastabi_value_n(regs, 2),
+            .timeout = fastabi_value_n(regs, 3)
+        };
+
+        ret = domain_watchdog(
+            current->domain, sched_watchdog.id, sched_watchdog.timeout);
+        break;
+    }
+
+    case SCHEDOP_pin_override:
+    {
+        struct sched_pin_override sched_pin_override = {
+            .pcpu = fastabi_value_n(regs, 2),
+        };
+        unsigned int cpu;
+
+        ret = -EPERM;
+        if ( !is_hardware_domain(current->domain) )
+            break;
+
+        ret = -EINVAL;
+        if ( sched_pin_override.pcpu >= NR_CPUS )
+           break;
+
+        cpu = sched_pin_override.pcpu < 0 ? NR_CPUS : sched_pin_override.pcpu;
+        ret = vcpu_temporary_affinity(current, cpu, VCPU_AFFINITY_OVERRIDE);
+
+        break;
+    }
+
+    default:
+        ret = -ENOSYS;
+        break;
+    }
+
+    fastabi_value_n(regs, 0) = ret;
+}
+#endif
+
 #endif /* !COMPAT */
 
 ret_t do_sched_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
@@ -1961,7 +2069,6 @@ ret_t do_sched_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) 
arg)
             break;
 
         ret = do_poll(&sched_poll);
-
         break;
     }
 
diff --git a/xen/include/public/event_channel.h 
b/xen/include/public/event_channel.h
index c5548d206c..969c9ec264 100644
--- a/xen/include/public/event_channel.h
+++ b/xen/include/public/event_channel.h
@@ -208,10 +208,17 @@ struct evtchn_status {
         } unbound;                 /* EVTCHNSTAT_unbound */
         struct {
             domid_t dom;
+            uint16_t _pad;
             evtchn_port_t port;
         } interdomain;             /* EVTCHNSTAT_interdomain */
         uint32_t pirq;             /* EVTCHNSTAT_pirq        */
         uint32_t virq;             /* EVTCHNSTAT_virq        */
+#ifndef __XEN__
+        struct {
+            uint32_t _output1;
+            uint32_t _output2;
+        };
+#endif
     } u;
 };
 typedef struct evtchn_status evtchn_status_t;
diff --git a/xen/include/public/fastabi.h b/xen/include/public/fastabi.h
new file mode 100644
index 0000000000..51f5085ce6
--- /dev/null
+++ b/xen/include/public/fastabi.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: MIT */
+#ifndef __XEN_PUBLIC_FASTABI_H__
+#define __XEN_PUBLIC_FASTABI_H__
+
+#if defined(__x86_64__)
+#define __HYPERVISOR_FASTABI_MASK 0x40000000U
+
+enum xen_hypercall_vendor {
+    Intel,
+    Amd
+};
+#else
+#define __HYPERVISOR_FASTABI_MASK 0
+
+enum xen_hypercall_vendor {
+    Native
+};
+#endif
+
+#endif
diff --git a/xen/include/xen/fastabi.h b/xen/include/xen/fastabi.h
new file mode 100644
index 0000000000..83ede943e0
--- /dev/null
+++ b/xen/include/xen/fastabi.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef XEN_FASTABI_H
+#define XEN_FASTABI_H
+
+#include <asm/fastabi.h>
+
+void fastabi_dispatch(unsigned long index, struct cpu_user_regs *regs);
+void fastabi_make_continuation(void);
+
+void do_event_channel_fast_op(struct cpu_user_regs *regs);
+
+long common_vcpu_fast_op(struct cpu_user_regs *regs, int cmd, struct vcpu *v);
+void do_vcpu_fast_op(struct cpu_user_regs *regs);
+void do_hvm_fast_op(struct cpu_user_regs *regs);
+void do_memory_fast_op(struct cpu_user_regs *regs);
+void do_grant_table_fast_op(struct cpu_user_regs *regs);
+void do_sched_fast_op(struct cpu_user_regs *regs);
+void do_xen_version_fast_op(struct cpu_user_regs *regs);
+
+#endif /* XEN_FASTABI_H */
\ No newline at end of file
-- 
2.50.1



Teddy Astie | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech


Reply via email to