xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 0/9] x86/hvm: New Xen HVM ABI proposal ("HVMv2" part 1)
@ 2025-08-21 15:25 Teddy Astie
  2025-08-21 15:25 ` [RFC PATCH 1/9] x86/hvm: Use direct structures instead of guest handles Teddy Astie
                   ` (8 more replies)
  0 siblings, 9 replies; 24+ messages in thread
From: Teddy Astie @ 2025-08-21 15:25 UTC (permalink / raw)
  To: xen-devel
  Cc: Teddy Astie, Jan Beulich, Andrew Cooper, Roger Pau Monné,
	Anthony PERARD, Michal Orzel, Julien Grall, Stefano Stabellini,
	Juergen Gross, Dario Faggioli, George Dunlap, Daniel P. Smith

Hello, this series introduce a new hypercall ABI proposal (x86 only for now).

The current Xen ABI has some shortcommings :

First, the hypercall parameters are usually pointers that point to a structure
in guest memory, this pointer is usually a virtual address. 
It causes various issues as :
 - you need to define a format for these structures which is currently C
   structures, but it complicates support with non LP64 platforms (e.g Windows)
   or other programming languages (e.g Rust, where solutions are hard to come with)
 - the translation from virtual address to machine physical address is very expensive
   as you need to translate the GVA to GPA, and then GPA to HPA each time you want to
   access a virtual address
 - such virtual addresses are not readable under confidential computing guests which
   makes such new ABI required.

Another issue is that all possible Xen hypercalls are exposed through this
single interface, it makes hardening the hypervisor more complicated as you
need to permission check on a per-hypercall basis (e.g through XSM) instead
of having a minimal strict safe-for-guest-use set of operations.

The current ABI allows the guest to modify its physmap; this is notably used for
mapping the shared info, grant table and ballooning. While we could make that work
for confidential guests. It comes with its own set of problems, and in order to
simplify the memory management, this series come with a proposal for mapping these
specific pages in advance and telling the guest the location. That helps reducing
the scope of this new ABI. Ballooning implementation hasn't been fully considered yet.

This series propose a new hypercall interface designed for use by guests kernels
with high performance (low hypercall overhead) and confidential computing environments
(notably AMD SEV) compatibility in mind. It currently only supports x86 long mode
(64-bits) due to specific register requirements.

It doesn't aim to entirely replace the current ABI, but to propose a alternative
one that could be used by guests as a fast-path ABI or for confidential computing
guests.

This new ABI maps into current many operations (with some limitations), a tool is
provided to generate C stubs using the yaml specification.
These C stubs reuse the existing hypercall structures to ease adding support
for this ABI in guests.

You can find some example generated headers in Linux SEV WIP branch [1].

[1] https://github.com/xcp-ng/linux/tree/xen-sev-6.14/include/xen/interface/fastabi

Teddy Astie (9):
  x86/hvm: Use direct structures instead of guest handles
  common: Isolate XENVER_get_features into a separate function
  common/grant_table: Use direct structures instead of guest handles
  hvm: Introduce "fixed memory layout" feature
  docs/x86: Introduce FastABI
  sched: Extract do_poll main logic into vcpu_poll
  x86/hvm: Introduce FastABI implementation
  hvm: Introduce XEN_HVM_MEMMAP_TYPE_HOTPLUG_ZONE
  tools: Introduce abi-tool

 docs/guest-guide/x86/fastabi.pandoc           |  50 +++++
 .../x86/fixed-memory-layout.pandoc            |  24 ++
 docs/guest-guide/x86/index.rst                |   2 +
 tools/include/xen-tools/common-macros.h       |   4 +
 tools/libs/guest/xg_dom_x86.c                 |  84 +++++++
 tools/libs/light/libxl_create.c               |   1 +
 tools/libs/light/libxl_types.idl              |   1 +
 tools/libs/light/libxl_x86.c                  |  71 ++++++
 tools/xl/xl_parse.c                           |   1 +
 xen/abi/event_channel.yml                     | 130 +++++++++++
 xen/abi/grant_table.yml                       |  46 ++++
 xen/abi/hvm.yml                               |  50 +++++
 xen/abi/memory.yml                            |  11 +
 xen/abi/sched.yml                             |  48 ++++
 xen/abi/vcpu.yml                              | 139 ++++++++++++
 xen/abi/version.yml                           |  15 ++
 xen/arch/x86/cpuid.c                          |   3 +
 xen/arch/x86/domain.c                         |  71 ++++++
 xen/arch/x86/hvm/hvm.c                        | 205 +++++++++++++-----
 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                      | 112 +++++++---
 xen/common/kernel.c                           | 117 ++++++----
 xen/common/memory.c                           | 110 ++++++++++
 xen/common/sched/core.c                       | 149 +++++++++++--
 xen/include/public/arch-x86/cpuid.h           |   4 +
 xen/include/public/arch-x86/hvm/start_info.h  |   8 +
 xen/include/public/event_channel.h            |   7 +
 xen/include/public/fastabi.h                  |  20 ++
 xen/include/xen/fastabi.h                     |  21 ++
 xen/tools/abi-tool/.gitignore                 |   1 +
 xen/tools/abi-tool/Cargo.lock                 | 145 +++++++++++++
 xen/tools/abi-tool/Cargo.toml                 |  11 +
 xen/tools/abi-tool/src/abi.rs                 |  23 ++
 xen/tools/abi-tool/src/c_lang.rs              | 173 +++++++++++++++
 xen/tools/abi-tool/src/main.rs                |  17 ++
 xen/tools/abi-tool/src/spec.rs                |  61 ++++++
 42 files changed, 2265 insertions(+), 143 deletions(-)
 create mode 100644 docs/guest-guide/x86/fastabi.pandoc
 create mode 100644 docs/guest-guide/x86/fixed-memory-layout.pandoc
 create mode 100644 xen/abi/event_channel.yml
 create mode 100644 xen/abi/grant_table.yml
 create mode 100644 xen/abi/hvm.yml
 create mode 100644 xen/abi/memory.yml
 create mode 100644 xen/abi/sched.yml
 create mode 100644 xen/abi/vcpu.yml
 create mode 100644 xen/abi/version.yml
 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
 create mode 100644 xen/tools/abi-tool/.gitignore
 create mode 100644 xen/tools/abi-tool/Cargo.lock
 create mode 100644 xen/tools/abi-tool/Cargo.toml
 create mode 100644 xen/tools/abi-tool/src/abi.rs
 create mode 100644 xen/tools/abi-tool/src/c_lang.rs
 create mode 100644 xen/tools/abi-tool/src/main.rs
 create mode 100644 xen/tools/abi-tool/src/spec.rs

-- 
2.50.1



Teddy Astie | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech



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

* [RFC PATCH 1/9] x86/hvm: Use direct structures instead of guest handles
  2025-08-21 15:25 [RFC PATCH 0/9] x86/hvm: New Xen HVM ABI proposal ("HVMv2" part 1) Teddy Astie
@ 2025-08-21 15:25 ` Teddy Astie
  2025-08-28 12:16   ` Jan Beulich
  2025-08-21 15:25 ` [RFC PATCH 2/9] common: Isolate XENVER_get_features into a separate function Teddy Astie
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 24+ messages in thread
From: Teddy Astie @ 2025-08-21 15:25 UTC (permalink / raw)
  To: xen-devel; +Cc: Teddy Astie, Jan Beulich, Andrew Cooper, Roger Pau Monné

Make these functions work with hypervisor-owned pointer rather than
guest handles, so the function parameters don't have to live in guest memory.

No functional changes intended.

Signed-off-by: Teddy Astie <teddy.astie@vates.tech>
---
 xen/arch/x86/hvm/hvm.c | 126 +++++++++++++++++++++++------------------
 1 file changed, 70 insertions(+), 56 deletions(-)

diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 56c7de3977..8bf59c63fe 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -4142,19 +4142,14 @@ static int hvmop_flush_tlb_all(void)
     return paging_flush_tlb(NULL) ? 0 : -ERESTART;
 }
 
-static int hvmop_set_evtchn_upcall_vector(
-    XEN_GUEST_HANDLE_PARAM(xen_hvm_evtchn_upcall_vector_t) uop)
+static int hvmop_set_evtchn_upcall_vector(xen_hvm_evtchn_upcall_vector_t op)
 {
-    xen_hvm_evtchn_upcall_vector_t op;
     struct domain *d = current->domain;
     struct vcpu *v;
 
     if ( !is_hvm_domain(d) )
         return -EINVAL;
 
-    if ( copy_from_guest(&op, uop, 1) )
-        return -EFAULT;
-
     if ( op.vector < 0x10 )
         return -EINVAL;
 
@@ -4434,26 +4429,21 @@ static int hvm_set_param(struct domain *d, uint32_t index, uint64_t value)
     return rc;
 }
 
-static int hvmop_set_param(
-    XEN_GUEST_HANDLE_PARAM(xen_hvm_param_t) arg)
+static int hvmop_set_param(struct xen_hvm_param op)
 {
-    struct xen_hvm_param a;
     struct domain *d;
     int rc;
 
-    if ( copy_from_guest(&a, arg, 1) )
-        return -EFAULT;
-
-    if ( a.index >= HVM_NR_PARAMS )
+    if ( op.index >= HVM_NR_PARAMS )
         return -EINVAL;
 
-    d = rcu_lock_domain_by_any_id(a.domid);
+    d = rcu_lock_domain_by_any_id(op.domid);
     if ( d == NULL )
         return -ESRCH;
 
     rc = -EINVAL;
     if ( is_hvm_domain(d) )
-        rc = hvm_set_param(d, a.index, a.value);
+        rc = hvm_set_param(d, op.index, op.value);
 
     rcu_unlock_domain(d);
     return rc;
@@ -4544,31 +4534,21 @@ int hvm_get_param(struct domain *d, uint32_t index, uint64_t *value)
     return 0;
 };
 
-static int hvmop_get_param(
-    XEN_GUEST_HANDLE_PARAM(xen_hvm_param_t) arg)
+static int hvmop_get_param(struct xen_hvm_param *op)
 {
-    struct xen_hvm_param a;
     struct domain *d;
     int rc;
 
-    if ( copy_from_guest(&a, arg, 1) )
-        return -EFAULT;
-
-    if ( a.index >= HVM_NR_PARAMS )
+    if ( op->index >= HVM_NR_PARAMS )
         return -EINVAL;
 
-    d = rcu_lock_domain_by_any_id(a.domid);
+    d = rcu_lock_domain_by_any_id(op->domid);
     if ( d == NULL )
         return -ESRCH;
 
     rc = -EINVAL;
-    if ( is_hvm_domain(d) && !(rc = hvm_get_param(d, a.index, &a.value)) )
-    {
-        rc = __copy_to_guest(arg, &a, 1) ? -EFAULT : 0;
-
-        HVM_DBG_LOG(DBG_LEVEL_HCALL, "get param %u = %"PRIx64,
-                    a.index, a.value);
-    }
+    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);
 
     rcu_unlock_domain(d);
     return rc;
@@ -5046,18 +5026,13 @@ static int compat_altp2m_op(
     return rc;
 }
 
-static int hvmop_get_mem_type(
-    XEN_GUEST_HANDLE_PARAM(xen_hvm_get_mem_type_t) arg)
+static int hvmop_get_mem_type(struct xen_hvm_get_mem_type *op)
 {
-    struct xen_hvm_get_mem_type a;
     struct domain *d;
     p2m_type_t t;
     int rc;
 
-    if ( copy_from_guest(&a, arg, 1) )
-        return -EFAULT;
-
-    d = rcu_lock_domain_by_any_id(a.domid);
+    d = rcu_lock_domain_by_any_id(op->domid);
     if ( d == NULL )
         return -ESRCH;
 
@@ -5074,25 +5049,22 @@ static int hvmop_get_mem_type(
      * type, not in allocating or unsharing. That'll happen
      * on access.
      */
-    get_gfn_query_unlocked(d, a.pfn, &t);
+    get_gfn_query_unlocked(d, op->pfn, &t);
     if ( p2m_is_mmio(t) )
-        a.mem_type =  HVMMEM_mmio_dm;
+        op->mem_type =  HVMMEM_mmio_dm;
     else if ( t == p2m_ioreq_server )
-        a.mem_type = HVMMEM_ioreq_server;
+        op->mem_type = HVMMEM_ioreq_server;
     else if ( p2m_is_readonly(t) )
-        a.mem_type =  HVMMEM_ram_ro;
+        op->mem_type =  HVMMEM_ram_ro;
     else if ( p2m_is_ram(t) )
-        a.mem_type =  HVMMEM_ram_rw;
+        op->mem_type =  HVMMEM_ram_rw;
     else if ( p2m_is_pod(t) )
-        a.mem_type =  HVMMEM_ram_rw;
+        op->mem_type =  HVMMEM_ram_rw;
     else if ( p2m_is_grant(t) )
-        a.mem_type =  HVMMEM_ram_rw;
+        op->mem_type =  HVMMEM_ram_rw;
     else
-        a.mem_type =  HVMMEM_mmio_dm;
+        op->mem_type =  HVMMEM_mmio_dm;
 
-    rc = -EFAULT;
-    if ( __copy_to_guest(arg, &a, 1) )
-        goto out;
     rc = 0;
 
  out:
@@ -5115,28 +5087,70 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg)
     switch ( op )
     {
     case HVMOP_set_evtchn_upcall_vector:
-        rc = hvmop_set_evtchn_upcall_vector(
-            guest_handle_cast(arg, xen_hvm_evtchn_upcall_vector_t));
+    {
+        struct xen_hvm_evtchn_upcall_vector op;
+
+        if ( copy_from_guest(&op, arg, 1) )
+        {
+            rc = -EFAULT;
+            break;
+        }
+
+        rc = hvmop_set_evtchn_upcall_vector(op);
         break;
+    }
     
     case HVMOP_set_param:
-        rc = hvmop_set_param(
-            guest_handle_cast(arg, xen_hvm_param_t));
+    {
+        struct xen_hvm_param op;
+        
+        if ( copy_from_guest(&op, arg, 1) )
+        {
+            rc = -EFAULT;
+            break;
+        }
+
+        rc = hvmop_set_param(op);
         break;
+    }
 
     case HVMOP_get_param:
-        rc = hvmop_get_param(
-            guest_handle_cast(arg, xen_hvm_param_t));
+    {
+        struct xen_hvm_param op;
+        
+        if ( copy_from_guest(&op, arg, 1) )
+        {
+            rc = -EFAULT;
+            break;
+        }
+
+        rc = hvmop_get_param(&op);
+
+        if ( !rc && copy_to_guest(arg, &op, 1) )
+            rc = -EFAULT;
         break;
+    }
 
     case HVMOP_flush_tlbs:
         rc = guest_handle_is_null(arg) ? hvmop_flush_tlb_all() : -EINVAL;
         break;
 
     case HVMOP_get_mem_type:
-        rc = hvmop_get_mem_type(
-            guest_handle_cast(arg, xen_hvm_get_mem_type_t));
+    {
+        struct xen_hvm_get_mem_type op;
+
+        if ( copy_from_guest(&op, arg, 1) )
+        {
+            rc = -EFAULT;
+            break;
+        }
+        
+        rc = hvmop_get_mem_type(&op);
+
+        if ( !rc && copy_to_guest(arg, &op, 1) )
+            rc = -EFAULT;
         break;
+    }
 
     case HVMOP_pagetable_dying:
     {
-- 
2.50.1



Teddy Astie | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech



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

* [RFC PATCH 2/9] common: Isolate XENVER_get_features into a separate function
  2025-08-21 15:25 [RFC PATCH 0/9] x86/hvm: New Xen HVM ABI proposal ("HVMv2" part 1) Teddy Astie
  2025-08-21 15:25 ` [RFC PATCH 1/9] x86/hvm: Use direct structures instead of guest handles Teddy Astie
@ 2025-08-21 15:25 ` Teddy Astie
  2025-08-28 12:18   ` Jan Beulich
  2025-08-21 15:25 ` [RFC PATCH 3/9] common/grant_table: Use direct structures instead of guest handles Teddy Astie
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 24+ messages in thread
From: Teddy Astie @ 2025-08-21 15:25 UTC (permalink / raw)
  To: xen-devel
  Cc: Teddy Astie, Andrew Cooper, Anthony PERARD, Michal Orzel,
	Jan Beulich, Julien Grall, Roger Pau Monné,
	Stefano Stabellini

Make do_xen_version more readable by moving the main XENVER_get_features
into a separate function.

No functional changes intended.

Signed-off-by: Teddy Astie <teddy.astie@vates.tech>
---
 xen/common/kernel.c | 84 +++++++++++++++++++++++++--------------------
 1 file changed, 46 insertions(+), 38 deletions(-)

diff --git a/xen/common/kernel.c b/xen/common/kernel.c
index 5be668ba85..eff6db6c8f 100644
--- a/xen/common/kernel.c
+++ b/xen/common/kernel.c
@@ -569,6 +569,50 @@ static long xenver_varbuf_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
     return sz;
 }
 
+static long xenver_get_features(struct domain *d, uint32_t submap_idx, uint32_t *submap)
+{
+    switch ( submap_idx )
+    {
+    case 0:
+        *submap = (1U << XENFEAT_memory_op_vnode_supported) |
+#ifdef CONFIG_X86
+                  (1U << XENFEAT_vcpu_time_phys_area) |
+#endif
+                  (1U << XENFEAT_runstate_phys_area);
+        if ( VM_ASSIST(d, pae_extended_cr3) )
+            *submap |= (1U << XENFEAT_pae_pgdir_above_4gb);
+        if ( paging_mode_translate(d) )
+            *submap |=
+                (1U << XENFEAT_writable_page_tables) |
+                (1U << XENFEAT_auto_translated_physmap);
+        if ( is_hardware_domain(d) )
+            *submap |= 1U << XENFEAT_dom0;
+#ifdef CONFIG_ARM
+        *submap |= (1U << XENFEAT_ARM_SMCCC_supported);
+#endif
+#ifdef CONFIG_X86
+        if ( is_pv_domain(d) )
+            *submap |= (1U << XENFEAT_mmu_pt_update_preserve_ad) |
+                      (1U << XENFEAT_highmem_assist) |
+                      (1U << XENFEAT_gnttab_map_avail_bits);
+        else
+            *submap |= (1U << XENFEAT_hvm_safe_pvclock) |
+                       (1U << XENFEAT_hvm_callback_vector) |
+                       (has_pirq(d) ? (1U << XENFEAT_hvm_pirqs) : 0);
+        *submap |= (1U << XENFEAT_dm_msix_all_writes);
+#endif
+        if ( !paging_mode_translate(d) || is_domain_direct_mapped(d) )
+            *submap |= (1U << XENFEAT_direct_mapped);
+        else
+            *submap |= (1U << XENFEAT_not_direct_mapped);
+        break;
+    default:
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
 long do_xen_version(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
 {
     bool deny = xsm_xen_version(XSM_OTHER, cmd);
@@ -675,45 +719,9 @@ long do_xen_version(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
         if ( copy_from_guest(&fi, arg, 1) )
             return -EFAULT;
 
-        switch ( fi.submap_idx )
-        {
-        case 0:
-            fi.submap = (1U << XENFEAT_memory_op_vnode_supported) |
-#ifdef CONFIG_X86
-                        (1U << XENFEAT_vcpu_time_phys_area) |
-#endif
-                        (1U << XENFEAT_runstate_phys_area);
-            if ( VM_ASSIST(d, pae_extended_cr3) )
-                fi.submap |= (1U << XENFEAT_pae_pgdir_above_4gb);
-            if ( paging_mode_translate(d) )
-                fi.submap |=
-                    (1U << XENFEAT_writable_page_tables) |
-                    (1U << XENFEAT_auto_translated_physmap);
-            if ( is_hardware_domain(d) )
-                fi.submap |= 1U << XENFEAT_dom0;
-#ifdef CONFIG_ARM
-            fi.submap |= (1U << XENFEAT_ARM_SMCCC_supported);
-#endif
-#ifdef CONFIG_X86
-            if ( is_pv_domain(d) )
-                fi.submap |= (1U << XENFEAT_mmu_pt_update_preserve_ad) |
-                             (1U << XENFEAT_highmem_assist) |
-                             (1U << XENFEAT_gnttab_map_avail_bits);
-            else
-                fi.submap |= (1U << XENFEAT_hvm_safe_pvclock) |
-                             (1U << XENFEAT_hvm_callback_vector) |
-                             (has_pirq(d) ? (1U << XENFEAT_hvm_pirqs) : 0);
-            fi.submap |= (1U << XENFEAT_dm_msix_all_writes);
-#endif
-            if ( !paging_mode_translate(d) || is_domain_direct_mapped(d) )
-                fi.submap |= (1U << XENFEAT_direct_mapped);
-            else
-                fi.submap |= (1U << XENFEAT_not_direct_mapped);
-            break;
-        default:
+        if ( xenver_get_features(d, fi.submap_idx, &fi.submap) )
             return -EINVAL;
-        }
-
+            
         if ( __copy_to_guest(arg, &fi, 1) )
             return -EFAULT;
         return 0;
-- 
2.50.1



Teddy Astie | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech



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

* [RFC PATCH 3/9] common/grant_table: Use direct structures instead of guest handles
  2025-08-21 15:25 [RFC PATCH 0/9] x86/hvm: New Xen HVM ABI proposal ("HVMv2" part 1) Teddy Astie
  2025-08-21 15:25 ` [RFC PATCH 1/9] x86/hvm: Use direct structures instead of guest handles Teddy Astie
  2025-08-21 15:25 ` [RFC PATCH 2/9] common: Isolate XENVER_get_features into a separate function Teddy Astie
@ 2025-08-21 15:25 ` Teddy Astie
  2025-08-28 12:21   ` Jan Beulich
  2025-08-21 15:25 ` [RFC PATCH 4/9] hvm: Introduce "fixed memory layout" feature Teddy Astie
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 24+ messages in thread
From: Teddy Astie @ 2025-08-21 15:25 UTC (permalink / raw)
  To: xen-devel
  Cc: Teddy Astie, Andrew Cooper, Anthony PERARD, Michal Orzel,
	Jan Beulich, Julien Grall, Roger Pau Monné,
	Stefano Stabellini

Make these functions work with hypervisor-owned pointer rather than
guest handles, so the function parameters don't have to live in guest memory.

No functional changes.

Signed-off-by: Teddy Astie <teddy.astie@vates.tech>
---
 xen/common/grant_table.c | 68 +++++++++++++++++++++++-----------------
 1 file changed, 39 insertions(+), 29 deletions(-)

diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index cf131c43a1..3c3bbca2fc 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -3164,29 +3164,24 @@ static long gnttab_copy(
     return rc;
 }
 
-static long
-gnttab_set_version(XEN_GUEST_HANDLE_PARAM(gnttab_set_version_t) uop)
+static long gnttab_set_version(gnttab_set_version_t *op)
 {
-    gnttab_set_version_t op;
     struct domain *currd = current->domain;
     struct grant_table *gt = currd->grant_table;
     grant_entry_v1_t reserved_entries[GNTTAB_NR_RESERVED_ENTRIES];
     int res;
     unsigned int i, nr_ents;
 
-    if ( copy_from_guest(&op, uop, 1) )
-        return -EFAULT;
-
     res = -EINVAL;
-    if ( op.version != 1 && op.version != 2 )
+    if ( op->version != 1 && op->version != 2 )
         goto out;
 
     res = -ENOSYS;
-    if ( op.version == 2 && gt->max_version == 1 )
+    if ( op->version == 2 && gt->max_version == 1 )
         goto out; /* Behave as before set_version was introduced. */
 
     res = 0;
-    if ( gt->gt_version == op.version )
+    if ( gt->gt_version == op->version )
         goto out;
 
     grant_write_lock(gt);
@@ -3203,7 +3198,7 @@ gnttab_set_version(XEN_GUEST_HANDLE_PARAM(gnttab_set_version_t) uop)
         {
             gdprintk(XENLOG_WARNING,
                      "tried to change grant table version from %u to %u, but some grant entries still in use\n",
-                     gt->gt_version, op.version);
+                     gt->gt_version, op->version);
             res = -EBUSY;
             goto out_unlock;
         }
@@ -3268,7 +3263,7 @@ gnttab_set_version(XEN_GUEST_HANDLE_PARAM(gnttab_set_version_t) uop)
         break;
     }
 
-    if ( op.version < 2 && gt->gt_version == 2 &&
+    if ( op->version < 2 && gt->gt_version == 2 &&
          (res = gnttab_unpopulate_status_frames(currd, gt)) != 0 )
         goto out_unlock;
 
@@ -3279,7 +3274,7 @@ gnttab_set_version(XEN_GUEST_HANDLE_PARAM(gnttab_set_version_t) uop)
     /* Restore the first 8 entries (toolstack reserved grants). */
     if ( gt->gt_version )
     {
-        switch ( op.version )
+        switch ( op->version )
         {
         case 1:
             memcpy(&shared_entry_v1(gt, 0), reserved_entries, sizeof(reserved_entries));
@@ -3300,16 +3295,14 @@ gnttab_set_version(XEN_GUEST_HANDLE_PARAM(gnttab_set_version_t) uop)
         }
     }
 
-    gt->gt_version = op.version;
+    gt->gt_version = op->version;
 
  out_unlock:
     grant_write_unlock(gt);
 
  out:
-    op.version = gt->gt_version;
+    op->version = gt->gt_version;
 
-    if ( __copy_to_guest(uop, &op, 1) )
-        res = -EFAULT;
 
     return res;
 }
@@ -3387,17 +3380,12 @@ gnttab_get_status_frames(XEN_GUEST_HANDLE_PARAM(gnttab_get_status_frames_t) uop,
     return 0;
 }
 
-static long
-gnttab_get_version(XEN_GUEST_HANDLE_PARAM(gnttab_get_version_t) uop)
+static long gnttab_get_version(gnttab_get_version_t *op)
 {
-    gnttab_get_version_t op;
     struct domain *d;
     int rc;
 
-    if ( copy_from_guest(&op, uop, 1) )
-        return -EFAULT;
-
-    d = rcu_lock_domain_by_any_id(op.dom);
+    d = rcu_lock_domain_by_any_id(op->dom);
     if ( d == NULL )
         return -ESRCH;
 
@@ -3408,13 +3396,10 @@ gnttab_get_version(XEN_GUEST_HANDLE_PARAM(gnttab_get_version_t) uop)
         return rc;
     }
 
-    op.version = d->grant_table->gt_version;
+    op->version = d->grant_table->gt_version;
 
     rcu_unlock_domain(d);
 
-    if ( __copy_field_to_guest(uop, &op, version) )
-        return -EFAULT;
-
     return 0;
 }
 
@@ -3749,8 +3734,20 @@ long do_grant_table_op(
         break;
 
     case GNTTABOP_set_version:
-        rc = gnttab_set_version(guest_handle_cast(uop, gnttab_set_version_t));
+    {
+        gnttab_set_version_t op;
+        if ( copy_from_guest(&op, uop, 1) )
+        {
+            rc = -EFAULT;
+            break;
+        }
+
+        rc = gnttab_set_version(&op);
+
+        if ( copy_to_guest(uop, &op, 1) )
+            rc = -EFAULT;
         break;
+    }
 
     case GNTTABOP_get_status_frames:
         rc = gnttab_get_status_frames(
@@ -3758,8 +3755,21 @@ long do_grant_table_op(
         break;
 
     case GNTTABOP_get_version:
-        rc = gnttab_get_version(guest_handle_cast(uop, gnttab_get_version_t));
+    {
+        gnttab_get_version_t op;
+
+        if ( copy_from_guest(&op, uop, 1) )
+        {
+            rc = -EFAULT;
+            break;
+        }
+
+        rc = gnttab_get_version(&op);
+
+        if ( copy_to_guest(uop, &op, 1) )
+            rc = -EFAULT;
         break;
+    }
 
     case GNTTABOP_swap_grant_ref:
     {
-- 
2.50.1



Teddy Astie | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech



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

* [RFC PATCH 5/9] docs/x86: Introduce FastABI
  2025-08-21 15:25 [RFC PATCH 0/9] x86/hvm: New Xen HVM ABI proposal ("HVMv2" part 1) Teddy Astie
                   ` (4 preceding siblings ...)
  2025-08-21 15:25 ` [RFC PATCH 6/9] sched: Extract do_poll main logic into vcpu_poll Teddy Astie
@ 2025-08-21 15:25 ` Teddy Astie
  2025-08-28 12:32   ` Jan Beulich
  2025-08-21 15:25 ` [RFC PATCH 7/9] x86/hvm: Introduce FastABI implementation Teddy Astie
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 24+ messages in thread
From: Teddy Astie @ 2025-08-21 15:25 UTC (permalink / raw)
  To: xen-devel
  Cc: Teddy Astie, Andrew Cooper, Anthony PERARD, Michal Orzel,
	Jan Beulich, Julien Grall, Roger Pau Monné,
	Stefano Stabellini

FastABI is a alternative ABI designed with performance and coco-enabled
guest in mind. It is register-oriented instead of refering to C structures
in the guest memory (through a virtual memory pointer).

It only focuses on kernel-side hypercalls, it doesn't aim to provide toolstack
operations.

Signed-off-by: Teddy Astie <teddy.astie@vates.tech>
---
 docs/guest-guide/x86/fastabi.pandoc |  50 ++++++++++
 docs/guest-guide/x86/index.rst      |   1 +
 xen/abi/event_channel.yml           | 130 ++++++++++++++++++++++++++
 xen/abi/grant_table.yml             |  46 +++++++++
 xen/abi/hvm.yml                     |  50 ++++++++++
 xen/abi/memory.yml                  |  11 +++
 xen/abi/sched.yml                   |  48 ++++++++++
 xen/abi/vcpu.yml                    | 139 ++++++++++++++++++++++++++++
 xen/abi/version.yml                 |  15 +++
 xen/include/public/arch-x86/cpuid.h |   4 +
 10 files changed, 494 insertions(+)
 create mode 100644 docs/guest-guide/x86/fastabi.pandoc
 create mode 100644 xen/abi/event_channel.yml
 create mode 100644 xen/abi/grant_table.yml
 create mode 100644 xen/abi/hvm.yml
 create mode 100644 xen/abi/memory.yml
 create mode 100644 xen/abi/sched.yml
 create mode 100644 xen/abi/vcpu.yml
 create mode 100644 xen/abi/version.yml

diff --git a/docs/guest-guide/x86/fastabi.pandoc b/docs/guest-guide/x86/fastabi.pandoc
new file mode 100644
index 0000000000..8ff8609f37
--- /dev/null
+++ b/docs/guest-guide/x86/fastabi.pandoc
@@ -0,0 +1,50 @@
+# x86 FastABI
+
+## Introduction
+
+FastABI is a alternative hypercall ABI designed with performance and confidential
+computing enabled guests (AMD SEV, Intel TDX, ...) in mind. It provides a minimal
+subset of the traditional ABI that is sufficient for having a working guest.
+
+This hypercall interface is designed around using registers for passing hypercall
+parameters and outputs rather than using pointer to C structures, thus it avoids
+potentially complicated or expensive memory copies from/to the guest.
+
+This ABI currently only supports HVM/PVH and x86 long mode.
+
+Each hypercall operation interface is described in a parsable yaml file, which
+defines each hypercall suboperation inputs and outputs and eventual metadata for
+code generation (e.g C stubs).
+
+## Support
+
+This interface is only supported if XEN_HVM_CPUID_FASTABI is set.
+
+## Semantics
+
+8 registers can be used as either input or output.
+
+Each hypercall operation (or sub-operation) defines its own set of used input and
+output registers. There is no implicit clobbering of unused registers, i.e input
+registers are not allowed to be modified by the hypervisor unless it is explicitely
+also marked as a output (or cloberred register).
+
+- reg0: `rax`: IN: hypercall operation index, OUT: error code
+- reg1: `rdi`: (if operation has sub-operations) IN: hypercall sub-operation index
+- reg2: `rsi`
+- reg3: `r8`
+- reg4: `r9`
+- reg5: `r10`
+- reg6: `r11`
+- reg7: `r12`
+
+`reg0` input is reserved for hypercall index.
+In order to distinguish FastABI with traditional hypercalls or viridian hypercalls,
+reg0 input needs to be OR-ed with 0x40000000 (__HYPERVISOR_FASTABI_MASK).
+
+`reg0` output is reserved for standard hypercall return code (errno) or returned value.
+
+`reg1` input can be used for identifying a sub-operation. output is available for use.
+
+The hypercall uses the native hypercall instruction, which is `vmcall` on Intel platforms
+and `vmmcall` on AMD platforms.
\ No newline at end of file
diff --git a/docs/guest-guide/x86/index.rst b/docs/guest-guide/x86/index.rst
index 6927271e53..aaae42da5a 100644
--- a/docs/guest-guide/x86/index.rst
+++ b/docs/guest-guide/x86/index.rst
@@ -7,4 +7,5 @@ x86
    :maxdepth: 2
 
    hypercall-abi
+   fastabi
    fixed-memory-layout
diff --git a/xen/abi/event_channel.yml b/xen/abi/event_channel.yml
new file mode 100644
index 0000000000..44a769cdbb
--- /dev/null
+++ b/xen/abi/event_channel.yml
@@ -0,0 +1,130 @@
+name: event_channel
+hypercall_index: 32
+
+subops:
+  alloc_unbound:
+    index: 6
+    input:
+      dom: 2
+      remote_dom: 3
+    output:
+      port: 4
+    c_lang:
+      struct: evtchn_alloc_unbound
+
+  bind_interdomain:
+    index: 0
+    input:
+      remote_dom: 2
+      remote_port: 3
+    output:
+      local_port: 4
+    c_lang:
+      struct: evtchn_bind_interdomain
+
+  bind_virq:
+    index: 1
+    input:
+      virq: 2
+      vcpu: 3
+    output:
+      port: 4
+    c_lang:
+      struct: evtchn_bind_virq
+
+  bind_ipi:
+    index: 7
+    input:
+      vcpu: 2
+    output:
+      port: 4
+    c_lang:
+      struct: evtchn_bind_ipi
+
+  bind_pirq:
+    index: 2
+    input:
+      pirq: 2
+      flags: 3
+    output:
+      port: 4
+    c_lang:
+      struct: evtchn_bind_pirq
+  
+  close:
+    index: 3
+    input:
+      port: 2
+    c_lang:
+      struct: evtchn_close
+  
+  send:
+    index: 4
+    input:
+      port: 2
+    c_lang:
+      struct: evtchn_send
+
+  status:
+    index: 5
+    input:
+      dom: 2
+      port: 3
+    output:
+      status: 4
+      vcpu: 5
+      output1: 6
+      output2: 7
+    c_lang:
+      struct: evtchn_status
+      mapping:
+        output1: u._output1
+        output2: u._output2
+  
+  bind_vcpu:
+    index: 8
+    input:
+      vcpu: 2
+      port: 3
+    c_lang:
+      struct: evtchn_bind_vcpu
+  
+  unmask:
+    index: 9
+    input:
+      port: 2
+    c_lang:
+      struct: evtchn_unmask
+  
+  reset:
+    index: 10
+    input:
+      dom: 2
+    c_lang:
+      struct: evtchn_reset
+
+  init_control:
+    index: 11
+    input:
+      control_gfn: 2
+      offset: 3
+      vcpu: 4
+    output:
+      link_bits: 5
+    c_lang:
+      struct: evtchn_init_control
+  
+  expand_array:
+    index: 12
+    input:
+      array_gfn: 2
+    c_lang:
+      struct: evtchn_expand_array
+
+  set_priority:
+    index: 13
+    input:
+      port: 2
+      priority: 3
+    c_lang:
+      struct: evtchn_set_priority
diff --git a/xen/abi/grant_table.yml b/xen/abi/grant_table.yml
new file mode 100644
index 0000000000..bcedaa966b
--- /dev/null
+++ b/xen/abi/grant_table.yml
@@ -0,0 +1,46 @@
+name: grant_table
+hypercall_index: 20
+
+subops:
+  map_grant_ref:
+    index: 0
+    input:
+      dom: 2
+      host_addr: 3
+      flags: 4
+      ref: 5
+    output:
+      handle: 6
+      status: 7
+    c_lang:
+      struct: gnttab_map_grant_ref
+  
+  unmap_grant_ref:
+    index: 1
+    input:
+      host_addr: 3
+      handle: 6
+    c_lang:
+      struct: gnttab_unmap_grant_ref
+  
+  query_size:
+    index: 6
+    output:
+      nr_frames: 2
+      max_nr_frames: 3
+    c_lang:
+      struct: gnttab_query_size
+
+  set_version:
+    index: 8
+    input:
+      version: 2
+    c_lang:
+      struct: gnttab_set_version
+
+  get_version:
+    index: 10
+    output:
+      version: 2
+    c_lang:
+      struct: gnttab_get_version
diff --git a/xen/abi/hvm.yml b/xen/abi/hvm.yml
new file mode 100644
index 0000000000..20c2421bdf
--- /dev/null
+++ b/xen/abi/hvm.yml
@@ -0,0 +1,50 @@
+name: hvm
+hypercall_index: 34
+
+subops:
+  set_param:
+    index: 0
+    input:
+      domid: 2
+      index: 3
+      value: 4
+    c_lang:
+      struct: xen_hvm_param
+
+  get_param:
+    index: 1
+    input:
+      domid: 2
+      index: 3
+    output:
+      value: 4
+    c_lang:
+      struct: xen_hvm_param
+
+  flush_tlbs:
+    index: 5
+
+  get_time:
+    index: 10
+    output:
+      now: 2
+    c_lang:
+      struct: xen_hvm_get_time
+
+  get_mem_type:
+    index: 15
+    input:
+      domid: 2
+      pfn: 3
+    output:
+      mem_type: 4
+    c_lang:
+      struct: xen_hvm_get_mem_type
+
+  set_evtchn_upcall_vector:
+    index: 23
+    input:
+      vcpu: 2
+      vector: 3
+    c_lang:
+      struct: xen_hvm_evtchn_upcall_vector
diff --git a/xen/abi/memory.yml b/xen/abi/memory.yml
new file mode 100644
index 0000000000..8b51490f8a
--- /dev/null
+++ b/xen/abi/memory.yml
@@ -0,0 +1,11 @@
+name: memory
+hypercall_index: 12
+
+subops:
+  memory_map:
+    index: 9
+    input:
+      nr_entries: 2
+      buffer: 3
+    c_lang:
+      struct: xen_memory_map
diff --git a/xen/abi/sched.yml b/xen/abi/sched.yml
new file mode 100644
index 0000000000..1b1ef50c7a
--- /dev/null
+++ b/xen/abi/sched.yml
@@ -0,0 +1,48 @@
+name: sched
+hypercall_index: 29
+
+subops:
+  yield:
+    index: 0
+
+  block:
+    index: 1
+
+  shutdown:
+    index: 2
+    input:
+      reason: 2
+    c_lang:
+      struct: sched_shutdown
+
+  poll:
+    index: 3
+    input:
+      timeout: 2
+      port: 3
+    c_lang:
+      params:
+        timeout: uint64_t
+        port: evtchn_port_t
+
+  shutdown_code:
+    index: 5
+    input:
+      reason: 2
+    c_lang:
+      struct: sched_shutdown
+
+  watchdog:
+    index: 6
+    input:
+      id: 2
+      timeout: 3
+    c_lang:
+      struct: sched_watchdog
+
+  pin_override:
+    index: 7
+    input:
+      pcpu: 2
+    c_lang:
+      struct: sched_pin_override
diff --git a/xen/abi/vcpu.yml b/xen/abi/vcpu.yml
new file mode 100644
index 0000000000..0b4fe4ea1f
--- /dev/null
+++ b/xen/abi/vcpu.yml
@@ -0,0 +1,139 @@
+name: vcpu
+hypercall_index: 24
+
+subops:
+  initialise:
+    index: 0
+    input:
+      vcpuid: 2
+      context_gfn: 3
+    c_lang:
+      params:
+        vcpuid: uint32_t
+        context_gfn: uint64_t
+
+  up:
+    index: 1
+    input:
+      vcpuid: 2
+    c_lang:
+      params:
+        vcpuid: uint32_t
+
+  down:
+    index: 2
+    input:
+      vcpuid: 2
+    c_lang:
+      params:
+        vcpuid: uint32_t
+
+  is_up:
+    index: 3
+    input:
+      vcpuid: 2
+    c_lang:
+      params:
+        vcpuid: uint32_t
+
+  get_runstate_info:
+    index: 4
+    input:
+      vcpuid: 2
+    output:
+      state: 2
+      state_entry_time: 3
+      time[0]: 4
+      time[1]: 5
+      time[2]: 6
+      time[3]: 7
+    c_lang:
+      struct: vcpu_runstate_info
+      params:
+        vcpuid: uint32_t
+
+  register_runstate_phys_area:
+    index: 14
+    input:
+      vcpuid: 2
+      addr.p: 3
+    c_lang:
+      struct: vcpu_register_time_memory_area
+      params:
+        vcpuid: uint32_t
+
+  set_periodic_timer:
+    index: 6
+    input:
+      vcpuid: 2
+      period_ns: 3
+    c_lang:
+      struct: vcpu_set_periodic_timer
+      params:
+        vcpuid: uint32_t
+
+  stop_periodic_timer:
+    index: 7
+    input:
+      vcpuid: 2
+    c_lang:
+      params:
+        vcpuid: uint32_t
+  
+  set_singleshot_timer:
+    index: 8
+    input:
+      vcpuid: 2
+      timeout_abs_ns: 3
+      flags: 4
+    c_lang:
+      struct: vcpu_set_singleshot_timer
+      params:
+        vcpuid: uint32_t
+
+  stop_singleshot_timer:
+    index: 9
+    input:
+      vcpuid: 2
+    c_lang:
+      params:
+        vcpuid: uint32_t
+
+  register_vcpu_info:
+    index: 10
+    input:
+      vcpuid: 2
+      mfn: 3
+      offset: 4
+    c_lang:
+      struct: vcpu_register_vcpu_info
+      params:
+        vcpuid: uint32_t
+
+  send_nmi:
+    index: 11
+    input:
+      vcpuid: 2
+    c_lang:
+      params:
+        vcpuid: uint32_t
+
+  get_physid:
+    index: 12
+    input:
+      vcpuid: 2
+      phys_id: 3
+    c_lang:
+      struct: vcpu_get_physid
+      params:
+        vcpuid: uint32_t
+
+  register_vcpu_time_phys_area:
+    index: 15
+    input:
+      vcpuid: 2
+      addr.p: 3
+    c_lang:
+      struct: vcpu_register_time_memory_area
+      params:
+        vcpuid: uint32_t
diff --git a/xen/abi/version.yml b/xen/abi/version.yml
new file mode 100644
index 0000000000..bce64a4d69
--- /dev/null
+++ b/xen/abi/version.yml
@@ -0,0 +1,15 @@
+name: version
+hypercall_index: 17
+
+subops:
+  version:
+    index: 0
+
+  get_features:
+    index: 6
+    input:
+      submap_idx: 2
+    output:
+      submap: 3
+    c_lang:
+      struct: xen_feature_info
diff --git a/xen/include/public/arch-x86/cpuid.h b/xen/include/public/arch-x86/cpuid.h
index 3bb0dd249f..ff44ce0e7b 100644
--- a/xen/include/public/arch-x86/cpuid.h
+++ b/xen/include/public/arch-x86/cpuid.h
@@ -106,6 +106,10 @@
  * bound to event channels.
  */
 #define XEN_HVM_CPUID_UPCALL_VECTOR    (1u << 6)
+/*
+ * Support for fast HVM ABI.
+ */
+#define XEN_HVM_CPUID_FASTABI          (1u << 7)
 
 /*
  * Leaf 6 (0x40000x05)
-- 
2.50.1



Teddy Astie | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech



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

* [RFC PATCH 6/9] sched: Extract do_poll main logic into vcpu_poll
  2025-08-21 15:25 [RFC PATCH 0/9] x86/hvm: New Xen HVM ABI proposal ("HVMv2" part 1) Teddy Astie
                   ` (3 preceding siblings ...)
  2025-08-21 15:25 ` [RFC PATCH 4/9] hvm: Introduce "fixed memory layout" feature Teddy Astie
@ 2025-08-21 15:25 ` Teddy Astie
  2025-08-28 12:36   ` Jan Beulich
  2025-08-21 15:25 ` [RFC PATCH 5/9] docs/x86: Introduce FastABI Teddy Astie
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 24+ messages in thread
From: Teddy Astie @ 2025-08-21 15:25 UTC (permalink / raw)
  To: xen-devel; +Cc: Teddy Astie, Dario Faggioli, Juergen Gross, George Dunlap

do_poll takes sched_poll* as parameter, but that's actually in guest memory
(so it's more a guest handle). Split its copy from/to guest logic from
the main logic, so that we have a separate vcpu_poll which takes the sched_poll
parameters directly.

Signed-off-by: Teddy Astie <teddy.astie@vates.tech>
---
 xen/common/sched/core.c | 40 +++++++++++++++++++++-------------------
 1 file changed, 21 insertions(+), 19 deletions(-)

diff --git a/xen/common/sched/core.c b/xen/common/sched/core.c
index 13fdf57e57..b2c784c60e 100644
--- a/xen/common/sched/core.c
+++ b/xen/common/sched/core.c
@@ -1437,21 +1437,13 @@ static void vcpu_block_enable_events(void)
     vcpu_block();
 }
 
-static long do_poll(const struct sched_poll *sched_poll)
+static long vcpu_poll(unsigned int nr_ports, uint64_t timeout, evtchn_port_t *ports)
 {
     struct vcpu   *v = current;
     struct domain *d = v->domain;
-    evtchn_port_t  port = 0;
     long           rc;
     unsigned int   i;
 
-    /* Fairly arbitrary limit. */
-    if ( sched_poll->nr_ports > 128 )
-        return -EINVAL;
-
-    if ( !guest_handle_okay(sched_poll->ports, sched_poll->nr_ports) )
-        return -EFAULT;
-
     set_bit(_VPF_blocked, &v->pause_flags);
     v->poll_evtchn = -1;
     set_bit(v->vcpu_id, d->poll_mask);
@@ -1478,13 +1470,9 @@ static long do_poll(const struct sched_poll *sched_poll)
     if ( local_events_need_delivery() )
         goto out;
 
-    for ( i = 0; i < sched_poll->nr_ports; i++ )
+    for ( i = 0; i < nr_ports; i++ )
     {
-        rc = -EFAULT;
-        if ( __copy_from_guest_offset(&port, sched_poll->ports, i, 1) )
-            goto out;
-
-        rc = evtchn_port_poll(d, port);
+        rc = evtchn_port_poll(d, ports[i]);
         if ( rc )
         {
             if ( rc > 0 )
@@ -1493,11 +1481,11 @@ static long do_poll(const struct sched_poll *sched_poll)
         }
     }
 
-    if ( sched_poll->nr_ports == 1 )
-        v->poll_evtchn = port;
+    if ( nr_ports == 1 )
+        v->poll_evtchn = ports[0];
 
-    if ( sched_poll->timeout != 0 )
-        set_timer(&v->poll_timer, sched_poll->timeout);
+    if ( timeout != 0 )
+        set_timer(&v->poll_timer, timeout);
 
     TRACE_TIME(TRC_SCHED_BLOCK, d->domain_id, v->vcpu_id);
     raise_softirq(SCHEDULE_SOFTIRQ);
@@ -1511,6 +1499,20 @@ static long do_poll(const struct sched_poll *sched_poll)
     return rc;
 }
 
+static long do_poll(struct sched_poll *sched_poll)
+{
+    evtchn_port_t ports[128];
+
+    /* Fairly arbitrary limit */
+    if ( sched_poll->nr_ports > 128 )
+        return -EINVAL;
+
+    if ( copy_from_guest(ports, sched_poll->ports, sched_poll->nr_ports) )
+        return -EFAULT;
+
+    return vcpu_poll(sched_poll->nr_ports, sched_poll->timeout, ports);
+}
+
 /* Voluntarily yield the processor for this allocation. */
 long vcpu_yield(void)
 {
-- 
2.50.1



Teddy Astie | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech



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

* [RFC PATCH 4/9] hvm: Introduce "fixed memory layout" feature
  2025-08-21 15:25 [RFC PATCH 0/9] x86/hvm: New Xen HVM ABI proposal ("HVMv2" part 1) Teddy Astie
                   ` (2 preceding siblings ...)
  2025-08-21 15:25 ` [RFC PATCH 3/9] common/grant_table: Use direct structures instead of guest handles Teddy Astie
@ 2025-08-21 15:25 ` Teddy Astie
  2025-08-28 12:30   ` Jan Beulich
  2025-08-21 15:25 ` [RFC PATCH 6/9] sched: Extract do_poll main logic into vcpu_poll Teddy Astie
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 24+ messages in thread
From: Teddy Astie @ 2025-08-21 15:25 UTC (permalink / raw)
  To: xen-devel
  Cc: Teddy Astie, Andrew Cooper, Anthony PERARD, Michal Orzel,
	Jan Beulich, Julien Grall, Roger Pau Monné,
	Stefano Stabellini, Juergen Gross

Currently, guests needs to explicitely map their shared info and
grant table through hypercalls. It has proved to be complicated
and had been traditionally placed in the Xen PCI Platform device
BAR, but has caused confusions regarding MTRR [1].

Introduce a optional feature to let the toolstack map these pages in
advance, and exposing their location through the memory map (i.e E820).

When this feature is active, guests are expected to not invalidate such
mappings (e.g by calling xen_remove_from_physmap); as they may be used
by the operating system or firmware (i.e OVMF).

Moreover, this feature is useful to allow having a working guest without
having to expose to it physmap manipulation.

[1] https://lore.kernel.org/xen-devel/20250610162930.89055-1-roger.pau@citrix.com/

Signed-off-by: Teddy Astie <teddy.astie@vates.tech>
---
 .../x86/fixed-memory-layout.pandoc            | 24 ++++++
 docs/guest-guide/x86/index.rst                |  1 +
 tools/include/xen-tools/common-macros.h       |  4 +
 tools/libs/guest/xg_dom_x86.c                 | 84 +++++++++++++++++++
 tools/libs/light/libxl_create.c               |  1 +
 tools/libs/light/libxl_types.idl              |  1 +
 tools/libs/light/libxl_x86.c                  | 71 ++++++++++++++++
 tools/xl/xl_parse.c                           |  1 +
 xen/include/public/arch-x86/hvm/start_info.h  |  7 ++
 9 files changed, 194 insertions(+)
 create mode 100644 docs/guest-guide/x86/fixed-memory-layout.pandoc

diff --git a/docs/guest-guide/x86/fixed-memory-layout.pandoc b/docs/guest-guide/x86/fixed-memory-layout.pandoc
new file mode 100644
index 0000000000..b394dc1cff
--- /dev/null
+++ b/docs/guest-guide/x86/fixed-memory-layout.pandoc
@@ -0,0 +1,24 @@
+# Fixed memory layout
+
+When creating a guest with "fixed_mem_layout", the guest has additional special
+pages mapped in advance. These mappings may be required in some cases due to FastABI
+not providing the ability for the guest to modify its physical memory layout (which is
+usually used to map the shared info page or the grant table).
+
+The guest is informed of such mappings and their location through the memory map using
+Xen specific memory map types (in the OEM range of ACPI specification).
+
+It's expected that these mappings stay stable, therefore, the guest shouldn't try to
+modify such mappings as it may be actively used by guest firmware or operating system.
+
+    /* Xen-specific types (OEM-specific range of the ACPI spec) */
+    #define XEN_HVM_MEMMAP_TYPE_SHARED_INFO   0xF0000001 /* Shared info page */
+    #define XEN_HVM_MEMMAP_TYPE_GRANT_TABLE   0xF0000002 /* Grant table pages */
+    #define XEN_HVM_MEMMAP_TYPE_GNTTAB_STATUS 0xF0000003 /* Grant table status page (v2) */
+    #define XEN_HVM_MEMMAP_TYPE_FOREIGN_REG   0xF0000004 /* Suitable region for grant mappings */
+                                                         /* and foreign mappings */
+
+These mappings are likely to be placed outside the 4G range.
+
+XEN_HVM_MEMMAP_TYPE_FOREIGN_REG is a special region which doesn't contain any mapping,
+but is safe to use for placing grant and foreign mappings.
diff --git a/docs/guest-guide/x86/index.rst b/docs/guest-guide/x86/index.rst
index 502968490d..6927271e53 100644
--- a/docs/guest-guide/x86/index.rst
+++ b/docs/guest-guide/x86/index.rst
@@ -7,3 +7,4 @@ x86
    :maxdepth: 2
 
    hypercall-abi
+   fixed-memory-layout
diff --git a/tools/include/xen-tools/common-macros.h b/tools/include/xen-tools/common-macros.h
index 0088208c2e..8b286b3da5 100644
--- a/tools/include/xen-tools/common-macros.h
+++ b/tools/include/xen-tools/common-macros.h
@@ -72,6 +72,10 @@
 #define ROUNDUP(_x,_w) (((unsigned long)(_x)+(1UL<<(_w))-1) & ~((1UL<<(_w))-1))
 #endif
 
+#ifndef DIV_ROUNDUP
+#define DIV_ROUNDUP(n, d) (((n) + (d) - 1) / (d))
+#endif
+
 #define MASK_EXTR(v, m) (((v) & (m)) / ((m) & -(m)))
 #define MASK_INSR(v, m) (((v) * ((m) & -(m))) & (m))
 
diff --git a/tools/libs/guest/xg_dom_x86.c b/tools/libs/guest/xg_dom_x86.c
index cba01384ae..ab1c5063a4 100644
--- a/tools/libs/guest/xg_dom_x86.c
+++ b/tools/libs/guest/xg_dom_x86.c
@@ -624,6 +624,82 @@ static void build_hvm_info(void *hvm_info_page, struct xc_dom_image *dom)
     hvm_info->checksum = -sum;
 }
 
+/* Prepare special (shared_info, grant table, ...) regions marked in E820. */
+static int prepare_fixed_special_regions(xc_interface *xch, struct xc_dom_image *dom)
+{
+    int rc = 0; unsigned int i;
+    uint32_t domid = dom->guest_domid;
+    gnttab_query_size_t gnttab_query;
+    size_t gnttab_frame_count, gnttab_status_frame_count;
+    
+    gnttab_query.dom = domid;
+    rc = xc_gnttab_query_size(xch, &gnttab_query);
+
+    if ( rc != 0 || gnttab_query.status != GNTST_okay )
+    {
+        DOMPRINTF("Unable to query grant table size.");
+        return rc;
+    }
+
+    gnttab_frame_count = gnttab_query.max_nr_frames;
+    gnttab_status_frame_count = DIV_ROUNDUP(
+        gnttab_frame_count * (XC_DOM_PAGE_SIZE(dom) / sizeof(grant_entry_v2_t)),
+        XC_DOM_PAGE_SIZE(dom) / sizeof(grant_status_t));
+
+    for ( i = 0; i < dom->e820_entries; i++ )
+    {
+        struct e820entry entry = dom->e820[i];
+        rc = 0;
+
+        switch ( entry.type ) {
+        case XEN_HVM_MEMMAP_TYPE_SHARED_INFO:
+            rc = xc_domain_add_to_physmap(xch, domid, XENMAPSPACE_shared_info,
+                                          0, entry.addr >> PAGE_SHIFT);
+            break;
+        case XEN_HVM_MEMMAP_TYPE_GRANT_TABLE:
+            if ( gnttab_frame_count != entry.size >> PAGE_SHIFT )
+            {
+                DOMPRINTF("Invalid grant table memmap region size");
+                return -EINVAL;
+            }
+
+            for ( i = 0; i < gnttab_frame_count; i++ )
+            {
+                rc = xc_domain_add_to_physmap(xch, domid, XENMAPSPACE_grant_table, i,
+                                              (entry.addr >> PAGE_SHIFT) + i);
+                
+                if ( rc !=  0 )
+                    break;
+            }
+            break;
+        case XEN_HVM_MEMMAP_TYPE_GNTTAB_STATUS:
+        {
+            if ( gnttab_status_frame_count != entry.size >> PAGE_SHIFT )
+            {
+                DOMPRINTF("Invalid grant table status memmap region size");
+                return -EINVAL;
+            }
+
+            for ( i = 0; i < gnttab_status_frame_count; i++ )
+            {
+                rc = xc_domain_add_to_physmap(xch, domid, XENMAPSPACE_grant_table,
+                                              i | XENMAPIDX_grant_table_status,
+                                              (entry.addr >> PAGE_SHIFT) + i);
+                
+                if ( rc !=  0 )
+                    break;
+            }
+            break;
+        }
+        }
+
+        if ( rc != 0 )
+            break;
+    }
+
+    return rc;
+}
+
 static int alloc_magic_pages_hvm(struct xc_dom_image *dom)
 {
     unsigned long i;
@@ -718,6 +794,14 @@ static int alloc_magic_pages_hvm(struct xc_dom_image *dom)
         goto out;
     }
 
+    rc = prepare_fixed_special_regions(xch, dom);
+
+    if ( rc != 0 )
+    {
+        DOMPRINTF("Unable to prepare fixed special regions");
+        goto out;
+    }
+
     /*
      * Identity-map page table is required for running with CR0.PG=0 when
      * using Intel EPT. Create a 32-bit non-PAE page directory of superpages.
diff --git a/tools/libs/light/libxl_create.c b/tools/libs/light/libxl_create.c
index 8a85fba1cf..5e23e122fc 100644
--- a/tools/libs/light/libxl_create.c
+++ b/tools/libs/light/libxl_create.c
@@ -2363,6 +2363,7 @@ int libxl_domain_create_restore(libxl_ctx *ctx, libxl_domain_config *d_config,
      * configuration.
      */
     libxl_defbool_setdefault(&d_config->b_info.arch_x86.msr_relaxed, true);
+    libxl_defbool_setdefault(&d_config->b_info.arch_x86.fixed_mem_layout, false);
     libxl_defbool_setdefault(&d_config->b_info.u.hvm.pirq, true);
 
     return do_domain_create(ctx, d_config, domid, restore_fd, send_back_fd,
diff --git a/tools/libs/light/libxl_types.idl b/tools/libs/light/libxl_types.idl
index a3a79d12b2..74edfdebc1 100644
--- a/tools/libs/light/libxl_types.idl
+++ b/tools/libs/light/libxl_types.idl
@@ -727,6 +727,7 @@ libxl_domain_build_info = Struct("domain_build_info",[
                                ("nr_spis", uint32, {'init_val': 'LIBXL_NR_SPIS_DEFAULT'}),
                               ])),
     ("arch_x86", Struct(None, [("msr_relaxed", libxl_defbool),
+                               ("fixed_mem_layout", libxl_defbool),
                               ])),
     # Alternate p2m is not bound to any architecture or guest type, as it is
     # supported by x86 HVM and ARM support is planned.
diff --git a/tools/libs/light/libxl_x86.c b/tools/libs/light/libxl_x86.c
index 60d4e8661c..de19f722ab 100644
--- a/tools/libs/light/libxl_x86.c
+++ b/tools/libs/light/libxl_x86.c
@@ -1,6 +1,7 @@
 #include "libxl_internal.h"
 #include "libxl_arch.h"
 #include <xen/arch-x86/cpuid.h>
+#include <xen/arch-x86/hvm/start_info.h>
 
 int libxl__arch_domain_prepare_config(libxl__gc *gc,
                                       libxl_domain_config *d_config,
@@ -50,6 +51,10 @@ static const char *e820_names(int type)
         case E820_ACPI: return "ACPI";
         case E820_NVS: return "ACPI NVS";
         case E820_UNUSABLE: return "Unusable";
+        case XEN_HVM_MEMMAP_TYPE_SHARED_INFO: return "HVM Shared Info";
+        case XEN_HVM_MEMMAP_TYPE_GRANT_TABLE: return "HVM Grant Table";
+        case XEN_HVM_MEMMAP_TYPE_GNTTAB_STATUS: return "HVM Grant Status";
+        case XEN_HVM_MEMMAP_TYPE_FOREIGN_REG: return "HVM Foreign mapping region";
         default: break;
     }
     return "Unknown";
@@ -686,10 +691,31 @@ static int domain_construct_memmap(libxl__gc *gc,
     /* We always own at least one lowmem entry. */
     unsigned int e820_entries = 1;
     struct e820entry *e820 = NULL;
+    uint64_t highmem_start = ((uint64_t)1 << 32);
     uint64_t highmem_size =
                     dom->highmem_end ? dom->highmem_end - (1ull << 32) : 0;
     uint32_t lowmem_start = dom->device_model ? GUEST_LOW_MEM_START_DEFAULT : 0;
     unsigned page_size = XC_DOM_PAGE_SIZE(dom);
+    /* Special region starts at the first 1G boundary after the highmem */
+    uint64_t special_region_start =
+        (highmem_start + highmem_size + GB(1) - 1) & ~(GB(1) - 1);
+    uint64_t special_region_offset = special_region_start;
+    size_t gnttab_frame_count, gnttab_status_frame_count;
+    gnttab_query_size_t gnttab_query;
+
+    gnttab_query.dom = domid;
+    rc = xc_gnttab_query_size(dom->xch, &gnttab_query);
+
+    if (rc != 0 || gnttab_query.status != GNTST_okay)
+    {
+        gnttab_frame_count = 0;
+        gnttab_status_frame_count = 0;
+    }
+
+    gnttab_frame_count = gnttab_query.max_nr_frames;
+    gnttab_status_frame_count = DIV_ROUNDUP(
+        gnttab_frame_count * (page_size / sizeof(grant_entry_v2_t)),
+        page_size / sizeof(grant_status_t));
 
     /* Add all rdm entries. */
     for (i = 0; i < d_config->num_rdms; i++)
@@ -703,6 +729,16 @@ static int domain_construct_memmap(libxl__gc *gc,
     /* If we should have a highmem range. */
     if (highmem_size)
         e820_entries++;
+    
+    if (libxl_defbool_val(d_config->b_info.arch_x86.fixed_mem_layout))
+    {
+        e820_entries++; /* XEN_HVM_MEMMAP_TYPE_SHARED_INFO */
+        if ( gnttab_frame_count )
+            e820_entries++; /* XEN_HVM_MEMMAP_TYPE_GRANT_TABLE */
+        if (d_config->b_info.max_grant_version >= 2 && gnttab_status_frame_count)
+            e820_entries++; /* XEN_HVM_MEMMAP_TYPE_GNTTAB_STATUS status */
+        e820_entries++; /* XEN_HVM_MEMMAP_TYPE_FOREIGN_REG */
+    }
 
     for (i = 0; i < MAX_ACPI_MODULES; i++)
         if (dom->acpi_modules[i].length)
@@ -769,6 +805,40 @@ static int domain_construct_memmap(libxl__gc *gc,
         e820[nr].type = E820_RAM;
     }
 
+    /* Special regions */
+    if (libxl_defbool_val(d_config->b_info.arch_x86.fixed_mem_layout))
+    {
+        e820[nr].type = XEN_HVM_MEMMAP_TYPE_SHARED_INFO;
+        e820[nr].addr = special_region_offset;
+        e820[nr].size = page_size;
+        special_region_offset += e820[nr].size;
+        nr++;
+
+        if ( gnttab_frame_count )
+        {
+            e820[nr].type = XEN_HVM_MEMMAP_TYPE_GRANT_TABLE;
+            e820[nr].addr = special_region_offset;
+            e820[nr].size = gnttab_frame_count * page_size;
+            special_region_offset += e820[nr].size;
+            nr++;
+        }
+
+        if (d_config->b_info.max_grant_version >= 2 && gnttab_status_frame_count)
+        {
+            e820[nr].type = XEN_HVM_MEMMAP_TYPE_GNTTAB_STATUS;
+            e820[nr].addr = special_region_offset;
+            e820[nr].size = gnttab_status_frame_count * page_size;
+            special_region_offset += e820[nr].size;
+            nr++;
+        }
+
+        e820[nr].type = XEN_HVM_MEMMAP_TYPE_FOREIGN_REG;
+        e820[nr].addr = special_region_offset;
+        e820[nr].size = MB(512);
+        special_region_offset += e820[nr].size;
+        nr++;
+    }
+
     if (xc_domain_set_memory_map(CTX->xch, domid, e820, e820_entries) != 0) {
         rc = ERROR_FAIL;
         goto out;
@@ -819,6 +889,7 @@ int libxl__arch_domain_build_info_setdefault(libxl__gc *gc,
     libxl_defbool_setdefault(&b_info->acpi, true);
     libxl_defbool_setdefault(&b_info->arch_x86.msr_relaxed, false);
     libxl_defbool_setdefault(&b_info->trap_unmapped_accesses, false);
+    libxl_defbool_setdefault(&b_info->arch_x86.fixed_mem_layout, false);
 
     if (b_info->type == LIBXL_DOMAIN_TYPE_HVM) {
         /*
diff --git a/tools/xl/xl_parse.c b/tools/xl/xl_parse.c
index 7e11c62ba0..a74cc577e9 100644
--- a/tools/xl/xl_parse.c
+++ b/tools/xl/xl_parse.c
@@ -2992,6 +2992,7 @@ skip_usbdev:
                     "WARNING: msr_relaxed will be removed in future versions.\n"
                     "If it fixes an issue you are having please report to "
                     "xen-devel@lists.xenproject.org.\n");
+    xlu_cfg_get_defbool(config, "fixed_mem_layout", &b_info->arch_x86.fixed_mem_layout, 0);
 
     xlu_cfg_get_defbool(config, "vpmu", &b_info->vpmu, 0);
 
diff --git a/xen/include/public/arch-x86/hvm/start_info.h b/xen/include/public/arch-x86/hvm/start_info.h
index e33557c0b4..0b3dfe91af 100644
--- a/xen/include/public/arch-x86/hvm/start_info.h
+++ b/xen/include/public/arch-x86/hvm/start_info.h
@@ -99,6 +99,13 @@
 #define XEN_HVM_MEMMAP_TYPE_DISABLED  6
 #define XEN_HVM_MEMMAP_TYPE_PMEM      7
 
+/* Xen-specific types (OEM-specific range of the ACPI spec) */
+#define XEN_HVM_MEMMAP_TYPE_SHARED_INFO   0xF0000001 /* Shared info page */
+#define XEN_HVM_MEMMAP_TYPE_GRANT_TABLE   0xF0000002 /* Grant table pages */
+#define XEN_HVM_MEMMAP_TYPE_GNTTAB_STATUS 0xF0000003 /* Grant table status page (v2) */
+#define XEN_HVM_MEMMAP_TYPE_FOREIGN_REG   0xF0000004 /* Suitable region for grant mappings */
+                                                     /* and foreign mappings */
+
 /*
  * C representation of the x86/HVM start info layout.
  *
-- 
2.50.1



Teddy Astie | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech



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

* [RFC PATCH 7/9] x86/hvm: Introduce FastABI implementation
  2025-08-21 15:25 [RFC PATCH 0/9] x86/hvm: New Xen HVM ABI proposal ("HVMv2" part 1) Teddy Astie
                   ` (5 preceding siblings ...)
  2025-08-21 15:25 ` [RFC PATCH 5/9] docs/x86: Introduce FastABI Teddy Astie
@ 2025-08-21 15:25 ` Teddy Astie
  2025-08-21 15:25 ` [RFC PATCH 8/9] hvm: Introduce XEN_HVM_MEMMAP_TYPE_HOTPLUG_ZONE Teddy Astie
  2025-08-21 15:25 ` [RFC PATCH 9/9] tools: Introduce abi-tool Teddy Astie
  8 siblings, 0 replies; 24+ messages in thread
From: Teddy Astie @ 2025-08-21 15:25 UTC (permalink / raw)
  To: xen-devel
  Cc: Teddy Astie, Jan Beulich, Andrew Cooper, Roger Pau Monné,
	Anthony PERARD, Michal Orzel, Julien Grall, Stefano Stabellini,
	Dario Faggioli, Juergen Gross, George Dunlap, Daniel P. Smith

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

Signed-off-by: Teddy Astie <teddy.astie@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



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

* [RFC PATCH 8/9] hvm: Introduce XEN_HVM_MEMMAP_TYPE_HOTPLUG_ZONE
  2025-08-21 15:25 [RFC PATCH 0/9] x86/hvm: New Xen HVM ABI proposal ("HVMv2" part 1) Teddy Astie
                   ` (6 preceding siblings ...)
  2025-08-21 15:25 ` [RFC PATCH 7/9] x86/hvm: Introduce FastABI implementation Teddy Astie
@ 2025-08-21 15:25 ` Teddy Astie
  2025-08-28 12:38   ` Jan Beulich
  2025-08-21 15:25 ` [RFC PATCH 9/9] tools: Introduce abi-tool Teddy Astie
  8 siblings, 1 reply; 24+ messages in thread
From: Teddy Astie @ 2025-08-21 15:25 UTC (permalink / raw)
  To: xen-devel; +Cc: Teddy Astie, Jan Beulich, Andrew Cooper, Roger Pau Monné

Allow specifying in memory map a region which can be hotplugged.

This will be used by a future memory hotplug feature.

Signed-off-by: Teddy Astie <teddy.astie@vates.tech>
---
 xen/include/public/arch-x86/hvm/start_info.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/xen/include/public/arch-x86/hvm/start_info.h b/xen/include/public/arch-x86/hvm/start_info.h
index 0b3dfe91af..bdae8371d6 100644
--- a/xen/include/public/arch-x86/hvm/start_info.h
+++ b/xen/include/public/arch-x86/hvm/start_info.h
@@ -105,6 +105,7 @@
 #define XEN_HVM_MEMMAP_TYPE_GNTTAB_STATUS 0xF0000003 /* Grant table status page (v2) */
 #define XEN_HVM_MEMMAP_TYPE_FOREIGN_REG   0xF0000004 /* Suitable region for grant mappings */
                                                      /* and foreign mappings */
+#define XEN_HVM_MEMMAP_TYPE_HOTPLUG_ZONE  0xF0000005 /* Memory hotpluggable zone */
 
 /*
  * C representation of the x86/HVM start info layout.
-- 
2.50.1



Teddy Astie | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech



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

* [RFC PATCH 9/9] tools: Introduce abi-tool
  2025-08-21 15:25 [RFC PATCH 0/9] x86/hvm: New Xen HVM ABI proposal ("HVMv2" part 1) Teddy Astie
                   ` (7 preceding siblings ...)
  2025-08-21 15:25 ` [RFC PATCH 8/9] hvm: Introduce XEN_HVM_MEMMAP_TYPE_HOTPLUG_ZONE Teddy Astie
@ 2025-08-21 15:25 ` Teddy Astie
  2025-08-24 22:36   ` Demi Marie Obenour
  8 siblings, 1 reply; 24+ messages in thread
From: Teddy Astie @ 2025-08-21 15:25 UTC (permalink / raw)
  To: xen-devel
  Cc: Teddy Astie, Andrew Cooper, Anthony PERARD, Michal Orzel,
	Jan Beulich, Julien Grall, Roger Pau Monné,
	Stefano Stabellini

abi-tool is a small Rust tool that is able to parse ABI yaml
files and generate C stubs for performing hypercalls.

Signed-off-by: Teddy Astie <teddy.astie@vates.tech>
---
Usage :
./abi-tool < abi.yaml  > abi.h
---
 xen/tools/abi-tool/.gitignore    |   1 +
 xen/tools/abi-tool/Cargo.lock    | 145 ++++++++++++++++++++++++++
 xen/tools/abi-tool/Cargo.toml    |  11 ++
 xen/tools/abi-tool/src/abi.rs    |  23 ++++
 xen/tools/abi-tool/src/c_lang.rs | 173 +++++++++++++++++++++++++++++++
 xen/tools/abi-tool/src/main.rs   |  17 +++
 xen/tools/abi-tool/src/spec.rs   |  61 +++++++++++
 7 files changed, 431 insertions(+)
 create mode 100644 xen/tools/abi-tool/.gitignore
 create mode 100644 xen/tools/abi-tool/Cargo.lock
 create mode 100644 xen/tools/abi-tool/Cargo.toml
 create mode 100644 xen/tools/abi-tool/src/abi.rs
 create mode 100644 xen/tools/abi-tool/src/c_lang.rs
 create mode 100644 xen/tools/abi-tool/src/main.rs
 create mode 100644 xen/tools/abi-tool/src/spec.rs

diff --git a/xen/tools/abi-tool/.gitignore b/xen/tools/abi-tool/.gitignore
new file mode 100644
index 0000000000..1de565933b
--- /dev/null
+++ b/xen/tools/abi-tool/.gitignore
@@ -0,0 +1 @@
+target
\ No newline at end of file
diff --git a/xen/tools/abi-tool/Cargo.lock b/xen/tools/abi-tool/Cargo.lock
new file mode 100644
index 0000000000..056a68f20f
--- /dev/null
+++ b/xen/tools/abi-tool/Cargo.lock
@@ -0,0 +1,145 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "abi-tool"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "bimap",
+ "indexmap",
+ "serde",
+ "serde_yaml",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.98"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
+
+[[package]]
+name = "arbitrary"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223"
+
+[[package]]
+name = "bimap"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[package]]
+name = "hashbrown"
+version = "0.15.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
+
+[[package]]
+name = "indexmap"
+version = "2.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
+dependencies = [
+ "arbitrary",
+ "equivalent",
+ "hashbrown",
+ "serde",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.95"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
+
+[[package]]
+name = "serde"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_yaml"
+version = "0.9.34+deprecated"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
+dependencies = [
+ "indexmap",
+ "itoa",
+ "ryu",
+ "serde",
+ "unsafe-libyaml",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.104"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+
+[[package]]
+name = "unsafe-libyaml"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
diff --git a/xen/tools/abi-tool/Cargo.toml b/xen/tools/abi-tool/Cargo.toml
new file mode 100644
index 0000000000..eee8ad18a9
--- /dev/null
+++ b/xen/tools/abi-tool/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "abi-tool"
+version = "0.1.0"
+edition = "2024"
+
+[dependencies]
+anyhow = "1.0.98"
+bimap = { version = "0.6.3", features = ["serde"] }
+indexmap = { version = "2.10.0", features = ["arbitrary", "serde"] }
+serde = { version = "1.0.219", features = ["derive"] }
+serde_yaml = "0.9.34"
diff --git a/xen/tools/abi-tool/src/abi.rs b/xen/tools/abi-tool/src/abi.rs
new file mode 100644
index 0000000000..9ca427e821
--- /dev/null
+++ b/xen/tools/abi-tool/src/abi.rs
@@ -0,0 +1,23 @@
+pub trait XenABI {
+    fn get_register_name(id: u8) -> &'static str;
+}
+
+pub struct Amd64ABI;
+
+impl XenABI for Amd64ABI {
+    fn get_register_name(id: u8) -> &'static str {
+        match id {
+            0 => "rax",
+            1 => "rdi",
+            2 => "rsi",
+            3 => "r8",
+            4 => "r9",
+            5 => "r10",
+            6 => "r11",
+            7 => "r12",
+            8 => "r13",
+
+            _ => panic!("Unexpected register id: {id}"),
+        }
+    }
+}
diff --git a/xen/tools/abi-tool/src/c_lang.rs b/xen/tools/abi-tool/src/c_lang.rs
new file mode 100644
index 0000000000..20389d305d
--- /dev/null
+++ b/xen/tools/abi-tool/src/c_lang.rs
@@ -0,0 +1,173 @@
+use std::{collections::HashMap, fmt::Write};
+
+use crate::{
+    abi::{Amd64ABI, XenABI},
+    spec::{AbiSpec, CType, HypercallOp},
+};
+
+fn emit_register_variable<ABI: XenABI>(
+    w: &mut impl Write,
+    id: u8,
+    value: Option<&str>,
+) -> anyhow::Result<()> {
+    write!(
+        w,
+        "    register {ctype} reg{id} __asm__(\"{reg}\")",
+        ctype = if id == 0 { "long" } else { "uint64_t" },
+        reg = ABI::get_register_name(id)
+    )?;
+    if let Some(value) = value {
+        write!(w, " = {value}")?;
+    }
+    writeln!(w, ";")?;
+
+    Ok(())
+}
+
+fn emit_hypercall<ABI: XenABI>(
+    w: &mut impl Write,
+    op: &HypercallOp,
+    ident: usize,
+    instruction: &str,
+) -> anyhow::Result<()> {
+    let start = format!("{:ident$}__asm__ volatile (\"{instruction}\" ", "");
+    let pad = start.len();
+
+    /* All the exclusive inputs. */
+    let reg_input = op
+        .input
+        .right_values()
+        .filter(|&input| !op.output.contains_right(input))
+        .map(|input| format!("\"r\"(reg{input})"))
+        .collect::<Box<[_]>>()
+        .join(", ");
+
+    /* Outputs that are also inputs are transformed into +r, the rest is =r */
+    let reg_output = op
+        .output
+        .right_values()
+        .chain(&[0]) /* 0 is always a input/output */
+        .map(|output| {
+            if *output == 0 || op.input.contains_right(output) {
+                format!("\"+r\"(reg{output})")
+            } else {
+                format!("\"=r\"(reg{output})")
+            }
+        })
+        .collect::<Box<[_]>>()
+        .join(", ");
+
+    writeln!(w, "{:ident$}{start}: {reg_output}", "")?;
+    writeln!(w, "{:ident$}{:pad$}: {reg_input}", "", "")?;
+    writeln!(w, "{:ident$}{:pad$}: \"memory\");", "", "")?;
+
+    Ok(())
+}
+
+fn generate_hypercall_function(
+    w: &mut impl Write,
+    hypercall_name: &str,
+    op: &HypercallOp,
+    function_name: &str,
+    subop_index: Option<u32>,
+) -> anyhow::Result<()> {
+    writeln!(w, "static inline")?;
+
+    eprintln!("Processing {hypercall_name}.{function_name}");
+    let annotations = op.c_lang.clone().unwrap_or_default();
+
+    assert!(
+        annotations.cstruct.is_some() || op.output.is_empty(),
+        "struct-less wrappers doesn't allow outputs, please use a C structure"
+    );
+
+    // Match each input register with its C value.
+    let input_map: HashMap<u8, String> = op
+        .input
+        .iter()
+        .map(|(name, &id)| {
+            if annotations.params.contains_key(name) {
+                (id, name.clone())
+            } else {
+                // Struct may have a custom mapping
+                let field = annotations.mapping.get(name).unwrap_or(name);
+
+                (id, format!("param->{field}"))
+            }
+        })
+        .collect();
+
+    write!(w, "long {function_name}(enum xen_hypercall_vendor vendor")?;
+    let pad = 6 + function_name.len();
+
+    if let Some(cstruct) = &annotations.cstruct {
+        write!(w, ",\n{:pad$}struct {cstruct} *param", "",)?;
+    }
+
+    for (name, CType(ctype)) in &annotations.params {
+        write!(w, ",\n{:pad$}{ctype} {name}", "",)?;
+    }
+
+    writeln!(w, ")")?;
+
+    writeln!(w, "{{")?;
+
+    for id in op.used_registers() {
+        // If it is a input, we need to set it here.
+        let value = match (id, subop_index) {
+            /* Hypercall index */
+            (0, _) => Some(format!(
+                "__HYPERVISOR_FASTABI_MASK | __HYPERVISOR_{hypercall_name}_op"
+            )),
+            /* Sub-operation index */
+            (1, Some(subop_index)) => Some(format!("{subop_index}")),
+            /* Other input parameter */
+            (id, _) => input_map.get(&id).cloned(),
+        };
+
+        emit_register_variable::<Amd64ABI>(w, id, value.as_deref())?;
+    }
+    writeln!(w)?;
+
+    writeln!(w, "    if ( vendor == Intel )")?;
+    emit_hypercall::<Amd64ABI>(w, op, 4, "vmcall")?;
+    writeln!(w, "    else")?;
+    emit_hypercall::<Amd64ABI>(w, op, 4, "vmmcall")?;
+
+    writeln!(w, "")?;
+
+    for (field, output) in &op.output {
+        let field = annotations.mapping.get(field).unwrap_or(field);
+
+        writeln!(w, "    param->{field} = reg{output};")?;
+    }
+
+    writeln!(w, "    return reg0;")?;
+
+    writeln!(w, "}}")?;
+
+    Ok(())
+}
+
+pub fn generate_code(w: &mut impl Write, spec: AbiSpec) -> anyhow::Result<()> {
+    writeln!(w, "/* SPDX-License-Identifier: MIT */")?;
+    writeln!(w, "/* AUTOGENERATED. DO NOT MODIFY */")?;
+    writeln!(w)?;
+
+    if let Some(op) = spec.direct {
+        let function_name = ["xen_hypercall", &spec.name].join("_");
+
+        generate_hypercall_function(w, &spec.name, &op, &function_name, None)?;
+        writeln!(w)?;
+    }
+
+    for (name, mut subop) in spec.subops {
+        let function_name = ["xen_hypercall", &spec.name, &name].join("_");
+        subop.op.input.insert("subop_index".to_string(), 1);
+
+        generate_hypercall_function(w, &spec.name, &subop.op, &function_name, Some(subop.index))?;
+        writeln!(w)?;
+    }
+
+    Ok(())
+}
diff --git a/xen/tools/abi-tool/src/main.rs b/xen/tools/abi-tool/src/main.rs
new file mode 100644
index 0000000000..dda85c24d5
--- /dev/null
+++ b/xen/tools/abi-tool/src/main.rs
@@ -0,0 +1,17 @@
+use std::io::{Read, stdin};
+
+pub mod abi;
+pub mod c_lang;
+pub mod spec;
+
+fn main() {
+    let mut buffer = String::new();
+    stdin().read_to_string(&mut buffer).unwrap();
+
+    let abi_spec: spec::AbiSpec = serde_yaml::from_str(&buffer).unwrap();
+
+    let mut buffer = String::new();
+
+    c_lang::generate_code(&mut buffer, abi_spec).unwrap();
+    print!("{buffer}");
+}
diff --git a/xen/tools/abi-tool/src/spec.rs b/xen/tools/abi-tool/src/spec.rs
new file mode 100644
index 0000000000..e5fb2c85d2
--- /dev/null
+++ b/xen/tools/abi-tool/src/spec.rs
@@ -0,0 +1,61 @@
+use std::collections::{BTreeSet, HashMap};
+
+use bimap::BiBTreeMap;
+use indexmap::IndexMap; /* use indexmap to keep consistent ordering */
+use serde::Deserialize;
+
+fn default_ctype() -> String {
+    "uint64_t".into()
+}
+
+#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Hash)]
+pub struct CType(#[serde(default = "default_ctype")] pub String);
+
+#[derive(Clone, Debug, Default, Deserialize)]
+pub struct CAnnotations {
+    #[serde(rename = "struct")]
+    pub cstruct: Option<String>,
+    #[serde(default)]
+    pub mapping: HashMap<String, String>,
+    #[serde(default)]
+    pub params: HashMap<String, CType>,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct HypercallOp {
+    #[serde(default)]
+    pub input: BiBTreeMap<String, u8>,
+    #[serde(default)]
+    pub output: BiBTreeMap<String, u8>,
+
+    pub c_lang: Option<CAnnotations>,
+}
+
+impl HypercallOp {
+    pub fn used_registers(&self) -> BTreeSet<u8> {
+        self.input
+            .right_values()
+            .chain(self.output.right_values())
+            .chain(&[0])
+            .cloned()
+            .collect()
+    }
+}
+
+#[derive(Debug, Deserialize)]
+pub struct HypercallSubOp {
+    pub index: u32,
+    #[serde(flatten)]
+    pub op: HypercallOp,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct AbiSpec {
+    pub hypercall_index: u32,
+    pub name: String,
+
+    pub direct: Option<HypercallOp>,
+
+    #[serde(default)]
+    pub subops: IndexMap<String, HypercallSubOp>,
+}
-- 
2.50.1



Teddy Astie | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech



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

* Re: [RFC PATCH 9/9] tools: Introduce abi-tool
  2025-08-21 15:25 ` [RFC PATCH 9/9] tools: Introduce abi-tool Teddy Astie
@ 2025-08-24 22:36   ` Demi Marie Obenour
  0 siblings, 0 replies; 24+ messages in thread
From: Demi Marie Obenour @ 2025-08-24 22:36 UTC (permalink / raw)
  To: Teddy Astie, xen-devel
  Cc: Andrew Cooper, Anthony PERARD, Michal Orzel, Jan Beulich,
	Julien Grall, Roger Pau Monné, Stefano Stabellini


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

On 8/21/25 11:25, Teddy Astie wrote:
> abi-tool is a small Rust tool that is able to parse ABI yaml
> files and generate C stubs for performing hypercalls.
> 
> Signed-off-by: Teddy Astie <teddy.astie@vates.tech>
Would it make sense to generate the hypervisor side of the
interface in this way as well?
-- 
Sincerely,
Demi Marie Obenour (she/her/hers)

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

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

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

* Re: [RFC PATCH 1/9] x86/hvm: Use direct structures instead of guest handles
  2025-08-21 15:25 ` [RFC PATCH 1/9] x86/hvm: Use direct structures instead of guest handles Teddy Astie
@ 2025-08-28 12:16   ` Jan Beulich
  2025-08-29 13:10     ` Teddy Astie
  0 siblings, 1 reply; 24+ messages in thread
From: Jan Beulich @ 2025-08-28 12:16 UTC (permalink / raw)
  To: Teddy Astie; +Cc: Andrew Cooper, Roger Pau Monné, xen-devel

On 21.08.2025 17:25, Teddy Astie wrote:
> Make these functions work with hypervisor-owned pointer rather than
> guest handles, so the function parameters don't have to live in guest memory.

This is odd to read - the function parameters (arguments) didn't live in
guest memory before either.

> No functional changes intended.
> 
> Signed-off-by: Teddy Astie <teddy.astie@vates.tech>
> ---
>  xen/arch/x86/hvm/hvm.c | 126 +++++++++++++++++++++++------------------
>  1 file changed, 70 insertions(+), 56 deletions(-)
> 
> diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
> index 56c7de3977..8bf59c63fe 100644
> --- a/xen/arch/x86/hvm/hvm.c
> +++ b/xen/arch/x86/hvm/hvm.c
> @@ -4142,19 +4142,14 @@ static int hvmop_flush_tlb_all(void)
>      return paging_flush_tlb(NULL) ? 0 : -ERESTART;
>  }
>  
> -static int hvmop_set_evtchn_upcall_vector(
> -    XEN_GUEST_HANDLE_PARAM(xen_hvm_evtchn_upcall_vector_t) uop)
> +static int hvmop_set_evtchn_upcall_vector(xen_hvm_evtchn_upcall_vector_t op)

Please can we avoid passing structures by value?

More generally: This one-by-one adjustment is what I'd really like to avoid
with any new interface. It would be far better if ...

>  {
> -    xen_hvm_evtchn_upcall_vector_t op;
>      struct domain *d = current->domain;
>      struct vcpu *v;
>  
>      if ( !is_hvm_domain(d) )
>          return -EINVAL;
>  
> -    if ( copy_from_guest(&op, uop, 1) )
> -        return -EFAULT;

... copy_from_guest() could transparantly handle both cases (virtual and
physical addresses being used). And yes, this would exclude an "everying in
registers" approach.

> @@ -5115,28 +5087,70 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg)
>      switch ( op )
>      {
>      case HVMOP_set_evtchn_upcall_vector:
> -        rc = hvmop_set_evtchn_upcall_vector(
> -            guest_handle_cast(arg, xen_hvm_evtchn_upcall_vector_t));
> +    {
> +        struct xen_hvm_evtchn_upcall_vector op;
> +
> +        if ( copy_from_guest(&op, arg, 1) )
> +        {
> +            rc = -EFAULT;
> +            break;
> +        }
> +
> +        rc = hvmop_set_evtchn_upcall_vector(op);
>          break;
> +    }
>      
>      case HVMOP_set_param:
> -        rc = hvmop_set_param(
> -            guest_handle_cast(arg, xen_hvm_param_t));
> +    {
> +        struct xen_hvm_param op;
> +        
> +        if ( copy_from_guest(&op, arg, 1) )
> +        {
> +            rc = -EFAULT;
> +            break;
> +        }
> +
> +        rc = hvmop_set_param(op);
>          break;
> +    }
>  
>      case HVMOP_get_param:
> -        rc = hvmop_get_param(
> -            guest_handle_cast(arg, xen_hvm_param_t));
> +    {
> +        struct xen_hvm_param op;
> +        
> +        if ( copy_from_guest(&op, arg, 1) )
> +        {
> +            rc = -EFAULT;
> +            break;
> +        }
> +
> +        rc = hvmop_get_param(&op);
> +
> +        if ( !rc && copy_to_guest(arg, &op, 1) )

Why would the original __copy_to_guest() need to change to copy_to_guest()?

Jan


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

* Re: [RFC PATCH 2/9] common: Isolate XENVER_get_features into a separate function
  2025-08-21 15:25 ` [RFC PATCH 2/9] common: Isolate XENVER_get_features into a separate function Teddy Astie
@ 2025-08-28 12:18   ` Jan Beulich
  0 siblings, 0 replies; 24+ messages in thread
From: Jan Beulich @ 2025-08-28 12:18 UTC (permalink / raw)
  To: Teddy Astie
  Cc: Andrew Cooper, Anthony PERARD, Michal Orzel, Julien Grall,
	Roger Pau Monné, Stefano Stabellini, xen-devel

On 21.08.2025 17:25, Teddy Astie wrote:
> Make do_xen_version more readable by moving the main XENVER_get_features
> into a separate function.

I can't spot much of a readability gain, to be honest.

> --- a/xen/common/kernel.c
> +++ b/xen/common/kernel.c
> @@ -569,6 +569,50 @@ static long xenver_varbuf_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
>      return sz;
>  }
>  
> +static long xenver_get_features(struct domain *d, uint32_t submap_idx, uint32_t *submap)

Why "long", when you only return "int" -errno values?

Speaking of "long", why such long a line?

Jan


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

* Re: [RFC PATCH 3/9] common/grant_table: Use direct structures instead of guest handles
  2025-08-21 15:25 ` [RFC PATCH 3/9] common/grant_table: Use direct structures instead of guest handles Teddy Astie
@ 2025-08-28 12:21   ` Jan Beulich
  0 siblings, 0 replies; 24+ messages in thread
From: Jan Beulich @ 2025-08-28 12:21 UTC (permalink / raw)
  To: Teddy Astie
  Cc: Andrew Cooper, Anthony PERARD, Michal Orzel, Julien Grall,
	Roger Pau Monné, Stefano Stabellini, xen-devel

On 21.08.2025 17:25, Teddy Astie wrote:
> Make these functions work with hypervisor-owned pointer rather than
> guest handles, so the function parameters don't have to live in guest memory.
> 
> No functional changes.
> 
> Signed-off-by: Teddy Astie <teddy.astie@vates.tech>

Unlike title/description suggest, this only touched two out of many sub-ops.
As others don't lend themselves to your goal, that makes things overall
inconsistent, for a questionable gain.

Jan


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

* Re: [RFC PATCH 4/9] hvm: Introduce "fixed memory layout" feature
  2025-08-21 15:25 ` [RFC PATCH 4/9] hvm: Introduce "fixed memory layout" feature Teddy Astie
@ 2025-08-28 12:30   ` Jan Beulich
  2025-08-29 13:32     ` Teddy Astie
  0 siblings, 1 reply; 24+ messages in thread
From: Jan Beulich @ 2025-08-28 12:30 UTC (permalink / raw)
  To: Teddy Astie
  Cc: Andrew Cooper, Anthony PERARD, Michal Orzel, Julien Grall,
	Roger Pau Monné, Stefano Stabellini, Juergen Gross,
	xen-devel

On 21.08.2025 17:25, Teddy Astie wrote:
> @@ -686,10 +691,31 @@ static int domain_construct_memmap(libxl__gc *gc,
>      /* We always own at least one lowmem entry. */
>      unsigned int e820_entries = 1;
>      struct e820entry *e820 = NULL;
> +    uint64_t highmem_start = ((uint64_t)1 << 32);
>      uint64_t highmem_size =
>                      dom->highmem_end ? dom->highmem_end - (1ull << 32) : 0;
>      uint32_t lowmem_start = dom->device_model ? GUEST_LOW_MEM_START_DEFAULT : 0;
>      unsigned page_size = XC_DOM_PAGE_SIZE(dom);
> +    /* Special region starts at the first 1G boundary after the highmem */
> +    uint64_t special_region_start =
> +        (highmem_start + highmem_size + GB(1) - 1) & ~(GB(1) - 1);

That is, inaccessible before entering PAE mode?

The open-coding of ROUNDUP() also isn't nice, but sadly unavoidable as long
the the macro works in terms of unsigned long.

> @@ -769,6 +805,40 @@ static int domain_construct_memmap(libxl__gc *gc,
>          e820[nr].type = E820_RAM;
>      }
>  
> +    /* Special regions */
> +    if (libxl_defbool_val(d_config->b_info.arch_x86.fixed_mem_layout))
> +    {
> +        e820[nr].type = XEN_HVM_MEMMAP_TYPE_SHARED_INFO;
> +        e820[nr].addr = special_region_offset;
> +        e820[nr].size = page_size;
> +        special_region_offset += e820[nr].size;
> +        nr++;
> +
> +        if ( gnttab_frame_count )
> +        {
> +            e820[nr].type = XEN_HVM_MEMMAP_TYPE_GRANT_TABLE;
> +            e820[nr].addr = special_region_offset;
> +            e820[nr].size = gnttab_frame_count * page_size;
> +            special_region_offset += e820[nr].size;
> +            nr++;
> +        }
> +
> +        if (d_config->b_info.max_grant_version >= 2 && gnttab_status_frame_count)
> +        {
> +            e820[nr].type = XEN_HVM_MEMMAP_TYPE_GNTTAB_STATUS;
> +            e820[nr].addr = special_region_offset;
> +            e820[nr].size = gnttab_status_frame_count * page_size;
> +            special_region_offset += e820[nr].size;
> +            nr++;
> +        }
> +
> +        e820[nr].type = XEN_HVM_MEMMAP_TYPE_FOREIGN_REG;
> +        e820[nr].addr = special_region_offset;
> +        e820[nr].size = MB(512);

Can we really know this is going to be enough for all use cases?

> --- a/xen/include/public/arch-x86/hvm/start_info.h
> +++ b/xen/include/public/arch-x86/hvm/start_info.h
> @@ -99,6 +99,13 @@
>  #define XEN_HVM_MEMMAP_TYPE_DISABLED  6
>  #define XEN_HVM_MEMMAP_TYPE_PMEM      7
>  
> +/* Xen-specific types (OEM-specific range of the ACPI spec) */
> +#define XEN_HVM_MEMMAP_TYPE_SHARED_INFO   0xF0000001 /* Shared info page */
> +#define XEN_HVM_MEMMAP_TYPE_GRANT_TABLE   0xF0000002 /* Grant table pages */
> +#define XEN_HVM_MEMMAP_TYPE_GNTTAB_STATUS 0xF0000003 /* Grant table status page (v2) */
> +#define XEN_HVM_MEMMAP_TYPE_FOREIGN_REG   0xF0000004 /* Suitable region for grant mappings */
> +                                                     /* and foreign mappings */

I question it being legitimate for us to introduce new E820 types.

Jan


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

* Re: [RFC PATCH 5/9] docs/x86: Introduce FastABI
  2025-08-21 15:25 ` [RFC PATCH 5/9] docs/x86: Introduce FastABI Teddy Astie
@ 2025-08-28 12:32   ` Jan Beulich
  2025-08-29 13:59     ` Teddy Astie
  0 siblings, 1 reply; 24+ messages in thread
From: Jan Beulich @ 2025-08-28 12:32 UTC (permalink / raw)
  To: Teddy Astie
  Cc: Andrew Cooper, Anthony PERARD, Michal Orzel, Julien Grall,
	Roger Pau Monné, Stefano Stabellini, xen-devel

On 21.08.2025 17:25, Teddy Astie wrote:
> FastABI is a alternative ABI designed with performance and coco-enabled
> guest in mind. It is register-oriented instead of refering to C structures
> in the guest memory (through a virtual memory pointer).
> 
> It only focuses on kernel-side hypercalls, it doesn't aim to provide toolstack
> operations.

And even there it excludes certain pretty relevant ones, like many of the
gnttabop sub-ops. As alluded to by a reply to an earlier patch, I don't
think having an ABI for just a subset of the hypercalls is going to help.

Jan


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

* Re: [RFC PATCH 6/9] sched: Extract do_poll main logic into vcpu_poll
  2025-08-21 15:25 ` [RFC PATCH 6/9] sched: Extract do_poll main logic into vcpu_poll Teddy Astie
@ 2025-08-28 12:36   ` Jan Beulich
  0 siblings, 0 replies; 24+ messages in thread
From: Jan Beulich @ 2025-08-28 12:36 UTC (permalink / raw)
  To: Teddy Astie; +Cc: Dario Faggioli, Juergen Gross, George Dunlap, xen-devel

On 21.08.2025 17:25, Teddy Astie wrote:
> do_poll takes sched_poll* as parameter, but that's actually in guest memory
> (so it's more a guest handle).

No, it's not, or else ...

> --- a/xen/common/sched/core.c
> +++ b/xen/common/sched/core.c
> @@ -1437,21 +1437,13 @@ static void vcpu_block_enable_events(void)
>      vcpu_block();
>  }
>  
> -static long do_poll(const struct sched_poll *sched_poll)
> +static long vcpu_poll(unsigned int nr_ports, uint64_t timeout, evtchn_port_t *ports)
>  {
>      struct vcpu   *v = current;
>      struct domain *d = v->domain;
> -    evtchn_port_t  port = 0;
>      long           rc;
>      unsigned int   i;
>  
> -    /* Fairly arbitrary limit. */
> -    if ( sched_poll->nr_ports > 128 )

... this access would be a security issue. The handle is ...

> -        return -EINVAL;
> -
> -    if ( !guest_handle_okay(sched_poll->ports, sched_poll->nr_ports) )

... seen here, the ->ports member.

Here as well as for patch 1 and 3 what is entirely lacking from the description
is the mentioning of why the change is actually going to be useful.

Jan


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

* Re: [RFC PATCH 8/9] hvm: Introduce XEN_HVM_MEMMAP_TYPE_HOTPLUG_ZONE
  2025-08-21 15:25 ` [RFC PATCH 8/9] hvm: Introduce XEN_HVM_MEMMAP_TYPE_HOTPLUG_ZONE Teddy Astie
@ 2025-08-28 12:38   ` Jan Beulich
  2025-08-29 13:48     ` Teddy Astie
  0 siblings, 1 reply; 24+ messages in thread
From: Jan Beulich @ 2025-08-28 12:38 UTC (permalink / raw)
  To: Teddy Astie; +Cc: Andrew Cooper, Roger Pau Monné, xen-devel

On 21.08.2025 17:25, Teddy Astie wrote:
> Allow specifying in memory map a region which can be hotplugged.
> 
> This will be used by a future memory hotplug feature.

Why could this not be done the ACPI way, with the regions properly specified
in SRAT?

Jan


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

* Re: [RFC PATCH 1/9] x86/hvm: Use direct structures instead of guest handles
  2025-08-28 12:16   ` Jan Beulich
@ 2025-08-29 13:10     ` Teddy Astie
  0 siblings, 0 replies; 24+ messages in thread
From: Teddy Astie @ 2025-08-29 13:10 UTC (permalink / raw)
  To: Jan Beulich; +Cc: Andrew Cooper, Roger Pau Monné, xen-devel

Le 28/08/2025 à 14:16, Jan Beulich a écrit :
> On 21.08.2025 17:25, Teddy Astie wrote:
>> Make these functions work with hypervisor-owned pointer rather than
>> guest handles, so the function parameters don't have to live in guest memory.
>
> This is odd to read - the function parameters (arguments) didn't live in
> guest memory before either.
>

I agree, I should reword that so that it's less confusing.

>> No functional changes intended.
>>
>> Signed-off-by: Teddy Astie <teddy.astie@vates.tech>
>> ---
>>   xen/arch/x86/hvm/hvm.c | 126 +++++++++++++++++++++++------------------
>>   1 file changed, 70 insertions(+), 56 deletions(-)
>>
>> diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
>> index 56c7de3977..8bf59c63fe 100644
>> --- a/xen/arch/x86/hvm/hvm.c
>> +++ b/xen/arch/x86/hvm/hvm.c
>> @@ -4142,19 +4142,14 @@ static int hvmop_flush_tlb_all(void)
>>       return paging_flush_tlb(NULL) ? 0 : -ERESTART;
>>   }
>>
>> -static int hvmop_set_evtchn_upcall_vector(
>> -    XEN_GUEST_HANDLE_PARAM(xen_hvm_evtchn_upcall_vector_t) uop)
>> +static int hvmop_set_evtchn_upcall_vector(xen_hvm_evtchn_upcall_vector_t op)
>
> Please can we avoid passing structures by value?
>

We could, but we would end up having to modify more code to go there i.e
replacing all op.* with op->* which I tried to avoid here.

> More generally: This one-by-one adjustment is what I'd really like to avoid
> with any new interface. It would be far better if ...
>
>>   {
>> -    xen_hvm_evtchn_upcall_vector_t op;
>>       struct domain *d = current->domain;
>>       struct vcpu *v;
>>
>>       if ( !is_hvm_domain(d) )
>>           return -EINVAL;
>>
>> -    if ( copy_from_guest(&op, uop, 1) )
>> -        return -EFAULT;
>
> ... copy_from_guest() could transparantly handle both cases (virtual and
> physical addresses being used). And yes, this would exclude an "everying in
> registers" approach.
>

A part of the goal here is to split the ABI part from the hypercall
logic; such as it gets possible to have ABI that don't need to refer to
guest addresses (either virtual or physical); and could help dealing
with current 32-bits vs 64-bits ABIs. All without duplicating the main
hypercall logic.

>> @@ -5115,28 +5087,70 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg)
>>       switch ( op )
>>       {
>>       case HVMOP_set_evtchn_upcall_vector:
>> -        rc = hvmop_set_evtchn_upcall_vector(
>> -            guest_handle_cast(arg, xen_hvm_evtchn_upcall_vector_t));
>> +    {
>> +        struct xen_hvm_evtchn_upcall_vector op;
>> +
>> +        if ( copy_from_guest(&op, arg, 1) )
>> +        {
>> +            rc = -EFAULT;
>> +            break;
>> +        }
>> +
>> +        rc = hvmop_set_evtchn_upcall_vector(op);
>>           break;
>> +    }
>>
>>       case HVMOP_set_param:
>> -        rc = hvmop_set_param(
>> -            guest_handle_cast(arg, xen_hvm_param_t));
>> +    {
>> +        struct xen_hvm_param op;
>> +
>> +        if ( copy_from_guest(&op, arg, 1) )
>> +        {
>> +            rc = -EFAULT;
>> +            break;
>> +        }
>> +
>> +        rc = hvmop_set_param(op);
>>           break;
>> +    }
>>
>>       case HVMOP_get_param:
>> -        rc = hvmop_get_param(
>> -            guest_handle_cast(arg, xen_hvm_param_t));
>> +    {
>> +        struct xen_hvm_param op;
>> +
>> +        if ( copy_from_guest(&op, arg, 1) )
>> +        {
>> +            rc = -EFAULT;
>> +            break;
>> +        }
>> +
>> +        rc = hvmop_get_param(&op);
>> +
>> +        if ( !rc && copy_to_guest(arg, &op, 1) )
>
> Why would the original __copy_to_guest() need to change to copy_to_guest()?
>

That doesn't need to.

> Jan

Teddy


Teddy Astie | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech




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

* Re: [RFC PATCH 4/9] hvm: Introduce "fixed memory layout" feature
  2025-08-28 12:30   ` Jan Beulich
@ 2025-08-29 13:32     ` Teddy Astie
  2025-09-01 15:48       ` Jan Beulich
  0 siblings, 1 reply; 24+ messages in thread
From: Teddy Astie @ 2025-08-29 13:32 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Andrew Cooper, Anthony PERARD, Michal Orzel, Julien Grall,
	Roger Pau Monné, Stefano Stabellini, Juergen Gross,
	xen-devel

Le 28/08/2025 à 14:30, Jan Beulich a écrit :
> On 21.08.2025 17:25, Teddy Astie wrote:
>> @@ -686,10 +691,31 @@ static int domain_construct_memmap(libxl__gc *gc,
>>       /* We always own at least one lowmem entry. */
>>       unsigned int e820_entries = 1;
>>       struct e820entry *e820 = NULL;
>> +    uint64_t highmem_start = ((uint64_t)1 << 32);
>>       uint64_t highmem_size =
>>                       dom->highmem_end ? dom->highmem_end - (1ull << 32) : 0;
>>       uint32_t lowmem_start = dom->device_model ? GUEST_LOW_MEM_START_DEFAULT : 0;
>>       unsigned page_size = XC_DOM_PAGE_SIZE(dom);
>> +    /* Special region starts at the first 1G boundary after the highmem */
>> +    uint64_t special_region_start =
>> +        (highmem_start + highmem_size + GB(1) - 1) & ~(GB(1) - 1);
>
> That is, inaccessible before entering PAE mode?
>

Yes, I expect this to be only used by newer guests which hopefully
aren't limited to 4G range (i.e supports PAE or long mode). The issue of
trying to put that below 4G is that much of the space is already taken
for the MMIO hole, so that area would quite complicated with more
special regions.

> The open-coding of ROUNDUP() also isn't nice, but sadly unavoidable as long
> the the macro works in terms of unsigned long.
>
>> @@ -769,6 +805,40 @@ static int domain_construct_memmap(libxl__gc *gc,
>>           e820[nr].type = E820_RAM;
>>       }
>>
>> +    /* Special regions */
>> +    if (libxl_defbool_val(d_config->b_info.arch_x86.fixed_mem_layout))
>> +    {
>> +        e820[nr].type = XEN_HVM_MEMMAP_TYPE_SHARED_INFO;
>> +        e820[nr].addr = special_region_offset;
>> +        e820[nr].size = page_size;
>> +        special_region_offset += e820[nr].size;
>> +        nr++;
>> +
>> +        if ( gnttab_frame_count )
>> +        {
>> +            e820[nr].type = XEN_HVM_MEMMAP_TYPE_GRANT_TABLE;
>> +            e820[nr].addr = special_region_offset;
>> +            e820[nr].size = gnttab_frame_count * page_size;
>> +            special_region_offset += e820[nr].size;
>> +            nr++;
>> +        }
>> +
>> +        if (d_config->b_info.max_grant_version >= 2 && gnttab_status_frame_count)
>> +        {
>> +            e820[nr].type = XEN_HVM_MEMMAP_TYPE_GNTTAB_STATUS;
>> +            e820[nr].addr = special_region_offset;
>> +            e820[nr].size = gnttab_status_frame_count * page_size;
>> +            special_region_offset += e820[nr].size;
>> +            nr++;
>> +        }
>> +
>> +        e820[nr].type = XEN_HVM_MEMMAP_TYPE_FOREIGN_REG;
>> +        e820[nr].addr = special_region_offset;
>> +        e820[nr].size = MB(512);
>
> Can we really know this is going to be enough for all use cases?
>

Probably not, but we could make this area larger in the future without
changing this ABI.

>> --- a/xen/include/public/arch-x86/hvm/start_info.h
>> +++ b/xen/include/public/arch-x86/hvm/start_info.h
>> @@ -99,6 +99,13 @@
>>   #define XEN_HVM_MEMMAP_TYPE_DISABLED  6
>>   #define XEN_HVM_MEMMAP_TYPE_PMEM      7
>>
>> +/* Xen-specific types (OEM-specific range of the ACPI spec) */
>> +#define XEN_HVM_MEMMAP_TYPE_SHARED_INFO   0xF0000001 /* Shared info page */
>> +#define XEN_HVM_MEMMAP_TYPE_GRANT_TABLE   0xF0000002 /* Grant table pages */
>> +#define XEN_HVM_MEMMAP_TYPE_GNTTAB_STATUS 0xF0000003 /* Grant table status page (v2) */
>> +#define XEN_HVM_MEMMAP_TYPE_FOREIGN_REG   0xF0000004 /* Suitable region for grant mappings */
>> +                                                     /* and foreign mappings */
>
> I question it being legitimate for us to introduce new E820 types.
>

These E820 types are (at least in ACPI specification) in the OEM-defined
range which seems appropriate for me to use for Xen-specific mappings.

We could use reserved, but we still need a way to tell the OS what each
of these "reserved" regions actually means (or it is gonna be ignored).

> Jan
Teddy



Teddy Astie | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech




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

* Re: [RFC PATCH 8/9] hvm: Introduce XEN_HVM_MEMMAP_TYPE_HOTPLUG_ZONE
  2025-08-28 12:38   ` Jan Beulich
@ 2025-08-29 13:48     ` Teddy Astie
  0 siblings, 0 replies; 24+ messages in thread
From: Teddy Astie @ 2025-08-29 13:48 UTC (permalink / raw)
  To: Jan Beulich; +Cc: Andrew Cooper, Roger Pau Monné, xen-devel

Le 28/08/2025 à 14:40, Jan Beulich a écrit :
> On 21.08.2025 17:25, Teddy Astie wrote:
>> Allow specifying in memory map a region which can be hotplugged.
>>
>> This will be used by a future memory hotplug feature.
>
> Why could this not be done the ACPI way, with the regions properly specified
> in SRAT?
>

I am not sure whether or not ACPI mandates a specific way of doing
memory hotplug when SRAT is advertised. But if doesn't, SRAT sounds like
a better alternative.

> Jan
>



Teddy Astie | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech




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

* Re: [RFC PATCH 5/9] docs/x86: Introduce FastABI
  2025-08-28 12:32   ` Jan Beulich
@ 2025-08-29 13:59     ` Teddy Astie
  2025-09-01 15:52       ` Jan Beulich
  0 siblings, 1 reply; 24+ messages in thread
From: Teddy Astie @ 2025-08-29 13:59 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Andrew Cooper, Anthony PERARD, Michal Orzel, Julien Grall,
	Roger Pau Monné, Stefano Stabellini, xen-devel

Le 28/08/2025 à 14:35, Jan Beulich a écrit :
> On 21.08.2025 17:25, Teddy Astie wrote:
>> FastABI is a alternative ABI designed with performance and coco-enabled
>> guest in mind. It is register-oriented instead of refering to C structures
>> in the guest memory (through a virtual memory pointer).
>>
>> It only focuses on kernel-side hypercalls, it doesn't aim to provide toolstack
>> operations.
>
> And even there it excludes certain pretty relevant ones, like many of the
> gnttabop sub-ops. As alluded to by a reply to an earlier patch, I don't
> think having an ABI for just a subset of the hypercalls is going to help.
>

Many hypercalls are missing in current RFC, including the grant
map/unmap ones. But a part of the idea is to still having some
hypercalls out of scope (mainly legacy and toolstack-specific ones) to
reduce the complexity.

> Jan
>



Teddy Astie | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech




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

* Re: [RFC PATCH 4/9] hvm: Introduce "fixed memory layout" feature
  2025-08-29 13:32     ` Teddy Astie
@ 2025-09-01 15:48       ` Jan Beulich
  0 siblings, 0 replies; 24+ messages in thread
From: Jan Beulich @ 2025-09-01 15:48 UTC (permalink / raw)
  To: Teddy Astie
  Cc: Andrew Cooper, Anthony PERARD, Michal Orzel, Julien Grall,
	Roger Pau Monné, Stefano Stabellini, Juergen Gross,
	xen-devel

On 29.08.2025 15:32, Teddy Astie wrote:
> Le 28/08/2025 à 14:30, Jan Beulich a écrit :
>> On 21.08.2025 17:25, Teddy Astie wrote:
>>> @@ -686,10 +691,31 @@ static int domain_construct_memmap(libxl__gc *gc,
>>>       /* We always own at least one lowmem entry. */
>>>       unsigned int e820_entries = 1;
>>>       struct e820entry *e820 = NULL;
>>> +    uint64_t highmem_start = ((uint64_t)1 << 32);
>>>       uint64_t highmem_size =
>>>                       dom->highmem_end ? dom->highmem_end - (1ull << 32) : 0;
>>>       uint32_t lowmem_start = dom->device_model ? GUEST_LOW_MEM_START_DEFAULT : 0;
>>>       unsigned page_size = XC_DOM_PAGE_SIZE(dom);
>>> +    /* Special region starts at the first 1G boundary after the highmem */
>>> +    uint64_t special_region_start =
>>> +        (highmem_start + highmem_size + GB(1) - 1) & ~(GB(1) - 1);
>>
>> That is, inaccessible before entering PAE mode?
> 
> Yes, I expect this to be only used by newer guests which hopefully 
> aren't limited to 4G range (i.e supports PAE or long mode). The issue of 
> trying to put that below 4G is that much of the space is already taken 
> for the MMIO hole, so that area would quite complicated with more 
> special regions.

Which excludes any boot loaders simple enough to not even require entering
paging mode.

>>> --- a/xen/include/public/arch-x86/hvm/start_info.h
>>> +++ b/xen/include/public/arch-x86/hvm/start_info.h
>>> @@ -99,6 +99,13 @@
>>>   #define XEN_HVM_MEMMAP_TYPE_DISABLED  6
>>>   #define XEN_HVM_MEMMAP_TYPE_PMEM      7
>>>   
>>> +/* Xen-specific types (OEM-specific range of the ACPI spec) */
>>> +#define XEN_HVM_MEMMAP_TYPE_SHARED_INFO   0xF0000001 /* Shared info page */
>>> +#define XEN_HVM_MEMMAP_TYPE_GRANT_TABLE   0xF0000002 /* Grant table pages */
>>> +#define XEN_HVM_MEMMAP_TYPE_GNTTAB_STATUS 0xF0000003 /* Grant table status page (v2) */
>>> +#define XEN_HVM_MEMMAP_TYPE_FOREIGN_REG   0xF0000004 /* Suitable region for grant mappings */
>>> +                                                     /* and foreign mappings */
>>
>> I question it being legitimate for us to introduce new E820 types.
> 
> These E820 types are (at least in ACPI specification) in the OEM-defined 
> range which seems appropriate for me to use for Xen-specific mappings.

Just that we're not an OEM.

Jan


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

* Re: [RFC PATCH 5/9] docs/x86: Introduce FastABI
  2025-08-29 13:59     ` Teddy Astie
@ 2025-09-01 15:52       ` Jan Beulich
  0 siblings, 0 replies; 24+ messages in thread
From: Jan Beulich @ 2025-09-01 15:52 UTC (permalink / raw)
  To: Teddy Astie
  Cc: Andrew Cooper, Anthony PERARD, Michal Orzel, Julien Grall,
	Roger Pau Monné, Stefano Stabellini, xen-devel

On 29.08.2025 15:59, Teddy Astie wrote:
> Le 28/08/2025 à 14:35, Jan Beulich a écrit :
>> On 21.08.2025 17:25, Teddy Astie wrote:
>>> FastABI is a alternative ABI designed with performance and coco-enabled
>>> guest in mind. It is register-oriented instead of refering to C structures
>>> in the guest memory (through a virtual memory pointer).
>>>
>>> It only focuses on kernel-side hypercalls, it doesn't aim to provide toolstack
>>> operations.
>>
>> And even there it excludes certain pretty relevant ones, like many of the
>> gnttabop sub-ops. As alluded to by a reply to an earlier patch, I don't
>> think having an ABI for just a subset of the hypercalls is going to help.
>>
> 
> Many hypercalls are missing in current RFC, including the grant 
> map/unmap ones.

Yet the built-in batching that these come with would make it particularly
interesting to see how you envision to support them without needing to
access guest memory. (I simply can't see how that could work.)

Jan

> But a part of the idea is to still having some 
> hypercalls out of scope (mainly legacy and toolstack-specific ones) to 
> reduce the complexity.
> 
> Teddy Astie | Vates XCP-ng Developer
> 
> XCP-ng & Xen Orchestra - Vates solutions
> 
> web: https://vates.tech
> 
> 



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

end of thread, other threads:[~2025-09-01 15:52 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-21 15:25 [RFC PATCH 0/9] x86/hvm: New Xen HVM ABI proposal ("HVMv2" part 1) Teddy Astie
2025-08-21 15:25 ` [RFC PATCH 1/9] x86/hvm: Use direct structures instead of guest handles Teddy Astie
2025-08-28 12:16   ` Jan Beulich
2025-08-29 13:10     ` Teddy Astie
2025-08-21 15:25 ` [RFC PATCH 2/9] common: Isolate XENVER_get_features into a separate function Teddy Astie
2025-08-28 12:18   ` Jan Beulich
2025-08-21 15:25 ` [RFC PATCH 3/9] common/grant_table: Use direct structures instead of guest handles Teddy Astie
2025-08-28 12:21   ` Jan Beulich
2025-08-21 15:25 ` [RFC PATCH 4/9] hvm: Introduce "fixed memory layout" feature Teddy Astie
2025-08-28 12:30   ` Jan Beulich
2025-08-29 13:32     ` Teddy Astie
2025-09-01 15:48       ` Jan Beulich
2025-08-21 15:25 ` [RFC PATCH 6/9] sched: Extract do_poll main logic into vcpu_poll Teddy Astie
2025-08-28 12:36   ` Jan Beulich
2025-08-21 15:25 ` [RFC PATCH 5/9] docs/x86: Introduce FastABI Teddy Astie
2025-08-28 12:32   ` Jan Beulich
2025-08-29 13:59     ` Teddy Astie
2025-09-01 15:52       ` Jan Beulich
2025-08-21 15:25 ` [RFC PATCH 7/9] x86/hvm: Introduce FastABI implementation Teddy Astie
2025-08-21 15:25 ` [RFC PATCH 8/9] hvm: Introduce XEN_HVM_MEMMAP_TYPE_HOTPLUG_ZONE Teddy Astie
2025-08-28 12:38   ` Jan Beulich
2025-08-29 13:48     ` Teddy Astie
2025-08-21 15:25 ` [RFC PATCH 9/9] tools: Introduce abi-tool Teddy Astie
2025-08-24 22:36   ` Demi Marie Obenour

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).