All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs
@ 2024-11-15 11:51 Alejandro Vallejo
  2024-11-15 11:51 ` [RFC PATCH 01/25] xen/domctl: Refine grant_opts into max_grant_version Alejandro Vallejo
                   ` (25 more replies)
  0 siblings, 26 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel
  Cc: Alejandro Vallejo, Juergen Gross, Julien Grall, Anthony PERARD,
	Andrew Cooper, Jan Beulich, Stefano Stabellini, Christian Lindig,
	David Scott, Marek Marczykowski-Górecki, Bertrand Marquis,
	Michal Orzel, Volodymyr Babchuk, Roger Pau Monné,
	Samuel Thibault, Daniel P. Smith, Tim Deegan, Lukasz Hawrylko,
	Mateusz Mówka, Doug Goldstein, Teddy Astie, Yann Dirson

This series is the result of my "Interfacing Rust with Xen" talk in Xen Summit.
It adds a hypercall ABI IDL parser and generator to the xen tree, replaces a
couple of existing hypercalls, creates a Rust crate with autogenerated contents
an creates a CI job to ensure nothing goes out of sync.

The changes are fairly invasive because the various autogenerated items appear
in many places (specially the domaincreate flags). However, the changes to the
hypervisor are all mechanical and not functional (not intentionally so, at
least).

I've split the generator in reasonably small pieces, but it's still not a small
tool. The Rust backend remains monolithic in a single patch until the RFC goes
further. It mirrors the C backend for the most part.

The hypercall ABI is specified in a schema of TOML. Most of it should be fairly
obvious as to what it does and means, with the possible exception of the "typ"
field. That has the look of a dictionary because that helps the deserializer to
automatically resolve the typ to a convenient Rust enum type (Typ). In time,
that will become something nicer to write, but that's fairly far in my list of
priorities at the moment.

After the series sysctl::readconsole and domctl::createdomain are autogenerated
from their formalized forms. In the course of formalizing the ABI it became
apparent readconsole has a different ABI in 32 and 64 bits. While benign in
that particular case, it's yet one more reason to formalize the ABI in a
language agnostic way and have it machine-checked.

======== The Plan ===========

So, the idea of the series is to adjust 2 meaningful hypercalls to TOML-based
specifications (sysctl::readconsole and domctl::createdomain). The series is
organised in the following chunks of work

  1. Sanitise domctl::createdomain to remove packed subfields.
  2. Introduce xenbindgen (IDL parser and generator for C).
  3. Specify hypercalls in TOML, and replace the hand-crafted public bits.
  4. Introduce Rust generator for xenbindgen.
  5. Introduce a xen-sys crate, with the autogenerated Rust constructs.
  6. Introduce CI checks for Rust linters, ABI validation and autogenerated
     file consistency.

Future work involves migrating more hypercalls, in the same way patch 12 does.
Most hypercalls should not take the amount of churn createdomain did. With the
foundations laid down the involved work should be simple.

I have considered integrating the hypercall generation in the build process.
That forces the Rust toolchain to be in the list of build dependencies for
downstreams, which might be complicated or annoying. For the time being, I
think checking in the autogenerated files and confirming in CI that they are
in-sync is (imo) more than enough.

======== Patch grouping ===========

Patches 1 and 2 remove packed subfields to allow encoding it in the TOML specs
(e.g: see patch 13, replace hand-crafted altp2m_mode). It's non-functional
changes aiming to reach simpler representability.

  Patch 1.  xen/domctl: Refine grant_opts into max_grant_version
  Patch 2.  xen/domctl: Replace altp2m_opts with altp2m_mode

Patches 3 to 10 are xenbindgen (with the C generator backend only). The
Cargo.lock file in patch 4 is required for build reproducibility and is
recommended to have checked in the repo.

  Patch 3.  tools/xenbindgen: Introduce a Xen hypercall IDL generator
  Patch 4.  tools/xenbindgen: Add a TOML spec reader
  Patch 5.  tools/xenbindgen: Add basic plumbing for the C backend
  Patch 6.  tools/xenbindgen: Add xenbindgen's Cargo.lock file
  Patch 7.  tools/xenbindgen: Add support for structs in TOML specs
  Patch 8.  tools/xenbindgen: Add support for enums in TOML specs
  Patch 9.  tools/xenbindgen: Add support for bitmaps in TOML specs
  Patch 10. tools/xenbindgen: Add support for includes in the TOML specs

Patch 11 goes a step beyond and validates the ABI has no implicit padding and
that all names are unique. In the future, when we define rules for stable ABIs,
all of those can be checked here, at generation time.

  Patch 11. tools/xenbindgen: Validate ABI rules at generation time

Patches 12 to 19 replace current items in the C headers with autogenerated
versions. They should all be mechanical translations.

  Patch 12. xen: Replace sysctl/readconsole with autogenerated version
  Patch 13. xen: Replace hand-crafted altp2m_mode descriptions with
            autogenerated ones
  Patch 14. xen: Replace common bitmaps in domctl.createdomain with
            autogenerated versions
  Patch 15. xen/arm: Replace hand-crafted xen_arch_domainconfig with
            autogenerated one
  Patch 16. xen/x86: Replace hand-crafted xen_arch_domainconfig with
            autogenerated one
  Patch 17. xen/ppc: Replace empty xen_arch_domainconfig with autogenerated
            one
  Patch 18. xen/riscv: Replace empty xen_arch_domainconfig with autogenerated
            one
  Patch 19. xen: Replace hand-crafted domctl/createdomain with autogenerated
            version

Patches 20 to 23 add a Rust backend to xenbindgen, and create a barebones
xen-sys crate containing the autogenerated constructs.

  Patch 20. tools/xen-sys: Create a crate with autogenerated Rust constructs
  Patch 21. tools/xenbindgen: Add Rust backend to xenbindgen
  Patch 22. tools/xen-sys: Add autogenerated Rust files
  Patch 23. licence: Add Unicode-DFS-2016 to the list of licences

Patches 24 and 25 include CI checks to avoid regressions in all this. A new job
under "analysis" validates ABI invariants and consistency between autogenerated
headers and specs, and lints all Rust code.

  Patch 24. tools/rust: Add deny.toml
  Patch 25. ci: Add a CI checker for Rust-related helpful properties

======== The question ===========

It would be nice to have at least the IDL parser checked in before the 4.20
freeze, but that assumes everyone is onboard with the general plan.

Patch 25 needs a dedicated container before it can go in, but otherwise
everything else should be in a pretty decent shape. With all of this on the
table, are there any reasons why this work should be deferred any longer?

Does this all sound like a credible plan?

Alejandro Vallejo (25):
  xen/domctl: Refine grant_opts into max_grant_version
  xen/domctl: Replace altp2m_opts with altp2m_mode
  tools/xenbindgen: Introduce a Xen hypercall IDL generator
  tools/xenbindgen: Add a TOML spec reader
  tools/xenbindgen: Add basic plumbing for the C backend
  tools/xenbindgen: Add xenbindgen's Cargo.lock file
  tools/xenbindgen: Add support for structs in TOML specs
  tools/xenbindgen: Add support for enums in TOML specs
  tools/xenbindgen: Add support for bitmaps in TOML specs
  tools/xenbindgen: Add support for includes in the TOML specs
  tools/xenbindgen: Validate ABI rules at generation time
  xen: Replace sysctl/readconsole with autogenerated version
  xen: Replace hand-crafted altp2m_mode descriptions with autogenerated
    ones
  xen: Replace common bitmaps in domctl.createdomain with autogenerated
    versions
  xen/arm: Replace hand-crafted xen_arch_domainconfig with autogenerated
    one
  xen/x86: Replace hand-crafted xen_arch_domainconfig with autogenerated
    one
  xen/ppc: Replace empty xen_arch_domainconfig with autogenerated one
  xen/riscv: Replace empty xen_arch_domainconfig with autogenerated one
  xen: Replace hand-crafted domctl/createdomain with autogenerated
    version
  tools/xen-sys: Create a crate with autogenerated Rust constructs
  tools/xenbindgen: Add Rust backend to xenbindgen
  tools/xen-sys: Add autogenerated Rust files
  licence: Add Unicode-DFS-2016 to the list of licences
  tools/rust: Add deny.toml
  ci: Add a CI checker for Rust-related helpful properties

 LICENSES/Unicode-DFS-2016                     |  56 ++
 automation/gitlab-ci/analyze.yaml             |  14 +
 stubdom/Makefile                              |   2 +-
 tools/helpers/init-xenstore-domain.c          |   6 +-
 tools/libs/light/libxl_create.c               |  31 +-
 tools/libs/light/libxl_x86.c                  |   4 +-
 tools/ocaml/libs/xc/xenctrl.ml                |   6 +-
 tools/ocaml/libs/xc/xenctrl.mli               |   6 +-
 tools/ocaml/libs/xc/xenctrl_stubs.c           |  21 +-
 tools/python/xen/lowlevel/xc/xc.c             |   6 +-
 tools/rust/Makefile                           |  83 +++
 tools/rust/deny.toml                          | 236 +++++++
 tools/rust/xen-sys/.gitignore                 |   2 +
 tools/rust/xen-sys/Cargo.toml                 |   8 +
 tools/rust/xen-sys/src/autogen.rs             |  27 +
 tools/rust/xen-sys/src/autogen/arch_arm.rs    |  56 ++
 tools/rust/xen-sys/src/autogen/arch_ppc.rs    |   8 +
 tools/rust/xen-sys/src/autogen/arch_riscv.rs  |   8 +
 tools/rust/xen-sys/src/autogen/arch_x86.rs    |  55 ++
 tools/rust/xen-sys/src/autogen/domctl.rs      | 104 ++++
 tools/rust/xen-sys/src/autogen/sysctl.rs      |  26 +
 tools/rust/xen-sys/src/lib.rs                 |  45 ++
 tools/rust/xenbindgen/.gitignore              |   1 +
 tools/rust/xenbindgen/Cargo.lock              | 430 +++++++++++++
 tools/rust/xenbindgen/Cargo.toml              |  15 +
 .../extra/arch-arm/domainconfig.toml          |  83 +++
 .../extra/arch-ppc/domainconfig.toml          |   4 +
 .../extra/arch-riscv/domainconfig.toml        |   4 +
 .../extra/arch-x86/domainconfig.toml          |  87 +++
 .../xenbindgen/extra/domctl/createdomain.toml | 185 ++++++
 .../xenbindgen/extra/sysctl/readconsole.toml  |  43 ++
 tools/rust/xenbindgen/src/c_lang.rs           | 267 ++++++++
 tools/rust/xenbindgen/src/main.rs             | 103 ++++
 tools/rust/xenbindgen/src/rs_lang.rs          | 227 +++++++
 tools/rust/xenbindgen/src/spec.rs             | 577 ++++++++++++++++++
 .../paging-mempool/test-paging-mempool.c      |   4 +-
 tools/tests/resource/test-resource.c          |  14 +-
 tools/tests/tsx/test-tsx.c                    |   8 +-
 xen/arch/arm/dom0less-build.c                 |   8 +-
 xen/arch/arm/domain.c                         |  12 +-
 xen/arch/arm/domain_build.c                   |   6 +-
 xen/arch/arm/tee/tee.c                        |   1 +
 xen/arch/x86/domain.c                         |  33 +-
 xen/arch/x86/hvm/hvm.c                        |  12 +-
 xen/arch/x86/include/asm/domain.h             |   4 +-
 xen/arch/x86/include/asm/hvm/nestedhvm.h      |   2 +-
 xen/arch/x86/mm/shadow/common.c               |   4 +-
 xen/arch/x86/setup.c                          |  12 +-
 xen/arch/x86/tboot.c                          |   2 +-
 xen/common/domain.c                           |  25 +-
 xen/common/grant_table.c                      |   3 +-
 xen/drivers/char/console.c                    |  12 +-
 xen/drivers/passthrough/iommu.c               |   4 +-
 xen/include/public/arch-arm.h                 |  36 --
 xen/include/public/arch-ppc.h                 |   3 -
 xen/include/public/arch-riscv.h               |   3 -
 xen/include/public/arch-x86/xen.h             |  51 --
 xen/include/public/autogen/arch_arm.h         |  59 ++
 xen/include/public/autogen/arch_ppc.h         |  14 +
 xen/include/public/autogen/arch_riscv.h       |  14 +
 xen/include/public/autogen/arch_x86.h         |  52 ++
 xen/include/public/autogen/domctl.h           | 117 ++++
 xen/include/public/autogen/sysctl.h           |  35 ++
 xen/include/public/domctl.h                   |  93 +--
 xen/include/public/sysctl.h                   |  24 +-
 xen/include/public/xen.h                      |   1 +
 xen/include/xen/grant_table.h                 |   6 +-
 xen/include/xen/sched.h                       |  10 +-
 68 files changed, 3180 insertions(+), 340 deletions(-)
 create mode 100644 LICENSES/Unicode-DFS-2016
 create mode 100644 tools/rust/Makefile
 create mode 100644 tools/rust/deny.toml
 create mode 100644 tools/rust/xen-sys/.gitignore
 create mode 100644 tools/rust/xen-sys/Cargo.toml
 create mode 100644 tools/rust/xen-sys/src/autogen.rs
 create mode 100644 tools/rust/xen-sys/src/autogen/arch_arm.rs
 create mode 100644 tools/rust/xen-sys/src/autogen/arch_ppc.rs
 create mode 100644 tools/rust/xen-sys/src/autogen/arch_riscv.rs
 create mode 100644 tools/rust/xen-sys/src/autogen/arch_x86.rs
 create mode 100644 tools/rust/xen-sys/src/autogen/domctl.rs
 create mode 100644 tools/rust/xen-sys/src/autogen/sysctl.rs
 create mode 100644 tools/rust/xen-sys/src/lib.rs
 create mode 100644 tools/rust/xenbindgen/.gitignore
 create mode 100644 tools/rust/xenbindgen/Cargo.lock
 create mode 100644 tools/rust/xenbindgen/Cargo.toml
 create mode 100644 tools/rust/xenbindgen/extra/arch-arm/domainconfig.toml
 create mode 100644 tools/rust/xenbindgen/extra/arch-ppc/domainconfig.toml
 create mode 100644 tools/rust/xenbindgen/extra/arch-riscv/domainconfig.toml
 create mode 100644 tools/rust/xenbindgen/extra/arch-x86/domainconfig.toml
 create mode 100644 tools/rust/xenbindgen/extra/domctl/createdomain.toml
 create mode 100644 tools/rust/xenbindgen/extra/sysctl/readconsole.toml
 create mode 100644 tools/rust/xenbindgen/src/c_lang.rs
 create mode 100644 tools/rust/xenbindgen/src/main.rs
 create mode 100644 tools/rust/xenbindgen/src/rs_lang.rs
 create mode 100644 tools/rust/xenbindgen/src/spec.rs
 create mode 100644 xen/include/public/autogen/arch_arm.h
 create mode 100644 xen/include/public/autogen/arch_ppc.h
 create mode 100644 xen/include/public/autogen/arch_riscv.h
 create mode 100644 xen/include/public/autogen/arch_x86.h
 create mode 100644 xen/include/public/autogen/domctl.h
 create mode 100644 xen/include/public/autogen/sysctl.h


base-commit: d2bbb0d4554aa08649985d790317ba78f0db22ff
-- 
2.47.0



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

* [RFC PATCH 01/25] xen/domctl: Refine grant_opts into max_grant_version
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
@ 2024-11-15 11:51 ` Alejandro Vallejo
  2024-11-15 11:51 ` [RFC PATCH 02/25] xen/domctl: Replace altp2m_opts with altp2m_mode Alejandro Vallejo
                   ` (24 subsequent siblings)
  25 siblings, 0 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel
  Cc: Alejandro Vallejo, Juergen Gross, Julien Grall, Anthony PERARD,
	Andrew Cooper, Jan Beulich, Stefano Stabellini, Christian Lindig,
	David Scott, Marek Marczykowski-Górecki, Bertrand Marquis,
	Michal Orzel, Volodymyr Babchuk, Roger Pau Monné

grant_opts is overoptimizing for space packing in a hypercall that
doesn't warrant the effort. Tweak the ABI without breaking it in order
to remove the bitfield by extending it to 8 bits.

Xen only supports little-endian systems, so the transformation from
uint32_t to uint8_t followed by 3 octets worth of padding is not an ABI
breakage.

No functional change

Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
 tools/helpers/init-xenstore-domain.c             |  2 +-
 tools/libs/light/libxl_create.c                  |  6 +-----
 tools/ocaml/libs/xc/xenctrl_stubs.c              |  3 +--
 tools/python/xen/lowlevel/xc/xc.c                |  2 +-
 tools/tests/paging-mempool/test-paging-mempool.c |  2 +-
 tools/tests/resource/test-resource.c             |  6 +++---
 tools/tests/tsx/test-tsx.c                       |  4 ++--
 xen/arch/arm/dom0less-build.c                    |  4 ++--
 xen/arch/arm/domain_build.c                      |  2 +-
 xen/arch/x86/setup.c                             |  2 +-
 xen/common/domain.c                              |  6 +++---
 xen/common/grant_table.c                         |  3 +--
 xen/include/public/domctl.h                      | 15 +++++++++++----
 xen/include/xen/grant_table.h                    |  6 +++---
 14 files changed, 32 insertions(+), 31 deletions(-)

diff --git a/tools/helpers/init-xenstore-domain.c b/tools/helpers/init-xenstore-domain.c
index 01ca667d25d1..a9f2f9859df6 100644
--- a/tools/helpers/init-xenstore-domain.c
+++ b/tools/helpers/init-xenstore-domain.c
@@ -96,7 +96,7 @@ static int build(xc_interface *xch)
          */
         .max_grant_frames = 4,
         .max_maptrack_frames = 128,
-        .grant_opts = XEN_DOMCTL_GRANT_version(1),
+        .max_grant_version = 1,
     };
 
     xs_fd = open("/dev/xen/xenbus_backend", O_RDWR);
diff --git a/tools/libs/light/libxl_create.c b/tools/libs/light/libxl_create.c
index edeadd57ef5a..87594809abc8 100644
--- a/tools/libs/light/libxl_create.c
+++ b/tools/libs/light/libxl_create.c
@@ -476,10 +476,6 @@ int libxl__domain_build_info_setdefault(libxl__gc *gc,
         else
             /* No grant table support reported */
             b_info->max_grant_version = 0;
-    } else if (b_info->max_grant_version & ~XEN_DOMCTL_GRANT_version_mask) {
-        LOG(ERROR, "max grant version %d out of range",
-            b_info->max_grant_version);
-        return -ERROR_INVAL;
     }
 
     /* Assume that providing a bootloader user implies enabling restrict. */
@@ -646,7 +642,7 @@ int libxl__domain_make(libxl__gc *gc, libxl_domain_config *d_config,
             .max_evtchn_port = b_info->event_channels,
             .max_grant_frames = b_info->max_grant_frames,
             .max_maptrack_frames = b_info->max_maptrack_frames,
-            .grant_opts = XEN_DOMCTL_GRANT_version(b_info->max_grant_version),
+            .max_grant_version = b_info->max_grant_version,
             .vmtrace_size = ROUNDUP(b_info->vmtrace_buf_kb << 10, XC_PAGE_SHIFT),
             .cpupool_id = info->poolid,
         };
diff --git a/tools/ocaml/libs/xc/xenctrl_stubs.c b/tools/ocaml/libs/xc/xenctrl_stubs.c
index c78191f95abc..67a690308f1a 100644
--- a/tools/ocaml/libs/xc/xenctrl_stubs.c
+++ b/tools/ocaml/libs/xc/xenctrl_stubs.c
@@ -223,8 +223,7 @@ CAMLprim value stub_xc_domain_create(value xch_val, value wanted_domid, value co
 		.max_evtchn_port = Int_val(VAL_MAX_EVTCHN_PORT),
 		.max_grant_frames = Int_val(VAL_MAX_GRANT_FRAMES),
 		.max_maptrack_frames = Int_val(VAL_MAX_MAPTRACK_FRAMES),
-		.grant_opts =
-		    XEN_DOMCTL_GRANT_version(Int_val(VAL_MAX_GRANT_VERSION)),
+		.max_grant_version = Int_val(VAL_MAX_GRANT_VERSION),
 		.altp2m_opts = Int32_val(VAL_ALTP2M_OPTS),
 		.vmtrace_size = vmtrace_size,
 		.cpupool_id = Int32_val(VAL_CPUPOOL_ID),
diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c
index 9feb12ae2b16..ba6a61217f9f 100644
--- a/tools/python/xen/lowlevel/xc/xc.c
+++ b/tools/python/xen/lowlevel/xc/xc.c
@@ -167,7 +167,7 @@ static PyObject *pyxc_domain_create(XcObject *self,
 #else
 #error Architecture not supported
 #endif
-    config.grant_opts = XEN_DOMCTL_GRANT_version(max_grant_version);
+    config.max_grant_version = max_grant_version;
 
     if ( (ret = xc_domain_create(self->xc_handle, &dom, &config)) < 0 )
         return pyxc_error_to_exception(self->xc_handle);
diff --git a/tools/tests/paging-mempool/test-paging-mempool.c b/tools/tests/paging-mempool/test-paging-mempool.c
index 1ebc13455ac2..512c42803c0e 100644
--- a/tools/tests/paging-mempool/test-paging-mempool.c
+++ b/tools/tests/paging-mempool/test-paging-mempool.c
@@ -24,7 +24,7 @@ static struct xen_domctl_createdomain create = {
     .flags = XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap,
     .max_vcpus = 1,
     .max_grant_frames = 1,
-    .grant_opts = XEN_DOMCTL_GRANT_version(1),
+    .max_grant_version = 1,
 
     .arch = {
 #if defined(__x86_64__) || defined(__i386__)
diff --git a/tools/tests/resource/test-resource.c b/tools/tests/resource/test-resource.c
index 1b10be16a6b4..b0a9f5f1e8b6 100644
--- a/tools/tests/resource/test-resource.c
+++ b/tools/tests/resource/test-resource.c
@@ -137,7 +137,7 @@ static void test_domain_configurations(void)
             .create = {
                 .max_vcpus = 2,
                 .max_grant_frames = 40,
-                .grant_opts = XEN_DOMCTL_GRANT_version(1),
+                .max_grant_version = 1,
             },
         },
         {
@@ -146,7 +146,7 @@ static void test_domain_configurations(void)
                 .flags = XEN_DOMCTL_CDF_hvm,
                 .max_vcpus = 2,
                 .max_grant_frames = 40,
-                .grant_opts = XEN_DOMCTL_GRANT_version(1),
+                .max_grant_version = 1,
                 .arch = {
                     .emulation_flags = XEN_X86_EMU_LAPIC,
                 },
@@ -159,7 +159,7 @@ static void test_domain_configurations(void)
                 .flags = XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap,
                 .max_vcpus = 2,
                 .max_grant_frames = 40,
-                .grant_opts = XEN_DOMCTL_GRANT_version(1),
+                .max_grant_version = 1,
             },
         },
 #endif
diff --git a/tools/tests/tsx/test-tsx.c b/tools/tests/tsx/test-tsx.c
index 5af04953f340..324bcf67153a 100644
--- a/tools/tests/tsx/test-tsx.c
+++ b/tools/tests/tsx/test-tsx.c
@@ -457,7 +457,7 @@ static void test_guests(void)
         struct xen_domctl_createdomain c = {
             .max_vcpus = 1,
             .max_grant_frames = 1,
-            .grant_opts = XEN_DOMCTL_GRANT_version(1),
+            .max_grant_version = 1,
         };
 
         printf("Testing PV guest\n");
@@ -470,7 +470,7 @@ static void test_guests(void)
             .flags = XEN_DOMCTL_CDF_hvm,
             .max_vcpus = 1,
             .max_grant_frames = 1,
-            .grant_opts = XEN_DOMCTL_GRANT_version(1),
+            .max_grant_version = 1,
             .arch = {
                 .emulation_flags = XEN_X86_EMU_LAPIC,
             },
diff --git a/xen/arch/arm/dom0less-build.c b/xen/arch/arm/dom0less-build.c
index f328a044e9d3..1c6219c7cc82 100644
--- a/xen/arch/arm/dom0less-build.c
+++ b/xen/arch/arm/dom0less-build.c
@@ -877,7 +877,7 @@ void __init create_domUs(void)
             .max_evtchn_port = 1023,
             .max_grant_frames = -1,
             .max_maptrack_frames = -1,
-            .grant_opts = XEN_DOMCTL_GRANT_version(opt_gnttab_max_version),
+            .max_grant_version = opt_gnttab_max_version,
         };
         unsigned int flags = 0U;
         uint32_t val;
@@ -959,7 +959,7 @@ void __init create_domUs(void)
         }
 
         if ( dt_property_read_u32(node, "max_grant_version", &val) )
-            d_cfg.grant_opts = XEN_DOMCTL_GRANT_version(val);
+            d_cfg.max_grant_version = val;
 
         if ( dt_property_read_u32(node, "max_grant_frames", &val) )
         {
diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 2c30792de88b..773412ba2acb 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -2194,7 +2194,7 @@ void __init create_dom0(void)
         .max_evtchn_port = -1,
         .max_grant_frames = gnttab_dom0_frames(),
         .max_maptrack_frames = -1,
-        .grant_opts = XEN_DOMCTL_GRANT_version(opt_gnttab_max_version),
+        .max_grant_version = opt_gnttab_max_version,
     };
     int rc;
 
diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c
index 5da1c6a34519..0443555d9bb8 100644
--- a/xen/arch/x86/setup.c
+++ b/xen/arch/x86/setup.c
@@ -964,7 +964,7 @@ static struct domain *__init create_dom0(const module_t *image,
         .max_evtchn_port = -1,
         .max_grant_frames = -1,
         .max_maptrack_frames = -1,
-        .grant_opts = XEN_DOMCTL_GRANT_version(opt_gnttab_max_version),
+        .max_grant_version = opt_gnttab_max_version,
         .max_vcpus = dom0_max_vcpus(),
         .arch = {
             .misc_flags = opt_dom0_msr_relaxed ? XEN_X86_MSR_RELAXED : 0,
diff --git a/xen/common/domain.c b/xen/common/domain.c
index 92263a4fbdc5..86f0e99e0d4a 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -579,9 +579,9 @@ static int sanitise_domain_config(struct xen_domctl_createdomain *config)
         return -EINVAL;
     }
 
-    if ( config->grant_opts & ~XEN_DOMCTL_GRANT_version_mask )
+    if ( config->rsvd0[0] | config->rsvd0[1] | config->rsvd0[2] )
     {
-        dprintk(XENLOG_INFO, "Unknown grant options %#x\n", config->grant_opts);
+        dprintk(XENLOG_INFO, "Rubble in rsvd0 padding\n");
         return -EINVAL;
     }
 
@@ -788,7 +788,7 @@ struct domain *domain_create(domid_t domid,
 
     if ( (err = grant_table_init(d, config->max_grant_frames,
                                  config->max_maptrack_frames,
-                                 config->grant_opts)) != 0 )
+                                 config->max_grant_version)) != 0 )
         goto fail;
     init_status |= INIT_gnttab;
 
diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index 6c77867f8cdd..51a3f72a9601 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -1963,10 +1963,9 @@ active_alloc_failed:
 }
 
 int grant_table_init(struct domain *d, int max_grant_frames,
-                     int max_maptrack_frames, unsigned int options)
+                     int max_maptrack_frames, uint8_t max_grant_version)
 {
     struct grant_table *gt;
-    unsigned int max_grant_version = options & XEN_DOMCTL_GRANT_version_mask;
     int ret = -ENOMEM;
 
     if ( !max_grant_version )
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index 353f831e402e..e37d4337dcf9 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -90,11 +90,18 @@ struct xen_domctl_createdomain {
     int32_t max_grant_frames;
     int32_t max_maptrack_frames;
 
-/* Grant version, use low 4 bits. */
-#define XEN_DOMCTL_GRANT_version_mask    0xf
-#define XEN_DOMCTL_GRANT_version(v)      ((v) & XEN_DOMCTL_GRANT_version_mask)
+    /*
+     * Maximum grant table version the domain can be configured with.
+     *
+     * Domains always start with v1 (if CONFIG_GRANT_TABLE) and can be bumped
+     * to use up to `max_grant_version` via GNTTABOP_set_version.
+     *
+     * Must be zero iff !CONFIG_GRANT_TABLE.
+     */
+    uint8_t max_grant_version;
 
-    uint32_t grant_opts;
+    /* Unused. Reserved to zero. */
+    uint8_t rsvd0[3];
 
 /*
  * Enable altp2m mixed mode.
diff --git a/xen/include/xen/grant_table.h b/xen/include/xen/grant_table.h
index 50edfecfb62f..a483d5a216a4 100644
--- a/xen/include/xen/grant_table.h
+++ b/xen/include/xen/grant_table.h
@@ -40,7 +40,7 @@ extern unsigned int opt_max_grant_frames;
 
 /* Create/destroy per-domain grant table context. */
 int grant_table_init(struct domain *d, int max_grant_frames,
-                     int max_maptrack_frames, unsigned int options);
+                     int max_maptrack_frames, uint8_t max_grant_version);
 void grant_table_destroy(
     struct domain *d);
 void grant_table_init_vcpu(struct vcpu *v);
@@ -73,9 +73,9 @@ int gnttab_acquire_resource(
 static inline int grant_table_init(struct domain *d,
                                    int max_grant_frames,
                                    int max_maptrack_frames,
-                                   unsigned int options)
+                                   uint8_t max_grant_version)
 {
-    if ( options )
+    if ( max_grant_version )
         return -EINVAL;
 
     return 0;
-- 
2.47.0



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

* [RFC PATCH 02/25] xen/domctl: Replace altp2m_opts with altp2m_mode
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
  2024-11-15 11:51 ` [RFC PATCH 01/25] xen/domctl: Refine grant_opts into max_grant_version Alejandro Vallejo
@ 2024-11-15 11:51 ` Alejandro Vallejo
  2024-11-15 11:51 ` [RFC PATCH 03/25] tools/xenbindgen: Introduce a Xen hypercall IDL generator Alejandro Vallejo
                   ` (23 subsequent siblings)
  25 siblings, 0 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel
  Cc: Alejandro Vallejo, Anthony PERARD, Juergen Gross, Andrew Cooper,
	Jan Beulich, Julien Grall, Stefano Stabellini, Christian Lindig,
	David Scott, Bertrand Marquis, Michal Orzel, Volodymyr Babchuk,
	Roger Pau Monné

No functional change, in the same direction as the previous grant_opts
to max_grant_version.

Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
 tools/libs/light/libxl_create.c     | 11 ++++-------
 tools/ocaml/libs/xc/xenctrl.ml      |  2 +-
 tools/ocaml/libs/xc/xenctrl.mli     |  2 +-
 tools/ocaml/libs/xc/xenctrl_stubs.c |  6 +++---
 xen/arch/arm/domain.c               |  2 +-
 xen/arch/x86/domain.c               | 13 ++-----------
 xen/arch/x86/hvm/hvm.c              |  6 +++++-
 xen/common/domain.c                 |  3 ++-
 xen/include/public/domctl.h         | 12 +++++++-----
 9 files changed, 26 insertions(+), 31 deletions(-)

diff --git a/tools/libs/light/libxl_create.c b/tools/libs/light/libxl_create.c
index 87594809abc8..3ae922e8931b 100644
--- a/tools/libs/light/libxl_create.c
+++ b/tools/libs/light/libxl_create.c
@@ -676,22 +676,19 @@ int libxl__domain_make(libxl__gc *gc, libxl_domain_config *d_config,
         LOG(DETAIL, "altp2m: %s", libxl_altp2m_mode_to_string(b_info->altp2m));
         switch(b_info->altp2m) {
         case LIBXL_ALTP2M_MODE_MIXED:
-            create.altp2m_opts |=
-                XEN_DOMCTL_ALTP2M_mode(XEN_DOMCTL_ALTP2M_mixed);
+            create.altp2m_mode = XEN_DOMCTL_ALTP2M_mixed;
             break;
 
         case LIBXL_ALTP2M_MODE_EXTERNAL:
-            create.altp2m_opts |=
-                XEN_DOMCTL_ALTP2M_mode(XEN_DOMCTL_ALTP2M_external);
+            create.altp2m_mode = XEN_DOMCTL_ALTP2M_external;
             break;
 
         case LIBXL_ALTP2M_MODE_LIMITED:
-            create.altp2m_opts |=
-                XEN_DOMCTL_ALTP2M_mode(XEN_DOMCTL_ALTP2M_limited);
+            create.altp2m_mode = XEN_DOMCTL_ALTP2M_limited;
             break;
 
         case LIBXL_ALTP2M_MODE_DISABLED:
-            /* Nothing to do - altp2m disabled is signaled as mode == 0. */
+            create.altp2m_mode = XEN_DOMCTL_ALTP2M_disabled;
             break;
         }
 
diff --git a/tools/ocaml/libs/xc/xenctrl.ml b/tools/ocaml/libs/xc/xenctrl.ml
index 2690f9a92316..3c4c95d48319 100644
--- a/tools/ocaml/libs/xc/xenctrl.ml
+++ b/tools/ocaml/libs/xc/xenctrl.ml
@@ -85,7 +85,7 @@ type domctl_create_config =
     max_grant_frames: int;
     max_maptrack_frames: int;
     max_grant_version: int;
-    altp2m_opts: int32;
+    altp2m_mode: int32;
     vmtrace_buf_kb: int32;
     cpupool_id: int32;
     arch: arch_domainconfig;
diff --git a/tools/ocaml/libs/xc/xenctrl.mli b/tools/ocaml/libs/xc/xenctrl.mli
index febbe1f6ae3f..74919a14bec4 100644
--- a/tools/ocaml/libs/xc/xenctrl.mli
+++ b/tools/ocaml/libs/xc/xenctrl.mli
@@ -77,7 +77,7 @@ type domctl_create_config = {
   max_grant_frames: int;
   max_maptrack_frames: int;
   max_grant_version: int;
-  altp2m_opts: int32;
+  altp2m_mode: int32;
   vmtrace_buf_kb: int32;
   cpupool_id: int32;
   arch: arch_domainconfig;
diff --git a/tools/ocaml/libs/xc/xenctrl_stubs.c b/tools/ocaml/libs/xc/xenctrl_stubs.c
index 67a690308f1a..b701f45daa8d 100644
--- a/tools/ocaml/libs/xc/xenctrl_stubs.c
+++ b/tools/ocaml/libs/xc/xenctrl_stubs.c
@@ -204,7 +204,7 @@ CAMLprim value stub_xc_domain_create(value xch_val, value wanted_domid, value co
 #define VAL_MAX_GRANT_FRAMES    Field(config, 6)
 #define VAL_MAX_MAPTRACK_FRAMES Field(config, 7)
 #define VAL_MAX_GRANT_VERSION   Field(config, 8)
-#define VAL_ALTP2M_OPTS         Field(config, 9)
+#define VAL_ALTP2M_MODE         Field(config, 9)
 #define VAL_VMTRACE_BUF_KB      Field(config, 10)
 #define VAL_CPUPOOL_ID          Field(config, 11)
 #define VAL_ARCH                Field(config, 12)
@@ -224,7 +224,7 @@ CAMLprim value stub_xc_domain_create(value xch_val, value wanted_domid, value co
 		.max_grant_frames = Int_val(VAL_MAX_GRANT_FRAMES),
 		.max_maptrack_frames = Int_val(VAL_MAX_MAPTRACK_FRAMES),
 		.max_grant_version = Int_val(VAL_MAX_GRANT_VERSION),
-		.altp2m_opts = Int32_val(VAL_ALTP2M_OPTS),
+		.altp2m_mode = Int32_val(VAL_ALTP2M_MODE),
 		.vmtrace_size = vmtrace_size,
 		.cpupool_id = Int32_val(VAL_CPUPOOL_ID),
 	};
@@ -283,7 +283,7 @@ CAMLprim value stub_xc_domain_create(value xch_val, value wanted_domid, value co
 #undef VAL_ARCH
 #undef VAL_CPUPOOL_ID
 #undef VAL_VMTRACE_BUF_KB
-#undef VAL_ALTP2M_OPTS
+#undef VAL_ALTP2M_MODE
 #undef VAL_MAX_GRANT_VERSION
 #undef VAL_MAX_MAPTRACK_FRAMES
 #undef VAL_MAX_GRANT_FRAMES
diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 3ba959f86633..c6c5a0d1af23 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -688,7 +688,7 @@ int arch_sanitise_domain_config(struct xen_domctl_createdomain *config)
         return -EINVAL;
     }
 
-    if ( config->altp2m_opts )
+    if ( config->altp2m_mode )
     {
         dprintk(XENLOG_INFO, "Altp2m not supported\n");
         return -EINVAL;
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index 78a13e6812c9..1ef095f349f7 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -637,8 +637,6 @@ int arch_sanitise_domain_config(struct xen_domctl_createdomain *config)
     bool hap = config->flags & XEN_DOMCTL_CDF_hap;
     bool nested_virt = config->flags & XEN_DOMCTL_CDF_nested_virt;
     unsigned int max_vcpus;
-    unsigned int altp2m_mode = MASK_EXTR(config->altp2m_opts,
-                                         XEN_DOMCTL_ALTP2M_mode_mask);
 
     if ( hvm ? !hvm_enabled : !IS_ENABLED(CONFIG_PV) )
     {
@@ -717,21 +715,14 @@ int arch_sanitise_domain_config(struct xen_domctl_createdomain *config)
         return -EINVAL;
     }
 
-    if ( config->altp2m_opts & ~XEN_DOMCTL_ALTP2M_mode_mask )
-    {
-        dprintk(XENLOG_INFO, "Invalid altp2m options selected: %#x\n",
-                config->flags);
-        return -EINVAL;
-    }
-
-    if ( altp2m_mode && nested_virt )
+    if ( config->altp2m_mode && nested_virt )
     {
         dprintk(XENLOG_INFO,
                 "Nested virt and altp2m are not supported together\n");
         return -EINVAL;
     }
 
-    if ( altp2m_mode && !hap )
+    if ( config->altp2m_mode && !hap )
     {
         dprintk(XENLOG_INFO, "altp2m is only supported with HAP\n");
         return -EINVAL;
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 74e58c653e6f..e30c3026479e 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -659,7 +659,7 @@ int hvm_domain_initialise(struct domain *d,
     d->arch.hvm.params[HVM_PARAM_TRIPLE_FAULT_REASON] = SHUTDOWN_reboot;
 
     /* Set altp2m based on domctl flags. */
-    switch ( MASK_EXTR(config->altp2m_opts, XEN_DOMCTL_ALTP2M_mode_mask) )
+    switch ( config->altp2m_mode )
     {
     case XEN_DOMCTL_ALTP2M_mixed:
         d->arch.hvm.params[HVM_PARAM_ALTP2M] = XEN_ALTP2M_mixed;
@@ -672,6 +672,10 @@ int hvm_domain_initialise(struct domain *d,
     case XEN_DOMCTL_ALTP2M_limited:
         d->arch.hvm.params[HVM_PARAM_ALTP2M] = XEN_ALTP2M_limited;
         break;
+
+    case XEN_DOMCTL_ALTP2M_disabled:
+        d->arch.hvm.params[HVM_PARAM_ALTP2M] = XEN_ALTP2M_disabled;
+        break;
     }
 
     vpic_init(d);
diff --git a/xen/common/domain.c b/xen/common/domain.c
index 86f0e99e0d4a..ad19ff1cef23 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -579,7 +579,8 @@ static int sanitise_domain_config(struct xen_domctl_createdomain *config)
         return -EINVAL;
     }
 
-    if ( config->rsvd0[0] | config->rsvd0[1] | config->rsvd0[2] )
+    if ( config->rsvd0_a[0] | config->rsvd0_a[1] | config->rsvd0_a[2] |
+         config->rsvd0_b[0] | config->rsvd0_b[1] | config->rsvd0_b[2] )
     {
         dprintk(XENLOG_INFO, "Rubble in rsvd0 padding\n");
         return -EINVAL;
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index e37d4337dcf9..95a3b6769f7f 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -101,8 +101,10 @@ struct xen_domctl_createdomain {
     uint8_t max_grant_version;
 
     /* Unused. Reserved to zero. */
-    uint8_t rsvd0[3];
+    uint8_t rsvd0_a[3];
 
+/* Keep altp2m disabled */
+#define XEN_DOMCTL_ALTP2M_disabled   (0U)
 /*
  * Enable altp2m mixed mode.
  *
@@ -116,10 +118,10 @@ struct xen_domctl_createdomain {
 #define XEN_DOMCTL_ALTP2M_external   (2U)
 /* Enable altp2m limited mode. */
 #define XEN_DOMCTL_ALTP2M_limited    (3U)
-/* Altp2m mode signaling uses bits [0, 1]. */
-#define XEN_DOMCTL_ALTP2M_mode_mask  (0x3U)
-#define XEN_DOMCTL_ALTP2M_mode(m)    ((m) & XEN_DOMCTL_ALTP2M_mode_mask)
-    uint32_t altp2m_opts;
+    uint8_t altp2m_mode;
+
+    /* Unused. Reserved to zero. */
+    uint8_t rsvd0_b[3];
 
     /* Per-vCPU buffer size in bytes.  0 to disable. */
     uint32_t vmtrace_size;
-- 
2.47.0



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

* [RFC PATCH 03/25] tools/xenbindgen: Introduce a Xen hypercall IDL generator
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
  2024-11-15 11:51 ` [RFC PATCH 01/25] xen/domctl: Refine grant_opts into max_grant_version Alejandro Vallejo
  2024-11-15 11:51 ` [RFC PATCH 02/25] xen/domctl: Replace altp2m_opts with altp2m_mode Alejandro Vallejo
@ 2024-11-15 11:51 ` Alejandro Vallejo
  2024-11-15 11:51 ` [RFC PATCH 04/25] tools/xenbindgen: Add a TOML spec reader Alejandro Vallejo
                   ` (22 subsequent siblings)
  25 siblings, 0 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel; +Cc: Alejandro Vallejo, Anthony PERARD, Teddy Astie, Yann Dirson

To be used for parsing TOML-based hypercall ABI specifications and
generating language-specific items (structs, enums, etc.).

Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
 tools/rust/Makefile               | 29 +++++++++++++++++++++++++++++
 tools/rust/xenbindgen/.gitignore  |  1 +
 tools/rust/xenbindgen/Cargo.toml  | 15 +++++++++++++++
 tools/rust/xenbindgen/src/main.rs | 21 +++++++++++++++++++++
 4 files changed, 66 insertions(+)
 create mode 100644 tools/rust/Makefile
 create mode 100644 tools/rust/xenbindgen/.gitignore
 create mode 100644 tools/rust/xenbindgen/Cargo.toml
 create mode 100644 tools/rust/xenbindgen/src/main.rs

diff --git a/tools/rust/Makefile b/tools/rust/Makefile
new file mode 100644
index 000000000000..f5db0a9c5e81
--- /dev/null
+++ b/tools/rust/Makefile
@@ -0,0 +1,29 @@
+XEN_ROOT=$(CURDIR)/../..
+
+# Path to the Xen hypercall IDL parser
+XENBINDGEN=$(CURDIR)/xenbindgen
+
+# Clippy settings for all Rust projects
+CLIPPY_ARGS=-D warnings \
+            -D missing_docs \
+            -D clippy::missing_docs_in_private_items \
+            -D clippy::all \
+            -D clippy::pedantic
+
+# Not integrated in Xen installations to avoid depending on the Rust toolchain
+.PHONY: all install uninstall clean
+all install uninstall clean:
+
+# Verify Rust crates pass lint checks. This is enforced in CI
+.PHONY: verify
+verify:
+	set -eu; \
+	for i in "${XENBINDGEN}"; do \
+	    echo "Verifying $$i"; \
+	    cd "$$i"; \
+	    cargo fmt -- --check; \
+	    cargo clippy -- $(CLIPPY_ARGS); \
+	    cargo deny check; \
+	    cd -; \
+	done
+
diff --git a/tools/rust/xenbindgen/.gitignore b/tools/rust/xenbindgen/.gitignore
new file mode 100644
index 000000000000..b83d22266ac8
--- /dev/null
+++ b/tools/rust/xenbindgen/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/tools/rust/xenbindgen/Cargo.toml b/tools/rust/xenbindgen/Cargo.toml
new file mode 100644
index 000000000000..4cb3af9ce0de
--- /dev/null
+++ b/tools/rust/xenbindgen/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "xenbindgen"
+version = "0.2.0"
+edition = "2021"
+license = "MIT"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+clap = { version = "4.5.7", features = ["std", "derive"] }
+convert_case = "0.6.0"
+env_logger = "0.11.3"
+log = "0.4.22"
+serde = { version = "1.0.203", default-features = false, features = ["derive"] }
+toml = { version = "0.8.14", default-features = false, features = ["parse"] }
diff --git a/tools/rust/xenbindgen/src/main.rs b/tools/rust/xenbindgen/src/main.rs
new file mode 100644
index 000000000000..08fcf8fe4da6
--- /dev/null
+++ b/tools/rust/xenbindgen/src/main.rs
@@ -0,0 +1,21 @@
+//! CLI tool to generate structs in different languages from specially
+//! crafted TOML files. The format of these files follows the following
+//! rules.
+
+use clap::Parser;
+use env_logger::Env;
+use log::info;
+
+/// A CLI tool to generate struct definitions in several languages.
+#[derive(Parser, Debug)]
+#[command(version, about)]
+struct Cli;
+
+fn main() {
+    env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
+
+    let cli = Cli::parse();
+    info!("args: {:?}", cli);
+
+    todo!("read spec files and generate output files");
+}
-- 
2.47.0



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

* [RFC PATCH 04/25] tools/xenbindgen: Add a TOML spec reader
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
                   ` (2 preceding siblings ...)
  2024-11-15 11:51 ` [RFC PATCH 03/25] tools/xenbindgen: Introduce a Xen hypercall IDL generator Alejandro Vallejo
@ 2024-11-15 11:51 ` Alejandro Vallejo
  2024-11-25 15:13   ` Teddy Astie
  2024-11-15 11:51 ` [RFC PATCH 05/25] tools/xenbindgen: Add basic plumbing for the C backend Alejandro Vallejo
                   ` (21 subsequent siblings)
  25 siblings, 1 reply; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel; +Cc: Alejandro Vallejo, Anthony PERARD, Teddy Astie, Yann Dirson

There isn't any deserialisation yet. It's mere plumbing.

Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
 tools/rust/xenbindgen/src/main.rs | 28 ++++++++-
 tools/rust/xenbindgen/src/spec.rs | 96 +++++++++++++++++++++++++++++++
 2 files changed, 121 insertions(+), 3 deletions(-)
 create mode 100644 tools/rust/xenbindgen/src/spec.rs

diff --git a/tools/rust/xenbindgen/src/main.rs b/tools/rust/xenbindgen/src/main.rs
index 08fcf8fe4da6..497cf39d3bbd 100644
--- a/tools/rust/xenbindgen/src/main.rs
+++ b/tools/rust/xenbindgen/src/main.rs
@@ -2,14 +2,22 @@
 //! crafted TOML files. The format of these files follows the following
 //! rules.
 
+mod spec;
+
+use std::path::PathBuf;
+
 use clap::Parser;
 use env_logger::Env;
-use log::info;
+use log::{error, info};
 
 /// A CLI tool to generate struct definitions in several languages.
 #[derive(Parser, Debug)]
 #[command(version, about)]
-struct Cli;
+struct Cli {
+    /// Path to the input directory containing the hypercall specification
+    #[arg(short, long)]
+    indir: PathBuf,
+}
 
 fn main() {
     env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
@@ -17,5 +25,19 @@ fn main() {
     let cli = Cli::parse();
     info!("args: {:?}", cli);
 
-    todo!("read spec files and generate output files");
+    let _specification = match spec::Spec::new(&cli.indir) {
+        Ok(x) => x,
+        Err(spec::Error::Toml(x)) => {
+            error!("TOML parsing error:");
+            error!("{x:#?}");
+            std::process::exit(1);
+        }
+        Err(spec::Error::Io(x)) => {
+            error!("IO error:");
+            error!("{x:#?}");
+            std::process::exit(1);
+        }
+    };
+
+    todo!("generate output files");
 }
diff --git a/tools/rust/xenbindgen/src/spec.rs b/tools/rust/xenbindgen/src/spec.rs
new file mode 100644
index 000000000000..e69f7c78dc7a
--- /dev/null
+++ b/tools/rust/xenbindgen/src/spec.rs
@@ -0,0 +1,96 @@
+//! Specification descriptions
+//!
+//! The TOML files are not parsed by hand. This module provides a sort of
+//! schema for the TOML descriptions, in the sense that `serde` itself ensures
+//! every field is deserialised into its equivalent Rust structure or the
+//! deserialization procedure fails.
+//!
+//! If the specification is clearly invalid (i.e: missing fields) it'll scream
+//! in a rather obvious way.
+//!
+//! A special case is the `typ` field in the specifications is meant to have
+//! the format present in the specifications under `extra`. This allows `serde`
+//! to properly decode the type and match it with a variant of the [`Typ`] type
+//! with the payload landing in the payload of the variant itself.
+
+use std::{fs::read_to_string, path::Path};
+
+use log::{debug, info};
+
+/// A language-agnostic specification.
+#[derive(Debug, serde::Deserialize)]
+struct InFileDef;
+
+/// Description of an abstract output (i.e: `.rs`, `.h`, etc).
+///
+/// Contains every element of the ABI that needs representing.
+#[derive(Debug)]
+pub struct OutFileDef {
+    /// The name of the output file, without the final extension.
+    pub name: String,
+}
+
+impl OutFileDef {
+    /// Creates a new _output_ file description. Each [`OutFileDef`] is
+    /// associated with a number of [`InFileDef`] and holds the merged
+    /// contents described in all of them.
+    ///
+    /// # Errors
+    /// Fails if the TOML is invalid or on IO error.
+    pub fn new(name: String, dir: &Path) -> Result<Self, Error> {
+        info!("Reading {dir:?} to generate an output file");
+
+        let mut ret = Self { name };
+
+        for entry in from_ioerr(dir.read_dir())? {
+            let path = from_ioerr(entry)?.path();
+            debug!("Reading {:?} to generate outfile={}", path, ret.name);
+            let toml_str = from_ioerr(read_to_string(path))?;
+            let filedef: InFileDef = toml::from_str(&toml_str).map_err(Error::Toml)?;
+        }
+
+        Ok(ret)
+    }
+}
+
+/// Internal error type for every error spec parsing could encounter
+#[derive(Debug)]
+pub enum Error {
+    /// Wrapper around IO errors
+    Io(std::io::Error),
+    /// Wrapper around deserialization errors
+    Toml(toml::de::Error),
+}
+
+/// Maps an [`std::io::Error`] onto a [`Error`] type for easier propagation
+fn from_ioerr<T>(t: std::io::Result<T>) -> Result<T, Error> {
+    t.map_err(Error::Io)
+}
+
+/// Object containing the abstract definitions of all output files.
+///
+/// See [`OutFileDef`] to details on the specification contents of each output.
+#[derive(Debug)]
+pub struct Spec(pub Vec<OutFileDef>);
+
+impl Spec {
+    /// Creates a new abstract specification from a top-level directory full
+    /// of specification files. This is used later to aggregate all the content
+    /// and generate the appropriate language outputs.
+    ///
+    /// # Errors
+    /// Fails on IO errors.
+    pub fn new(root: &Path) -> Result<Self, Error> {
+        info!("Reading {root:?} as top-level directory");
+
+        let mut ret = Self(Vec::new());
+        for outfile in from_ioerr(root.read_dir())? {
+            // Each folder in the root defines a single output file
+            let outfile = from_ioerr(outfile)?;
+            let name = outfile.file_name().to_string_lossy().to_string();
+            ret.0.push(OutFileDef::new(name, &outfile.path())?);
+        }
+
+        Ok(ret)
+    }
+}
-- 
2.47.0



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

* [RFC PATCH 05/25] tools/xenbindgen: Add basic plumbing for the C backend
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
                   ` (3 preceding siblings ...)
  2024-11-15 11:51 ` [RFC PATCH 04/25] tools/xenbindgen: Add a TOML spec reader Alejandro Vallejo
@ 2024-11-15 11:51 ` Alejandro Vallejo
  2024-11-15 11:51 ` [RFC PATCH 06/25] tools/xenbindgen: Add xenbindgen's Cargo.lock file Alejandro Vallejo
                   ` (20 subsequent siblings)
  25 siblings, 0 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel; +Cc: Alejandro Vallejo, Anthony PERARD, Teddy Astie, Yann Dirson

Takes an OutFileDef to generate a string with the file content. That
will be all the structs, enums, bitmaps and includes we parse.

For the time being, add the guards only, as the others are implemented
by follow-up patches.

Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
 tools/rust/xenbindgen/src/c_lang.rs | 73 +++++++++++++++++++++++++++++
 tools/rust/xenbindgen/src/main.rs   | 54 +++++++++++++++++++--
 tools/rust/xenbindgen/src/spec.rs   |  2 +-
 3 files changed, 125 insertions(+), 4 deletions(-)
 create mode 100644 tools/rust/xenbindgen/src/c_lang.rs

diff --git a/tools/rust/xenbindgen/src/c_lang.rs b/tools/rust/xenbindgen/src/c_lang.rs
new file mode 100644
index 000000000000..f05e36bb362f
--- /dev/null
+++ b/tools/rust/xenbindgen/src/c_lang.rs
@@ -0,0 +1,73 @@
+//! C backend
+//!
+//! A backend for the C programming language. Enums and bitmaps appear as their
+//! backing primitive type. This is in order to mandate size and alignment at
+//! the ABI boundary.
+//!
+//! Otherwise, enums and struct are declared with their native C counterparts,
+//! whereas bitmaps are declared as `#define` items.
+//!
+//! There's an expectation that the supporting library will have the
+//! `(u)int64_aligned_t` types and `XEN_GUEST_HANDLE_64()`, These are important
+//! in order to allow 32bit domains to interact with 64bit hypervisors.
+//!
+//! As far as definitions go, `enums` are stored in native `enums`, but bitmaps
+//! are given in `#define` instead, with an empty struct on top to provide grep
+//! fodder and a tag to follow using an LSP, global, cscope, etc.
+
+use std::fmt::Write;
+
+use crate::spec::OutFileDef;
+
+use convert_case::{Case, Casing};
+
+/// An abstract indentation level. 0 is no indentation, 1 is [`INDENT_WIDTH`]
+/// and so on.
+#[derive(Copy, Clone)]
+struct Indentation(usize);
+
+/// Default width of each level of indentation
+const INDENT_WIDTH: usize = 4;
+
+/// Add a comment to a struct or a field.
+fn comment(out: &mut String, comment: &str, ind: Indentation) {
+    let spaces = " ".repeat(INDENT_WIDTH * ind.0);
+
+    if comment.contains('\n') {
+        writeln!(out, "{spaces}/*").unwrap();
+        for line in comment.split('\n') {
+            write!(out, "{spaces} *").unwrap();
+            if !line.is_empty() {
+                write!(out, " {line}").unwrap();
+            }
+            writeln!(out).unwrap();
+        }
+        writeln!(out, "{spaces} */").unwrap();
+    } else {
+        writeln!(out, "{spaces}/* {comment} */").unwrap();
+    }
+}
+
+/// Generates a single `.h` file.
+///
+/// `filedef` is a language-agnostic high level description of what the output
+/// must contain. The function returns the contents of the new
+///
+/// # Aborts
+/// Aborts the process with `rc=1` on known illegal specifications.
+pub fn parse(filedef: &OutFileDef) -> String {
+    let mut out = String::new();
+    let name = filedef
+        .name
+        .from_case(Case::Kebab)
+        .to_case(Case::UpperSnake);
+    let hdr = format!("{}\n\nAUTOGENERATED. DO NOT MODIFY", filedef.name);
+
+    comment(&mut out, &hdr, Indentation(0));
+    writeln!(out, "#ifndef __XEN_AUTOGEN_{name}_H").unwrap();
+    writeln!(out, "#define __XEN_AUTOGEN_{name}_H\n").unwrap();
+
+    writeln!(out, "#endif /* __XEN_AUTOGEN_{name}_H */\n").unwrap();
+
+    out
+}
diff --git a/tools/rust/xenbindgen/src/main.rs b/tools/rust/xenbindgen/src/main.rs
index 497cf39d3bbd..00abf5ed7f33 100644
--- a/tools/rust/xenbindgen/src/main.rs
+++ b/tools/rust/xenbindgen/src/main.rs
@@ -4,11 +4,15 @@
 
 mod spec;
 
-use std::path::PathBuf;
+mod c_lang;
+
+use std::{io::Write, path::PathBuf};
 
 use clap::Parser;
+use convert_case::{Case, Casing};
 use env_logger::Env;
 use log::{error, info};
+use spec::OutFileDef;
 
 /// A CLI tool to generate struct definitions in several languages.
 #[derive(Parser, Debug)]
@@ -17,6 +21,20 @@ struct Cli {
     /// Path to the input directory containing the hypercall specification
     #[arg(short, long)]
     indir: PathBuf,
+    /// Path to the output directory for the generated bindings.
+    #[arg(short, long)]
+    outdir: PathBuf,
+    /// Target language for the contents of `outdir`.
+    #[arg(short, long, value_enum)]
+    lang: Lang,
+}
+
+/// Supported target languages
+#[derive(clap::ValueEnum, Clone, Debug)]
+#[clap(rename_all = "kebab_case")]
+enum Lang {
+    #[doc(hidden)]
+    C,
 }
 
 fn main() {
@@ -25,7 +43,7 @@ fn main() {
     let cli = Cli::parse();
     info!("args: {:?}", cli);
 
-    let _specification = match spec::Spec::new(&cli.indir) {
+    let specification = match spec::Spec::new(&cli.indir) {
         Ok(x) => x,
         Err(spec::Error::Toml(x)) => {
             error!("TOML parsing error:");
@@ -39,5 +57,35 @@ fn main() {
         }
     };
 
-    todo!("generate output files");
+    let (extension, parser): (&str, fn(&OutFileDef) -> String) = match cli.lang {
+        Lang::C => (".h", c_lang::parse),
+    };
+
+    if let Err(x) = std::fs::create_dir_all(&cli.outdir) {
+        error!("Can't create outdir {:?}: {x}", cli.outdir);
+        std::process::exit(1);
+    }
+
+    for outfile in &specification.0 {
+        let mut path = cli.outdir.clone();
+        let name = outfile.name.from_case(Case::Kebab).to_case(Case::Snake);
+        path.push(format!("{name}{extension}"));
+
+        info!("Generating {path:?}");
+
+        // Parse the input file before creating the output
+        let output = parser(outfile);
+
+        let Ok(mut file) = std::fs::OpenOptions::new()
+            .write(true)
+            .create(true)
+            .truncate(true)
+            .open(path)
+        else {
+            error!("Can't open {}", outfile.name);
+            std::process::exit(1);
+        };
+
+        file.write_all(output.as_bytes()).unwrap();
+    }
 }
diff --git a/tools/rust/xenbindgen/src/spec.rs b/tools/rust/xenbindgen/src/spec.rs
index e69f7c78dc7a..08c4dc3a7eba 100644
--- a/tools/rust/xenbindgen/src/spec.rs
+++ b/tools/rust/xenbindgen/src/spec.rs
@@ -40,7 +40,7 @@ impl OutFileDef {
     pub fn new(name: String, dir: &Path) -> Result<Self, Error> {
         info!("Reading {dir:?} to generate an output file");
 
-        let mut ret = Self { name };
+        let ret = Self { name };
 
         for entry in from_ioerr(dir.read_dir())? {
             let path = from_ioerr(entry)?.path();
-- 
2.47.0



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

* [RFC PATCH 06/25] tools/xenbindgen: Add xenbindgen's Cargo.lock file
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
                   ` (4 preceding siblings ...)
  2024-11-15 11:51 ` [RFC PATCH 05/25] tools/xenbindgen: Add basic plumbing for the C backend Alejandro Vallejo
@ 2024-11-15 11:51 ` Alejandro Vallejo
  2024-11-15 11:51 ` [RFC PATCH 07/25] tools/xenbindgen: Add support for structs in TOML specs Alejandro Vallejo
                   ` (19 subsequent siblings)
  25 siblings, 0 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel; +Cc: Alejandro Vallejo, Anthony PERARD, Teddy Astie, Yann Dirson

Libraries mustn't have lock files, but binaries do. Add the lockfile
with all dependencies of xenbindgen.

Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
 tools/rust/xenbindgen/Cargo.lock | 430 +++++++++++++++++++++++++++++++
 1 file changed, 430 insertions(+)
 create mode 100644 tools/rust/xenbindgen/Cargo.lock

diff --git a/tools/rust/xenbindgen/Cargo.lock b/tools/rust/xenbindgen/Cargo.lock
new file mode 100644
index 000000000000..2c20c4ae8598
--- /dev/null
+++ b/tools/rust/xenbindgen/Cargo.lock
@@ -0,0 +1,430 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "anstream"
+version = "0.6.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
+dependencies = [
+ "anstyle",
+ "windows-sys",
+]
+
+[[package]]
+name = "clap"
+version = "4.5.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.5.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
+
+[[package]]
+name = "convert_case"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "env_filter"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab"
+dependencies = [
+ "log",
+ "regex",
+]
+
+[[package]]
+name = "env_logger"
+version = "0.11.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "env_filter",
+ "humantime",
+ "log",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "hashbrown"
+version = "0.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "humantime"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
+
+[[package]]
+name = "indexmap"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+
+[[package]]
+name = "log"
+version = "0.4.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "regex"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
+
+[[package]]
+name = "serde"
+version = "1.0.215"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.215"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_spanned"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "syn"
+version = "2.0.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "toml"
+version = "0.8.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
+dependencies = [
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_edit",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.22.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
+dependencies = [
+ "indexmap",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "winnow"
+version = "0.6.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "xenbindgen"
+version = "0.2.0"
+dependencies = [
+ "clap",
+ "convert_case",
+ "env_logger",
+ "log",
+ "serde",
+ "toml",
+]
-- 
2.47.0



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

* [RFC PATCH 07/25] tools/xenbindgen: Add support for structs in TOML specs
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
                   ` (5 preceding siblings ...)
  2024-11-15 11:51 ` [RFC PATCH 06/25] tools/xenbindgen: Add xenbindgen's Cargo.lock file Alejandro Vallejo
@ 2024-11-15 11:51 ` Alejandro Vallejo
  2024-11-25 12:39   ` Teddy Astie
  2024-11-25 15:03   ` Teddy Astie
  2024-11-15 11:51 ` [RFC PATCH 08/25] tools/xenbindgen: Add support for enums " Alejandro Vallejo
                   ` (18 subsequent siblings)
  25 siblings, 2 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel; +Cc: Alejandro Vallejo, Anthony PERARD, Teddy Astie, Yann Dirson

Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
 tools/rust/xenbindgen/src/c_lang.rs | 56 ++++++++++++++++++++++++-
 tools/rust/xenbindgen/src/spec.rs   | 64 ++++++++++++++++++++++++++++-
 2 files changed, 117 insertions(+), 3 deletions(-)

diff --git a/tools/rust/xenbindgen/src/c_lang.rs b/tools/rust/xenbindgen/src/c_lang.rs
index f05e36bb362f..597e0ed41362 100644
--- a/tools/rust/xenbindgen/src/c_lang.rs
+++ b/tools/rust/xenbindgen/src/c_lang.rs
@@ -17,9 +17,10 @@
 
 use std::fmt::Write;
 
-use crate::spec::OutFileDef;
+use crate::spec::{OutFileDef, StructDef, Typ};
 
 use convert_case::{Case, Casing};
+use log::{debug, trace};
 
 /// An abstract indentation level. 0 is no indentation, 1 is [`INDENT_WIDTH`]
 /// and so on.
@@ -29,6 +30,39 @@ struct Indentation(usize);
 /// Default width of each level of indentation
 const INDENT_WIDTH: usize = 4;
 
+/// Create a C-compatible struct field. Without the terminating semicolon.
+fn structfield(typ: &Typ, name: &str) -> String {
+    match typ {
+        Typ::Ptr(x) => {
+            let t: &Typ = x;
+            format!(
+                "XEN_GUEST_HANDLE_64({}) {name}",
+                match t {
+                    Typ::U8 => "uint8",
+                    Typ::U16 => "uint16",
+                    Typ::U32 => "uint32",
+                    Typ::U64 => "uint64_aligned_t",
+                    Typ::I8 => "int8",
+                    Typ::I16 => "int16",
+                    Typ::I32 => "int32",
+                    Typ::I64 => "int64_aligned_t",
+                    _ => panic!("foo {t:?}"),
+                }
+            )
+        }
+        Typ::Struct(x) => format!("struct {x} {name}"),
+        Typ::Array(x, len) => format!("{}{name}[{len}]", structfield(x, "")),
+        Typ::U8 => format!("uint8_t {name}"),
+        Typ::U16 => format!("uint16_t {name}"),
+        Typ::U32 => format!("uint32_t {name}"),
+        Typ::U64 => format!("uint64_aligned_t {name}"),
+        Typ::I8 => format!("int8_t {name}"),
+        Typ::I16 => format!("int16_t {name}"),
+        Typ::I32 => format!("int32_t {name}"),
+        Typ::I64 => format!("int64_aligned_t {name}"),
+    }
+}
+
 /// Add a comment to a struct or a field.
 fn comment(out: &mut String, comment: &str, ind: Indentation) {
     let spaces = " ".repeat(INDENT_WIDTH * ind.0);
@@ -48,6 +82,22 @@ fn comment(out: &mut String, comment: &str, ind: Indentation) {
     }
 }
 
+/// Write a C-compatible struct onto `out`
+fn structgen(out: &mut String, def: &StructDef) {
+    debug!("struct {}", def.name);
+
+    comment(out, &def.description, Indentation(0));
+    writeln!(out, "struct {} {{", def.name.to_case(Case::Snake)).unwrap();
+    for f in &def.fields {
+        trace!("  field {} type={:?}", f.name, f.typ);
+
+        comment(out, &f.description, Indentation(1));
+        writeln!(out, "    {};", structfield(&f.typ, &f.name),).unwrap();
+    }
+    writeln!(out, "}};").unwrap();
+    writeln!(out).unwrap();
+}
+
 /// Generates a single `.h` file.
 ///
 /// `filedef` is a language-agnostic high level description of what the output
@@ -67,6 +117,10 @@ pub fn parse(filedef: &OutFileDef) -> String {
     writeln!(out, "#ifndef __XEN_AUTOGEN_{name}_H").unwrap();
     writeln!(out, "#define __XEN_AUTOGEN_{name}_H\n").unwrap();
 
+    for def in &filedef.structs {
+        structgen(&mut out, def);
+    }
+
     writeln!(out, "#endif /* __XEN_AUTOGEN_{name}_H */\n").unwrap();
 
     out
diff --git a/tools/rust/xenbindgen/src/spec.rs b/tools/rust/xenbindgen/src/spec.rs
index 08c4dc3a7eba..e183378329ad 100644
--- a/tools/rust/xenbindgen/src/spec.rs
+++ b/tools/rust/xenbindgen/src/spec.rs
@@ -17,9 +17,61 @@ use std::{fs::read_to_string, path::Path};
 
 use log::{debug, info};
 
+/// An IDL type. A type may be a primitive integer, a pointer to an IDL type,
+/// an array of IDL types or a struct composed of IDL types. Every integer must
+/// be aligned to its size.
+///
+/// FIXME: This enumerated type is recovered as-is from the `typ` field in the
+/// TOML files. Ideally, that representation should be more ergonomic and the
+/// parser instructed to deal with it.
+#[allow(clippy::missing_docs_in_private_items)]
+#[derive(Debug, serde::Deserialize, PartialEq)]
+#[serde(rename_all = "lowercase", tag = "tag", content = "args")]
+pub enum Typ {
+    Struct(String),
+    U8,
+    U16,
+    U32,
+    U64,
+    I8,
+    I16,
+    I32,
+    I64,
+    Ptr(Box<Typ>),
+    Array(Box<Typ>, usize),
+}
+
+/// Deserialized form of a hypercall struct
+#[derive(Debug, serde::Deserialize)]
+pub struct StructDef {
+    /// Name of the struct
+    pub name: String,
+    /// Description of what the struct is for. This string is added as a comment
+    /// on top of the autogenerated struct.
+    pub description: String,
+    /// Fields contained in the struct. May be none, in which case it's a zero
+    /// length struct.
+    pub fields: Vec<FieldDef>,
+}
+
+/// Deserialized form of a field within a hypercall struct (see [`StructDef`])
+#[derive(Debug, serde::Deserialize)]
+pub struct FieldDef {
+    /// Name of the field
+    pub name: String,
+    /// Description of what the field is for. This string is added as a comment
+    /// on top of the autogenerated field.
+    pub description: String,
+    /// Type of the field.
+    pub typ: Typ,
+}
+
 /// A language-agnostic specification.
 #[derive(Debug, serde::Deserialize)]
-struct InFileDef;
+struct InFileDef {
+    /// List of structs described in this input specification.
+    structs: Option<Vec<StructDef>>,
+}
 
 /// Description of an abstract output (i.e: `.rs`, `.h`, etc).
 ///
@@ -28,6 +80,8 @@ struct InFileDef;
 pub struct OutFileDef {
     /// The name of the output file, without the final extension.
     pub name: String,
+    /// List of structs described by all input spec files merged on this file.
+    pub structs: Vec<StructDef>,
 }
 
 impl OutFileDef {
@@ -40,13 +94,19 @@ impl OutFileDef {
     pub fn new(name: String, dir: &Path) -> Result<Self, Error> {
         info!("Reading {dir:?} to generate an output file");
 
-        let ret = Self { name };
+        let mut ret = Self {
+            name,
+            structs: Vec::new(),
+        };
 
         for entry in from_ioerr(dir.read_dir())? {
             let path = from_ioerr(entry)?.path();
             debug!("Reading {:?} to generate outfile={}", path, ret.name);
             let toml_str = from_ioerr(read_to_string(path))?;
             let filedef: InFileDef = toml::from_str(&toml_str).map_err(Error::Toml)?;
+            if let Some(structs) = filedef.structs {
+                ret.structs.extend(structs);
+            }
         }
 
         Ok(ret)
-- 
2.47.0



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

* [RFC PATCH 08/25] tools/xenbindgen: Add support for enums in TOML specs
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
                   ` (6 preceding siblings ...)
  2024-11-15 11:51 ` [RFC PATCH 07/25] tools/xenbindgen: Add support for structs in TOML specs Alejandro Vallejo
@ 2024-11-15 11:51 ` Alejandro Vallejo
  2024-11-25 16:39   ` Teddy Astie
  2024-11-15 11:51 ` [RFC PATCH 09/25] tools/xenbindgen: Add support for bitmaps " Alejandro Vallejo
                   ` (17 subsequent siblings)
  25 siblings, 1 reply; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel; +Cc: Alejandro Vallejo, Anthony PERARD, Teddy Astie, Yann Dirson

Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
 tools/rust/xenbindgen/src/c_lang.rs | 57 +++++++++++++++++++++++++----
 tools/rust/xenbindgen/src/spec.rs   | 45 +++++++++++++++++++++++
 2 files changed, 95 insertions(+), 7 deletions(-)

diff --git a/tools/rust/xenbindgen/src/c_lang.rs b/tools/rust/xenbindgen/src/c_lang.rs
index 597e0ed41362..f15feca8df91 100644
--- a/tools/rust/xenbindgen/src/c_lang.rs
+++ b/tools/rust/xenbindgen/src/c_lang.rs
@@ -17,10 +17,10 @@
 
 use std::fmt::Write;
 
-use crate::spec::{OutFileDef, StructDef, Typ};
+use crate::spec::{EnumDef, OutFileDef, StructDef, Typ};
 
 use convert_case::{Case, Casing};
-use log::{debug, trace};
+use log::{debug, error, trace};
 
 /// An abstract indentation level. 0 is no indentation, 1 is [`INDENT_WIDTH`]
 /// and so on.
@@ -31,7 +31,7 @@ struct Indentation(usize);
 const INDENT_WIDTH: usize = 4;
 
 /// Create a C-compatible struct field. Without the terminating semicolon.
-fn structfield(typ: &Typ, name: &str) -> String {
+fn structfield(filedef: &OutFileDef, typ: &Typ, name: &str) -> String {
     match typ {
         Typ::Ptr(x) => {
             let t: &Typ = x;
@@ -51,7 +51,20 @@ fn structfield(typ: &Typ, name: &str) -> String {
             )
         }
         Typ::Struct(x) => format!("struct {x} {name}"),
-        Typ::Array(x, len) => format!("{}{name}[{len}]", structfield(x, "")),
+        Typ::Enum(x) => {
+            // C can't use an enum as a field and fix its width. Look for its
+            // underlying layout and use that type instead.
+            let Some(e) = filedef.enums.iter().find(|y| *x == y.name) else {
+                error!("Can't find enum {x}. Typo?");
+                std::process::exit(1);
+            };
+            format!(
+                "{} /* See {} */",
+                structfield(filedef, &e.typ, name),
+                e.name
+            )
+        }
+        Typ::Array(x, len) => format!("{}{name}[{len}]", structfield(filedef, x, "")),
         Typ::U8 => format!("uint8_t {name}"),
         Typ::U16 => format!("uint16_t {name}"),
         Typ::U32 => format!("uint32_t {name}"),
@@ -83,7 +96,7 @@ fn comment(out: &mut String, comment: &str, ind: Indentation) {
 }
 
 /// Write a C-compatible struct onto `out`
-fn structgen(out: &mut String, def: &StructDef) {
+fn structgen(out: &mut String, filedef: &OutFileDef, def: &StructDef) {
     debug!("struct {}", def.name);
 
     comment(out, &def.description, Indentation(0));
@@ -92,7 +105,33 @@ fn structgen(out: &mut String, def: &StructDef) {
         trace!("  field {} type={:?}", f.name, f.typ);
 
         comment(out, &f.description, Indentation(1));
-        writeln!(out, "    {};", structfield(&f.typ, &f.name),).unwrap();
+        writeln!(out, "    {};", structfield(filedef, &f.typ, &f.name),).unwrap();
+    }
+    writeln!(out, "}};").unwrap();
+    writeln!(out).unwrap();
+}
+
+/// Write a C-compatible enum onto `out`
+///
+/// This is a generator for the enum _type_, not an instantiation of a bitmap
+/// in a struct field. Use [`structfield`] for that.
+fn enumgen(out: &mut String, def: &EnumDef) {
+    debug!("enum {}", def.name);
+
+    comment(out, &def.description, Indentation(0));
+    writeln!(out, "enum {} {{", def.name).unwrap();
+    for f in &def.variants {
+        trace!("  variant {}={}", f.name, f.value);
+
+        comment(out, &f.description, Indentation(1));
+        writeln!(
+            out,
+            "    {}_{} = {},",
+            def.name.from_case(Case::Snake).to_case(Case::UpperSnake),
+            f.name.from_case(Case::Snake).to_case(Case::UpperSnake),
+            f.value
+        )
+        .unwrap();
     }
     writeln!(out, "}};").unwrap();
     writeln!(out).unwrap();
@@ -117,8 +156,12 @@ pub fn parse(filedef: &OutFileDef) -> String {
     writeln!(out, "#ifndef __XEN_AUTOGEN_{name}_H").unwrap();
     writeln!(out, "#define __XEN_AUTOGEN_{name}_H\n").unwrap();
 
+    for def in &filedef.enums {
+        enumgen(&mut out, def);
+    }
+
     for def in &filedef.structs {
-        structgen(&mut out, def);
+        structgen(&mut out, filedef, def);
     }
 
     writeln!(out, "#endif /* __XEN_AUTOGEN_{name}_H */\n").unwrap();
diff --git a/tools/rust/xenbindgen/src/spec.rs b/tools/rust/xenbindgen/src/spec.rs
index e183378329ad..f6cfedad2150 100644
--- a/tools/rust/xenbindgen/src/spec.rs
+++ b/tools/rust/xenbindgen/src/spec.rs
@@ -28,6 +28,7 @@ use log::{debug, info};
 #[derive(Debug, serde::Deserialize, PartialEq)]
 #[serde(rename_all = "lowercase", tag = "tag", content = "args")]
 pub enum Typ {
+    Enum(String),
     Struct(String),
     U8,
     U16,
@@ -66,11 +67,47 @@ pub struct FieldDef {
     pub typ: Typ,
 }
 
+/// Description of a lang-agnostic enumerated type.
+#[derive(Debug, serde::Deserialize)]
+pub struct EnumDef {
+    /// snake-cased name of this enumeration.
+    ///
+    /// Must be converted to whatever is idiomatic in the target language.
+    pub name: String,
+    /// Description of what the type is for.
+    ///
+    /// Must be turned into documentation in the autogenerated file.
+    pub description: String,
+    /// Width of the type given as an equivalent primitive unsigned integer
+    /// of the same width.
+    pub typ: Typ,
+    /// List of variants present in this enum.
+    ///
+    /// The backend must export all of these under the same namespace if
+    /// possible.
+    pub variants: Vec<VariantDef>,
+}
+
+/// A lang-agnostic description of a single variant of an enumerated type.
+#[derive(Debug, serde::Deserialize)]
+pub struct VariantDef {
+    /// Name of this variant. Depending on the backend, the name might be
+    /// prefixed by the name of its type (as is commonly done in C).
+    pub name: String,
+    /// Meaning of this variant in the context of its type.
+    pub description: String,
+    /// Actual value associated with this variant. Must be explicit to enable
+    /// deprecation of variants.
+    pub value: u64,
+}
+
 /// A language-agnostic specification.
 #[derive(Debug, serde::Deserialize)]
 struct InFileDef {
     /// List of structs described in this input specification.
     structs: Option<Vec<StructDef>>,
+    /// List of lang-agnostic enumerated descriptions.
+    enums: Option<Vec<EnumDef>>,
 }
 
 /// Description of an abstract output (i.e: `.rs`, `.h`, etc).
@@ -82,6 +119,10 @@ pub struct OutFileDef {
     pub name: String,
     /// List of structs described by all input spec files merged on this file.
     pub structs: Vec<StructDef>,
+    /// List of enumerated descriptions.
+    ///
+    /// Implementation is lang-specific.
+    pub enums: Vec<EnumDef>,
 }
 
 impl OutFileDef {
@@ -97,6 +138,7 @@ impl OutFileDef {
         let mut ret = Self {
             name,
             structs: Vec::new(),
+            enums: Vec::new(),
         };
 
         for entry in from_ioerr(dir.read_dir())? {
@@ -107,6 +149,9 @@ impl OutFileDef {
             if let Some(structs) = filedef.structs {
                 ret.structs.extend(structs);
             }
+            if let Some(enums) = filedef.enums {
+                ret.enums.extend(enums);
+            }
         }
 
         Ok(ret)
-- 
2.47.0



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

* [RFC PATCH 09/25] tools/xenbindgen: Add support for bitmaps in TOML specs
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
                   ` (7 preceding siblings ...)
  2024-11-15 11:51 ` [RFC PATCH 08/25] tools/xenbindgen: Add support for enums " Alejandro Vallejo
@ 2024-11-15 11:51 ` Alejandro Vallejo
  2024-11-15 11:51 ` [RFC PATCH 10/25] tools/xenbindgen: Add support for includes in the " Alejandro Vallejo
                   ` (16 subsequent siblings)
  25 siblings, 0 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel; +Cc: Alejandro Vallejo, Anthony PERARD, Teddy Astie, Yann Dirson

Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
 tools/rust/xenbindgen/src/c_lang.rs | 62 ++++++++++++++++++++++++++++-
 tools/rust/xenbindgen/src/spec.rs   | 51 ++++++++++++++++++++++--
 2 files changed, 108 insertions(+), 5 deletions(-)

diff --git a/tools/rust/xenbindgen/src/c_lang.rs b/tools/rust/xenbindgen/src/c_lang.rs
index f15feca8df91..bba310233e60 100644
--- a/tools/rust/xenbindgen/src/c_lang.rs
+++ b/tools/rust/xenbindgen/src/c_lang.rs
@@ -17,7 +17,7 @@
 
 use std::fmt::Write;
 
-use crate::spec::{EnumDef, OutFileDef, StructDef, Typ};
+use crate::spec::{BitmapDef, EnumDef, OutFileDef, StructDef, Typ};
 
 use convert_case::{Case, Casing};
 use log::{debug, error, trace};
@@ -51,6 +51,20 @@ fn structfield(filedef: &OutFileDef, typ: &Typ, name: &str) -> String {
             )
         }
         Typ::Struct(x) => format!("struct {x} {name}"),
+        Typ::Bitmap(x) => {
+            // Dealing with bitfields at the ABI boundary is a
+            // pain, so we just use the underlying type instead.
+            let Some(e) = filedef.bitmaps.iter().find(|y| *x == y.name) else {
+                error!("Can't find bitmap {x}. Typo?");
+                trace!("{filedef:#?}");
+                std::process::exit(1);
+            };
+            format!(
+                "{} /* See {} */",
+                structfield(filedef, &e.typ, name),
+                e.name
+            )
+        }
         Typ::Enum(x) => {
             // C can't use an enum as a field and fix its width. Look for its
             // underlying layout and use that type instead.
@@ -137,6 +151,48 @@ fn enumgen(out: &mut String, def: &EnumDef) {
     writeln!(out).unwrap();
 }
 
+/// Write a C-compatible enum onto `out`
+fn bitmapgen(out: &mut String, def: &BitmapDef) {
+    debug!("bitmap {}", def.name);
+
+    comment(out, &def.description, Indentation(0));
+    writeln!(out, "struct {} {{}}; /* GREP FODDER */", def.name).unwrap();
+
+    let mut mask = 0;
+    for f in &def.bits {
+        trace!("  shift {}={}", f.name, f.shift);
+
+        if (1 << f.shift) & mask != 0 {
+            error!("Bad shift({}) on {}. Shadows another bit.", f.shift, f.name);
+            std::process::exit(1);
+        }
+
+        mask |= 1 << f.shift;
+
+        comment(out, &f.description, Indentation(0));
+        writeln!(
+            out,
+            "#define {}_{} (1U{} << {})",
+            def.name.from_case(Case::Snake).to_case(Case::UpperSnake),
+            f.name.from_case(Case::Snake).to_case(Case::UpperSnake),
+            if def.typ == Typ::U64 { "LL" } else { "" },
+            f.shift
+        )
+        .unwrap();
+    }
+
+    comment(out, "Mask covering all defined bits", Indentation(0));
+    writeln!(
+        out,
+        "#define {}__ALL ({:#X}U{})",
+        def.name.from_case(Case::Snake).to_case(Case::UpperSnake),
+        mask,
+        if def.typ == Typ::U64 { "LL" } else { "" },
+    )
+    .unwrap();
+    writeln!(out).unwrap();
+}
+
 /// Generates a single `.h` file.
 ///
 /// `filedef` is a language-agnostic high level description of what the output
@@ -160,6 +216,10 @@ pub fn parse(filedef: &OutFileDef) -> String {
         enumgen(&mut out, def);
     }
 
+    for def in &filedef.bitmaps {
+        bitmapgen(&mut out, def);
+    }
+
     for def in &filedef.structs {
         structgen(&mut out, filedef, def);
     }
diff --git a/tools/rust/xenbindgen/src/spec.rs b/tools/rust/xenbindgen/src/spec.rs
index f6cfedad2150..4a9c5e7d028b 100644
--- a/tools/rust/xenbindgen/src/spec.rs
+++ b/tools/rust/xenbindgen/src/spec.rs
@@ -28,6 +28,7 @@ use log::{debug, info};
 #[derive(Debug, serde::Deserialize, PartialEq)]
 #[serde(rename_all = "lowercase", tag = "tag", content = "args")]
 pub enum Typ {
+    Bitmap(String),
     Enum(String),
     Struct(String),
     U8,
@@ -72,7 +73,7 @@ pub struct FieldDef {
 pub struct EnumDef {
     /// snake-cased name of this enumeration.
     ///
-    /// Must be converted to whatever is idiomatic in the target language.
+    /// Must be converted to idiomatic casing in the target language.
     pub name: String,
     /// Description of what the type is for.
     ///
@@ -88,11 +89,43 @@ pub struct EnumDef {
     pub variants: Vec<VariantDef>,
 }
 
-/// A lang-agnostic description of a single variant of an enumerated type.
+/// Lang-agnostic description of a bitmap type.
+#[derive(Debug, serde::Deserialize)]
+pub struct BitmapDef {
+    /// Snake-cased name of this bitmap.
+    ///
+    /// Must be converted to idiomatic casing in the target language.
+    pub name: String,
+    /// Description of what the type is for.
+    ///
+    /// Must be turned into documentation in the autogenerated file.
+    pub description: String,
+    /// Width of the type given as an equivalent primitive unsigned integer
+    /// of the same width.
+    pub typ: Typ,
+    /// List of bits in the bitmap with a described meaning. All other bits are
+    /// reserved to zero.
+    pub bits: Vec<BitDef>,
+}
+
+/// Lang-agnostic description of a single bit within a particular bitmap type.
+#[derive(Debug, serde::Deserialize)]
+pub struct BitDef {
+    /// Snake-cased name of this bit. Depending on the backend, the name
+    /// might be prefixed by the name of its type (as is commonly done in C).
+    pub name: String,
+    /// Meaning of this bit in the context of its type.
+    pub description: String,
+    /// Position of the bit in the underlying type, following a little-endian
+    /// convention.
+    pub shift: u8,
+}
+
+/// Lang-agnostic description of a single variant of an enumerated type.
 #[derive(Debug, serde::Deserialize)]
 pub struct VariantDef {
-    /// Name of this variant. Depending on the backend, the name might be
-    /// prefixed by the name of its type (as is commonly done in C).
+    /// Snake-cased name of this variant. Depending on the backend, the name
+    /// might be prefixed by the name of its type (as is commonly done in C).
     pub name: String,
     /// Meaning of this variant in the context of its type.
     pub description: String,
@@ -108,6 +141,8 @@ struct InFileDef {
     structs: Option<Vec<StructDef>>,
     /// List of lang-agnostic enumerated descriptions.
     enums: Option<Vec<EnumDef>>,
+    /// List of lang-agnostic bitmap descriptions.
+    bitmaps: Option<Vec<BitmapDef>>,
 }
 
 /// Description of an abstract output (i.e: `.rs`, `.h`, etc).
@@ -123,6 +158,10 @@ pub struct OutFileDef {
     ///
     /// Implementation is lang-specific.
     pub enums: Vec<EnumDef>,
+    /// List of bitmap descriptions.
+    ///
+    /// Implementation is lang-specific.
+    pub bitmaps: Vec<BitmapDef>,
 }
 
 impl OutFileDef {
@@ -139,6 +178,7 @@ impl OutFileDef {
             name,
             structs: Vec::new(),
             enums: Vec::new(),
+            bitmaps: Vec::new(),
         };
 
         for entry in from_ioerr(dir.read_dir())? {
@@ -152,6 +192,9 @@ impl OutFileDef {
             if let Some(enums) = filedef.enums {
                 ret.enums.extend(enums);
             }
+            if let Some(bitmaps) = filedef.bitmaps {
+                ret.bitmaps.extend(bitmaps);
+            }
         }
 
         Ok(ret)
-- 
2.47.0



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

* [RFC PATCH 10/25] tools/xenbindgen: Add support for includes in the TOML specs
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
                   ` (8 preceding siblings ...)
  2024-11-15 11:51 ` [RFC PATCH 09/25] tools/xenbindgen: Add support for bitmaps " Alejandro Vallejo
@ 2024-11-15 11:51 ` Alejandro Vallejo
  2024-11-15 11:51 ` [RFC PATCH 11/25] tools/xenbindgen: Validate ABI rules at generation time Alejandro Vallejo
                   ` (15 subsequent siblings)
  25 siblings, 0 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel; +Cc: Alejandro Vallejo, Anthony PERARD, Teddy Astie, Yann Dirson

Adds include-like semantics to the TOML files. Note that "arch" is
special to allow (a) generating all arch-specific files in one go and
(b) demultiplex appropriately.

Signed-off-by: Teddy Astie <teddy.astie@vates.tech>
Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
 tools/rust/xenbindgen/src/c_lang.rs | 39 ++++++++++++++++++++++++++++-
 tools/rust/xenbindgen/src/spec.rs   | 24 ++++++++++++++++++
 2 files changed, 62 insertions(+), 1 deletion(-)

diff --git a/tools/rust/xenbindgen/src/c_lang.rs b/tools/rust/xenbindgen/src/c_lang.rs
index bba310233e60..be6be3756dc0 100644
--- a/tools/rust/xenbindgen/src/c_lang.rs
+++ b/tools/rust/xenbindgen/src/c_lang.rs
@@ -17,7 +17,7 @@
 
 use std::fmt::Write;
 
-use crate::spec::{BitmapDef, EnumDef, OutFileDef, StructDef, Typ};
+use crate::spec::{BitmapDef, EnumDef, IncludeDef, OutFileDef, StructDef, Typ};
 
 use convert_case::{Case, Casing};
 use log::{debug, error, trace};
@@ -109,6 +109,39 @@ fn comment(out: &mut String, comment: &str, ind: Indentation) {
     }
 }
 
+/// Adds specified `includes`. `arch` must be treated specially in order to
+/// demultiplex the target architecture.
+///
+/// The reason for the inclusion must be printed as a comment on top of the
+/// `include` itself.
+fn includegen(out: &mut String, def: &IncludeDef) {
+    if !def.imports.is_empty() {
+        comment(
+            out,
+            &format!("for {}", def.imports.join(",\n    ")),
+            Indentation(0),
+        );
+    }
+
+    if def.from == "arch" {
+        writeln!(out, "#if defined(__i386__) || defined(__x86_64__)").unwrap();
+        writeln!(out, "#include \"arch_x86.h\"").unwrap();
+        writeln!(out, "#elif defined(__arm__) || defined(__aarch64__)").unwrap();
+        writeln!(out, "#include \"arch_arm.h\"").unwrap();
+        writeln!(out, "#elif defined(__powerpc64__)").unwrap();
+        writeln!(out, "#include \"arch_ppc.h\"").unwrap();
+        writeln!(out, "#elif defined(__riscv)").unwrap();
+        writeln!(out, "#include \"arch_riscv.h\"").unwrap();
+        writeln!(out, "#else").unwrap();
+        writeln!(out, "#error \"Unsupported architecture\"").unwrap();
+        writeln!(out, "#endif").unwrap();
+    } else {
+        writeln!(out, "#include \"{}.h\"", def.from).unwrap();
+    }
+
+    writeln!(out).unwrap();
+}
+
 /// Write a C-compatible struct onto `out`
 fn structgen(out: &mut String, filedef: &OutFileDef, def: &StructDef) {
     debug!("struct {}", def.name);
@@ -212,6 +245,10 @@ pub fn parse(filedef: &OutFileDef) -> String {
     writeln!(out, "#ifndef __XEN_AUTOGEN_{name}_H").unwrap();
     writeln!(out, "#define __XEN_AUTOGEN_{name}_H\n").unwrap();
 
+    for def in &filedef.includes {
+        includegen(&mut out, def);
+    }
+
     for def in &filedef.enums {
         enumgen(&mut out, def);
     }
diff --git a/tools/rust/xenbindgen/src/spec.rs b/tools/rust/xenbindgen/src/spec.rs
index 4a9c5e7d028b..04be05187ac8 100644
--- a/tools/rust/xenbindgen/src/spec.rs
+++ b/tools/rust/xenbindgen/src/spec.rs
@@ -134,9 +134,24 @@ pub struct VariantDef {
     pub value: u64,
 }
 
+/// Dependency links between files.
+///
+/// Used in specifications to state a number of types (described in `imports`)
+/// is needed from another generated file (the `from` field).
+#[derive(Debug, serde::Deserialize)]
+pub struct IncludeDef {
+    /// Name of the [`InFileDef`] that contains the imported tokens of
+    /// `imports`.
+    pub from: String,
+    /// List of tokens used in this spec file that exist in `from`.
+    pub imports: Vec<String>,
+}
+
 /// A language-agnostic specification.
 #[derive(Debug, serde::Deserialize)]
 struct InFileDef {
+    /// List of types described in other [`InFileDef`] that are required here.
+    includes: Option<Vec<IncludeDef>>,
     /// List of structs described in this input specification.
     structs: Option<Vec<StructDef>>,
     /// List of lang-agnostic enumerated descriptions.
@@ -152,7 +167,12 @@ struct InFileDef {
 pub struct OutFileDef {
     /// The name of the output file, without the final extension.
     pub name: String,
+    /// Represents the dependencies between various [`OutFileDef`]. A language
+    /// backend is free to ignore these if they are not required.
+    pub includes: Vec<IncludeDef>,
     /// List of structs described by all input spec files merged on this file.
+    ///
+    /// Implementation is lang-specific.
     pub structs: Vec<StructDef>,
     /// List of enumerated descriptions.
     ///
@@ -176,6 +196,7 @@ impl OutFileDef {
 
         let mut ret = Self {
             name,
+            includes: Vec::new(),
             structs: Vec::new(),
             enums: Vec::new(),
             bitmaps: Vec::new(),
@@ -195,6 +216,9 @@ impl OutFileDef {
             if let Some(bitmaps) = filedef.bitmaps {
                 ret.bitmaps.extend(bitmaps);
             }
+            if let Some(includes) = filedef.includes {
+                ret.includes.extend(includes);
+            }
         }
 
         Ok(ret)
-- 
2.47.0



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

* [RFC PATCH 11/25] tools/xenbindgen: Validate ABI rules at generation time
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
                   ` (9 preceding siblings ...)
  2024-11-15 11:51 ` [RFC PATCH 10/25] tools/xenbindgen: Add support for includes in the " Alejandro Vallejo
@ 2024-11-15 11:51 ` Alejandro Vallejo
  2024-11-15 11:51 ` [RFC PATCH 12/25] xen: Replace sysctl/readconsole with autogenerated version Alejandro Vallejo
                   ` (14 subsequent siblings)
  25 siblings, 0 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel; +Cc: Alejandro Vallejo, Anthony PERARD, Teddy Astie, Yann Dirson

Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
 tools/rust/xenbindgen/src/main.rs |   8 +
 tools/rust/xenbindgen/src/spec.rs | 357 ++++++++++++++++++++++++++++--
 2 files changed, 341 insertions(+), 24 deletions(-)

diff --git a/tools/rust/xenbindgen/src/main.rs b/tools/rust/xenbindgen/src/main.rs
index 00abf5ed7f33..dbc610e420f2 100644
--- a/tools/rust/xenbindgen/src/main.rs
+++ b/tools/rust/xenbindgen/src/main.rs
@@ -55,6 +55,14 @@ fn main() {
             error!("{x:#?}");
             std::process::exit(1);
         }
+        Err(spec::Error::BadAbi(x)) => {
+            error!("Broken ABI rule: {x}");
+            std::process::exit(1);
+        }
+        Err(spec::Error::MissingDefinition(x)) => {
+            error!("Missing include: {x}");
+            std::process::exit(1);
+        }
     };
 
     let (extension, parser): (&str, fn(&OutFileDef) -> String) = match cli.lang {
diff --git a/tools/rust/xenbindgen/src/spec.rs b/tools/rust/xenbindgen/src/spec.rs
index 04be05187ac8..919f3206c1f6 100644
--- a/tools/rust/xenbindgen/src/spec.rs
+++ b/tools/rust/xenbindgen/src/spec.rs
@@ -13,7 +13,7 @@
 //! to properly decode the type and match it with a variant of the [`Typ`] type
 //! with the payload landing in the payload of the variant itself.
 
-use std::{fs::read_to_string, path::Path};
+use std::{cmp::max, fs::read_to_string, path::Path};
 
 use log::{debug, info};
 
@@ -25,7 +25,7 @@ use log::{debug, info};
 /// TOML files. Ideally, that representation should be more ergonomic and the
 /// parser instructed to deal with it.
 #[allow(clippy::missing_docs_in_private_items)]
-#[derive(Debug, serde::Deserialize, PartialEq)]
+#[derive(Clone, Debug, serde::Deserialize, PartialEq)]
 #[serde(rename_all = "lowercase", tag = "tag", content = "args")]
 pub enum Typ {
     Bitmap(String),
@@ -43,8 +43,120 @@ pub enum Typ {
     Array(Box<Typ>, usize),
 }
 
+impl Typ {
+    /// Returns the size of this type in octets. The specification must be
+    /// passed on the side so the function can look-up subordinate types.
+    ///
+    /// # Errors
+    /// `Err` on type lookup failure (e.g: enum doesn't exist).
+    pub fn size(&self, spec: &Spec) -> Result<usize, Error> {
+        match self {
+            Typ::U8 | Typ::I8 => Ok(1),
+            Typ::U16 | Typ::I16 => Ok(2),
+            Typ::U32 | Typ::I32 => Ok(4),
+            Typ::U64 | Typ::I64 | Typ::Ptr(_) => Ok(8),
+            Typ::Enum(s) => spec.find_enum(s)?.typ.size(spec),
+            Typ::Bitmap(s) => spec.find_bitmap(s)?.typ.size(spec),
+            Typ::Struct(s) => {
+                // The size of a struct is the sum of the sizes of its subfields
+                // as long as it's packed, and that is mandated by the ABI.
+                let mut size = 0;
+                for f in &spec.find_struct(s)?.fields {
+                    size += f.typ.size(spec)?;
+                }
+                Ok(size)
+            }
+            Typ::Array(t, n) => Ok(n * t.size(spec)?),
+        }
+    }
+
+    /// Returns the alignment of this type in octets. The specification must
+    /// be passed on the side so the function can look-up subordinate types.
+    ///
+    /// # Errors
+    /// `Err` on type lookup failure (e.g: enum doesn't exist).
+    pub fn alignment(&self, spec: &Spec) -> Result<usize, Error> {
+        match self {
+            Typ::U8 | Typ::I8 => Ok(1),
+            Typ::U16 | Typ::I16 => Ok(2),
+            Typ::U32 | Typ::I32 => Ok(4),
+            Typ::U64 | Typ::I64 | Typ::Ptr(_) => Ok(8),
+            Typ::Enum(s) => spec.find_enum(s)?.typ.alignment(spec),
+            Typ::Bitmap(s) => spec.find_bitmap(s)?.typ.alignment(spec),
+            Typ::Struct(s) => {
+                // The alignment of a struct is as large as its largest field
+                let mut alignment = 1;
+                for f in &spec.find_struct(s)?.fields {
+                    alignment = max(alignment, f.typ.alignment(spec)?);
+                }
+                Ok(alignment)
+            }
+            Typ::Array(t, _) => t.alignment(spec),
+        }
+    }
+
+    /// `Ok` iff the type is {i,u}{8,16,32,64}.
+    pub fn is_primitive(&self) -> Result<(), Error> {
+        match self {
+            Typ::U8 | Typ::I8 | Typ::U16 | Typ::I16 | Typ::U32 | Typ::I32 | Typ::U64 | Typ::I64 => {
+                Ok(())
+            }
+            _ => Err(Error::BadAbi(format!("{self:?} while expecting primitive"))),
+        }
+    }
+
+    /// `Ok` iff the type respects all ABI rules. Note that for a spec to
+    /// satisfy the ABI restrictions _all_ types must satisfy them.
+    pub fn abi_compatible(&self, spec: &Spec) -> Result<(), Error> {
+        match self {
+            // Unconditionally ok. They have fixed size with equal alignment
+            Typ::U8
+            | Typ::I8
+            | Typ::U16
+            | Typ::I16
+            | Typ::U32
+            | Typ::I32
+            | Typ::U64
+            | Typ::I64
+            | Typ::Ptr(_) => Ok(()),
+
+            // Ok as long as their backing type is itself primitive
+            Typ::Enum(s) => spec.find_enum(s)?.typ.is_primitive(),
+            Typ::Bitmap(s) => spec.find_bitmap(s)?.typ.is_primitive(),
+
+            // Every field must be compatible and there can be no padding
+            Typ::Struct(s) => {
+                let def = spec.find_struct(s)?;
+                let mut offset = 0;
+
+                for f in &def.fields {
+                    f.typ.abi_compatible(spec)?;
+
+                    if offset & (f.typ.alignment(spec)? - 1) != 0 {
+                        return Err(Error::BadAbi(format!(
+                            "implicit padding in struct {s}, before {}",
+                            f.name
+                        )));
+                    }
+
+                    offset += f.typ.size(spec)?;
+                }
+
+                if offset & (self.alignment(spec)? - 1) != 0 {
+                    return Err(Error::BadAbi(format!(
+                        "implicit padding in struct {s} at the tail",
+                    )));
+                }
+
+                Ok(())
+            }
+            Typ::Array(t, _) => t.abi_compatible(spec),
+        }
+    }
+}
+
 /// Deserialized form of a hypercall struct
-#[derive(Debug, serde::Deserialize)]
+#[derive(Clone, Debug, serde::Deserialize)]
 pub struct StructDef {
     /// Name of the struct
     pub name: String,
@@ -57,7 +169,7 @@ pub struct StructDef {
 }
 
 /// Deserialized form of a field within a hypercall struct (see [`StructDef`])
-#[derive(Debug, serde::Deserialize)]
+#[derive(Clone, Debug, serde::Deserialize)]
 pub struct FieldDef {
     /// Name of the field
     pub name: String,
@@ -69,7 +181,7 @@ pub struct FieldDef {
 }
 
 /// Description of a lang-agnostic enumerated type.
-#[derive(Debug, serde::Deserialize)]
+#[derive(Clone, Debug, serde::Deserialize)]
 pub struct EnumDef {
     /// snake-cased name of this enumeration.
     ///
@@ -90,7 +202,7 @@ pub struct EnumDef {
 }
 
 /// Lang-agnostic description of a bitmap type.
-#[derive(Debug, serde::Deserialize)]
+#[derive(Clone, Debug, serde::Deserialize)]
 pub struct BitmapDef {
     /// Snake-cased name of this bitmap.
     ///
@@ -109,7 +221,7 @@ pub struct BitmapDef {
 }
 
 /// Lang-agnostic description of a single bit within a particular bitmap type.
-#[derive(Debug, serde::Deserialize)]
+#[derive(Clone, Debug, serde::Deserialize)]
 pub struct BitDef {
     /// Snake-cased name of this bit. Depending on the backend, the name
     /// might be prefixed by the name of its type (as is commonly done in C).
@@ -122,7 +234,7 @@ pub struct BitDef {
 }
 
 /// Lang-agnostic description of a single variant of an enumerated type.
-#[derive(Debug, serde::Deserialize)]
+#[derive(Clone, Debug, serde::Deserialize)]
 pub struct VariantDef {
     /// Snake-cased name of this variant. Depending on the backend, the name
     /// might be prefixed by the name of its type (as is commonly done in C).
@@ -138,7 +250,7 @@ pub struct VariantDef {
 ///
 /// Used in specifications to state a number of types (described in `imports`)
 /// is needed from another generated file (the `from` field).
-#[derive(Debug, serde::Deserialize)]
+#[derive(Clone, Debug, serde::Deserialize)]
 pub struct IncludeDef {
     /// Name of the [`InFileDef`] that contains the imported tokens of
     /// `imports`.
@@ -148,7 +260,7 @@ pub struct IncludeDef {
 }
 
 /// A language-agnostic specification.
-#[derive(Debug, serde::Deserialize)]
+#[derive(Clone, Debug, serde::Deserialize)]
 struct InFileDef {
     /// List of types described in other [`InFileDef`] that are required here.
     includes: Option<Vec<IncludeDef>>,
@@ -163,7 +275,7 @@ struct InFileDef {
 /// Description of an abstract output (i.e: `.rs`, `.h`, etc).
 ///
 /// Contains every element of the ABI that needs representing.
-#[derive(Debug)]
+#[derive(Clone, Debug)]
 pub struct OutFileDef {
     /// The name of the output file, without the final extension.
     pub name: String,
@@ -206,18 +318,18 @@ impl OutFileDef {
             let path = from_ioerr(entry)?.path();
             debug!("Reading {:?} to generate outfile={}", path, ret.name);
             let toml_str = from_ioerr(read_to_string(path))?;
-            let filedef: InFileDef = toml::from_str(&toml_str).map_err(Error::Toml)?;
-            if let Some(structs) = filedef.structs {
-                ret.structs.extend(structs);
+            let infiledef: InFileDef = toml::from_str(&toml_str).map_err(Error::Toml)?;
+            if let Some(x) = infiledef.structs {
+                ret.structs.extend(x);
             }
-            if let Some(enums) = filedef.enums {
-                ret.enums.extend(enums);
+            if let Some(x) = infiledef.enums {
+                ret.enums.extend(x);
             }
-            if let Some(bitmaps) = filedef.bitmaps {
-                ret.bitmaps.extend(bitmaps);
+            if let Some(x) = infiledef.bitmaps {
+                ret.bitmaps.extend(x);
             }
-            if let Some(includes) = filedef.includes {
-                ret.includes.extend(includes);
+            if let Some(x) = infiledef.includes {
+                ret.includes.extend(x);
             }
         }
 
@@ -228,10 +340,14 @@ impl OutFileDef {
 /// Internal error type for every error spec parsing could encounter
 #[derive(Debug)]
 pub enum Error {
-    /// Wrapper around IO errors
+    /// IO errors (e.g: opening files, etc)
     Io(std::io::Error),
-    /// Wrapper around deserialization errors
+    /// Deserialization errors (i.e: from malformed specifications)
     Toml(toml::de::Error),
+    /// Failed ABI consistency checks
+    BadAbi(String),
+    /// Failed definition lookups (typically typos)
+    MissingDefinition(String),
 }
 
 /// Maps an [`std::io::Error`] onto a [`Error`] type for easier propagation
@@ -242,7 +358,7 @@ fn from_ioerr<T>(t: std::io::Result<T>) -> Result<T, Error> {
 /// Object containing the abstract definitions of all output files.
 ///
 /// See [`OutFileDef`] to details on the specification contents of each output.
-#[derive(Debug)]
+#[derive(Debug, Default)]
 pub struct Spec(pub Vec<OutFileDef>);
 
 impl Spec {
@@ -255,7 +371,7 @@ impl Spec {
     pub fn new(root: &Path) -> Result<Self, Error> {
         info!("Reading {root:?} as top-level directory");
 
-        let mut ret = Self(Vec::new());
+        let mut ret: Spec = Self::default();
         for outfile in from_ioerr(root.read_dir())? {
             // Each folder in the root defines a single output file
             let outfile = from_ioerr(outfile)?;
@@ -263,6 +379,199 @@ impl Spec {
             ret.0.push(OutFileDef::new(name, &outfile.path())?);
         }
 
+        for arch in &[ret.x86(), ret.arm(), ret.riscv(), ret.ppc()] {
+            arch.is_valid()?;
+        }
+
         Ok(ret)
     }
+
+    /// Checks names are not duplicated. Some languages might not support type namespaces
+    /// so and it simplifies type lookup in [`Spec::abi_is_compliant`].
+    fn has_unique_names(&self) -> Result<(), Error> {
+        let mut all_names = Vec::<String>::new();
+
+        for outfile in &self.0 {
+            all_names.extend(outfile.structs.iter().map(|e| e.name.clone()));
+            all_names.extend(outfile.enums.iter().map(|e| e.name.clone()));
+            all_names.extend(outfile.bitmaps.iter().map(|e| e.name.clone()));
+        }
+
+        if all_names.is_empty() {
+            return Err(Error::BadAbi("Empty spec".to_string()));
+        }
+
+        let mut dedupped = all_names.clone();
+        dedupped.sort();
+        dedupped.dedup();
+
+        if dedupped.len() != all_names.len() {
+            // There's duplicates. Be nice and point out which
+            let mut dup = all_names.last().unwrap();
+            for (i, name) in dedupped.iter().enumerate() {
+                if all_names[i] != *name {
+                    dup = name;
+                    break;
+                }
+            }
+
+            return Err(Error::BadAbi(format!("Duplicate identifier: {dup}")));
+        }
+
+        Ok(())
+    }
+
+    /// Enforce restrictions to guarantee ABI sanity
+    ///
+    ///   1. ABI must be identical in 32 and 64 bits.
+    ///   2. For every type, alignment must match size.
+    ///   3. Structs must have no implicit padding, not even at the tail.
+    ///   4. All type names are distinct.
+    fn is_valid(&self) -> Result<(), Error> {
+        info!("Validating specification");
+
+        self.has_unique_names()?;
+        for def in &self.0 {
+            for s in &def.structs {
+                debug!("Validating struct {}", s.name);
+                Typ::Struct(s.name.to_string()).abi_compatible(self)?;
+            }
+        }
+
+        Ok(())
+    }
+
+    /// Duplicates a specification; Leaves out arch-specific definitions.
+    ///
+    /// This has the effect of deduplicating the fields used polymorphically
+    /// across arch-specific code (e.g: See `xen_arch_domainconfig` in the spec)
+    fn common(&self) -> Self {
+        let mut ret = Self::default();
+
+        for def in &self.0 {
+            if !def.name.starts_with("arch-") {
+                ret.0.push(def.clone());
+            }
+        }
+
+        ret
+    }
+
+    /// Duplicates a specification; Leaves out non-x86 architectures.
+    ///
+    /// This has the effect of deduplicating the fields used polymorphically
+    /// across arch-specific code (e.g: See `xen_arch_domainconfig` in the spec)
+    pub fn x86(&self) -> Self {
+        let mut ret = self.common();
+
+        if let Some(x) = self.0.iter().find(|x| x.name == "arch-x86") {
+            let mut def = x.clone();
+            def.name = String::from("arch");
+            ret.0.push(def);
+        }
+
+        ret
+    }
+
+    /// Duplicates a specification; Leaves out non-ARM architectures.
+    ///
+    /// This has the effect of deduplicating the fields used polymorphically
+    /// across arch-specific code (e.g: See `xen_arch_domainconfig` in the spec)
+    pub fn arm(&self) -> Spec {
+        let mut ret = self.common();
+
+        if let Some(x) = self.0.iter().find(|x| x.name == "arch-arm") {
+            let mut def = x.clone();
+            def.name = String::from("arch");
+            ret.0.push(def);
+        }
+
+        ret
+    }
+
+    /// Duplicates a specification; Leaves out non-PowerPC architectures.
+    ///
+    /// This has the effect of deduplicating the fields used polymorphically
+    /// across arch-specific code (e.g: See `xen_arch_domainconfig` in the spec)
+    pub fn ppc(&self) -> Spec {
+        let mut ret = self.common();
+
+        if let Some(x) = self.0.iter().find(|x| x.name == "arch-ppc") {
+            let mut def = x.clone();
+            def.name = String::from("arch");
+            ret.0.push(def);
+        }
+
+        ret
+    }
+
+    /// Duplicates a specification; Leaves out non-RiscV architectures.
+    ///
+    /// This has the effect of deduplicating the fields used polymorphically
+    /// across arch-specific code (e.g: See `xen_arch_domainconfig` in the spec)
+    pub fn riscv(&self) -> Spec {
+        let mut ret = self.common();
+
+        if let Some(x) = self.0.iter().find(|x| x.name == "arch-riscv") {
+            let mut def = x.clone();
+            def.name = String::from("arch");
+            ret.0.push(def);
+        }
+
+        ret
+    }
+
+    /// Find a struct with a particular name within a [`Spec`] definition.
+    ///
+    /// Assumes a flat namespace, so there are no two types with the same
+    /// name. This is ensured with [`Spec::has_unique_names`].
+    pub fn find_struct(&self, name: &str) -> Result<&StructDef, Error> {
+        debug!("Looking up struct {name}");
+
+        for filedef in &self.0 {
+            for s in &filedef.structs {
+                if s.name == name {
+                    return Ok(s);
+                }
+            }
+        }
+
+        Err(Error::MissingDefinition(format!("missing struct {name}")))
+    }
+
+    /// Find an enum with a particular name within a [`Spec`] definition.
+    ///
+    /// Assumes a flat namespace, so there are no two types with the same
+    /// name. This is ensured with [`Spec::has_unique_names`].
+    pub fn find_enum(&self, name: &str) -> Result<&EnumDef, Error> {
+        debug!("Looking up enum {name}");
+
+        for filedef in &self.0 {
+            for s in &filedef.enums {
+                if s.name == name {
+                    return Ok(s);
+                }
+            }
+        }
+
+        Err(Error::MissingDefinition(format!("missing enum {name}")))
+    }
+
+    /// Find a bitmap with a particular name within a [`Spec`] definition.
+    ///
+    /// Assumes a flat namespace, so there are no two types with the same
+    /// name. This is ensured with [`Spec::has_unique_names`].
+    pub fn find_bitmap(&self, name: &str) -> Result<&BitmapDef, Error> {
+        debug!("Looking up bitmap {name}");
+
+        for filedef in &self.0 {
+            for s in &filedef.bitmaps {
+                if s.name == name {
+                    return Ok(s);
+                }
+            }
+        }
+
+        Err(Error::MissingDefinition(format!("missing enum {name}")))
+    }
 }
-- 
2.47.0



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

* [RFC PATCH 12/25] xen: Replace sysctl/readconsole with autogenerated version
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
                   ` (10 preceding siblings ...)
  2024-11-15 11:51 ` [RFC PATCH 11/25] tools/xenbindgen: Validate ABI rules at generation time Alejandro Vallejo
@ 2024-11-15 11:51 ` Alejandro Vallejo
  2024-11-25 12:05   ` Jan Beulich
  2024-11-15 11:51 ` [RFC PATCH 13/25] xen: Replace hand-crafted altp2m_mode descriptions with autogenerated ones Alejandro Vallejo
                   ` (13 subsequent siblings)
  25 siblings, 1 reply; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel
  Cc: Alejandro Vallejo, Anthony PERARD, Samuel Thibault, Andrew Cooper,
	Jan Beulich, Julien Grall, Stefano Stabellini, Daniel P. Smith

Describe sysctl/readconsole as a TOML specification, remove old
hand-coded version and replace it with autogenerated file.

While at it, transform the console driver to use uint8_t rather than
char in order to mandate the type to be unsigned and ensure the ABI is
not defined with regards to C-specific types.

Also grant stubdom access to the new autogen folder, or it won't build.

Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
 stubdom/Makefile                              |  2 +-
 tools/rust/Makefile                           | 19 ++++++++
 .../xenbindgen/extra/sysctl/readconsole.toml  | 43 +++++++++++++++++++
 xen/drivers/char/console.c                    | 12 +++---
 xen/include/public/autogen/sysctl.h           | 35 +++++++++++++++
 xen/include/public/sysctl.h                   | 23 +---------
 xen/include/public/xen.h                      |  1 +
 7 files changed, 108 insertions(+), 27 deletions(-)
 create mode 100644 tools/rust/xenbindgen/extra/sysctl/readconsole.toml
 create mode 100644 xen/include/public/autogen/sysctl.h

diff --git a/stubdom/Makefile b/stubdom/Makefile
index 2a81af28a16e..5e919889836b 100644
--- a/stubdom/Makefile
+++ b/stubdom/Makefile
@@ -362,7 +362,7 @@ LINK_STAMPS := $(foreach dir,$(LINK_DIRS),$(dir)/stamp)
 mk-headers-$(XEN_TARGET_ARCH): $(IOEMU_LINKFARM_TARGET) $(LINK_STAMPS)
 	mkdir -p include/xen && \
           ln -sf $(wildcard $(XEN_ROOT)/xen/include/public/*.h) include/xen && \
-          ln -sf $(addprefix $(XEN_ROOT)/xen/include/public/,arch-x86 hvm io xsm) include/xen && \
+          ln -sf $(addprefix $(XEN_ROOT)/xen/include/public/,arch-x86 autogen hvm io xsm) include/xen && \
           ( [ -h include/xen/sys ] || ln -sf $(XEN_ROOT)/tools/include/xen-sys/MiniOS include/xen/sys ) && \
           ( [ -h include/xen/libelf ] || ln -sf $(XEN_ROOT)/tools/include/xen/libelf include/xen/libelf ) && \
 	  mkdir -p include/xen-foreign && \
diff --git a/tools/rust/Makefile b/tools/rust/Makefile
index f5db0a9c5e81..80e2f0e2817e 100644
--- a/tools/rust/Makefile
+++ b/tools/rust/Makefile
@@ -3,6 +3,11 @@ XEN_ROOT=$(CURDIR)/../..
 # Path to the Xen hypercall IDL parser
 XENBINDGEN=$(CURDIR)/xenbindgen
 
+# Output folder for the autogenerated C headers
+#
+# Must contain autogenerated files only because they're all wiped on update
+AUTOGEN_C=$(XEN_ROOT)/xen/include/public/autogen/
+
 # Clippy settings for all Rust projects
 CLIPPY_ARGS=-D warnings \
             -D missing_docs \
@@ -14,6 +19,20 @@ CLIPPY_ARGS=-D warnings \
 .PHONY: all install uninstall clean
 all install uninstall clean:
 
+# Remove all autogenerated files
+.PHONY: clean-autogen
+clean-autogen:
+	rm -rf "${AUTOGEN_C}"
+
+# Refresh autogenerated files. Depending on clean-autogen is required in order
+# for removals of specification files to cause the removal of their
+# autogenerated files.
+.PHONY: update
+update: clean-autogen
+	# Update C bindings
+	cargo run --manifest-path "${XENBINDGEN}/Cargo.toml" -- --lang c \
+	          --indir "${XENBINDGEN}/extra" --outdir "${AUTOGEN_C}"
+
 # Verify Rust crates pass lint checks. This is enforced in CI
 .PHONY: verify
 verify:
diff --git a/tools/rust/xenbindgen/extra/sysctl/readconsole.toml b/tools/rust/xenbindgen/extra/sysctl/readconsole.toml
new file mode 100644
index 000000000000..868743a453ff
--- /dev/null
+++ b/tools/rust/xenbindgen/extra/sysctl/readconsole.toml
@@ -0,0 +1,43 @@
+[[structs]]
+name = "xen_sysctl_readconsole"
+description = "Read console content from Xen buffer ring."
+
+[[structs.fields]]
+name = "clear"
+description = "IN: Non-zero -> clear after reading."
+typ = { tag = "u8" }
+
+[[structs.fields]]
+name = "incremental"
+description = "IN: Non-zero -> start index specified by `index` field."
+typ = { tag = "u8" }
+
+[[structs.fields]]
+name = "_pad"
+description = "Unused."
+typ = { tag = "u16" }
+
+[[structs.fields]]
+name = "index"
+description = """
+IN:  Start index for consuming from ring buffer (if @incremental);
+OUT: End index after consuming from ring buffer."""
+typ = { tag = "u32" }
+
+[[structs.fields]]
+name = "buffer"
+description = """
+IN: Virtual address to write console data.
+
+NOTE: The pointer itself is IN, but the contents of the buffer are OUT."""
+typ = { tag = "ptr", args = { tag = "u8" } }
+
+[[structs.fields]]
+name = "count"
+description = "IN: Size of buffer; OUT: Bytes written to buffer."
+typ = { tag = "u32" }
+
+[[structs.fields]]
+name = "rsvd0_a"
+description = "Tail padding reserved to zero."
+typ = { tag = "u32" }
diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c
index 7da8c5296f3b..82f6ad7b32cb 100644
--- a/xen/drivers/char/console.c
+++ b/xen/drivers/char/console.c
@@ -42,6 +42,8 @@
 #include <asm/vpl011.h>
 #endif
 
+#include <public/xen.h>
+
 /* console: comma-separated list of console outputs. */
 static char __initdata opt_console[30] = OPT_CONSOLE_STR;
 string_param("console", opt_console);
@@ -108,8 +110,8 @@ size_param("conring_size", opt_conring_size);
 
 #define _CONRING_SIZE 16384
 #define CONRING_IDX_MASK(i) ((i)&(conring_size-1))
-static char __initdata _conring[_CONRING_SIZE];
-static char *__read_mostly conring = _conring;
+static uint8_t __initdata _conring[_CONRING_SIZE];
+static uint8_t *__read_mostly conring = _conring;
 static uint32_t __read_mostly conring_size = _CONRING_SIZE;
 static uint32_t conringc, conringp;
 
@@ -339,10 +341,10 @@ static void conring_puts(const char *str, size_t len)
 
 long read_console_ring(struct xen_sysctl_readconsole *op)
 {
-    XEN_GUEST_HANDLE_PARAM(char) str;
+    XEN_GUEST_HANDLE_PARAM(uint8_t) str;
     uint32_t idx, len, max, sofar, c, p;
 
-    str   = guest_handle_cast(op->buffer, char),
+    str   = guest_handle_cast(op->buffer, uint8_t),
     max   = op->count;
     sofar = 0;
 
@@ -1052,7 +1054,7 @@ void __init console_init_preirq(void)
 
 void __init console_init_ring(void)
 {
-    char *ring;
+    uint8_t *ring;
     unsigned int i, order, memflags;
     unsigned long flags;
 
diff --git a/xen/include/public/autogen/sysctl.h b/xen/include/public/autogen/sysctl.h
new file mode 100644
index 000000000000..f728b13374d3
--- /dev/null
+++ b/xen/include/public/autogen/sysctl.h
@@ -0,0 +1,35 @@
+/*
+ * sysctl
+ *
+ * AUTOGENERATED. DO NOT MODIFY
+ */
+#ifndef __XEN_AUTOGEN_SYSCTL_H
+#define __XEN_AUTOGEN_SYSCTL_H
+
+/* Read console content from Xen buffer ring. */
+struct xen_sysctl_readconsole {
+    /* IN: Non-zero -> clear after reading. */
+    uint8_t clear;
+    /* IN: Non-zero -> start index specified by `index` field. */
+    uint8_t incremental;
+    /* Unused. */
+    uint16_t _pad;
+    /*
+     * IN:  Start index for consuming from ring buffer (if @incremental);
+     * OUT: End index after consuming from ring buffer.
+     */
+    uint32_t index;
+    /*
+     * IN: Virtual address to write console data.
+     *
+     * NOTE: The pointer itself is IN, but the contents of the buffer are OUT.
+     */
+    XEN_GUEST_HANDLE_64(uint8) buffer;
+    /* IN: Size of buffer; OUT: Bytes written to buffer. */
+    uint32_t count;
+    /* Tail padding reserved to zero. */
+    uint32_t rsvd0_a;
+};
+
+#endif /* __XEN_AUTOGEN_SYSCTL_H */
+
diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h
index b0fec271d36f..9e773490a5ac 100644
--- a/xen/include/public/sysctl.h
+++ b/xen/include/public/sysctl.h
@@ -18,6 +18,8 @@
 #include "domctl.h"
 #include "physdev.h"
 
+#include "autogen/sysctl.h"
+
 /*
  * The interface version needs to be incremented by 1 in case the interface
  * is modified in an incompatible way AND if the version hasn't been
@@ -30,27 +32,6 @@
  */
 #define XEN_SYSCTL_INTERFACE_VERSION 0x00000015
 
-/*
- * Read console content from Xen buffer ring.
- */
-/* XEN_SYSCTL_readconsole */
-struct xen_sysctl_readconsole {
-    /* IN: Non-zero -> clear after reading. */
-    uint8_t clear;
-    /* IN: Non-zero -> start index specified by @index field. */
-    uint8_t incremental;
-    uint8_t pad0, pad1;
-    /*
-     * IN:  Start index for consuming from ring buffer (if @incremental);
-     * OUT: End index after consuming from ring buffer.
-     */
-    uint32_t index;
-    /* IN: Virtual address to write console data. */
-    XEN_GUEST_HANDLE_64(char) buffer;
-    /* IN: Size of buffer; OUT: Bytes written to buffer. */
-    uint32_t count;
-};
-
 /* Get trace buffers machine base address */
 /* XEN_SYSCTL_tbuf_op */
 struct xen_sysctl_tbuf_op {
diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h
index e051f989a5ca..cc5133fc19b8 100644
--- a/xen/include/public/xen.h
+++ b/xen/include/public/xen.h
@@ -36,6 +36,7 @@ __DEFINE_XEN_GUEST_HANDLE(ulong, unsigned long);
 #endif
 DEFINE_XEN_GUEST_HANDLE(void);
 
+DEFINE_XEN_GUEST_HANDLE(uint8_t);
 DEFINE_XEN_GUEST_HANDLE(uint64_t);
 DEFINE_XEN_GUEST_HANDLE(xen_pfn_t);
 DEFINE_XEN_GUEST_HANDLE(xen_ulong_t);
-- 
2.47.0



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

* [RFC PATCH 13/25] xen: Replace hand-crafted altp2m_mode descriptions with autogenerated ones
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
                   ` (11 preceding siblings ...)
  2024-11-15 11:51 ` [RFC PATCH 12/25] xen: Replace sysctl/readconsole with autogenerated version Alejandro Vallejo
@ 2024-11-15 11:51 ` Alejandro Vallejo
  2024-11-15 11:51 ` [RFC PATCH 14/25] xen: Replace common bitmaps in domctl.createdomain with autogenerated versions Alejandro Vallejo
                   ` (12 subsequent siblings)
  25 siblings, 0 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel
  Cc: Alejandro Vallejo, Anthony PERARD, Juergen Gross, Andrew Cooper,
	Jan Beulich, Julien Grall, Stefano Stabellini,
	Roger Pau Monné, Daniel P. Smith

Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
 tools/libs/light/libxl_create.c               |  8 +++----
 .../xenbindgen/extra/domctl/createdomain.toml | 24 +++++++++++++++++++
 xen/arch/x86/hvm/hvm.c                        |  8 +++----
 xen/include/public/autogen/domctl.h           | 22 +++++++++++++++++
 xen/include/public/domctl.h                   | 18 +++-----------
 5 files changed, 57 insertions(+), 23 deletions(-)
 create mode 100644 tools/rust/xenbindgen/extra/domctl/createdomain.toml
 create mode 100644 xen/include/public/autogen/domctl.h

diff --git a/tools/libs/light/libxl_create.c b/tools/libs/light/libxl_create.c
index 3ae922e8931b..791b0fac0601 100644
--- a/tools/libs/light/libxl_create.c
+++ b/tools/libs/light/libxl_create.c
@@ -676,19 +676,19 @@ int libxl__domain_make(libxl__gc *gc, libxl_domain_config *d_config,
         LOG(DETAIL, "altp2m: %s", libxl_altp2m_mode_to_string(b_info->altp2m));
         switch(b_info->altp2m) {
         case LIBXL_ALTP2M_MODE_MIXED:
-            create.altp2m_mode = XEN_DOMCTL_ALTP2M_mixed;
+            create.altp2m_mode = XEN_DOMCTL_ALTP2M_MODE_MIXED;
             break;
 
         case LIBXL_ALTP2M_MODE_EXTERNAL:
-            create.altp2m_mode = XEN_DOMCTL_ALTP2M_external;
+            create.altp2m_mode = XEN_DOMCTL_ALTP2M_MODE_EXTERNAL;
             break;
 
         case LIBXL_ALTP2M_MODE_LIMITED:
-            create.altp2m_mode = XEN_DOMCTL_ALTP2M_limited;
+            create.altp2m_mode = XEN_DOMCTL_ALTP2M_MODE_LIMITED;
             break;
 
         case LIBXL_ALTP2M_MODE_DISABLED:
-            create.altp2m_mode = XEN_DOMCTL_ALTP2M_disabled;
+            create.altp2m_mode = XEN_DOMCTL_ALTP2M_MODE_DISABLED;
             break;
         }
 
diff --git a/tools/rust/xenbindgen/extra/domctl/createdomain.toml b/tools/rust/xenbindgen/extra/domctl/createdomain.toml
new file mode 100644
index 000000000000..097dc202f352
--- /dev/null
+++ b/tools/rust/xenbindgen/extra/domctl/createdomain.toml
@@ -0,0 +1,24 @@
+[[enums]]
+name = "xen_domctl_altp2m_mode"
+description = "Content of the `altp2m_mode` field of the domain creation hypercall."
+typ = { tag = "u8" }
+
+[[enums.variants]]
+name = "disabled"
+description = "Keep altp2m disabled"
+value = 0
+
+[[enums.variants]]
+name = "mixed"
+description = "Use mixed-mode for the altp2m (not yet evaluated for safety)."
+value = 1
+
+[[enums.variants]]
+name = "external"
+description = "Use external mode for the altp2m."
+value = 2
+
+[[enums.variants]]
+name = "limited"
+description = "Use limited mode for the altp2m."
+value = 3
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index e30c3026479e..35caf6131190 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -661,19 +661,19 @@ int hvm_domain_initialise(struct domain *d,
     /* Set altp2m based on domctl flags. */
     switch ( config->altp2m_mode )
     {
-    case XEN_DOMCTL_ALTP2M_mixed:
+    case XEN_DOMCTL_ALTP2M_MODE_MIXED:
         d->arch.hvm.params[HVM_PARAM_ALTP2M] = XEN_ALTP2M_mixed;
         break;
 
-    case XEN_DOMCTL_ALTP2M_external:
+    case XEN_DOMCTL_ALTP2M_MODE_EXTERNAL:
         d->arch.hvm.params[HVM_PARAM_ALTP2M] = XEN_ALTP2M_external;
         break;
 
-    case XEN_DOMCTL_ALTP2M_limited:
+    case XEN_DOMCTL_ALTP2M_MODE_LIMITED:
         d->arch.hvm.params[HVM_PARAM_ALTP2M] = XEN_ALTP2M_limited;
         break;
 
-    case XEN_DOMCTL_ALTP2M_disabled:
+    case XEN_DOMCTL_ALTP2M_MODE_DISABLED:
         d->arch.hvm.params[HVM_PARAM_ALTP2M] = XEN_ALTP2M_disabled;
         break;
     }
diff --git a/xen/include/public/autogen/domctl.h b/xen/include/public/autogen/domctl.h
new file mode 100644
index 000000000000..00202f5e65b9
--- /dev/null
+++ b/xen/include/public/autogen/domctl.h
@@ -0,0 +1,22 @@
+/*
+ * domctl
+ *
+ * AUTOGENERATED. DO NOT MODIFY
+ */
+#ifndef __XEN_AUTOGEN_DOMCTL_H
+#define __XEN_AUTOGEN_DOMCTL_H
+
+/* Content of the `altp2m_mode` field of the domain creation hypercall. */
+enum xen_domctl_altp2m_mode {
+    /* Keep altp2m disabled */
+    XEN_DOMCTL_ALTP2M_MODE_DISABLED = 0,
+    /* Use mixed-mode for the altp2m (not yet evaluated for safety). */
+    XEN_DOMCTL_ALTP2M_MODE_MIXED = 1,
+    /* Use external mode for the altp2m. */
+    XEN_DOMCTL_ALTP2M_MODE_EXTERNAL = 2,
+    /* Use limited mode for the altp2m. */
+    XEN_DOMCTL_ALTP2M_MODE_LIMITED = 3,
+};
+
+#endif /* __XEN_AUTOGEN_DOMCTL_H */
+
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index 95a3b6769f7f..95d62c859302 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -21,6 +21,8 @@
 #include "hvm/save.h"
 #include "memory.h"
 
+#include "autogen/domctl.h"
+
 /*
  * The interface version needs to be incremented by 1 in case the interface
  * is modified in an incompatible way AND if the version hasn't been
@@ -103,21 +105,7 @@ struct xen_domctl_createdomain {
     /* Unused. Reserved to zero. */
     uint8_t rsvd0_a[3];
 
-/* Keep altp2m disabled */
-#define XEN_DOMCTL_ALTP2M_disabled   (0U)
-/*
- * Enable altp2m mixed mode.
- *
- * Note that 'mixed' mode has not been evaluated for safety from a security
- * perspective.  Before using this mode in a security-critical environment,
- * each subop should be evaluated for safety, with unsafe subops blacklisted in
- * XSM.
- */
-#define XEN_DOMCTL_ALTP2M_mixed      (1U)
-/* Enable altp2m external mode. */
-#define XEN_DOMCTL_ALTP2M_external   (2U)
-/* Enable altp2m limited mode. */
-#define XEN_DOMCTL_ALTP2M_limited    (3U)
+    /* See xen_domctl_altp2m_mode */
     uint8_t altp2m_mode;
 
     /* Unused. Reserved to zero. */
-- 
2.47.0



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

* [RFC PATCH 14/25] xen: Replace common bitmaps in domctl.createdomain with autogenerated versions
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
                   ` (12 preceding siblings ...)
  2024-11-15 11:51 ` [RFC PATCH 13/25] xen: Replace hand-crafted altp2m_mode descriptions with autogenerated ones Alejandro Vallejo
@ 2024-11-15 11:51 ` Alejandro Vallejo
  2024-11-15 11:51 ` [RFC PATCH 15/25] xen/arm: Replace hand-crafted xen_arch_domainconfig with autogenerated one Alejandro Vallejo
                   ` (11 subsequent siblings)
  25 siblings, 0 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel
  Cc: Alejandro Vallejo, Juergen Gross, Julien Grall, Anthony PERARD,
	Andrew Cooper, Jan Beulich, Stefano Stabellini, Christian Lindig,
	David Scott, Marek Marczykowski-Górecki, Bertrand Marquis,
	Michal Orzel, Volodymyr Babchuk, Roger Pau Monné, Tim Deegan,
	Lukasz Hawrylko, Daniel P. Smith, Mateusz Mówka

Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
 tools/helpers/init-xenstore-domain.c          |  4 +-
 tools/libs/light/libxl_create.c               | 14 ++---
 tools/ocaml/libs/xc/xenctrl.ml                |  4 +-
 tools/ocaml/libs/xc/xenctrl.mli               |  4 +-
 tools/ocaml/libs/xc/xenctrl_stubs.c           |  8 +--
 tools/python/xen/lowlevel/xc/xc.c             |  4 +-
 .../xenbindgen/extra/domctl/createdomain.toml | 59 +++++++++++++++++++
 .../paging-mempool/test-paging-mempool.c      |  2 +-
 tools/tests/resource/test-resource.c          |  8 +--
 tools/tests/tsx/test-tsx.c                    |  4 +-
 xen/arch/arm/dom0less-build.c                 |  4 +-
 xen/arch/arm/domain.c                         |  6 +-
 xen/arch/arm/domain_build.c                   |  4 +-
 xen/arch/x86/domain.c                         | 12 ++--
 xen/arch/x86/include/asm/hvm/nestedhvm.h      |  2 +-
 xen/arch/x86/mm/shadow/common.c               |  4 +-
 xen/arch/x86/setup.c                          |  8 +--
 xen/arch/x86/tboot.c                          |  2 +-
 xen/common/domain.c                           | 18 +++---
 xen/drivers/passthrough/iommu.c               |  4 +-
 xen/include/public/autogen/domctl.h           | 28 +++++++++
 xen/include/public/domctl.h                   | 34 +----------
 xen/include/xen/sched.h                       | 10 ++--
 23 files changed, 152 insertions(+), 95 deletions(-)

diff --git a/tools/helpers/init-xenstore-domain.c b/tools/helpers/init-xenstore-domain.c
index a9f2f9859df6..315aa8b8aec9 100644
--- a/tools/helpers/init-xenstore-domain.c
+++ b/tools/helpers/init-xenstore-domain.c
@@ -84,7 +84,7 @@ static int build(xc_interface *xch)
     struct e820entry e820[3];
     struct xen_domctl_createdomain config = {
         .ssidref = SECINITSID_DOMU,
-        .flags = XEN_DOMCTL_CDF_xs_domain,
+        .flags = XEN_DOMCTL_CDF_XS_DOMAIN,
         .max_vcpus = 1,
         .max_evtchn_port = -1, /* No limit. */
 
@@ -176,7 +176,7 @@ static int build(xc_interface *xch)
 
     if ( dom->container_type == XC_DOM_HVM_CONTAINER )
     {
-        config.flags |= XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap;
+        config.flags |= XEN_DOMCTL_CDF_HVM | XEN_DOMCTL_CDF_HAP;
         config.arch.emulation_flags = XEN_X86_EMU_LAPIC;
         dom->target_pages = mem_size >> XC_PAGE_SHIFT;
         dom->mmio_size = GB(4) - LAPIC_BASE_ADDRESS;
diff --git a/tools/libs/light/libxl_create.c b/tools/libs/light/libxl_create.c
index 791b0fac0601..042d01191528 100644
--- a/tools/libs/light/libxl_create.c
+++ b/tools/libs/light/libxl_create.c
@@ -648,30 +648,30 @@ int libxl__domain_make(libxl__gc *gc, libxl_domain_config *d_config,
         };
 
         if (info->type != LIBXL_DOMAIN_TYPE_PV) {
-            create.flags |= XEN_DOMCTL_CDF_hvm;
+            create.flags |= XEN_DOMCTL_CDF_HVM;
 
             if ( libxl_defbool_val(info->hap) )
-                create.flags |= XEN_DOMCTL_CDF_hap;
+                create.flags |= XEN_DOMCTL_CDF_HAP;
 
             if ( !libxl_defbool_val(info->oos) )
-                create.flags |= XEN_DOMCTL_CDF_oos_off;
+                create.flags |= XEN_DOMCTL_CDF_OOS_OFF;
 
             if ( libxl_defbool_val(b_info->nested_hvm) )
-                create.flags |= XEN_DOMCTL_CDF_nested_virt;
+                create.flags |= XEN_DOMCTL_CDF_NESTED_VIRT;
         }
 
         if (libxl_defbool_val(b_info->vpmu))
-            create.flags |= XEN_DOMCTL_CDF_vpmu;
+            create.flags |= XEN_DOMCTL_CDF_VPMU;
 
         assert(info->passthrough != LIBXL_PASSTHROUGH_DEFAULT);
         LOG(DETAIL, "passthrough: %s",
             libxl_passthrough_to_string(info->passthrough));
 
         if (info->passthrough != LIBXL_PASSTHROUGH_DISABLED)
-            create.flags |= XEN_DOMCTL_CDF_iommu;
+            create.flags |= XEN_DOMCTL_CDF_IOMMU;
 
         if (info->passthrough == LIBXL_PASSTHROUGH_SYNC_PT)
-            create.iommu_opts |= XEN_DOMCTL_IOMMU_no_sharept;
+            create.iommu_opts |= XEN_DOMCTL_IOMMU_OPTS_NO_SHAREPT;
 
         LOG(DETAIL, "altp2m: %s", libxl_altp2m_mode_to_string(b_info->altp2m));
         switch(b_info->altp2m) {
diff --git a/tools/ocaml/libs/xc/xenctrl.ml b/tools/ocaml/libs/xc/xenctrl.ml
index 3c4c95d48319..17c2228704f2 100644
--- a/tools/ocaml/libs/xc/xenctrl.ml
+++ b/tools/ocaml/libs/xc/xenctrl.ml
@@ -49,7 +49,7 @@ type x86_arch_emulation_flags =
   | X86_EMU_VPCI
 
 type x86_arch_misc_flags =
-  | X86_MSR_RELAXED
+  | X86_MISC_MSR_RELAXED
 
 type xen_x86_arch_domainconfig =
   {
@@ -72,7 +72,7 @@ type domain_create_flag =
   | CDF_VPMU
 
 type domain_create_iommu_opts =
-  | IOMMU_NO_SHAREPT
+  | IOMMU_OPTS_NO_SHAREPT
 
 type domctl_create_config =
   {
diff --git a/tools/ocaml/libs/xc/xenctrl.mli b/tools/ocaml/libs/xc/xenctrl.mli
index 74919a14bec4..0d351ec2e557 100644
--- a/tools/ocaml/libs/xc/xenctrl.mli
+++ b/tools/ocaml/libs/xc/xenctrl.mli
@@ -43,7 +43,7 @@ type x86_arch_emulation_flags =
   | X86_EMU_VPCI
 
 type x86_arch_misc_flags =
-  | X86_MSR_RELAXED
+  | X86_MISC_MSR_RELAXED
 
 type xen_x86_arch_domainconfig = {
   emulation_flags: x86_arch_emulation_flags list;
@@ -65,7 +65,7 @@ type domain_create_flag =
   | CDF_VPMU
 
 type domain_create_iommu_opts =
-  | IOMMU_NO_SHAREPT
+  | IOMMU_OPTS_NO_SHAREPT
 
 type domctl_create_config = {
   ssidref: int32;
diff --git a/tools/ocaml/libs/xc/xenctrl_stubs.c b/tools/ocaml/libs/xc/xenctrl_stubs.c
index b701f45daa8d..1f2cf41a9cc7 100644
--- a/tools/ocaml/libs/xc/xenctrl_stubs.c
+++ b/tools/ocaml/libs/xc/xenctrl_stubs.c
@@ -232,13 +232,13 @@ CAMLprim value stub_xc_domain_create(value xch_val, value wanted_domid, value co
 	domain_handle_of_uuid_string(cfg.handle, String_val(VAL_HANDLE));
 
 	cfg.flags = ocaml_list_to_c_bitmap
-		/* ! domain_create_flag CDF_ lc */
-		/* ! XEN_DOMCTL_CDF_ XEN_DOMCTL_CDF_MAX max */
+		/* ! domain_create_flag CDF_ none */
+		/* ! XEN_DOMCTL_CDF_ XEN_DOMCTL_CDF__ALL all */
 		(VAL_FLAGS);
 
 	cfg.iommu_opts = ocaml_list_to_c_bitmap
-		/* ! domain_create_iommu_opts IOMMU_ lc */
-		/* ! XEN_DOMCTL_IOMMU_ XEN_DOMCTL_IOMMU_MAX max */
+		/* ! domain_create_iommu_opts IOMMU_ none */
+		/* ! XEN_DOMCTL_IOMMU_ XEN_DOMCTL_IOMMU_OPTS__ALL all */
 		(VAL_IOMMU_OPTS);
 
 	arch_domconfig = Field(VAL_ARCH, 0);
diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c
index ba6a61217f9f..d98f18ccc87a 100644
--- a/tools/python/xen/lowlevel/xc/xc.c
+++ b/tools/python/xen/lowlevel/xc/xc.c
@@ -158,8 +158,8 @@ static PyObject *pyxc_domain_create(XcObject *self,
     }
 
 #if defined (__i386) || defined(__x86_64__)
-    if ( config.flags & XEN_DOMCTL_CDF_hvm )
-        config.arch.emulation_flags = XEN_X86_EMU_ALL &
+    if ( config.flags & XEN_DOMCTL_CDF_HVM )
+        config.arch.emulation_flags = XEN_X86_EMU__ALL &
                                       ~(XEN_X86_EMU_VPCI |
                                         XEN_X86_EMU_USE_PIRQ);
 #elif defined (__arm__) || defined(__aarch64__)
diff --git a/tools/rust/xenbindgen/extra/domctl/createdomain.toml b/tools/rust/xenbindgen/extra/domctl/createdomain.toml
index 097dc202f352..02f65d134b55 100644
--- a/tools/rust/xenbindgen/extra/domctl/createdomain.toml
+++ b/tools/rust/xenbindgen/extra/domctl/createdomain.toml
@@ -22,3 +22,62 @@ value = 2
 name = "limited"
 description = "Use limited mode for the altp2m."
 value = 3
+
+################################################################################
+
+[[bitmaps]]
+name = "xen_domctl_cdf"
+description = "Content of the `flags` field of the domain creation hypercall."
+typ = { tag = "u32" }
+
+[[bitmaps.bits]]
+name = "hvm"
+description = "Set if this is an HVM guest. Cleared if it's PV."
+shift = 0
+
+[[bitmaps.bits]]
+name = "hap"
+description = "Use hardware-assisted paging if available"
+shift = 1
+
+[[bitmaps.bits]]
+name = "s3_integrity"
+description = "Set if domain memory integrity is to be verified by tboot during Sx."
+shift = 2
+
+[[bitmaps.bits]]
+name = "oos_off"
+description = "Set if Out-of-Sync shadow page tables are to be disabled"
+shift = 3
+
+[[bitmaps.bits]]
+name = "xs_domain"
+description = "Set if this is a xenstore domain"
+shift = 4
+
+[[bitmaps.bits]]
+name = "iommu"
+description = "Set if this is domain can make use of the IOMMU"
+shift = 5
+
+[[bitmaps.bits]]
+name = "nested_virt"
+description = "Set for the domain to have nested virtualization enabled."
+shift = 6
+
+[[bitmaps.bits]]
+name = "vpmu"
+description = "Set to expose a vPMU to this domain."
+shift = 7
+
+################################################################################
+
+[[bitmaps]]
+name = "xen_domctl_iommu_opts"
+description = "Content of the `iommu_opts` field of the domain creation hypercall."
+typ = { tag = "u32" }
+
+[[bitmaps.bits]]
+name = "no_sharept"
+description = "Set to _NOT_ share page tables between the CPU and the IOMMU when it would be possible to do so."
+shift = 0
diff --git a/tools/tests/paging-mempool/test-paging-mempool.c b/tools/tests/paging-mempool/test-paging-mempool.c
index 512c42803c0e..511c4a710e1f 100644
--- a/tools/tests/paging-mempool/test-paging-mempool.c
+++ b/tools/tests/paging-mempool/test-paging-mempool.c
@@ -21,7 +21,7 @@ static xc_interface *xch;
 static uint32_t domid;
 
 static struct xen_domctl_createdomain create = {
-    .flags = XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap,
+    .flags = XEN_DOMCTL_CDF_HVM | XEN_DOMCTL_CDF_HAP,
     .max_vcpus = 1,
     .max_grant_frames = 1,
     .max_grant_version = 1,
diff --git a/tools/tests/resource/test-resource.c b/tools/tests/resource/test-resource.c
index b0a9f5f1e8b6..f541044036d9 100644
--- a/tools/tests/resource/test-resource.c
+++ b/tools/tests/resource/test-resource.c
@@ -143,7 +143,7 @@ static void test_domain_configurations(void)
         {
             .name = "x86 PVH",
             .create = {
-                .flags = XEN_DOMCTL_CDF_hvm,
+                .flags = XEN_DOMCTL_CDF_HVM,
                 .max_vcpus = 2,
                 .max_grant_frames = 40,
                 .max_grant_version = 1,
@@ -156,7 +156,7 @@ static void test_domain_configurations(void)
         {
             .name = "ARM",
             .create = {
-                .flags = XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap,
+                .flags = XEN_DOMCTL_CDF_HVM | XEN_DOMCTL_CDF_HAP,
                 .max_vcpus = 2,
                 .max_grant_frames = 40,
                 .max_grant_version = 1,
@@ -175,7 +175,7 @@ static void test_domain_configurations(void)
         printf("Test %s\n", t->name);
 
 #if defined(__x86_64__) || defined(__i386__)
-        if ( t->create.flags & XEN_DOMCTL_CDF_hvm )
+        if ( t->create.flags & XEN_DOMCTL_CDF_HVM )
         {
             if ( !(physinfo.capabilities & XEN_SYSCTL_PHYSCAP_hvm) )
             {
@@ -188,7 +188,7 @@ static void test_domain_configurations(void)
              * SHADOW is available.
              */
             if ( physinfo.capabilities & XEN_SYSCTL_PHYSCAP_hap )
-                t->create.flags |= XEN_DOMCTL_CDF_hap;
+                t->create.flags |= XEN_DOMCTL_CDF_HAP;
             else if ( !(physinfo.capabilities & XEN_SYSCTL_PHYSCAP_shadow) )
             {
                 printf("  Skip: Neither HAP or SHADOW available\n");
diff --git a/tools/tests/tsx/test-tsx.c b/tools/tests/tsx/test-tsx.c
index 324bcf67153a..a3097515b280 100644
--- a/tools/tests/tsx/test-tsx.c
+++ b/tools/tests/tsx/test-tsx.c
@@ -467,7 +467,7 @@ static void test_guests(void)
     if ( xen_has_hvm )
     {
         struct xen_domctl_createdomain c = {
-            .flags = XEN_DOMCTL_CDF_hvm,
+            .flags = XEN_DOMCTL_CDF_HVM,
             .max_vcpus = 1,
             .max_grant_frames = 1,
             .max_grant_version = 1,
@@ -477,7 +477,7 @@ static void test_guests(void)
         };
 
         if ( physinfo.capabilities & XEN_SYSCTL_PHYSCAP_hap )
-            c.flags |= XEN_DOMCTL_CDF_hap;
+            c.flags |= XEN_DOMCTL_CDF_HAP;
         else if ( !(physinfo.capabilities & XEN_SYSCTL_PHYSCAP_shadow) )
             return fail("  HVM available, but neither HAP nor Shadow\n");
 
diff --git a/xen/arch/arm/dom0less-build.c b/xen/arch/arm/dom0less-build.c
index 1c6219c7cc82..cd8e59aa762a 100644
--- a/xen/arch/arm/dom0less-build.c
+++ b/xen/arch/arm/dom0less-build.c
@@ -867,7 +867,7 @@ void __init create_domUs(void)
         struct domain *d;
         struct xen_domctl_createdomain d_cfg = {
             .arch.gic_version = XEN_DOMCTL_CONFIG_GIC_NATIVE,
-            .flags = XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap,
+            .flags = XEN_DOMCTL_CDF_HVM | XEN_DOMCTL_CDF_HAP,
             /*
              * The default of 1023 should be sufficient for guests because
              * on ARM we don't bind physical interrupts to event channels.
@@ -912,7 +912,7 @@ void __init create_domUs(void)
         if ( iommu_enabled &&
              (iommu || dt_find_compatible_node(node, NULL,
                                                "multiboot,device-tree")) )
-            d_cfg.flags |= XEN_DOMCTL_CDF_iommu;
+            d_cfg.flags |= XEN_DOMCTL_CDF_IOMMU;
 
         if ( !dt_property_read_u32(node, "nr_spis", &d_cfg.arch.nr_spis) )
         {
diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index c6c5a0d1af23..54e849b02f9e 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -567,7 +567,7 @@ int arch_vcpu_create(struct vcpu *v)
     v->arch.hcr_el2 = get_default_hcr_flags();
 
     v->arch.mdcr_el2 = HDCR_TDRA | HDCR_TDOSA | HDCR_TDA;
-    if ( !(v->domain->options & XEN_DOMCTL_CDF_vpmu) )
+    if ( !(v->domain->options & XEN_DOMCTL_CDF_VPMU) )
         v->arch.mdcr_el2 |= HDCR_TPM | HDCR_TPMCR;
 
     if ( (rc = vcpu_vgic_init(v)) != 0 )
@@ -607,8 +607,8 @@ void vcpu_switch_to_aarch64_mode(struct vcpu *v)
 int arch_sanitise_domain_config(struct xen_domctl_createdomain *config)
 {
     unsigned int max_vcpus;
-    unsigned int flags_required = (XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap);
-    unsigned int flags_optional = (XEN_DOMCTL_CDF_iommu | XEN_DOMCTL_CDF_vpmu);
+    unsigned int flags_required = (XEN_DOMCTL_CDF_HVM | XEN_DOMCTL_CDF_HAP);
+    unsigned int flags_optional = (XEN_DOMCTL_CDF_IOMMU | XEN_DOMCTL_CDF_VPMU);
     unsigned int sve_vl_bits = sve_decode_vl(config->arch.sve_vl);
 
     if ( (config->flags & ~flags_optional) != flags_required )
diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 773412ba2acb..08b251617bae 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -2190,7 +2190,7 @@ void __init create_dom0(void)
 {
     struct domain *dom0;
     struct xen_domctl_createdomain dom0_cfg = {
-        .flags = XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap,
+        .flags = XEN_DOMCTL_CDF_HVM | XEN_DOMCTL_CDF_HAP,
         .max_evtchn_port = -1,
         .max_grant_frames = gnttab_dom0_frames(),
         .max_maptrack_frames = -1,
@@ -2211,7 +2211,7 @@ void __init create_dom0(void)
     dom0_cfg.max_vcpus = dom0_max_vcpus();
 
     if ( iommu_enabled )
-        dom0_cfg.flags |= XEN_DOMCTL_CDF_iommu;
+        dom0_cfg.flags |= XEN_DOMCTL_CDF_IOMMU;
 
     if ( opt_dom0_sve )
     {
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index 1ef095f349f7..63a52a8ae23d 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -633,9 +633,9 @@ void arch_vcpu_destroy(struct vcpu *v)
 
 int arch_sanitise_domain_config(struct xen_domctl_createdomain *config)
 {
-    bool hvm = config->flags & XEN_DOMCTL_CDF_hvm;
-    bool hap = config->flags & XEN_DOMCTL_CDF_hap;
-    bool nested_virt = config->flags & XEN_DOMCTL_CDF_nested_virt;
+    bool hvm = config->flags & XEN_DOMCTL_CDF_HVM;
+    bool hap = config->flags & XEN_DOMCTL_CDF_HAP;
+    bool nested_virt = config->flags & XEN_DOMCTL_CDF_NESTED_VIRT;
     unsigned int max_vcpus;
 
     if ( hvm ? !hvm_enabled : !IS_ENABLED(CONFIG_PV) )
@@ -654,7 +654,7 @@ int arch_sanitise_domain_config(struct xen_domctl_createdomain *config)
     }
 
     if ( !IS_ENABLED(CONFIG_TBOOT) &&
-         (config->flags & XEN_DOMCTL_CDF_s3_integrity) )
+         (config->flags & XEN_DOMCTL_CDF_S3_INTEGRITY) )
     {
         dprintk(XENLOG_INFO, "S3 integrity check not valid without CONFIG_TBOOT\n");
         return -EINVAL;
@@ -668,10 +668,10 @@ int arch_sanitise_domain_config(struct xen_domctl_createdomain *config)
 
     if ( !hvm )
         /*
-         * It is only meaningful for XEN_DOMCTL_CDF_oos_off to be clear
+         * It is only meaningful for XEN_DOMCTL_CDF_OOS_OFF to be clear
          * for HVM guests.
          */
-        config->flags |= XEN_DOMCTL_CDF_oos_off;
+        config->flags |= XEN_DOMCTL_CDF_OOS_OFF;
 
     if ( nested_virt && !hvm_nested_virt_supported() )
     {
diff --git a/xen/arch/x86/include/asm/hvm/nestedhvm.h b/xen/arch/x86/include/asm/hvm/nestedhvm.h
index ea2c1bc328c7..64e9e18a8cfd 100644
--- a/xen/arch/x86/include/asm/hvm/nestedhvm.h
+++ b/xen/arch/x86/include/asm/hvm/nestedhvm.h
@@ -25,7 +25,7 @@ enum nestedhvm_vmexits {
 /* Nested HVM on/off per domain */
 static inline bool nestedhvm_enabled(const struct domain *d)
 {
-    return IS_ENABLED(CONFIG_HVM) && (d->options & XEN_DOMCTL_CDF_nested_virt);
+    return IS_ENABLED(CONFIG_HVM) && (d->options & XEN_DOMCTL_CDF_NESTED_VIRT);
 }
 
 /* Nested VCPU */
diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c
index 0176e33bc9c7..f103f19e9220 100644
--- a/xen/arch/x86/mm/shadow/common.c
+++ b/xen/arch/x86/mm/shadow/common.c
@@ -2344,7 +2344,7 @@ static void sh_update_paging_modes(struct vcpu *v)
 #endif /* (SHADOW_OPTIMIZATIONS & SHOPT_VIRTUAL_TLB) */
 
 #if (SHADOW_OPTIMIZATIONS & SHOPT_OUT_OF_SYNC)
-    if ( !(d->options & XEN_DOMCTL_CDF_oos_off) &&
+    if ( !(d->options & XEN_DOMCTL_CDF_OOS_OFF) &&
          mfn_eq(v->arch.paging.shadow.oos_snapshot[0], INVALID_MFN) )
     {
         int i;
@@ -2491,7 +2491,7 @@ static void sh_update_paging_modes(struct vcpu *v)
 #if (SHADOW_OPTIMIZATIONS & SHOPT_OUT_OF_SYNC)
     /* We need to check that all the vcpus have paging enabled to
      * unsync PTs. */
-    if ( !(d->options & XEN_DOMCTL_CDF_oos_off) )
+    if ( !(d->options & XEN_DOMCTL_CDF_OOS_OFF) )
     {
         int pe = 1;
         struct vcpu *vptr;
diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c
index 0443555d9bb8..65ea3fc86beb 100644
--- a/xen/arch/x86/setup.c
+++ b/xen/arch/x86/setup.c
@@ -960,7 +960,7 @@ static struct domain *__init create_dom0(const module_t *image,
     static char __initdata cmdline[MAX_GUEST_CMDLINE];
 
     struct xen_domctl_createdomain dom0_cfg = {
-        .flags = IS_ENABLED(CONFIG_TBOOT) ? XEN_DOMCTL_CDF_s3_integrity : 0,
+        .flags = IS_ENABLED(CONFIG_TBOOT) ? XEN_DOMCTL_CDF_S3_INTEGRITY : 0,
         .max_evtchn_port = -1,
         .max_grant_frames = -1,
         .max_maptrack_frames = -1,
@@ -975,16 +975,16 @@ static struct domain *__init create_dom0(const module_t *image,
 
     if ( opt_dom0_pvh )
     {
-        dom0_cfg.flags |= (XEN_DOMCTL_CDF_hvm |
+        dom0_cfg.flags |= (XEN_DOMCTL_CDF_HVM |
                            ((hvm_hap_supported() && !opt_dom0_shadow) ?
-                            XEN_DOMCTL_CDF_hap : 0));
+                            XEN_DOMCTL_CDF_HAP : 0));
 
         dom0_cfg.arch.emulation_flags |=
             XEN_X86_EMU_LAPIC | XEN_X86_EMU_IOAPIC | XEN_X86_EMU_VPCI;
     }
 
     if ( iommu_enabled )
-        dom0_cfg.flags |= XEN_DOMCTL_CDF_iommu;
+        dom0_cfg.flags |= XEN_DOMCTL_CDF_IOMMU;
 
     /* Create initial domain.  Not d0 for pvshim. */
     domid = get_initial_domain_id();
diff --git a/xen/arch/x86/tboot.c b/xen/arch/x86/tboot.c
index d5db60d335e3..648a5269bb8a 100644
--- a/xen/arch/x86/tboot.c
+++ b/xen/arch/x86/tboot.c
@@ -203,7 +203,7 @@ static void tboot_gen_domain_integrity(const uint8_t key[TB_KEY_SIZE],
     vmac_set_key((uint8_t *)key, &ctx);
     for_each_domain( d )
     {
-        if ( !(d->options & XEN_DOMCTL_CDF_s3_integrity) )
+        if ( !(d->options & XEN_DOMCTL_CDF_S3_INTEGRITY) )
             continue;
         printk("MACing Domain %u\n", d->domain_id);
 
diff --git a/xen/common/domain.c b/xen/common/domain.c
index ad19ff1cef23..799f76bf042d 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -564,16 +564,16 @@ static void _domain_destroy(struct domain *d)
 
 static int sanitise_domain_config(struct xen_domctl_createdomain *config)
 {
-    bool hvm = config->flags & XEN_DOMCTL_CDF_hvm;
-    bool hap = config->flags & XEN_DOMCTL_CDF_hap;
-    bool iommu = config->flags & XEN_DOMCTL_CDF_iommu;
-    bool vpmu = config->flags & XEN_DOMCTL_CDF_vpmu;
+    bool hvm = config->flags & XEN_DOMCTL_CDF_HVM;
+    bool hap = config->flags & XEN_DOMCTL_CDF_HAP;
+    bool iommu = config->flags & XEN_DOMCTL_CDF_IOMMU;
+    bool vpmu = config->flags & XEN_DOMCTL_CDF_VPMU;
 
     if ( config->flags &
-         ~(XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap |
-           XEN_DOMCTL_CDF_s3_integrity | XEN_DOMCTL_CDF_oos_off |
-           XEN_DOMCTL_CDF_xs_domain | XEN_DOMCTL_CDF_iommu |
-           XEN_DOMCTL_CDF_nested_virt | XEN_DOMCTL_CDF_vpmu) )
+         ~(XEN_DOMCTL_CDF_HVM | XEN_DOMCTL_CDF_HAP |
+           XEN_DOMCTL_CDF_S3_INTEGRITY | XEN_DOMCTL_CDF_OOS_OFF |
+           XEN_DOMCTL_CDF_XS_DOMAIN | XEN_DOMCTL_CDF_IOMMU |
+           XEN_DOMCTL_CDF_NESTED_VIRT | XEN_DOMCTL_CDF_VPMU) )
     {
         dprintk(XENLOG_INFO, "Unknown CDF flags %#x\n", config->flags);
         return -EINVAL;
@@ -600,7 +600,7 @@ static int sanitise_domain_config(struct xen_domctl_createdomain *config)
 
     if ( iommu )
     {
-        if ( config->iommu_opts & ~XEN_DOMCTL_IOMMU_no_sharept )
+        if ( config->iommu_opts & ~XEN_DOMCTL_IOMMU_OPTS_NO_SHAREPT )
         {
             dprintk(XENLOG_INFO, "Unknown IOMMU options %#x\n",
                     config->iommu_opts);
diff --git a/xen/drivers/passthrough/iommu.c b/xen/drivers/passthrough/iommu.c
index 9e74a1fc72fa..1d133e56c0bb 100644
--- a/xen/drivers/passthrough/iommu.c
+++ b/xen/drivers/passthrough/iommu.c
@@ -224,7 +224,7 @@ int iommu_domain_init(struct domain *d, unsigned int opts)
      * be enabled.
      */
     hd->hap_pt_share = hap_enabled(d) && iommu_hap_pt_share &&
-        !(opts & XEN_DOMCTL_IOMMU_no_sharept);
+        !(opts & XEN_DOMCTL_IOMMU_OPTS_NO_SHAREPT);
 
     /*
      * NB: 'relaxed' h/w domains don't need the IOMMU mappings to be kept
@@ -542,7 +542,7 @@ int iommu_quarantine_dev_init(device_t *dev)
 
 static int __init iommu_quarantine_init(void)
 {
-    dom_io->options |= XEN_DOMCTL_CDF_iommu;
+    dom_io->options |= XEN_DOMCTL_CDF_IOMMU;
 
     return iommu_domain_init(dom_io, 0);
 }
diff --git a/xen/include/public/autogen/domctl.h b/xen/include/public/autogen/domctl.h
index 00202f5e65b9..bd1f4bedc727 100644
--- a/xen/include/public/autogen/domctl.h
+++ b/xen/include/public/autogen/domctl.h
@@ -18,5 +18,33 @@ enum xen_domctl_altp2m_mode {
     XEN_DOMCTL_ALTP2M_MODE_LIMITED = 3,
 };
 
+/* Content of the `flags` field of the domain creation hypercall. */
+struct xen_domctl_cdf {}; /* GREP FODDER */
+/* Set if this is an HVM guest. Cleared if it's PV. */
+#define XEN_DOMCTL_CDF_HVM (1U << 0)
+/* Use hardware-assisted paging if available */
+#define XEN_DOMCTL_CDF_HAP (1U << 1)
+/* Set if domain memory integrity is to be verified by tboot during Sx. */
+#define XEN_DOMCTL_CDF_S3_INTEGRITY (1U << 2)
+/* Set if Out-of-Sync shadow page tables are to be disabled */
+#define XEN_DOMCTL_CDF_OOS_OFF (1U << 3)
+/* Set if this is a xenstore domain */
+#define XEN_DOMCTL_CDF_XS_DOMAIN (1U << 4)
+/* Set if this is domain can make use of the IOMMU */
+#define XEN_DOMCTL_CDF_IOMMU (1U << 5)
+/* Set for the domain to have nested virtualization enabled. */
+#define XEN_DOMCTL_CDF_NESTED_VIRT (1U << 6)
+/* Set to expose a vPMU to this domain. */
+#define XEN_DOMCTL_CDF_VPMU (1U << 7)
+/* Mask covering all defined bits */
+#define XEN_DOMCTL_CDF__ALL (0xFFU)
+
+/* Content of the `iommu_opts` field of the domain creation hypercall. */
+struct xen_domctl_iommu_opts {}; /* GREP FODDER */
+/* Set to _NOT_ share page tables between the CPU and the IOMMU when it would be possible to do so. */
+#define XEN_DOMCTL_IOMMU_OPTS_NO_SHAREPT (1U << 0)
+/* Mask covering all defined bits */
+#define XEN_DOMCTL_IOMMU_OPTS__ALL (0x1U)
+
 #endif /* __XEN_AUTOGEN_DOMCTL_H */
 
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index 95d62c859302..2d1423f6fd91 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -45,40 +45,10 @@ struct xen_domctl_createdomain {
     /* IN parameters */
     uint32_t ssidref;
     xen_domain_handle_t handle;
- /* Is this an HVM guest (as opposed to a PV guest)? */
-#define _XEN_DOMCTL_CDF_hvm           0
-#define XEN_DOMCTL_CDF_hvm            (1U<<_XEN_DOMCTL_CDF_hvm)
- /* Use hardware-assisted paging if available? */
-#define _XEN_DOMCTL_CDF_hap           1
-#define XEN_DOMCTL_CDF_hap            (1U<<_XEN_DOMCTL_CDF_hap)
- /* Should domain memory integrity be verifed by tboot during Sx? */
-#define _XEN_DOMCTL_CDF_s3_integrity  2
-#define XEN_DOMCTL_CDF_s3_integrity   (1U<<_XEN_DOMCTL_CDF_s3_integrity)
- /* Disable out-of-sync shadow page tables? */
-#define _XEN_DOMCTL_CDF_oos_off       3
-#define XEN_DOMCTL_CDF_oos_off        (1U<<_XEN_DOMCTL_CDF_oos_off)
- /* Is this a xenstore domain? */
-#define _XEN_DOMCTL_CDF_xs_domain     4
-#define XEN_DOMCTL_CDF_xs_domain      (1U<<_XEN_DOMCTL_CDF_xs_domain)
- /* Should this domain be permitted to use the IOMMU? */
-#define _XEN_DOMCTL_CDF_iommu         5
-#define XEN_DOMCTL_CDF_iommu          (1U<<_XEN_DOMCTL_CDF_iommu)
-#define _XEN_DOMCTL_CDF_nested_virt   6
-#define XEN_DOMCTL_CDF_nested_virt    (1U << _XEN_DOMCTL_CDF_nested_virt)
-/* Should we expose the vPMU to the guest? */
-#define XEN_DOMCTL_CDF_vpmu           (1U << 7)
-
-/* Max XEN_DOMCTL_CDF_* constant.  Used for ABI checking. */
-#define XEN_DOMCTL_CDF_MAX XEN_DOMCTL_CDF_vpmu
 
+    /* See xen_domctl_cdf */
     uint32_t flags;
-
-#define _XEN_DOMCTL_IOMMU_no_sharept  0
-#define XEN_DOMCTL_IOMMU_no_sharept   (1U << _XEN_DOMCTL_IOMMU_no_sharept)
-
-/* Max XEN_DOMCTL_IOMMU_* constant.  Used for ABI checking. */
-#define XEN_DOMCTL_IOMMU_MAX XEN_DOMCTL_IOMMU_no_sharept
-
+    /* See xen_domctl_iommu_opts */
     uint32_t iommu_opts;
 
     /*
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index 90666576c2f8..1b75277e5dea 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -1125,7 +1125,7 @@ static always_inline bool is_control_domain(const struct domain *d)
 static always_inline bool is_pv_domain(const struct domain *d)
 {
     return IS_ENABLED(CONFIG_PV) &&
-        evaluate_nospec(!(d->options & XEN_DOMCTL_CDF_hvm));
+        evaluate_nospec(!(d->options & XEN_DOMCTL_CDF_HVM));
 }
 
 static always_inline bool is_pv_vcpu(const struct vcpu *v)
@@ -1167,7 +1167,7 @@ static always_inline bool is_pv_64bit_vcpu(const struct vcpu *v)
 static always_inline bool is_hvm_domain(const struct domain *d)
 {
     return IS_ENABLED(CONFIG_HVM) &&
-        evaluate_nospec(d->options & XEN_DOMCTL_CDF_hvm);
+        evaluate_nospec(d->options & XEN_DOMCTL_CDF_HVM);
 }
 
 static always_inline bool is_hvm_vcpu(const struct vcpu *v)
@@ -1179,7 +1179,7 @@ static always_inline bool hap_enabled(const struct domain *d)
 {
     /* sanitise_domain_config() rejects HAP && !HVM */
     return IS_ENABLED(CONFIG_HVM) &&
-        evaluate_nospec(d->options & XEN_DOMCTL_CDF_hap);
+        evaluate_nospec(d->options & XEN_DOMCTL_CDF_HAP);
 }
 
 static inline bool is_hwdom_pinned_vcpu(const struct vcpu *v)
@@ -1195,12 +1195,12 @@ static inline bool is_vcpu_online(const struct vcpu *v)
 
 static inline bool is_xenstore_domain(const struct domain *d)
 {
-    return d->options & XEN_DOMCTL_CDF_xs_domain;
+    return d->options & XEN_DOMCTL_CDF_XS_DOMAIN;
 }
 
 static always_inline bool is_iommu_enabled(const struct domain *d)
 {
-    return evaluate_nospec(d->options & XEN_DOMCTL_CDF_iommu);
+    return evaluate_nospec(d->options & XEN_DOMCTL_CDF_IOMMU);
 }
 
 extern bool sched_smt_power_savings;
-- 
2.47.0



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

* [RFC PATCH 15/25] xen/arm: Replace hand-crafted xen_arch_domainconfig with autogenerated one
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
                   ` (13 preceding siblings ...)
  2024-11-15 11:51 ` [RFC PATCH 14/25] xen: Replace common bitmaps in domctl.createdomain with autogenerated versions Alejandro Vallejo
@ 2024-11-15 11:51 ` Alejandro Vallejo
  2024-11-15 11:51 ` [RFC PATCH 16/25] xen/x86: " Alejandro Vallejo
                   ` (10 subsequent siblings)
  25 siblings, 0 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel
  Cc: Alejandro Vallejo, Anthony PERARD, Andrew Cooper, Jan Beulich,
	Julien Grall, Stefano Stabellini, Bertrand Marquis, Michal Orzel,
	Volodymyr Babchuk

Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
 .../extra/arch-arm/domainconfig.toml          | 83 +++++++++++++++++++
 xen/arch/arm/domain.c                         |  4 +-
 xen/arch/arm/tee/tee.c                        |  1 +
 xen/include/public/arch-arm.h                 | 36 --------
 xen/include/public/autogen/arch_arm.h         | 59 +++++++++++++
 5 files changed, 145 insertions(+), 38 deletions(-)
 create mode 100644 tools/rust/xenbindgen/extra/arch-arm/domainconfig.toml
 create mode 100644 xen/include/public/autogen/arch_arm.h

diff --git a/tools/rust/xenbindgen/extra/arch-arm/domainconfig.toml b/tools/rust/xenbindgen/extra/arch-arm/domainconfig.toml
new file mode 100644
index 000000000000..d32963445765
--- /dev/null
+++ b/tools/rust/xenbindgen/extra/arch-arm/domainconfig.toml
@@ -0,0 +1,83 @@
+[[enums]]
+name = "xen_domctl_config_gic"
+description = "Content of the `gic_version` field of the domainconfig struct."
+typ = { tag = "u8" }
+
+[[enums.variants]]
+name = "native"
+description = "Emulate the underlying GIC present in the current host."
+value = 0
+
+[[enums.variants]]
+name = "v2"
+description = "Emulate a GICv2."
+value = 1
+
+[[enums.variants]]
+name = "v3"
+description = "Emulate a GICv3."
+value = 2
+
+################################################################################
+
+[[enums]]
+name = "xen_domctl_config_tee"
+description = "TEE mediator exposed to the guest"
+typ = { tag = "u16" }
+
+[[enums.variants]]
+name = "none"
+description = "No mediator. Guest can't communicate with the TEE."
+value = 0
+
+[[enums.variants]]
+name = "optee"
+description = "Expose an OP-TEE mediator."
+value = 1
+
+[[enums.variants]]
+name = "ffa"
+description = "Expose an FF-A mediator."
+value = 2
+
+################################################################################
+
+[[structs]]
+name = "xen_arch_domainconfig"
+description = "arm-specific domain settings."
+
+[[structs.fields]]
+name = "gic_version"
+description = """IN/OUT: GIC version exposed to the guest.
+
+When `native` on input the output value holds the automatically chosen version."""
+typ = { tag = "enum", args = "xen_domctl_config_gic" }
+
+[[structs.fields]]
+name = "sve_vl"
+description = "IN: SVE vector length (divided by 128) exposed to the guest."
+typ = { tag = "u8" }
+
+[[structs.fields]]
+name = "tee_type"
+description = "IN: TEE mediator exposed to the guest."
+typ = { tag = "enum", args = "xen_domctl_config_tee" }
+
+[[structs.fields]]
+name = "nr_spis"
+description = "IN: Number of SPIs exposed to the guest."
+typ = { tag = "u32" }
+
+[[structs.fields]]
+name = "clock_frequency"
+description = """OUT
+Based on the property clock-frequency in the DT timer node.
+The property may be present when the bootloader/firmware doesn't
+set correctly CNTFRQ which hold the timer frequency.
+
+As it's not possible to trap this register, we have to replicate
+the value in the guest DT.
+
+= 0 => property not present
+> 0 => Value of the property"""
+typ = { tag = "u32" }
diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 54e849b02f9e..57ed11598754 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -639,10 +639,10 @@ int arch_sanitise_domain_config(struct xen_domctl_createdomain *config)
     }
 
     /* The P2M table must always be shared between the CPU and the IOMMU */
-    if ( config->iommu_opts & XEN_DOMCTL_IOMMU_no_sharept )
+    if ( config->iommu_opts & XEN_DOMCTL_IOMMU_OPTS_NO_SHAREPT )
     {
         dprintk(XENLOG_INFO,
-                "Unsupported iommu option: XEN_DOMCTL_IOMMU_no_sharept\n");
+                "Unsupported iommu option: XEN_DOMCTL_IOMMU_OPTS_NO_SHAREPT\n");
         return -EINVAL;
     }
 
diff --git a/xen/arch/arm/tee/tee.c b/xen/arch/arm/tee/tee.c
index 3f65e45a7892..c5f7629a227a 100644
--- a/xen/arch/arm/tee/tee.c
+++ b/xen/arch/arm/tee/tee.c
@@ -21,6 +21,7 @@
 #include <xen/types.h>
 
 #include <asm/tee/tee.h>
+#include <public/autogen/arch_arm.h>
 
 extern const struct tee_mediator_desc _steemediator[], _eteemediator[];
 static const struct tee_mediator_desc __read_mostly *cur_mediator;
diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h
index e2412a17474e..42ce9e64ed00 100644
--- a/xen/include/public/arch-arm.h
+++ b/xen/include/public/arch-arm.h
@@ -315,42 +315,6 @@ struct vcpu_guest_context {
 typedef struct vcpu_guest_context vcpu_guest_context_t;
 DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t);
 
-/*
- * struct xen_arch_domainconfig's ABI is covered by
- * XEN_DOMCTL_INTERFACE_VERSION.
- */
-#define XEN_DOMCTL_CONFIG_GIC_NATIVE    0
-#define XEN_DOMCTL_CONFIG_GIC_V2        1
-#define XEN_DOMCTL_CONFIG_GIC_V3        2
-
-#define XEN_DOMCTL_CONFIG_TEE_NONE      0
-#define XEN_DOMCTL_CONFIG_TEE_OPTEE     1
-#define XEN_DOMCTL_CONFIG_TEE_FFA       2
-
-struct xen_arch_domainconfig {
-    /* IN/OUT */
-    uint8_t gic_version;
-    /* IN - Contains SVE vector length divided by 128 */
-    uint8_t sve_vl;
-    /* IN */
-    uint16_t tee_type;
-    /* IN */
-    uint32_t nr_spis;
-    /*
-     * OUT
-     * Based on the property clock-frequency in the DT timer node.
-     * The property may be present when the bootloader/firmware doesn't
-     * set correctly CNTFRQ which hold the timer frequency.
-     *
-     * As it's not possible to trap this register, we have to replicate
-     * the value in the guest DT.
-     *
-     * = 0 => property not present
-     * > 0 => Value of the property
-     *
-     */
-    uint32_t clock_frequency;
-};
 #endif /* __XEN__ || __XEN_TOOLS__ */
 
 struct arch_vcpu_info {
diff --git a/xen/include/public/autogen/arch_arm.h b/xen/include/public/autogen/arch_arm.h
new file mode 100644
index 000000000000..d19f639671e0
--- /dev/null
+++ b/xen/include/public/autogen/arch_arm.h
@@ -0,0 +1,59 @@
+/*
+ * arch-arm
+ *
+ * AUTOGENERATED. DO NOT MODIFY
+ */
+#ifndef __XEN_AUTOGEN_ARCH_ARM_H
+#define __XEN_AUTOGEN_ARCH_ARM_H
+
+/* Content of the `gic_version` field of the domainconfig struct. */
+enum xen_domctl_config_gic {
+    /* Emulate the underlying GIC present in the current host. */
+    XEN_DOMCTL_CONFIG_GIC_NATIVE = 0,
+    /* Emulate a GICv2. */
+    XEN_DOMCTL_CONFIG_GIC_V2 = 1,
+    /* Emulate a GICv3. */
+    XEN_DOMCTL_CONFIG_GIC_V3 = 2,
+};
+
+/* TEE mediator exposed to the guest */
+enum xen_domctl_config_tee {
+    /* No mediator. Guest can't communicate with the TEE. */
+    XEN_DOMCTL_CONFIG_TEE_NONE = 0,
+    /* Expose an OP-TEE mediator. */
+    XEN_DOMCTL_CONFIG_TEE_OPTEE = 1,
+    /* Expose an FF-A mediator. */
+    XEN_DOMCTL_CONFIG_TEE_FFA = 2,
+};
+
+/* arm-specific domain settings. */
+struct xen_arch_domainconfig {
+    /*
+     * IN/OUT: GIC version exposed to the guest.
+     *
+     * When `native` on input the output value holds the automatically chosen version.
+     */
+    uint8_t gic_version /* See xen_domctl_config_gic */;
+    /* IN: SVE vector length (divided by 128) exposed to the guest. */
+    uint8_t sve_vl;
+    /* IN: TEE mediator exposed to the guest. */
+    uint16_t tee_type /* See xen_domctl_config_tee */;
+    /* IN: Number of SPIs exposed to the guest. */
+    uint32_t nr_spis;
+    /*
+     * OUT
+     * Based on the property clock-frequency in the DT timer node.
+     * The property may be present when the bootloader/firmware doesn't
+     * set correctly CNTFRQ which hold the timer frequency.
+     *
+     * As it's not possible to trap this register, we have to replicate
+     * the value in the guest DT.
+     *
+     * = 0 => property not present
+     * > 0 => Value of the property
+     */
+    uint32_t clock_frequency;
+};
+
+#endif /* __XEN_AUTOGEN_ARCH_ARM_H */
+
-- 
2.47.0



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

* [RFC PATCH 16/25] xen/x86: Replace hand-crafted xen_arch_domainconfig with autogenerated one
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
                   ` (14 preceding siblings ...)
  2024-11-15 11:51 ` [RFC PATCH 15/25] xen/arm: Replace hand-crafted xen_arch_domainconfig with autogenerated one Alejandro Vallejo
@ 2024-11-15 11:51 ` Alejandro Vallejo
  2024-11-25 12:09   ` Jan Beulich
  2024-11-15 11:51 ` [RFC PATCH 17/25] xen/ppc: Replace empty " Alejandro Vallejo
                   ` (9 subsequent siblings)
  25 siblings, 1 reply; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel
  Cc: Alejandro Vallejo, Anthony PERARD, Juergen Gross, Andrew Cooper,
	Jan Beulich, Julien Grall, Stefano Stabellini, Christian Lindig,
	David Scott, Roger Pau Monné

Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
 tools/libs/light/libxl_x86.c                  |  4 +-
 tools/ocaml/libs/xc/xenctrl_stubs.c           |  4 +-
 .../extra/arch-x86/domainconfig.toml          | 87 +++++++++++++++++++
 .../xenbindgen/extra/domctl/createdomain.toml |  6 ++
 xen/arch/x86/domain.c                         |  8 +-
 xen/arch/x86/include/asm/domain.h             |  4 +-
 xen/arch/x86/setup.c                          |  2 +-
 xen/include/public/arch-x86/xen.h             | 51 -----------
 xen/include/public/autogen/arch_x86.h         | 52 +++++++++++
 xen/include/public/autogen/domctl.h           | 13 +++
 10 files changed, 170 insertions(+), 61 deletions(-)
 create mode 100644 tools/rust/xenbindgen/extra/arch-x86/domainconfig.toml
 create mode 100644 xen/include/public/autogen/arch_x86.h

diff --git a/tools/libs/light/libxl_x86.c b/tools/libs/light/libxl_x86.c
index a3164a3077fe..a3d856957b54 100644
--- a/tools/libs/light/libxl_x86.c
+++ b/tools/libs/light/libxl_x86.c
@@ -8,7 +8,7 @@ int libxl__arch_domain_prepare_config(libxl__gc *gc,
 {
     switch(d_config->c_info.type) {
     case LIBXL_DOMAIN_TYPE_HVM:
-        config->arch.emulation_flags = (XEN_X86_EMU_ALL & ~XEN_X86_EMU_VPCI);
+        config->arch.emulation_flags = (XEN_X86_EMU__ALL & ~XEN_X86_EMU_VPCI);
         if (!libxl_defbool_val(d_config->b_info.u.hvm.pirq))
             config->arch.emulation_flags &= ~XEN_X86_EMU_USE_PIRQ;
         break;
@@ -24,7 +24,7 @@ int libxl__arch_domain_prepare_config(libxl__gc *gc,
 
     config->arch.misc_flags = 0;
     if (libxl_defbool_val(d_config->b_info.arch_x86.msr_relaxed))
-        config->arch.misc_flags |= XEN_X86_MSR_RELAXED;
+        config->arch.misc_flags |= XEN_X86_MISC_MSR_RELAXED;
 
     return 0;
 }
diff --git a/tools/ocaml/libs/xc/xenctrl_stubs.c b/tools/ocaml/libs/xc/xenctrl_stubs.c
index 1f2cf41a9cc7..65ff4f636ea9 100644
--- a/tools/ocaml/libs/xc/xenctrl_stubs.c
+++ b/tools/ocaml/libs/xc/xenctrl_stubs.c
@@ -260,12 +260,12 @@ CAMLprim value stub_xc_domain_create(value xch_val, value wanted_domid, value co
 
 		cfg.arch.emulation_flags = ocaml_list_to_c_bitmap
 			/* ! x86_arch_emulation_flags X86_EMU_ none */
-			/* ! XEN_X86_EMU_ XEN_X86_EMU_ALL all */
+			/* ! XEN_X86_EMU_ XEN_X86_EMU__ALL all */
 			(VAL_EMUL_FLAGS);
 
 		cfg.arch.misc_flags = ocaml_list_to_c_bitmap
 			/* ! x86_arch_misc_flags X86_ none */
-			/* ! XEN_X86_ XEN_X86_MSR_RELAXED all */
+			/* ! XEN_X86_ XEN_X86_MISC__ALL all */
 			(VAL_MISC_FLAGS);
 
 #undef VAL_MISC_FLAGS
diff --git a/tools/rust/xenbindgen/extra/arch-x86/domainconfig.toml b/tools/rust/xenbindgen/extra/arch-x86/domainconfig.toml
new file mode 100644
index 000000000000..1f85b69de4a8
--- /dev/null
+++ b/tools/rust/xenbindgen/extra/arch-x86/domainconfig.toml
@@ -0,0 +1,87 @@
+[[bitmaps]]
+name = "xen_x86_emu"
+description = "Content of the `emulation_flags` field of the domain creation hypercall."
+typ = { tag = "u32" }
+
+[[bitmaps.bits]]
+name = "lapic"
+description = "Emulate Local APICs."
+shift = 0
+
+[[bitmaps.bits]]
+name = "hpet"
+description = "Emulate a HPET timer."
+shift = 1
+
+[[bitmaps.bits]]
+name = "pm"
+description = "Emulate the ACPI PM timer."
+shift = 2
+
+[[bitmaps.bits]]
+name = "rtc"
+description = "Emulate the RTC clock."
+shift = 3
+
+[[bitmaps.bits]]
+name = "ioapic"
+description = "Emulate an IOAPIC device."
+shift = 4
+
+[[bitmaps.bits]]
+name = "pic"
+description = "Emulate PIC devices."
+shift = 5
+
+[[bitmaps.bits]]
+name = "vga"
+description = "Emulate standard VGA."
+shift = 6
+
+[[bitmaps.bits]]
+name = "iommu"
+description = "Emulate an IOMMU."
+shift = 7
+
+[[bitmaps.bits]]
+name = "pit"
+description = "Emulate a PIT timer."
+shift = 8
+
+[[bitmaps.bits]]
+name = "use_pirq"
+description = "Route physical IRQs over event channels."
+shift = 9
+
+[[bitmaps.bits]]
+name = "vpci"
+description = "Handle PCI configuration space traps from within Xen."
+shift = 10
+
+################################################################################
+
+[[bitmaps]]
+name = "xen_x86_misc"
+description = "Contents of the `misc_flags` field of the domain creation hypercall"
+typ = { tag = "u32" }
+
+[[bitmaps.bits]]
+name = "msr_relaxed"
+description = "Grants access to the real physical MSR registers of the host."
+shift = 0
+
+################################################################################
+
+[[structs]]
+name = "xen_arch_domainconfig"
+description = "x86-specific domain settings."
+
+[[structs.fields]]
+name = "emulation_flags"
+description = "IN: Bitmap of devices to emulate."
+typ = { tag = "bitmap", args = "xen_x86_emu" }
+
+[[structs.fields]]
+name = "misc_flags"
+description = "IN: Miscellaneous x86-specific toggles."
+typ = { tag = "bitmap", args = "xen_x86_misc" }
diff --git a/tools/rust/xenbindgen/extra/domctl/createdomain.toml b/tools/rust/xenbindgen/extra/domctl/createdomain.toml
index 02f65d134b55..3a6872aa325f 100644
--- a/tools/rust/xenbindgen/extra/domctl/createdomain.toml
+++ b/tools/rust/xenbindgen/extra/domctl/createdomain.toml
@@ -1,3 +1,9 @@
+[[includes]]
+from = "arch"
+imports = ["xen_arch_domainconfig"]
+
+################################################################################
+
 [[enums]]
 name = "xen_domctl_altp2m_mode"
 description = "Content of the `altp2m_mode` field of the domain creation hypercall."
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index 63a52a8ae23d..3c1c8f03aa81 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -708,7 +708,7 @@ int arch_sanitise_domain_config(struct xen_domctl_createdomain *config)
         }
     }
 
-    if ( config->arch.misc_flags & ~XEN_X86_MSR_RELAXED )
+    if ( config->arch.misc_flags & ~XEN_X86_MISC_MSR_RELAXED )
     {
         dprintk(XENLOG_INFO, "Invalid arch misc flags %#x\n",
                 config->arch.misc_flags);
@@ -735,7 +735,7 @@ static bool emulation_flags_ok(const struct domain *d, uint32_t emflags)
 {
 #ifdef CONFIG_HVM
     /* This doesn't catch !CONFIG_HVM case but it is better than nothing */
-    BUILD_BUG_ON(X86_EMU_ALL != XEN_X86_EMU_ALL);
+    BUILD_BUG_ON(X86_EMU_ALL != XEN_X86_EMU__ALL);
 #endif
 
     if ( is_hvm_domain(d) )
@@ -800,7 +800,7 @@ int arch_domain_create(struct domain *d,
     if ( is_hardware_domain(d) && is_pv_domain(d) )
         emflags |= XEN_X86_EMU_PIT;
 
-    if ( emflags & ~XEN_X86_EMU_ALL )
+    if ( emflags & ~XEN_X86_EMU__ALL )
     {
         printk(XENLOG_G_ERR "d%d: Invalid emulation bitmap: %#x\n",
                d->domain_id, emflags);
@@ -887,7 +887,7 @@ int arch_domain_create(struct domain *d,
 
     domain_cpu_policy_changed(d);
 
-    d->arch.msr_relaxed = config->arch.misc_flags & XEN_X86_MSR_RELAXED;
+    d->arch.msr_relaxed = config->arch.misc_flags & XEN_X86_MISC_MSR_RELAXED;
 
     return 0;
 
diff --git a/xen/arch/x86/include/asm/domain.h b/xen/arch/x86/include/asm/domain.h
index b79d6badd71c..119604fadb5d 100644
--- a/xen/arch/x86/include/asm/domain.h
+++ b/xen/arch/x86/include/asm/domain.h
@@ -12,6 +12,8 @@
 #include <public/vcpu.h>
 #include <public/hvm/hvm_info_table.h>
 
+#include <public/autogen/arch_x86.h>
+
 #define has_32bit_shinfo(d)    ((d)->arch.has_32bit_shinfo)
 
 /*
@@ -486,7 +488,7 @@ struct arch_domain
 
 #define X86_EMU_PIT     XEN_X86_EMU_PIT
 
-/* This must match XEN_X86_EMU_ALL in xen.h */
+/* This must match XEN_X86_EMU__ALL */
 #define X86_EMU_ALL             (X86_EMU_LAPIC | X86_EMU_HPET |         \
                                  X86_EMU_PM | X86_EMU_RTC |             \
                                  X86_EMU_IOAPIC | X86_EMU_PIC |         \
diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c
index 65ea3fc86beb..d408af54d997 100644
--- a/xen/arch/x86/setup.c
+++ b/xen/arch/x86/setup.c
@@ -967,7 +967,7 @@ static struct domain *__init create_dom0(const module_t *image,
         .max_grant_version = opt_gnttab_max_version,
         .max_vcpus = dom0_max_vcpus(),
         .arch = {
-            .misc_flags = opt_dom0_msr_relaxed ? XEN_X86_MSR_RELAXED : 0,
+            .misc_flags = opt_dom0_msr_relaxed ? XEN_X86_MISC_MSR_RELAXED : 0,
         },
     };
     struct domain *d;
diff --git a/xen/include/public/arch-x86/xen.h b/xen/include/public/arch-x86/xen.h
index fc2487986642..e864459cfd93 100644
--- a/xen/include/public/arch-x86/xen.h
+++ b/xen/include/public/arch-x86/xen.h
@@ -255,57 +255,6 @@ struct arch_shared_info {
 };
 typedef struct arch_shared_info arch_shared_info_t;
 
-#if defined(__XEN__) || defined(__XEN_TOOLS__)
-/*
- * struct xen_arch_domainconfig's ABI is covered by
- * XEN_DOMCTL_INTERFACE_VERSION.
- */
-struct xen_arch_domainconfig {
-#define _XEN_X86_EMU_LAPIC          0
-#define XEN_X86_EMU_LAPIC           (1U<<_XEN_X86_EMU_LAPIC)
-#define _XEN_X86_EMU_HPET           1
-#define XEN_X86_EMU_HPET            (1U<<_XEN_X86_EMU_HPET)
-#define _XEN_X86_EMU_PM             2
-#define XEN_X86_EMU_PM              (1U<<_XEN_X86_EMU_PM)
-#define _XEN_X86_EMU_RTC            3
-#define XEN_X86_EMU_RTC             (1U<<_XEN_X86_EMU_RTC)
-#define _XEN_X86_EMU_IOAPIC         4
-#define XEN_X86_EMU_IOAPIC          (1U<<_XEN_X86_EMU_IOAPIC)
-#define _XEN_X86_EMU_PIC            5
-#define XEN_X86_EMU_PIC             (1U<<_XEN_X86_EMU_PIC)
-#define _XEN_X86_EMU_VGA            6
-#define XEN_X86_EMU_VGA             (1U<<_XEN_X86_EMU_VGA)
-#define _XEN_X86_EMU_IOMMU          7
-#define XEN_X86_EMU_IOMMU           (1U<<_XEN_X86_EMU_IOMMU)
-#define _XEN_X86_EMU_PIT            8
-#define XEN_X86_EMU_PIT             (1U<<_XEN_X86_EMU_PIT)
-#define _XEN_X86_EMU_USE_PIRQ       9
-#define XEN_X86_EMU_USE_PIRQ        (1U<<_XEN_X86_EMU_USE_PIRQ)
-#define _XEN_X86_EMU_VPCI           10
-#define XEN_X86_EMU_VPCI            (1U<<_XEN_X86_EMU_VPCI)
-
-#define XEN_X86_EMU_ALL             (XEN_X86_EMU_LAPIC | XEN_X86_EMU_HPET |  \
-                                     XEN_X86_EMU_PM | XEN_X86_EMU_RTC |      \
-                                     XEN_X86_EMU_IOAPIC | XEN_X86_EMU_PIC |  \
-                                     XEN_X86_EMU_VGA | XEN_X86_EMU_IOMMU |   \
-                                     XEN_X86_EMU_PIT | XEN_X86_EMU_USE_PIRQ |\
-                                     XEN_X86_EMU_VPCI)
-    uint32_t emulation_flags;
-
-/*
- * Select whether to use a relaxed behavior for accesses to MSRs not explicitly
- * handled by Xen instead of injecting a #GP to the guest. Note this option
- * doesn't allow the guest to read or write to the underlying MSR.
- */
-#define XEN_X86_MSR_RELAXED (1u << 0)
-    uint32_t misc_flags;
-};
-
-/* Max  XEN_X86_* constant. Used for ABI checking. */
-#define XEN_X86_MISC_FLAGS_MAX XEN_X86_MSR_RELAXED
-
-#endif
-
 /*
  * Representations of architectural CPUID and MSR information.  Used as the
  * serialised version of Xen's internal representation.
diff --git a/xen/include/public/autogen/arch_x86.h b/xen/include/public/autogen/arch_x86.h
new file mode 100644
index 000000000000..94f35218342e
--- /dev/null
+++ b/xen/include/public/autogen/arch_x86.h
@@ -0,0 +1,52 @@
+/*
+ * arch-x86
+ *
+ * AUTOGENERATED. DO NOT MODIFY
+ */
+#ifndef __XEN_AUTOGEN_ARCH_X86_H
+#define __XEN_AUTOGEN_ARCH_X86_H
+
+/* Content of the `emulation_flags` field of the domain creation hypercall. */
+struct xen_x86_emu {}; /* GREP FODDER */
+/* Emulate Local APICs. */
+#define XEN_X86_EMU_LAPIC (1U << 0)
+/* Emulate a HPET timer. */
+#define XEN_X86_EMU_HPET (1U << 1)
+/* Emulate the ACPI PM timer. */
+#define XEN_X86_EMU_PM (1U << 2)
+/* Emulate the RTC clock. */
+#define XEN_X86_EMU_RTC (1U << 3)
+/* Emulate an IOAPIC device. */
+#define XEN_X86_EMU_IOAPIC (1U << 4)
+/* Emulate PIC devices. */
+#define XEN_X86_EMU_PIC (1U << 5)
+/* Emulate standard VGA. */
+#define XEN_X86_EMU_VGA (1U << 6)
+/* Emulate an IOMMU. */
+#define XEN_X86_EMU_IOMMU (1U << 7)
+/* Emulate a PIT timer. */
+#define XEN_X86_EMU_PIT (1U << 8)
+/* Route physical IRQs over event channels. */
+#define XEN_X86_EMU_USE_PIRQ (1U << 9)
+/* Handle PCI configuration space traps from within Xen. */
+#define XEN_X86_EMU_VPCI (1U << 10)
+/* Mask covering all defined bits */
+#define XEN_X86_EMU__ALL (0x7FFU)
+
+/* Contents of the `misc_flags` field of the domain creation hypercall */
+struct xen_x86_misc {}; /* GREP FODDER */
+/* Grants access to the real physical MSR registers of the host. */
+#define XEN_X86_MISC_MSR_RELAXED (1U << 0)
+/* Mask covering all defined bits */
+#define XEN_X86_MISC__ALL (0x1U)
+
+/* x86-specific domain settings. */
+struct xen_arch_domainconfig {
+    /* IN: Bitmap of devices to emulate. */
+    uint32_t emulation_flags /* See xen_x86_emu */;
+    /* IN: Miscellaneous x86-specific toggles. */
+    uint32_t misc_flags /* See xen_x86_misc */;
+};
+
+#endif /* __XEN_AUTOGEN_ARCH_X86_H */
+
diff --git a/xen/include/public/autogen/domctl.h b/xen/include/public/autogen/domctl.h
index bd1f4bedc727..276e05168688 100644
--- a/xen/include/public/autogen/domctl.h
+++ b/xen/include/public/autogen/domctl.h
@@ -6,6 +6,19 @@
 #ifndef __XEN_AUTOGEN_DOMCTL_H
 #define __XEN_AUTOGEN_DOMCTL_H
 
+/* for xen_arch_domainconfig */
+#if defined(__i386__) || defined(__x86_64__)
+#include "arch_x86.h"
+#elif defined(__arm__) || defined(__aarch64__)
+#include "arch_arm.h"
+#elif defined(__powerpc64__)
+#include "arch_ppc.h"
+#elif defined(__riscv)
+#include "arch_riscv.h"
+#else
+#error "Unsupported architecture"
+#endif
+
 /* Content of the `altp2m_mode` field of the domain creation hypercall. */
 enum xen_domctl_altp2m_mode {
     /* Keep altp2m disabled */
-- 
2.47.0



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

* [RFC PATCH 17/25] xen/ppc: Replace empty xen_arch_domainconfig with autogenerated one
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
                   ` (15 preceding siblings ...)
  2024-11-15 11:51 ` [RFC PATCH 16/25] xen/x86: " Alejandro Vallejo
@ 2024-11-15 11:51 ` Alejandro Vallejo
  2024-11-15 11:51 ` [RFC PATCH 18/25] xen/riscv: " Alejandro Vallejo
                   ` (8 subsequent siblings)
  25 siblings, 0 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel
  Cc: Alejandro Vallejo, Anthony PERARD, Andrew Cooper, Jan Beulich,
	Julien Grall, Stefano Stabellini

Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
 .../xenbindgen/extra/arch-ppc/domainconfig.toml    |  4 ++++
 xen/include/public/arch-ppc.h                      |  3 ---
 xen/include/public/autogen/arch_ppc.h              | 14 ++++++++++++++
 3 files changed, 18 insertions(+), 3 deletions(-)
 create mode 100644 tools/rust/xenbindgen/extra/arch-ppc/domainconfig.toml
 create mode 100644 xen/include/public/autogen/arch_ppc.h

diff --git a/tools/rust/xenbindgen/extra/arch-ppc/domainconfig.toml b/tools/rust/xenbindgen/extra/arch-ppc/domainconfig.toml
new file mode 100644
index 000000000000..ecf9f1d9937d
--- /dev/null
+++ b/tools/rust/xenbindgen/extra/arch-ppc/domainconfig.toml
@@ -0,0 +1,4 @@
+[[structs]]
+name = "xen_arch_domainconfig"
+description = "ppc-specific domain settings."
+fields = []
diff --git a/xen/include/public/arch-ppc.h b/xen/include/public/arch-ppc.h
index 33a24e379551..1e0018e12c73 100644
--- a/xen/include/public/arch-ppc.h
+++ b/xen/include/public/arch-ppc.h
@@ -102,9 +102,6 @@ struct arch_shared_info {
 struct arch_vcpu_info {
 };
 
-struct xen_arch_domainconfig {
-};
-
 typedef struct xen_pmu_arch { uint8_t dummy; } xen_pmu_arch_t;
 
 #endif
diff --git a/xen/include/public/autogen/arch_ppc.h b/xen/include/public/autogen/arch_ppc.h
new file mode 100644
index 000000000000..48fcc302f341
--- /dev/null
+++ b/xen/include/public/autogen/arch_ppc.h
@@ -0,0 +1,14 @@
+/*
+ * arch-ppc
+ *
+ * AUTOGENERATED. DO NOT MODIFY
+ */
+#ifndef __XEN_AUTOGEN_ARCH_PPC_H
+#define __XEN_AUTOGEN_ARCH_PPC_H
+
+/* ppc-specific domain settings. */
+struct xen_arch_domainconfig {
+};
+
+#endif /* __XEN_AUTOGEN_ARCH_PPC_H */
+
-- 
2.47.0



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

* [RFC PATCH 18/25] xen/riscv: Replace empty xen_arch_domainconfig with autogenerated one
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
                   ` (16 preceding siblings ...)
  2024-11-15 11:51 ` [RFC PATCH 17/25] xen/ppc: Replace empty " Alejandro Vallejo
@ 2024-11-15 11:51 ` Alejandro Vallejo
  2024-11-15 11:51 ` [RFC PATCH 19/25] xen: Replace hand-crafted domctl/createdomain with autogenerated version Alejandro Vallejo
                   ` (7 subsequent siblings)
  25 siblings, 0 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel
  Cc: Alejandro Vallejo, Anthony PERARD, Andrew Cooper, Jan Beulich,
	Julien Grall, Stefano Stabellini

Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
 .../xenbindgen/extra/arch-riscv/domainconfig.toml  |  4 ++++
 xen/include/public/arch-riscv.h                    |  3 ---
 xen/include/public/autogen/arch_riscv.h            | 14 ++++++++++++++
 3 files changed, 18 insertions(+), 3 deletions(-)
 create mode 100644 tools/rust/xenbindgen/extra/arch-riscv/domainconfig.toml
 create mode 100644 xen/include/public/autogen/arch_riscv.h

diff --git a/tools/rust/xenbindgen/extra/arch-riscv/domainconfig.toml b/tools/rust/xenbindgen/extra/arch-riscv/domainconfig.toml
new file mode 100644
index 000000000000..ecac1ae22b1c
--- /dev/null
+++ b/tools/rust/xenbindgen/extra/arch-riscv/domainconfig.toml
@@ -0,0 +1,4 @@
+[[structs]]
+name = "xen_arch_domainconfig"
+description = "riscv-specific domain settings."
+fields = []
diff --git a/xen/include/public/arch-riscv.h b/xen/include/public/arch-riscv.h
index 168263b92074..a199dbc6a15f 100644
--- a/xen/include/public/arch-riscv.h
+++ b/xen/include/public/arch-riscv.h
@@ -55,9 +55,6 @@ struct vcpu_guest_context {
 typedef struct vcpu_guest_context vcpu_guest_context_t;
 DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t);
 
-struct xen_arch_domainconfig {
-};
-
 #endif
 
 /* TODO:  add a placeholder entry if no real ones surface */
diff --git a/xen/include/public/autogen/arch_riscv.h b/xen/include/public/autogen/arch_riscv.h
new file mode 100644
index 000000000000..e0d3aa681862
--- /dev/null
+++ b/xen/include/public/autogen/arch_riscv.h
@@ -0,0 +1,14 @@
+/*
+ * arch-riscv
+ *
+ * AUTOGENERATED. DO NOT MODIFY
+ */
+#ifndef __XEN_AUTOGEN_ARCH_RISCV_H
+#define __XEN_AUTOGEN_ARCH_RISCV_H
+
+/* riscv-specific domain settings. */
+struct xen_arch_domainconfig {
+};
+
+#endif /* __XEN_AUTOGEN_ARCH_RISCV_H */
+
-- 
2.47.0



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

* [RFC PATCH 19/25] xen: Replace hand-crafted domctl/createdomain with autogenerated version
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
                   ` (17 preceding siblings ...)
  2024-11-15 11:51 ` [RFC PATCH 18/25] xen/riscv: " Alejandro Vallejo
@ 2024-11-15 11:51 ` Alejandro Vallejo
  2024-12-04 14:48   ` Teddy Astie
  2024-11-15 11:51 ` [RFC PATCH 20/25] tools/xen-sys: Create a crate with autogenerated Rust constructs Alejandro Vallejo
                   ` (6 subsequent siblings)
  25 siblings, 1 reply; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel
  Cc: Alejandro Vallejo, Anthony PERARD, Andrew Cooper, Jan Beulich,
	Julien Grall, Stefano Stabellini, Daniel P. Smith

With xen_arch_domainconfig and every bitmap/enum already autogenerated,
add the final piece to enable autogeneration of the createdomain
hypercall.

Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
 .../xenbindgen/extra/domctl/createdomain.toml | 96 +++++++++++++++++++
 xen/include/public/autogen/domctl.h           | 54 +++++++++++
 xen/include/public/domctl.h                   | 56 +----------
 xen/include/public/sysctl.h                   |  1 +
 4 files changed, 152 insertions(+), 55 deletions(-)

diff --git a/tools/rust/xenbindgen/extra/domctl/createdomain.toml b/tools/rust/xenbindgen/extra/domctl/createdomain.toml
index 3a6872aa325f..f20cb8790039 100644
--- a/tools/rust/xenbindgen/extra/domctl/createdomain.toml
+++ b/tools/rust/xenbindgen/extra/domctl/createdomain.toml
@@ -87,3 +87,99 @@ typ = { tag = "u32" }
 name = "no_sharept"
 description = "Set to _NOT_ share page tables between the CPU and the IOMMU when it would be possible to do so."
 shift = 0
+
+################################################################################
+
+[[structs]]
+name = "xen_domctl_createdomain"
+description = """
+Create a new domain with the passed parameters.
+
+IMPORTANT: The domid part of the domctl is IN/OUT. When the passed
+domid is 0 or over `DOMID_FIRST_RESERVED` a new domid is auto-allocated
+and returned."""
+
+[[structs.fields]]
+name = "ssidref"
+description = "IN: `Source Security IDentifier` (See XSM)."
+typ = { tag = "u32" }
+
+[[structs.fields]]
+name = "handle"
+description = "IN: Unique identifier for this guest given by the toolstack."
+typ = { tag = "array", args = [{ tag = "u8" }, 16]  }
+
+[[structs.fields]]
+name = "flags"
+description = "IN: Bitmap of domain features to enable/disable."
+typ = { tag = "bitmap", args = "xen_domctl_cdf" }
+
+[[structs.fields]]
+name = "iommu_opts"
+description = "IN: Bitmap of configuration settings for the IOMMU."
+typ = { tag = "bitmap", args = "xen_domctl_iommu_opts" }
+
+[[structs.fields]]
+name = "max_vcpus"
+description = "IN: Maximum number of CPUs this domain can hold, including hotplug."
+typ = { tag = "u32" }
+
+[[structs.fields]]
+name = "max_evtchn_port"
+description = "IN: Maximum number of usable event channels"
+typ = { tag = "u32" }
+
+[[structs.fields]]
+name = "max_grant_frames"
+description = '''
+IN: Maximum number of pages this domain is able
+    to grant access to for other domains.
+
+`< 0` means "use default value in the hypervisor."'''
+typ = { tag = "i32" }
+
+[[structs.fields]]
+name = "max_maptrack_frames"
+description = '''
+IN: Maximum number of pages of foreign domains
+    can be accessed via the grant mechanism.
+
+`< 0` means "use default value in the hypervisor."'''
+typ = { tag = "i32" }
+
+[[structs.fields]]
+name = "max_grant_version"
+description = "Maximum grant table version allowed for this domain"
+typ = { tag = "u8" }
+
+[[structs.fields]]
+name = "rsvd0_a"
+description = "Unused padding. Reserved to zero."
+typ = { tag = "array", args = [{ tag = "u8" }, 3]  }
+
+[[structs.fields]]
+name = "altp2m_mode"
+description = "Which mode to configure altp2m with"
+typ = { tag = "u8" }
+
+[[structs.fields]]
+name = "rsvd0_b"
+description = "Unused padding. Reserved to zero."
+typ = { tag = "array", args = [{ tag = "u8" }, 3]  }
+
+[[structs.fields]]
+name = "vmtrace_size"
+description = "IN: Per-vCPU buffer size in octets. 0 to disable."
+typ = { tag = "u32" }
+
+[[structs.fields]]
+name = "cpupool_id"
+description = "IN: CPU pool to use; 0 or an existing CPU pool."
+typ = { tag = "u32" }
+
+[[structs.fields]]
+name = "arch"
+description = """Arch-specific settings.
+
+Each architecture is free to make its fields IN/OUT/INOUT"""
+typ = { tag = "struct", args = "xen_arch_domainconfig" }
diff --git a/xen/include/public/autogen/domctl.h b/xen/include/public/autogen/domctl.h
index 276e05168688..8a0934039169 100644
--- a/xen/include/public/autogen/domctl.h
+++ b/xen/include/public/autogen/domctl.h
@@ -59,5 +59,59 @@ struct xen_domctl_iommu_opts {}; /* GREP FODDER */
 /* Mask covering all defined bits */
 #define XEN_DOMCTL_IOMMU_OPTS__ALL (0x1U)
 
+/*
+ * Create a new domain with the passed parameters.
+ *
+ * IMPORTANT: The domid part of the domctl is IN/OUT. When the passed
+ * domid is 0 or over `DOMID_FIRST_RESERVED` a new domid is auto-allocated
+ * and returned.
+ */
+struct xen_domctl_createdomain {
+    /* IN: `Source Security IDentifier` (See XSM). */
+    uint32_t ssidref;
+    /* IN: Unique identifier for this guest given by the toolstack. */
+    uint8_t handle[16];
+    /* IN: Bitmap of domain features to enable/disable. */
+    uint32_t flags /* See xen_domctl_cdf */;
+    /* IN: Bitmap of configuration settings for the IOMMU. */
+    uint32_t iommu_opts /* See xen_domctl_iommu_opts */;
+    /* IN: Maximum number of CPUs this domain can hold, including hotplug. */
+    uint32_t max_vcpus;
+    /* IN: Maximum number of usable event channels */
+    uint32_t max_evtchn_port;
+    /*
+     * IN: Maximum number of pages this domain is able
+     *     to grant access to for other domains.
+     *
+     * `< 0` means "use default value in the hypervisor."
+     */
+    int32_t max_grant_frames;
+    /*
+     * IN: Maximum number of pages of foreign domains
+     *     can be accessed via the grant mechanism.
+     *
+     * `< 0` means "use default value in the hypervisor."
+     */
+    int32_t max_maptrack_frames;
+    /* Maximum grant table version allowed for this domain */
+    uint8_t max_grant_version;
+    /* Unused padding. Reserved to zero. */
+    uint8_t rsvd0_a[3];
+    /* Which mode to configure altp2m with */
+    uint8_t altp2m_mode;
+    /* Unused padding. Reserved to zero. */
+    uint8_t rsvd0_b[3];
+    /* IN: Per-vCPU buffer size in octets. 0 to disable. */
+    uint32_t vmtrace_size;
+    /* IN: CPU pool to use; 0 or an existing CPU pool. */
+    uint32_t cpupool_id;
+    /*
+     * Arch-specific settings.
+     *
+     * Each architecture is free to make its fields IN/OUT/INOUT
+     */
+    struct xen_arch_domainconfig arch;
+};
+
 #endif /* __XEN_AUTOGEN_DOMCTL_H */
 
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index 2d1423f6fd91..01404cf301fa 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -33,62 +33,8 @@
  *
  * Last version bump: Xen 4.19
  */
-#define XEN_DOMCTL_INTERFACE_VERSION 0x00000017
-
-/*
- * NB. xen_domctl.domain is an IN/OUT parameter for this operation.
- * If it is specified as an invalid value (0 or >= DOMID_FIRST_RESERVED),
- * an id is auto-allocated and returned.
- */
-/* XEN_DOMCTL_createdomain */
-struct xen_domctl_createdomain {
-    /* IN parameters */
-    uint32_t ssidref;
-    xen_domain_handle_t handle;
 
-    /* See xen_domctl_cdf */
-    uint32_t flags;
-    /* See xen_domctl_iommu_opts */
-    uint32_t iommu_opts;
-
-    /*
-     * Various domain limits, which impact the quantity of resources
-     * (global mapping space, xenheap, etc) a guest may consume.  For
-     * max_grant_frames and max_maptrack_frames, < 0 means "use the
-     * default maximum value in the hypervisor".
-     */
-    uint32_t max_vcpus;
-    uint32_t max_evtchn_port;
-    int32_t max_grant_frames;
-    int32_t max_maptrack_frames;
-
-    /*
-     * Maximum grant table version the domain can be configured with.
-     *
-     * Domains always start with v1 (if CONFIG_GRANT_TABLE) and can be bumped
-     * to use up to `max_grant_version` via GNTTABOP_set_version.
-     *
-     * Must be zero iff !CONFIG_GRANT_TABLE.
-     */
-    uint8_t max_grant_version;
-
-    /* Unused. Reserved to zero. */
-    uint8_t rsvd0_a[3];
-
-    /* See xen_domctl_altp2m_mode */
-    uint8_t altp2m_mode;
-
-    /* Unused. Reserved to zero. */
-    uint8_t rsvd0_b[3];
-
-    /* Per-vCPU buffer size in bytes.  0 to disable. */
-    uint32_t vmtrace_size;
-
-    /* CPU pool to use; specify 0 or a specific existing pool */
-    uint32_t cpupool_id;
-
-    struct xen_arch_domainconfig arch;
-};
+#define XEN_DOMCTL_INTERFACE_VERSION 0x00000017
 
 /* XEN_DOMCTL_getdomaininfo */
 struct xen_domctl_getdomaininfo {
diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h
index 9e773490a5ac..e882c1e31059 100644
--- a/xen/include/public/sysctl.h
+++ b/xen/include/public/sysctl.h
@@ -17,6 +17,7 @@
 #include "xen.h"
 #include "domctl.h"
 #include "physdev.h"
+#include "autogen/sysctl.h"
 
 #include "autogen/sysctl.h"
 
-- 
2.47.0



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

* [RFC PATCH 20/25] tools/xen-sys: Create a crate with autogenerated Rust constructs
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
                   ` (18 preceding siblings ...)
  2024-11-15 11:51 ` [RFC PATCH 19/25] xen: Replace hand-crafted domctl/createdomain with autogenerated version Alejandro Vallejo
@ 2024-11-15 11:51 ` Alejandro Vallejo
  2024-11-15 11:51 ` [RFC PATCH 21/25] tools/xenbindgen: Add Rust backend to xenbindgen Alejandro Vallejo
                   ` (5 subsequent siblings)
  25 siblings, 0 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel; +Cc: Alejandro Vallejo, Anthony PERARD

Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
 tools/rust/Makefile           |  5 ++++-
 tools/rust/xen-sys/.gitignore |  2 ++
 tools/rust/xen-sys/Cargo.toml |  8 +++++++
 tools/rust/xen-sys/src/lib.rs | 41 +++++++++++++++++++++++++++++++++++
 4 files changed, 55 insertions(+), 1 deletion(-)
 create mode 100644 tools/rust/xen-sys/.gitignore
 create mode 100644 tools/rust/xen-sys/Cargo.toml
 create mode 100644 tools/rust/xen-sys/src/lib.rs

diff --git a/tools/rust/Makefile b/tools/rust/Makefile
index 80e2f0e2817e..814e5b94447f 100644
--- a/tools/rust/Makefile
+++ b/tools/rust/Makefile
@@ -3,6 +3,9 @@ XEN_ROOT=$(CURDIR)/../..
 # Path to the Xen hypercall IDL parser
 XENBINDGEN=$(CURDIR)/xenbindgen
 
+# Path to the autogenerated Rust bindings crate
+CRATE_XENSYS=$(CURDIR)/xen-sys
+
 # Output folder for the autogenerated C headers
 #
 # Must contain autogenerated files only because they're all wiped on update
@@ -37,7 +40,7 @@ update: clean-autogen
 .PHONY: verify
 verify:
 	set -eu; \
-	for i in "${XENBINDGEN}"; do \
+	for i in "${CRATE_XENSYS}" "${XENBINDGEN}"; do \
 	    echo "Verifying $$i"; \
 	    cd "$$i"; \
 	    cargo fmt -- --check; \
diff --git a/tools/rust/xen-sys/.gitignore b/tools/rust/xen-sys/.gitignore
new file mode 100644
index 000000000000..ca98cd96efdc
--- /dev/null
+++ b/tools/rust/xen-sys/.gitignore
@@ -0,0 +1,2 @@
+/target/
+Cargo.lock
diff --git a/tools/rust/xen-sys/Cargo.toml b/tools/rust/xen-sys/Cargo.toml
new file mode 100644
index 000000000000..fb91beaa1525
--- /dev/null
+++ b/tools/rust/xen-sys/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "xen-sys"
+version = "0.1.0"
+edition = "2021"
+license = "MIT"
+
+[dependencies]
+bitflags = { version = "2.6.0", default-features = false }
diff --git a/tools/rust/xen-sys/src/lib.rs b/tools/rust/xen-sys/src/lib.rs
new file mode 100644
index 000000000000..7b3ea6c8ad4c
--- /dev/null
+++ b/tools/rust/xen-sys/src/lib.rs
@@ -0,0 +1,41 @@
+//! xen-sys
+//!
+//! This crate contains low-level primitives to interact with the Xen
+//! hypervisor. It relies on the autogenerated bindings of xenbindgen and
+//! a few closely related primitives, like [`Align64`].
+#![no_std]
+
+use core::ops::{Deref, DerefMut};
+
+/// Wrapper for pointers and 64bit integers so they are _always_ aligned to 8
+/// octets, even in 32bit machines.
+#[repr(align(8))]
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub struct Align64<T>(pub T);
+
+impl<T> Default for Align64<T> {
+    fn default() -> Self {
+        // Experimental feature
+        //
+        // This is required because `*mut U` can't implement Default. We take
+        // the convention that `Default` means "zero". For `t: Align64<*mut T>`
+        // that means `t` is null.
+        //
+        // If the `xen` crate stops needing this, then this impl must go away.
+        unsafe { Self(core::mem::zeroed()) }
+    }
+}
+
+impl<T> Deref for Align64<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl<T> DerefMut for Align64<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
-- 
2.47.0



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

* [RFC PATCH 21/25] tools/xenbindgen: Add Rust backend to xenbindgen
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
                   ` (19 preceding siblings ...)
  2024-11-15 11:51 ` [RFC PATCH 20/25] tools/xen-sys: Create a crate with autogenerated Rust constructs Alejandro Vallejo
@ 2024-11-15 11:51 ` Alejandro Vallejo
  2024-11-15 11:51 ` [RFC PATCH 22/25] tools/xen-sys: Add autogenerated Rust files Alejandro Vallejo
                   ` (4 subsequent siblings)
  25 siblings, 0 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel
  Cc: Alejandro Vallejo, Anthony PERARD, Teddy Astie, Yann Dirson,
	Teddy Astie

Teddy added support for includes in this backend, as in the C backend.

Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
Signed-off-by: Teddy Astie <teddy.astie@vates.fr>
---
 tools/rust/Makefile                  |  10 +-
 tools/rust/xen-sys/src/lib.rs        |   2 +
 tools/rust/xenbindgen/src/main.rs    |   4 +
 tools/rust/xenbindgen/src/rs_lang.rs | 227 +++++++++++++++++++++++++++
 4 files changed, 242 insertions(+), 1 deletion(-)
 create mode 100644 tools/rust/xenbindgen/src/rs_lang.rs

diff --git a/tools/rust/Makefile b/tools/rust/Makefile
index 814e5b94447f..4f064c37f45c 100644
--- a/tools/rust/Makefile
+++ b/tools/rust/Makefile
@@ -6,6 +6,9 @@ XENBINDGEN=$(CURDIR)/xenbindgen
 # Path to the autogenerated Rust bindings crate
 CRATE_XENSYS=$(CURDIR)/xen-sys
 
+# Output folder for the autogenerated Rust files
+AUTOGEN_RS=$(CRATE_XENSYS)/src/autogen
+
 # Output folder for the autogenerated C headers
 #
 # Must contain autogenerated files only because they're all wiped on update
@@ -25,13 +28,18 @@ all install uninstall clean:
 # Remove all autogenerated files
 .PHONY: clean-autogen
 clean-autogen:
-	rm -rf "${AUTOGEN_C}"
+	rm -rf "${AUTOGEN_RS}" "${AUTOGEN_C}"
 
 # Refresh autogenerated files. Depending on clean-autogen is required in order
 # for removals of specification files to cause the removal of their
 # autogenerated files.
 .PHONY: update
 update: clean-autogen
+	# Update Rust bindings
+	cargo run --manifest-path "${XENBINDGEN}/Cargo.toml" -- --lang rust \
+	          --indir "${XENBINDGEN}/extra" --outdir "${AUTOGEN_RS}"
+	cargo fmt --manifest-path "${CRATE_XENSYS}/Cargo.toml"
+	
 	# Update C bindings
 	cargo run --manifest-path "${XENBINDGEN}/Cargo.toml" -- --lang c \
 	          --indir "${XENBINDGEN}/extra" --outdir "${AUTOGEN_C}"
diff --git a/tools/rust/xen-sys/src/lib.rs b/tools/rust/xen-sys/src/lib.rs
index 7b3ea6c8ad4c..efab54ee1025 100644
--- a/tools/rust/xen-sys/src/lib.rs
+++ b/tools/rust/xen-sys/src/lib.rs
@@ -5,6 +5,8 @@
 //! a few closely related primitives, like [`Align64`].
 #![no_std]
 
+pub mod autogen;
+
 use core::ops::{Deref, DerefMut};
 
 /// Wrapper for pointers and 64bit integers so they are _always_ aligned to 8
diff --git a/tools/rust/xenbindgen/src/main.rs b/tools/rust/xenbindgen/src/main.rs
index dbc610e420f2..a1cf47e26bf5 100644
--- a/tools/rust/xenbindgen/src/main.rs
+++ b/tools/rust/xenbindgen/src/main.rs
@@ -5,6 +5,7 @@
 mod spec;
 
 mod c_lang;
+mod rs_lang;
 
 use std::{io::Write, path::PathBuf};
 
@@ -35,6 +36,8 @@ struct Cli {
 enum Lang {
     #[doc(hidden)]
     C,
+    #[doc(hidden)]
+    Rust,
 }
 
 fn main() {
@@ -66,6 +69,7 @@ fn main() {
     };
 
     let (extension, parser): (&str, fn(&OutFileDef) -> String) = match cli.lang {
+        Lang::Rust => (".rs", rs_lang::parse),
         Lang::C => (".h", c_lang::parse),
     };
 
diff --git a/tools/rust/xenbindgen/src/rs_lang.rs b/tools/rust/xenbindgen/src/rs_lang.rs
new file mode 100644
index 000000000000..cd5ce2989d51
--- /dev/null
+++ b/tools/rust/xenbindgen/src/rs_lang.rs
@@ -0,0 +1,227 @@
+//! Rust backend
+//!
+//! A backend for the Rust programming language. Enums, structs and bitmaps
+//! are native (with the latter being available via the `bitflags` crate.
+//!
+//! 64bit primitives and pointers are wrapped in a _magic_ type called `Align64`.
+//! This type is expected to exist in the target crate and is meant to provide
+//! ergonomic mechanisms to, create, access and modify its contents. Its whole
+//! purpose is make those types have 64bit size and be 64bit aligned even on
+//! 32bit targets.
+use std::fmt::Write;
+
+use crate::spec::{BitmapDef, EnumDef, IncludeDef, OutFileDef, StructDef, Typ};
+
+use convert_case::{Case, Casing};
+use log::{debug, trace};
+
+/// An abstract indentation level. 0 is no indentation, 1 is [`INDENT_WIDTH`]
+/// and so on.
+#[derive(Copy, Clone)]
+struct Indentation(usize);
+
+/// Default width of each level of indentation
+const INDENT_WIDTH: usize = 4;
+
+/// Convert an IDL type into its Rust type.
+fn typ_rs(typ: &Typ) -> String {
+    match typ {
+        Typ::Ptr(x) => format!("crate::Align64<*mut {}>", typ_rs(x)),
+        Typ::Enum(x) | Typ::Struct(x) | Typ::Bitmap(x) => x.to_case(Case::Pascal),
+        Typ::Array(x, len) => format!("[{}; {}]", typ_rs(x), len),
+        Typ::U8 => String::from("u8"),
+        Typ::U16 => String::from("u16"),
+        Typ::U32 => String::from("u32"),
+        Typ::U64 => String::from("crate::Align64<u64>"),
+        Typ::I8 => String::from("i8"),
+        Typ::I16 => String::from("i16"),
+        Typ::I32 => String::from("i32"),
+        Typ::I64 => String::from("crate::Align64<i64>"),
+    }
+}
+
+/// Add a comment to a struct or a field.
+fn comment(out: &mut String, comment: &str, ind: Indentation) {
+    let spaces = " ".repeat(INDENT_WIDTH * ind.0);
+    for line in comment.split('\n') {
+        write!(out, "{spaces}///").unwrap();
+        if !line.is_empty() {
+            write!(out, " {line}").unwrap();
+        }
+        writeln!(out).unwrap();
+    }
+}
+
+/// Perform external inclusion in the form of a Rust _use_ statement.
+fn includegen(out: &mut String, def: &IncludeDef) {
+    if def.imports.is_empty() {
+        return;
+    }
+
+    let refered_pascal: Vec<String> = def
+        .imports
+        .iter()
+        .map(|s| s.to_case(Case::Pascal))
+        .collect();
+
+    writeln!(
+        out,
+        "use super::{}::{{{}}};",
+        &def.from,
+        refered_pascal.join(",")
+    )
+    .unwrap();
+
+    writeln!(out).unwrap();
+}
+
+/// Write a Rust-compatible struct onto `out`
+fn structgen(out: &mut String, def: &StructDef) {
+    debug!("struct {}", def.name);
+
+    comment(out, &def.description, Indentation(0));
+    writeln!(out, "#[repr(C)]").unwrap();
+    writeln!(out, "#[derive(Clone, Debug, Default)]").unwrap();
+    write!(out, "pub struct {}", def.name.to_case(Case::Pascal)).unwrap();
+
+    if def.fields.is_empty() {
+        // zero-sized struct
+        writeln!(out, ";\n").unwrap();
+        return;
+    }
+
+    writeln!(out, " {{").unwrap();
+
+    for f in &def.fields {
+        trace!("  field {} type={:?}", f.name, f.typ);
+
+        comment(out, &f.description, Indentation(1));
+        writeln!(
+            out,
+            "    pub {}: {},",
+            f.name.to_case(Case::Snake),
+            typ_rs(&f.typ)
+        )
+        .unwrap();
+    }
+    writeln!(out, "}}\n").unwrap();
+}
+
+/// Write a Rust-compatible enum onto `out`
+fn enumgen(out: &mut String, def: &EnumDef) {
+    debug!("enum {}", def.name);
+
+    comment(out, &def.description, Indentation(0));
+
+    // If the underlying type is 64bits things get trickier. What we want
+    // in that case is to use u64 for the underlying type, but set
+    // align(8) on the overall repr. Otherwise 32bit platforms have the wrong
+    // alignment.
+    let repr: &str = if def.typ == Typ::U64 || def.typ == Typ::I64 {
+        "align(8)"
+    } else {
+        &typ_rs(&def.typ)
+    };
+
+    writeln!(out, "#[repr({repr})]").unwrap();
+    writeln!(out, "#[derive(Clone, Debug, Default, PartialEq, Eq)]").unwrap();
+    writeln!(out, "pub enum {} {{", def.name.to_case(Case::Pascal)).unwrap();
+    for (i, f) in def.variants.iter().enumerate() {
+        trace!("  variant {}={}", f.name, f.value);
+
+        comment(out, &f.description, Indentation(1));
+        if i == 0 {
+            writeln!(out, "    #[default]").unwrap();
+        }
+        writeln!(out, "    {} = {},", f.name.to_case(Case::Pascal), f.value).unwrap();
+    }
+    writeln!(out, "}}\n").unwrap();
+}
+
+/// Write a Rust-compatible bitmap onto `out`.
+///
+/// NOTE: Uses the bitflags crate underneath
+fn bitmapgen(out: &mut String, def: &BitmapDef) {
+    debug!("bitmap {}", def.name);
+
+    writeln!(out, "bitflags! {{").unwrap();
+    comment(out, &def.description, Indentation(1));
+
+    // If the underlying type is 64bits things get trickier. What we want
+    // in that case is to use u64 for the underlying type, but set
+    // align(8) on the overall repr.
+    let is_64bits = def.typ == Typ::U64 || def.typ == Typ::I64;
+    let repr = if is_64bits { "align(8)" } else { "C" };
+
+    writeln!(out, "    #[repr({repr})]").unwrap();
+    writeln!(
+        out,
+        "    #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]"
+    )
+    .unwrap();
+    writeln!(
+        out,
+        "    pub struct {}: {} {{",
+        def.name.from_case(Case::Snake).to_case(Case::Pascal),
+        if is_64bits {
+            "u64".to_owned()
+        } else {
+            typ_rs(&def.typ)
+        }
+    )
+    .unwrap();
+
+    for f in &def.bits {
+        trace!("  shift {}={}", f.name, f.shift);
+
+        comment(out, &f.description, Indentation(2));
+        writeln!(
+            out,
+            "        const {} = 1 << {};",
+            f.name.from_case(Case::Snake).to_case(Case::Pascal),
+            f.shift
+        )
+        .unwrap();
+    }
+    writeln!(out, "    }}").unwrap();
+
+    writeln!(out, "}}\n").unwrap();
+}
+
+/// Generates a single `.rs` file.
+///
+/// `filedef` is a language-agnostic high level description of what the output
+/// must contain. The function returns the contents of the new
+///
+/// # Aborts
+/// Aborts the process with `rc=1` on known illegal specifications.
+pub fn parse(filedef: &OutFileDef) -> String {
+    let mut out = String::new();
+
+    writeln!(out, "//! {}", &filedef.name).unwrap();
+    writeln!(out, "//!").unwrap();
+    writeln!(out, "//! AUTOGENERATED. DO NOT MODIFY").unwrap();
+    writeln!(out).unwrap();
+
+    if !filedef.bitmaps.is_empty() {
+        writeln!(out, "use bitflags::bitflags;\n").unwrap();
+    }
+
+    for def in &filedef.includes {
+        includegen(&mut out, def);
+    }
+
+    for def in &filedef.bitmaps {
+        bitmapgen(&mut out, def);
+    }
+
+    for def in &filedef.enums {
+        enumgen(&mut out, def);
+    }
+
+    for def in &filedef.structs {
+        structgen(&mut out, def);
+    }
+
+    out
+}
-- 
2.47.0



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

* [RFC PATCH 22/25] tools/xen-sys: Add autogenerated Rust files
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
                   ` (20 preceding siblings ...)
  2024-11-15 11:51 ` [RFC PATCH 21/25] tools/xenbindgen: Add Rust backend to xenbindgen Alejandro Vallejo
@ 2024-11-15 11:51 ` Alejandro Vallejo
  2024-11-15 11:51 ` [RFC PATCH 23/25] licence: Add Unicode-DFS-2016 to the list of licences Alejandro Vallejo
                   ` (3 subsequent siblings)
  25 siblings, 0 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel; +Cc: Alejandro Vallejo, Anthony PERARD, Daniel P. Smith

And a single autogen.rs file to demultiplex the arch module into
whatever arch-specific target is mandated by target_arch.

Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
 tools/rust/xen-sys/src/autogen.rs            |  27 +++++
 tools/rust/xen-sys/src/autogen/arch_arm.rs   |  56 ++++++++++
 tools/rust/xen-sys/src/autogen/arch_ppc.rs   |   8 ++
 tools/rust/xen-sys/src/autogen/arch_riscv.rs |   8 ++
 tools/rust/xen-sys/src/autogen/arch_x86.rs   |  55 ++++++++++
 tools/rust/xen-sys/src/autogen/domctl.rs     | 104 +++++++++++++++++++
 tools/rust/xen-sys/src/autogen/sysctl.rs     |  26 +++++
 tools/rust/xen-sys/src/lib.rs                |   2 +
 8 files changed, 286 insertions(+)
 create mode 100644 tools/rust/xen-sys/src/autogen.rs
 create mode 100644 tools/rust/xen-sys/src/autogen/arch_arm.rs
 create mode 100644 tools/rust/xen-sys/src/autogen/arch_ppc.rs
 create mode 100644 tools/rust/xen-sys/src/autogen/arch_riscv.rs
 create mode 100644 tools/rust/xen-sys/src/autogen/arch_x86.rs
 create mode 100644 tools/rust/xen-sys/src/autogen/domctl.rs
 create mode 100644 tools/rust/xen-sys/src/autogen/sysctl.rs

diff --git a/tools/rust/xen-sys/src/autogen.rs b/tools/rust/xen-sys/src/autogen.rs
new file mode 100644
index 000000000000..8a1cab8561f2
--- /dev/null
+++ b/tools/rust/xen-sys/src/autogen.rs
@@ -0,0 +1,27 @@
+//! Low-level description of buffers as used in hypercalls with the Xen hypervisor
+//!
+//! This module is fully autogenerated from TOML files defining the hypercall
+//! specification.
+
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+pub mod arch_x86;
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+pub use arch_x86 as arch;
+
+#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
+pub mod arch_arm;
+#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
+pub use arch_arm as arch;
+
+#[cfg(target_arch = "riscv64")]
+pub mod arch_riscv;
+#[cfg(target_arch = "riscv64")]
+pub use arch_riscv as arch;
+
+#[cfg(target_arch = "powerpc64")]
+pub mod arch_ppc;
+#[cfg(target_arch = "powerpc64")]
+pub use arch_ppc as arch;
+
+pub mod domctl;
+pub mod sysctl;
diff --git a/tools/rust/xen-sys/src/autogen/arch_arm.rs b/tools/rust/xen-sys/src/autogen/arch_arm.rs
new file mode 100644
index 000000000000..dc460557b2f0
--- /dev/null
+++ b/tools/rust/xen-sys/src/autogen/arch_arm.rs
@@ -0,0 +1,56 @@
+//! arch-arm
+//!
+//! AUTOGENERATED. DO NOT MODIFY
+
+/// Content of the `gic_version` field of the domainconfig struct.
+#[repr(u8)]
+#[derive(Clone, Debug, Default, PartialEq, Eq)]
+pub enum XenDomctlConfigGic {
+    /// Emulate the underlying GIC present in the current host.
+    #[default]
+    Native = 0,
+    /// Emulate a GICv2.
+    V2 = 1,
+    /// Emulate a GICv3.
+    V3 = 2,
+}
+
+/// TEE mediator exposed to the guest
+#[repr(u16)]
+#[derive(Clone, Debug, Default, PartialEq, Eq)]
+pub enum XenDomctlConfigTee {
+    /// No mediator. Guest can't communicate with the TEE.
+    #[default]
+    None = 0,
+    /// Expose an OP-TEE mediator.
+    Optee = 1,
+    /// Expose an FF-A mediator.
+    Ffa = 2,
+}
+
+/// arm-specific domain settings.
+#[repr(C)]
+#[derive(Clone, Debug, Default)]
+pub struct XenArchDomainconfig {
+    /// IN/OUT: GIC version exposed to the guest.
+    ///
+    /// When `native` on input the output value holds the automatically chosen version.
+    pub gic_version: XenDomctlConfigGic,
+    /// IN: SVE vector length (divided by 128) exposed to the guest.
+    pub sve_vl: u8,
+    /// IN: TEE mediator exposed to the guest.
+    pub tee_type: XenDomctlConfigTee,
+    /// IN: Number of SPIs exposed to the guest.
+    pub nr_spis: u32,
+    /// OUT
+    /// Based on the property clock-frequency in the DT timer node.
+    /// The property may be present when the bootloader/firmware doesn't
+    /// set correctly CNTFRQ which hold the timer frequency.
+    ///
+    /// As it's not possible to trap this register, we have to replicate
+    /// the value in the guest DT.
+    ///
+    /// = 0 => property not present
+    /// > 0 => Value of the property
+    pub clock_frequency: u32,
+}
diff --git a/tools/rust/xen-sys/src/autogen/arch_ppc.rs b/tools/rust/xen-sys/src/autogen/arch_ppc.rs
new file mode 100644
index 000000000000..8b68799648b9
--- /dev/null
+++ b/tools/rust/xen-sys/src/autogen/arch_ppc.rs
@@ -0,0 +1,8 @@
+//! arch-ppc
+//!
+//! AUTOGENERATED. DO NOT MODIFY
+
+/// ppc-specific domain settings.
+#[repr(C)]
+#[derive(Clone, Debug, Default)]
+pub struct XenArchDomainconfig;
diff --git a/tools/rust/xen-sys/src/autogen/arch_riscv.rs b/tools/rust/xen-sys/src/autogen/arch_riscv.rs
new file mode 100644
index 000000000000..1a68c7a02c7f
--- /dev/null
+++ b/tools/rust/xen-sys/src/autogen/arch_riscv.rs
@@ -0,0 +1,8 @@
+//! arch-riscv
+//!
+//! AUTOGENERATED. DO NOT MODIFY
+
+/// riscv-specific domain settings.
+#[repr(C)]
+#[derive(Clone, Debug, Default)]
+pub struct XenArchDomainconfig;
diff --git a/tools/rust/xen-sys/src/autogen/arch_x86.rs b/tools/rust/xen-sys/src/autogen/arch_x86.rs
new file mode 100644
index 000000000000..d63a3920c91e
--- /dev/null
+++ b/tools/rust/xen-sys/src/autogen/arch_x86.rs
@@ -0,0 +1,55 @@
+//! arch-x86
+//!
+//! AUTOGENERATED. DO NOT MODIFY
+
+use bitflags::bitflags;
+
+bitflags! {
+    /// Content of the `emulation_flags` field of the domain creation hypercall.
+    #[repr(C)]
+    #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
+    pub struct XenX86Emu: u32 {
+        /// Emulate Local APICs.
+        const Lapic = 1 << 0;
+        /// Emulate a HPET timer.
+        const Hpet = 1 << 1;
+        /// Emulate the ACPI PM timer.
+        const Pm = 1 << 2;
+        /// Emulate the RTC clock.
+        const Rtc = 1 << 3;
+        /// Emulate an IOAPIC device.
+        const Ioapic = 1 << 4;
+        /// Emulate PIC devices.
+        const Pic = 1 << 5;
+        /// Emulate standard VGA.
+        const Vga = 1 << 6;
+        /// Emulate an IOMMU.
+        const Iommu = 1 << 7;
+        /// Emulate a PIT timer.
+        const Pit = 1 << 8;
+        /// Route physical IRQs over event channels.
+        const UsePirq = 1 << 9;
+        /// Handle PCI configuration space traps from within Xen.
+        const Vpci = 1 << 10;
+    }
+}
+
+bitflags! {
+    /// Contents of the `misc_flags` field of the domain creation hypercall
+    #[repr(C)]
+    #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
+    pub struct XenX86Misc: u32 {
+        /// Grants access to the real physical MSR registers of the host.
+        const MsrRelaxed = 1 << 0;
+    }
+}
+
+/// x86-specific domain settings.
+#[repr(C)]
+#[derive(Clone, Debug, Default)]
+pub struct XenArchDomainconfig {
+    /// IN: Bitmap of devices to emulate.
+    pub emulation_flags: XenX86Emu,
+    /// IN: Miscellaneous x86-specific toggles.
+    pub misc_flags: XenX86Misc,
+}
diff --git a/tools/rust/xen-sys/src/autogen/domctl.rs b/tools/rust/xen-sys/src/autogen/domctl.rs
new file mode 100644
index 000000000000..7c3b872409be
--- /dev/null
+++ b/tools/rust/xen-sys/src/autogen/domctl.rs
@@ -0,0 +1,104 @@
+//! domctl
+//!
+//! AUTOGENERATED. DO NOT MODIFY
+
+use bitflags::bitflags;
+
+use super::arch::XenArchDomainconfig;
+
+bitflags! {
+    /// Content of the `flags` field of the domain creation hypercall.
+    #[repr(C)]
+    #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
+    pub struct XenDomctlCdf: u32 {
+        /// Set if this is an HVM guest. Cleared if it's PV.
+        const Hvm = 1 << 0;
+        /// Use hardware-assisted paging if available
+        const Hap = 1 << 1;
+        /// Set if domain memory integrity is to be verified by tboot during Sx.
+        const S3Integrity = 1 << 2;
+        /// Set if Out-of-Sync shadow page tables are to be disabled
+        const OosOff = 1 << 3;
+        /// Set if this is a xenstore domain
+        const XsDomain = 1 << 4;
+        /// Set if this is domain can make use of the IOMMU
+        const Iommu = 1 << 5;
+        /// Set for the domain to have nested virtualization enabled.
+        const NestedVirt = 1 << 6;
+        /// Set to expose a vPMU to this domain.
+        const Vpmu = 1 << 7;
+    }
+}
+
+bitflags! {
+    /// Content of the `iommu_opts` field of the domain creation hypercall.
+    #[repr(C)]
+    #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
+    pub struct XenDomctlIommuOpts: u32 {
+        /// Set to _NOT_ share page tables between the CPU and the IOMMU when it would be possible to do so.
+        const NoSharept = 1 << 0;
+    }
+}
+
+/// Content of the `altp2m_mode` field of the domain creation hypercall.
+#[repr(u8)]
+#[derive(Clone, Debug, Default, PartialEq, Eq)]
+pub enum XenDomctlAltp2MMode {
+    /// Keep altp2m disabled
+    #[default]
+    Disabled = 0,
+    /// Use mixed-mode for the altp2m (not yet evaluated for safety).
+    Mixed = 1,
+    /// Use external mode for the altp2m.
+    External = 2,
+    /// Use limited mode for the altp2m.
+    Limited = 3,
+}
+
+/// Create a new domain with the passed parameters.
+///
+/// IMPORTANT: The domid part of the domctl is IN/OUT. When the passed
+/// domid is 0 or over `DOMID_FIRST_RESERVED` a new domid is auto-allocated
+/// and returned.
+#[repr(C)]
+#[derive(Clone, Debug, Default)]
+pub struct XenDomctlCreatedomain {
+    /// IN: `Source Security IDentifier` (See XSM).
+    pub ssidref: u32,
+    /// IN: Unique identifier for this guest given by the toolstack.
+    pub handle: [u8; 16],
+    /// IN: Bitmap of domain features to enable/disable.
+    pub flags: XenDomctlCdf,
+    /// IN: Bitmap of configuration settings for the IOMMU.
+    pub iommu_opts: XenDomctlIommuOpts,
+    /// IN: Maximum number of CPUs this domain can hold, including hotplug.
+    pub max_vcpus: u32,
+    /// IN: Maximum number of usable event channels
+    pub max_evtchn_port: u32,
+    /// IN: Maximum number of pages this domain is able
+    ///     to grant access to for other domains.
+    ///
+    /// `< 0` means "use default value in the hypervisor."
+    pub max_grant_frames: i32,
+    /// IN: Maximum number of pages of foreign domains
+    ///     can be accessed via the grant mechanism.
+    ///
+    /// `< 0` means "use default value in the hypervisor."
+    pub max_maptrack_frames: i32,
+    /// Maximum grant table version allowed for this domain
+    pub max_grant_version: u8,
+    /// Unused padding. Reserved to zero.
+    pub rsvd_0_a: [u8; 3],
+    /// Which mode to configure altp2m with
+    pub altp_2_m_mode: u8,
+    /// Unused padding. Reserved to zero.
+    pub rsvd_0_b: [u8; 3],
+    /// IN: Per-vCPU buffer size in octets. 0 to disable.
+    pub vmtrace_size: u32,
+    /// IN: CPU pool to use; 0 or an existing CPU pool.
+    pub cpupool_id: u32,
+    /// Arch-specific settings.
+    ///
+    /// Each architecture is free to make its fields IN/OUT/INOUT
+    pub arch: XenArchDomainconfig,
+}
diff --git a/tools/rust/xen-sys/src/autogen/sysctl.rs b/tools/rust/xen-sys/src/autogen/sysctl.rs
new file mode 100644
index 000000000000..a2d8beb91d84
--- /dev/null
+++ b/tools/rust/xen-sys/src/autogen/sysctl.rs
@@ -0,0 +1,26 @@
+//! sysctl
+//!
+//! AUTOGENERATED. DO NOT MODIFY
+
+/// Read console content from Xen buffer ring.
+#[repr(C)]
+#[derive(Clone, Debug, Default)]
+pub struct XenSysctlReadconsole {
+    /// IN: Non-zero -> clear after reading.
+    pub clear: u8,
+    /// IN: Non-zero -> start index specified by `index` field.
+    pub incremental: u8,
+    /// Unused.
+    pub pad: u16,
+    /// IN:  Start index for consuming from ring buffer (if @incremental);
+    /// OUT: End index after consuming from ring buffer.
+    pub index: u32,
+    /// IN: Virtual address to write console data.
+    ///
+    /// NOTE: The pointer itself is IN, but the contents of the buffer are OUT.
+    pub buffer: crate::Align64<*mut u8>,
+    /// IN: Size of buffer; OUT: Bytes written to buffer.
+    pub count: u32,
+    /// Tail padding reserved to zero.
+    pub rsvd_0_a: u32,
+}
diff --git a/tools/rust/xen-sys/src/lib.rs b/tools/rust/xen-sys/src/lib.rs
index efab54ee1025..526193a920f8 100644
--- a/tools/rust/xen-sys/src/lib.rs
+++ b/tools/rust/xen-sys/src/lib.rs
@@ -7,6 +7,8 @@
 
 pub mod autogen;
 
+pub use autogen::*;
+
 use core::ops::{Deref, DerefMut};
 
 /// Wrapper for pointers and 64bit integers so they are _always_ aligned to 8
-- 
2.47.0



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

* [RFC PATCH 23/25] licence: Add Unicode-DFS-2016 to the list of licences
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
                   ` (21 preceding siblings ...)
  2024-11-15 11:51 ` [RFC PATCH 22/25] tools/xen-sys: Add autogenerated Rust files Alejandro Vallejo
@ 2024-11-15 11:51 ` Alejandro Vallejo
  2024-11-15 11:51 ` [RFC PATCH 24/25] tools/rust: Add deny.toml Alejandro Vallejo
                   ` (2 subsequent siblings)
  25 siblings, 0 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel
  Cc: Alejandro Vallejo, Andrew Cooper, Jan Beulich, Julien Grall,
	Stefano Stabellini

It's transitively reached by Rust code.

Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
 LICENSES/Unicode-DFS-2016 | 56 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)
 create mode 100644 LICENSES/Unicode-DFS-2016

diff --git a/LICENSES/Unicode-DFS-2016 b/LICENSES/Unicode-DFS-2016
new file mode 100644
index 000000000000..eca277f05e0e
--- /dev/null
+++ b/LICENSES/Unicode-DFS-2016
@@ -0,0 +1,56 @@
+UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
+
+See Terms of Use for definitions of Unicode Inc.'s Data Files and Software.
+
+Unicode Data Files include all data files under the directories
+http://www.unicode.org/Public/, http://www.unicode.org/reports/,
+http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/,
+http://www.unicode.org/ivd/data/, and
+http://www.unicode.org/utility/trac/browser/.
+
+Unicode Data Files do not include PDF online code charts under the directory
+http://www.unicode.org/Public/.
+
+Software includes any source code published in the Unicode Standard or under
+the directories http://www.unicode.org/Public/,
+http://www.unicode.org/reports/, http://www.unicode.org/cldr/data/,
+http://source.icu-project.org/repos/icu/, and
+http://www.unicode.org/utility/trac/browser/.
+
+NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING,
+INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA FILES ("DATA
+FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO
+BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT
+AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR
+SOFTWARE.
+
+COPYRIGHT AND PERMISSION NOTICE
+
+Copyright © 1991-2016 Unicode, Inc. All rights reserved. Distributed under the
+Terms of Use in http://www.unicode.org/copyright.html.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of the Unicode data files and any associated documentation (the "Data Files")
+or Unicode software and any associated documentation (the "Software") to deal
+in the Data Files or Software without restriction, including without
+limitation the rights to use, copy, modify, merge, publish, distribute, and/or
+sell copies of the Data Files or Software, and to permit persons to whom the
+Data Files or Software are furnished to do so, provided that either
+
+  * (a) this copyright and permission notice appear with all copies of the Data Files or Software, or 
+  * (b) this copyright and permission notice appear in associated Documentation. 
+
+THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD
+PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
+THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
+DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE
+DATA FILES OR SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder shall not
+be used in advertising or otherwise to promote the sale, use or other dealings
+in these Data Files or Software without prior written authorization of the
+copyright holder.
-- 
2.47.0



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

* [RFC PATCH 24/25] tools/rust: Add deny.toml
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
                   ` (22 preceding siblings ...)
  2024-11-15 11:51 ` [RFC PATCH 23/25] licence: Add Unicode-DFS-2016 to the list of licences Alejandro Vallejo
@ 2024-11-15 11:51 ` Alejandro Vallejo
  2024-11-15 11:51 ` [RFC PATCH 25/25] ci: Add a CI checker for Rust-related helpful properties Alejandro Vallejo
  2024-11-21 17:46 ` [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Anthony PERARD
  25 siblings, 0 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel; +Cc: Alejandro Vallejo, Anthony PERARD

deny.toml allows auditing transitive dependencies and allowed licences.
In particular it allows the use of cargo-deny for all Rust project.

Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
 tools/rust/deny.toml | 236 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 236 insertions(+)
 create mode 100644 tools/rust/deny.toml

diff --git a/tools/rust/deny.toml b/tools/rust/deny.toml
new file mode 100644
index 000000000000..1b74553569a7
--- /dev/null
+++ b/tools/rust/deny.toml
@@ -0,0 +1,236 @@
+# This template contains all of the possible sections and their default values
+
+# Note that all fields that take a lint level have these possible values:
+# * deny - An error will be produced and the check will fail
+# * warn - A warning will be produced, but the check will not fail
+# * allow - No warning or error will be produced, though in some cases a note
+# will be
+
+# The values provided in this template are the default values that will be used
+# when any section or field is not specified in your own configuration
+
+# Root options
+
+# The graph table configures how the dependency graph is constructed and thus
+# which crates the checks are performed against
+[graph]
+# If 1 or more target triples (and optionally, target_features) are specified,
+# only the specified targets will be checked when running `cargo deny check`.
+# This means, if a particular package is only ever used as a target specific
+# dependency, such as, for example, the `nix` crate only being used via the
+# `target_family = "unix"` configuration, that only having windows targets in
+# this list would mean the nix crate, as well as any of its exclusive
+# dependencies not shared by any other crates, would be ignored, as the target
+# list here is effectively saying which targets you are building for.
+targets = [
+    # The triple can be any string, but only the target triples built in to
+    # rustc (as of 1.40) can be checked against actual config expressions
+    #"x86_64-unknown-linux-musl",
+    # You can also specify which target_features you promise are enabled for a
+    # particular target. target_features are currently not validated against
+    # the actual valid features supported by the target architecture.
+    #{ triple = "wasm32-unknown-unknown", features = ["atomics"] },
+]
+# When creating the dependency graph used as the source of truth when checks are
+# executed, this field can be used to prune crates from the graph, removing them
+# from the view of cargo-deny. This is an extremely heavy hammer, as if a crate
+# is pruned from the graph, all of its dependencies will also be pruned unless
+# they are connected to another crate in the graph that hasn't been pruned,
+# so it should be used with care. The identifiers are [Package ID Specifications]
+# (https://doc.rust-lang.org/cargo/reference/pkgid-spec.html)
+#exclude = []
+# If true, metadata will be collected with `--all-features`. Note that this can't
+# be toggled off if true, if you want to conditionally enable `--all-features` it
+# is recommended to pass `--all-features` on the cmd line instead
+all-features = false
+# If true, metadata will be collected with `--no-default-features`. The same
+# caveat with `all-features` applies
+no-default-features = false
+# If set, these feature will be enabled when collecting metadata. If `--features`
+# is specified on the cmd line they will take precedence over this option.
+#features = []
+
+# The output table provides options for how/if diagnostics are outputted
+[output]
+# When outputting inclusion graphs in diagnostics that include features, this
+# option can be used to specify the depth at which feature edges will be added.
+# This option is included since the graphs can be quite large and the addition
+# of features from the crate(s) to all of the graph roots can be far too verbose.
+# This option can be overridden via `--feature-depth` on the cmd line
+feature-depth = 1
+
+# This section is considered when running `cargo deny check advisories`
+# More documentation for the advisories section can be found here:
+# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html
+[advisories]
+# The path where the advisory databases are cloned/fetched into
+#db-path = "$CARGO_HOME/advisory-dbs"
+# The url(s) of the advisory databases to use
+#db-urls = ["https://github.com/rustsec/advisory-db"]
+# A list of advisory IDs to ignore. Note that ignored advisories will still
+# output a note when they are encountered.
+ignore = [
+    #"RUSTSEC-0000-0000",
+    #{ id = "RUSTSEC-0000-0000", reason = "you can specify a reason the advisory is ignored" },
+    #"a-crate-that-is-yanked@0.1.1", # you can also ignore yanked crate versions if you wish
+    #{ crate = "a-crate-that-is-yanked@0.1.1", reason = "you can specify why you are ignoring the yanked crate" },
+]
+# If this is true, then cargo deny will use the git executable to fetch advisory database.
+# If this is false, then it uses a built-in git library.
+# Setting this to true can be helpful if you have special authentication requirements that cargo-deny does not support.
+# See Git Authentication for more information about setting up git authentication.
+#git-fetch-with-cli = true
+
+# This section is considered when running `cargo deny check licenses`
+# More documentation for the licenses section can be found here:
+# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html
+[licenses]
+# List of explicitly allowed licenses
+# See https://spdx.org/licenses/ for list of possible licenses
+# [possible values: any SPDX 3.11 short identifier (+ optional exception)].
+allow = [
+    "MIT",
+    "Apache-2.0",
+    "Unicode-DFS-2016",
+    #"Apache-2.0 WITH LLVM-exception",
+]
+# The confidence threshold for detecting a license from license text.
+# The higher the value, the more closely the license text must be to the
+# canonical license text of a valid SPDX license file.
+# [possible values: any between 0.0 and 1.0].
+confidence-threshold = 0.8
+# Allow 1 or more licenses on a per-crate basis, so that particular licenses
+# aren't accepted for every possible crate as with the normal allow list
+exceptions = [
+    # Each entry is the crate and version constraint, and its specific allow
+    # list
+    #{ allow = ["Zlib"], crate = "adler32" },
+]
+
+# Some crates don't have (easily) machine readable licensing information,
+# adding a clarification entry for it allows you to manually specify the
+# licensing information
+#[[licenses.clarify]]
+# The package spec the clarification applies to
+#crate = "ring"
+# The SPDX expression for the license requirements of the crate
+#expression = "MIT AND ISC AND OpenSSL"
+# One or more files in the crate's source used as the "source of truth" for
+# the license expression. If the contents match, the clarification will be used
+# when running the license check, otherwise the clarification will be ignored
+# and the crate will be checked normally, which may produce warnings or errors
+# depending on the rest of your configuration
+#license-files = [
+# Each entry is a crate relative path, and the (opaque) hash of its contents
+#{ path = "LICENSE", hash = 0xbd0eed23 }
+#]
+
+[licenses.private]
+# If true, ignores workspace crates that aren't published, or are only
+# published to private registries.
+# To see how to mark a crate as unpublished (to the official registry),
+# visit https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field.
+ignore = false
+# One or more private registries that you might publish crates to, if a crate
+# is only published to private registries, and ignore is true, the crate will
+# not have its license(s) checked
+registries = [
+    #"https://sekretz.com/registry
+]
+
+# This section is considered when running `cargo deny check bans`.
+# More documentation about the 'bans' section can be found here:
+# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html
+[bans]
+# Lint level for when multiple versions of the same crate are detected
+multiple-versions = "warn"
+# Lint level for when a crate version requirement is `*`
+wildcards = "deny"
+# The graph highlighting used when creating dotgraphs for crates
+# with multiple versions
+# * lowest-version - The path to the lowest versioned duplicate is highlighted
+# * simplest-path - The path to the version with the fewest edges is highlighted
+# * all - Both lowest-version and simplest-path are used
+highlight = "all"
+# The default lint level for `default` features for crates that are members of
+# the workspace that is being checked. This can be overridden by allowing/denying
+# `default` on a crate-by-crate basis if desired.
+workspace-default-features = "allow"
+# The default lint level for `default` features for external crates that are not
+# members of the workspace. This can be overridden by allowing/denying `default`
+# on a crate-by-crate basis if desired.
+external-default-features = "allow"
+# List of crates that are allowed. Use with care!
+allow = [
+    #"ansi_term@0.11.0",
+    #{ crate = "ansi_term@0.11.0", reason = "you can specify a reason it is allowed" },
+]
+# List of crates to deny
+deny = [
+    #"ansi_term@0.11.0",
+    #{ crate = "ansi_term@0.11.0", reason = "you can specify a reason it is banned" },
+    # Wrapper crates can optionally be specified to allow the crate when it
+    # is a direct dependency of the otherwise banned crate
+    #{ crate = "ansi_term@0.11.0", wrappers = ["this-crate-directly-depends-on-ansi_term"] },
+]
+
+# List of features to allow/deny
+# Each entry the name of a crate and a version range. If version is
+# not specified, all versions will be matched.
+#[[bans.features]]
+#crate = "reqwest"
+# Features to not allow
+#deny = ["json"]
+# Features to allow
+#allow = [
+#    "rustls",
+#    "__rustls",
+#    "__tls",
+#    "hyper-rustls",
+#    "rustls",
+#    "rustls-pemfile",
+#    "rustls-tls-webpki-roots",
+#    "tokio-rustls",
+#    "webpki-roots",
+#]
+# If true, the allowed features must exactly match the enabled feature set. If
+# this is set there is no point setting `deny`
+#exact = true
+
+# Certain crates/versions that will be skipped when doing duplicate detection.
+skip = [
+    #"ansi_term@0.11.0",
+    #{ crate = "ansi_term@0.11.0", reason = "you can specify a reason why it can't be updated/removed" },
+]
+# Similarly to `skip` allows you to skip certain crates during duplicate
+# detection. Unlike skip, it also includes the entire tree of transitive
+# dependencies starting at the specified crate, up to a certain depth, which is
+# by default infinite.
+skip-tree = [
+    #"ansi_term@0.11.0", # will be skipped along with _all_ of its direct and transitive dependencies
+    #{ crate = "ansi_term@0.11.0", depth = 20 },
+]
+
+# This section is considered when running `cargo deny check sources`.
+# More documentation about the 'sources' section can be found here:
+# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html
+[sources]
+# Lint level for what to happen when a crate from a crate registry that is not
+# in the allow list is encountered
+unknown-registry = "deny"
+# Lint level for what to happen when a crate from a git repository that is not
+# in the allow list is encountered
+unknown-git = "deny"
+# List of URLs for allowed crate registries. Defaults to the crates.io index
+# if not specified. If it is specified but empty, no registries are allowed.
+allow-registry = ["https://github.com/rust-lang/crates.io-index"]
+# List of URLs for allowed Git repositories
+allow-git = []
+
+[sources.allow-org]
+# 1 or more github.com organizations to allow git sources for
+#github = [""]
+# 1 or more gitlab.com organizations to allow git sources for
+#gitlab = [""]
+# 1 or more bitbucket.org organizations to allow git sources for
+#bitbucket = [""]
-- 
2.47.0



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

* [RFC PATCH 25/25] ci: Add a CI checker for Rust-related helpful properties
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
                   ` (23 preceding siblings ...)
  2024-11-15 11:51 ` [RFC PATCH 24/25] tools/rust: Add deny.toml Alejandro Vallejo
@ 2024-11-15 11:51 ` Alejandro Vallejo
  2024-11-21 17:46 ` [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Anthony PERARD
  25 siblings, 0 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-15 11:51 UTC (permalink / raw)
  To: xen-devel
  Cc: Alejandro Vallejo, Doug Goldstein, Stefano Stabellini,
	Anthony PERARD

Checks in both xenbindgen and xen-sys (including autogenerated headers) that:

 * Autogenerated files are in sync with the specification files.
 * Specification files abide by certain ABI rules (e.g: no padding).
 * Clippy and rustfmt are happy with the every .rs file.
 * All transitive licences are accounted for (cargo-deny).
 * No transitive dependency has outstanding security advisories (cargo-deny)

Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
 automation/gitlab-ci/analyze.yaml | 14 ++++++++++++++
 tools/rust/Makefile               | 26 +++++++++++++++++++++++++-
 2 files changed, 39 insertions(+), 1 deletion(-)

diff --git a/automation/gitlab-ci/analyze.yaml b/automation/gitlab-ci/analyze.yaml
index 02e0ea692c66..c63c909fe175 100644
--- a/automation/gitlab-ci/analyze.yaml
+++ b/automation/gitlab-ci/analyze.yaml
@@ -72,3 +72,17 @@ eclair-ARM64:on-schedule:
     ANALYSIS_KIND: "${RULESET}-scheduled"
     LOGFILE: "eclair-${VARIANT}-${RULESET}.log"
   allow_failure: true
+
+rust-verify:
+  stage: analyze
+  image: rust:latest # FIXME: Create and use dedicated container
+  script:
+    - rustup component add clippy rustfmt
+    - cargo install cargo-deny
+    - make -C tools/rust verify 2>&1 | tee rust-verify.log
+  artifacts:
+    when: always
+    paths:
+      - '*.log'
+  needs: []
+
diff --git a/tools/rust/Makefile b/tools/rust/Makefile
index 4f064c37f45c..602722f9d9cc 100644
--- a/tools/rust/Makefile
+++ b/tools/rust/Makefile
@@ -45,8 +45,33 @@ update: clean-autogen
 	          --indir "${XENBINDGEN}/extra" --outdir "${AUTOGEN_C}"
 
 # Verify Rust crates pass lint checks. This is enforced in CI
+#
+# Also ensures autogenerated files are up to date with TOML files. Generation
+# is done at commit time rather than build time to avoid a hard dependency on
+# the Rust toolchain.
 .PHONY: verify
 verify:
+	@echo "Checking autogenerated C headers to be consistent with TOML"
+	OUTDIR=`mktemp -d /tmp/xenbindgen-XXXXXXX`; \
+	cargo run --manifest-path "${XENBINDGEN}/Cargo.toml" -- --lang c \
+	          --indir "${XENBINDGEN}/extra" --outdir "$${OUTDIR}"; \
+	if ! diff -r "$${OUTDIR}" "${AUTOGEN_C}"; then \
+	    rm -rf "$${OUTDIR}"; \
+	    exit 1; \
+	fi; \
+	rm -rf "$${OUTDIR}"
+	
+	@echo "Checking autogenerated Rust files to be consistent with TOML"
+	OUTDIR=`mktemp -d /tmp/xenbindgen-XXXXXXX`; \
+	cargo run --manifest-path "${XENBINDGEN}/Cargo.toml" -- --lang rust \
+	          --indir "${XENBINDGEN}/extra" --outdir "$${OUTDIR}"; \
+	rustfmt $$( find "$${OUTDIR}" -name "*.rs" ); \
+	if ! diff -r "$${OUTDIR}" "${AUTOGEN_RS}"; then \
+	    rm -rf "$${OUTDIR}"; \
+	    exit 1; \
+	fi; \
+	rm -rf "$${OUTDIR}"
+	
 	set -eu; \
 	for i in "${CRATE_XENSYS}" "${XENBINDGEN}"; do \
 	    echo "Verifying $$i"; \
@@ -56,4 +81,3 @@ verify:
 	    cargo deny check; \
 	    cd -; \
 	done
-
-- 
2.47.0



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

* Re: [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs
  2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
                   ` (24 preceding siblings ...)
  2024-11-15 11:51 ` [RFC PATCH 25/25] ci: Add a CI checker for Rust-related helpful properties Alejandro Vallejo
@ 2024-11-21 17:46 ` Anthony PERARD
  2024-11-22 10:52   ` Teddy Astie
  2024-11-22 13:12   ` Alejandro Vallejo
  25 siblings, 2 replies; 51+ messages in thread
From: Anthony PERARD @ 2024-11-21 17:46 UTC (permalink / raw)
  To: Alejandro Vallejo
  Cc: xen-devel, Juergen Gross, Julien Grall, Andrew Cooper,
	Jan Beulich, Stefano Stabellini, Christian Lindig, David Scott,
	Marek Marczykowski-Górecki, Bertrand Marquis, Michal Orzel,
	Volodymyr Babchuk, Roger Pau Monné, Samuel Thibault,
	Daniel P. Smith, Tim Deegan, Lukasz Hawrylko, Mateusz Mówka,
	Doug Goldstein, Teddy Astie, Yann Dirson

Hi Alejandro,

Nice work :-).

On Fri, Nov 15, 2024 at 11:51:29AM +0000, Alejandro Vallejo wrote:
> This series is the result of my "Interfacing Rust with Xen" talk in Xen Summit.
> It adds a hypercall ABI IDL parser and generator to the xen tree, replaces a
> couple of existing hypercalls, creates a Rust crate with autogenerated contents
> an creates a CI job to ensure nothing goes out of sync.
>
> The changes are fairly invasive because the various autogenerated items appear
> in many places (specially the domaincreate flags). However, the changes to the
> hypervisor are all mechanical and not functional (not intentionally so, at
> least).

I tried to build QEMU with this series applied, and the build failed. In
this case nothing important, the "autogen" directory just need to be
installed. But I fear the changes introduce to the API (like change
of case for the flags) will also be done to other API that project
outside of the xen repo use, and thus introduce unneeded breakage.
Should the changes also introduce a compatibility with the previous API?

> I've split the generator in reasonably small pieces, but it's still not a small
> tool. The Rust backend remains monolithic in a single patch until the RFC goes
> further. It mirrors the C backend for the most part.
> 
> The hypercall ABI is specified in a schema of TOML. Most of it should be fairly
> obvious as to what it does and means, with the possible exception of the "typ"
> field. That has the look of a dictionary because that helps the deserializer to
> automatically resolve the typ to a convenient Rust enum type (Typ). In time,
> that will become something nicer to write, but that's fairly far in my list of
> priorities at the moment.

Instead of creating your own IDL specification, did you look for
existing project that would do just that? That is been able to describe
the existing ABI in IDL and use an existing project to generate C and
Rust headers.

I kind of look into this, but there's quite a few project to explore and
I didn't really spend enough time. Also, there's probably quite a lot
that are for client-server interfaces rather than syscall/hypercalls, or
they impose a data format.


Next, on the file format choice, is TOML the best for describing an ABI,
or would other existing file format make it a bit easier to read, like
JSON or YAML? (I quite like using YAML so I have a bias toward it :-),
and that's the format used for the CI). I don't think it mater much for
Serde which file format is used.

> After the series sysctl::readconsole and domctl::createdomain are autogenerated
> from their formalized forms. In the course of formalizing the ABI it became
> apparent readconsole has a different ABI in 32 and 64 bits. While benign in
> that particular case, it's yet one more reason to formalize the ABI in a
> language agnostic way and have it machine-checked.
> 
> ======== The Plan ===========
> 
> So, the idea of the series is to adjust 2 meaningful hypercalls to TOML-based
> specifications (sysctl::readconsole and domctl::createdomain). The series is
> organised in the following chunks of work
> 
>   1. Sanitise domctl::createdomain to remove packed subfields.
>   2. Introduce xenbindgen (IDL parser and generator for C).
>   3. Specify hypercalls in TOML, and replace the hand-crafted public bits.
>   4. Introduce Rust generator for xenbindgen.
>   5. Introduce a xen-sys crate, with the autogenerated Rust constructs.
>   6. Introduce CI checks for Rust linters, ABI validation and autogenerated
>      file consistency.
> 
> Future work involves migrating more hypercalls, in the same way patch 12 does.
> Most hypercalls should not take the amount of churn createdomain did. With the
> foundations laid down the involved work should be simple.
> 
> I have considered integrating the hypercall generation in the build process.
> That forces the Rust toolchain to be in the list of build dependencies for
> downstreams, which might be complicated or annoying. For the time being, I
> think checking in the autogenerated files and confirming in CI that they are
> in-sync is (imo) more than enough.

Having the generated header files been committed sound like a good idea
for now. For better or for worth we've got a few of those already, so
it isn't a first.

But the way the different pieces are spread out in the repository in
this patch series will make it difficult for future contributor to update
the hypercall ABI. They'll be meet with an "autogenerated file, don't
modify" with little clue as to how actually regenerate them. For that I
think it would be better to have the IDL description (TOML files) in
that "xen/public/include" directory or at the very least in "xen/".
Second, with "xenbindgen" been in in "tools/", this introduce a soft
dependency of "xen" on "tools", which should be avoided even if the
build system of "xen/" doesn't call into xenbindgen today. So I think it
would be better to have xenbindgen either live in "xen/" or in a
different directory at the root of the repo. There's already Kconfig in
"xen/" so xenbindgen isn't going to be the first parser/generator in
"xen/" directory.

> ======== Patch grouping ===========
> 
> Patches 1 and 2 remove packed subfields to allow encoding it in the TOML specs
> (e.g: see patch 13, replace hand-crafted altp2m_mode). It's non-functional
> changes aiming to reach simpler representability.
> 
>   Patch 1.  xen/domctl: Refine grant_opts into max_grant_version
>   Patch 2.  xen/domctl: Replace altp2m_opts with altp2m_mode
> 
> Patches 3 to 10 are xenbindgen (with the C generator backend only). The
> Cargo.lock file in patch 4 is required for build reproducibility and is
> recommended to have checked in the repo.
> 
>   Patch 3.  tools/xenbindgen: Introduce a Xen hypercall IDL generator
>   Patch 4.  tools/xenbindgen: Add a TOML spec reader
>   Patch 5.  tools/xenbindgen: Add basic plumbing for the C backend
>   Patch 6.  tools/xenbindgen: Add xenbindgen's Cargo.lock file
>   Patch 7.  tools/xenbindgen: Add support for structs in TOML specs
>   Patch 8.  tools/xenbindgen: Add support for enums in TOML specs
>   Patch 9.  tools/xenbindgen: Add support for bitmaps in TOML specs
>   Patch 10. tools/xenbindgen: Add support for includes in the TOML specs
> 
> Patch 11 goes a step beyond and validates the ABI has no implicit padding and
> that all names are unique. In the future, when we define rules for stable ABIs,
> all of those can be checked here, at generation time.
> 
>   Patch 11. tools/xenbindgen: Validate ABI rules at generation time
> 
> Patches 12 to 19 replace current items in the C headers with autogenerated
> versions. They should all be mechanical translations.
> 
>   Patch 12. xen: Replace sysctl/readconsole with autogenerated version
>   Patch 13. xen: Replace hand-crafted altp2m_mode descriptions with
>             autogenerated ones
>   Patch 14. xen: Replace common bitmaps in domctl.createdomain with
>             autogenerated versions
>   Patch 15. xen/arm: Replace hand-crafted xen_arch_domainconfig with
>             autogenerated one

I feel like you write "hand-crafted" in those patch description as if it
is a bad thing. Yet, you replace the hand-crafted C headers by
hand-crafted IDL. I think a better title could be "Translate
xen_arch_domainconfig into IDL" to avoid what I feel like is a
pejorative term.

Also, would it be possible to separate changes to the existing API from
the patch that introduce the newly generated headers? I think it would
be much easier to review that the generated headers don't introduce
any changes over the current one.

Cheers,

-- 

Anthony Perard | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech


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

* Re: [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs
  2024-11-21 17:46 ` [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Anthony PERARD
@ 2024-11-22 10:52   ` Teddy Astie
  2024-11-22 13:26     ` Alejandro Vallejo
  2024-11-22 13:12   ` Alejandro Vallejo
  1 sibling, 1 reply; 51+ messages in thread
From: Teddy Astie @ 2024-11-22 10:52 UTC (permalink / raw)
  To: Anthony PERARD, Alejandro Vallejo; +Cc: xen-devel

Le 21/11/2024 à 18:46, Anthony PERARD a écrit :
> Instead of creating your own IDL specification, did you look for
> existing project that would do just that? That is been able to describe
> the existing ABI in IDL and use an existing project to generate C and
> Rust headers.
>
> I kind of look into this, but there's quite a few project to explore and
> I didn't really spend enough time. Also, there's probably quite a lot
> that are for client-server interfaces rather than syscall/hypercalls, or
> they impose a data format.
>

I think a such IDL would be C headers, but it's easy to make C headers
that are hard to deal with in other languages. I checked briefly, and
there is Fuchsia IDL that could be interesting in that matter but is
much more complex than what we may be looking for.

>
> Next, on the file format choice, is TOML the best for describing an ABI,
> or would other existing file format make it a bit easier to read, like
> JSON or YAML? (I quite like using YAML so I have a bias toward it 🙂,
> and that's the format used for the CI). I don't think it mater much for
> Serde which file format is used.

It can be decided by making examples of IDL files in various formats and
deciding on which one would be the most readable/easy to deal with.

Teddy


Teddy Astie | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech



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

* Re: [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs
  2024-11-21 17:46 ` [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Anthony PERARD
  2024-11-22 10:52   ` Teddy Astie
@ 2024-11-22 13:12   ` Alejandro Vallejo
  2024-11-22 16:34     ` Anthony PERARD
  1 sibling, 1 reply; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-22 13:12 UTC (permalink / raw)
  To: Anthony PERARD
  Cc: xen-devel, Juergen Gross, Julien Grall, Andrew Cooper,
	Jan Beulich, Stefano Stabellini, Christian Lindig, David Scott,
	Marek Marczykowski-Górecki, Bertrand Marquis, Michal Orzel,
	Volodymyr Babchuk, Roger Pau Monné, Samuel Thibault,
	Daniel P. Smith, Tim Deegan, Lukasz Hawrylko, Mateusz Mówka,
	Doug Goldstein, Teddy Astie, Yann Dirson

On Thu Nov 21, 2024 at 5:47 PM GMT, Anthony PERARD wrote:

Hi,

> Hi Alejandro,
>
> Nice work :-).

Cheers! And thanks for having a look.

>
> On Fri, Nov 15, 2024 at 11:51:29AM +0000, Alejandro Vallejo wrote:
> > This series is the result of my "Interfacing Rust with Xen" talk in Xen Summit.
> > It adds a hypercall ABI IDL parser and generator to the xen tree, replaces a
> > couple of existing hypercalls, creates a Rust crate with autogenerated contents
> > an creates a CI job to ensure nothing goes out of sync.
> >
> > The changes are fairly invasive because the various autogenerated items appear
> > in many places (specially the domaincreate flags). However, the changes to the
> > hypervisor are all mechanical and not functional (not intentionally so, at
> > least).
>
> I tried to build QEMU with this series applied, and the build failed. In
> this case nothing important, the "autogen" directory just need to be
> installed. But I fear the changes introduce to the API (like change
> of case for the flags) will also be done to other API that project
> outside of the xen repo use, and thus introduce unneeded breakage.

That's bizarre, I run the series in CI and it came out green.

  https://gitlab.com/xen-project/people/agvallejo/xen/-/pipelines/1543402100

And I can do `make dist` without issues locally.

There might be some flaky dependency somewhere. I admit I'm not sure how the
headers are installed for the QEMU build.

> Should the changes also introduce a compatibility with the previous API?

Jan mentioned something to that effect when I first proposed the change to
grant_opts, but at the time the why was a bit lacking in substance. I then sent
this whole thing to show the why in context.

A more compatible alternative would be to retroactively widen the single
subfield inside *_opts to occupy the whole field. Then we can suitably extend
the masking macros to u32, keep them around for compatibility (outside the
autogenerated stuff; say, in xen.h) and the API would be preserved.

Does that sound like a better approach?

That said, I was under the impression the API to be maintained was in libxl and
everything else was fair game so long as libxc et al. were suitably updated.

What do we actually promise externally?

>
> > I've split the generator in reasonably small pieces, but it's still not a small
> > tool. The Rust backend remains monolithic in a single patch until the RFC goes
> > further. It mirrors the C backend for the most part.
> > 
> > The hypercall ABI is specified in a schema of TOML. Most of it should be fairly
> > obvious as to what it does and means, with the possible exception of the "typ"
> > field. That has the look of a dictionary because that helps the deserializer to
> > automatically resolve the typ to a convenient Rust enum type (Typ). In time,
> > that will become something nicer to write, but that's fairly far in my list of
> > priorities at the moment.
>
> Instead of creating your own IDL specification, did you look for
> existing project that would do just that? That is been able to describe
> the existing ABI in IDL and use an existing project to generate C and
> Rust headers.
>
> I kind of look into this, but there's quite a few project to explore and
> I didn't really spend enough time. Also, there's probably quite a lot
> that are for client-server interfaces rather than syscall/hypercalls, or
> they impose a data format.
>

I looked a fair bit. Alas, the biggest case for this is web microservices, so
the overwhelming majority of IDL projects focus on end-to-end RPC. That is,
given pairs of functions for producers/consumers and a byte-based comms channel
(typically a socket), they create their own ABI serialising on one side and
deserialising on the other. That's not adequate here because we care about the
precise semantics of the ABI at the hypercall boundary to avoid pushing a
deserialiser in the hypervisor.

Protocol buffers, flatbuffers and Cap'n Proto all fall in this category, and
gRPC is a higher level construct using protocol buffers or flatbuffers. So all
those are off the table, and virtually all others suffer from the same sin.

A notable exception is Kaitai Struct (https://kaitai.io/), because it was
designed to represent binary formats. I really wanted to use it, but Rust is
not officially supported and the last release dates from 2022. All in all, it
doesn't sound like something alive enough for use in a serious existing
project.

>
> Next, on the file format choice, is TOML the best for describing an ABI,
> or would other existing file format make it a bit easier to read, like
> JSON or YAML? (I quite like using YAML so I have a bias toward it :-),
> and that's the format used for the CI). I don't think it mater much for
> Serde which file format is used.

Sure. I don't really care which. I can use serde to convert anything to
anything else anyway. I happened to already have something set up for TOML, so
I shamelessly reused it. But I'm happy to use something else.

I'm halfway through formalising evtchn atm (with a few addition to the
generator), but I'll try migrating the specs to YAML and JSON to see how they
look like.

I'm only frontally opposed to XML :)

>
> > After the series sysctl::readconsole and domctl::createdomain are autogenerated
> > from their formalized forms. In the course of formalizing the ABI it became
> > apparent readconsole has a different ABI in 32 and 64 bits. While benign in
> > that particular case, it's yet one more reason to formalize the ABI in a
> > language agnostic way and have it machine-checked.
> > 
> > ======== The Plan ===========
> > 
> > So, the idea of the series is to adjust 2 meaningful hypercalls to TOML-based
> > specifications (sysctl::readconsole and domctl::createdomain). The series is
> > organised in the following chunks of work
> > 
> >   1. Sanitise domctl::createdomain to remove packed subfields.
> >   2. Introduce xenbindgen (IDL parser and generator for C).
> >   3. Specify hypercalls in TOML, and replace the hand-crafted public bits.
> >   4. Introduce Rust generator for xenbindgen.
> >   5. Introduce a xen-sys crate, with the autogenerated Rust constructs.
> >   6. Introduce CI checks for Rust linters, ABI validation and autogenerated
> >      file consistency.
> > 
> > Future work involves migrating more hypercalls, in the same way patch 12 does.
> > Most hypercalls should not take the amount of churn createdomain did. With the
> > foundations laid down the involved work should be simple.
> > 
> > I have considered integrating the hypercall generation in the build process.
> > That forces the Rust toolchain to be in the list of build dependencies for
> > downstreams, which might be complicated or annoying. For the time being, I
> > think checking in the autogenerated files and confirming in CI that they are
> > in-sync is (imo) more than enough.
>
> Having the generated header files been committed sound like a good idea
> for now. For better or for worth we've got a few of those already, so
> it isn't a first.

So long as CI checks for consistency (and it does here), it shouldn't be a
problem and helps a lot with review. I have noticed a few times regressions
while developing merely because it became apparent in `git status`.

>
> But the way the different pieces are spread out in the repository in
> this patch series will make it difficult for future contributor to update
> the hypercall ABI. They'll be meet with an "autogenerated file, don't
> modify" with little clue as to how actually regenerate them. For that I
> think it would be better to have the IDL description (TOML files) in
> that "xen/public/include" directory or at the very least in "xen/".

I can move the specs to <root>/xen/abi, or something like that. Having it in
the include folder might risk installing them on the targets, and while that
shouldn't matter it's better if we only ship .h files there.

Regardless of this, I should add a bit more context to the message in the
headers they reference where the spec lives and some README.

> Second, with "xenbindgen" been in in "tools/", this introduce a soft
> dependency of "xen" on "tools", which should be avoided even if the
> build system of "xen/" doesn't call into xenbindgen today. So I think it
> would be better to have xenbindgen either live in "xen/" or in a
> different directory at the root of the repo. There's already Kconfig in
> "xen/" so xenbindgen isn't going to be the first parser/generator in
> "xen/" directory.

I don't disagree, but what do I do with xen-sys then? Should I put it with the
hypervisor somewhere in <root>/xen? <root>/xen/rust/xen-sys, maybe?

Otherwise the same coupling exists between xen and tools, except in the other
direction.

>
> > ======== Patch grouping ===========
> > 
> > Patches 1 and 2 remove packed subfields to allow encoding it in the TOML specs
> > (e.g: see patch 13, replace hand-crafted altp2m_mode). It's non-functional
> > changes aiming to reach simpler representability.
> > 
> >   Patch 1.  xen/domctl: Refine grant_opts into max_grant_version
> >   Patch 2.  xen/domctl: Replace altp2m_opts with altp2m_mode
> > 
> > Patches 3 to 10 are xenbindgen (with the C generator backend only). The
> > Cargo.lock file in patch 4 is required for build reproducibility and is
> > recommended to have checked in the repo.
> > 
> >   Patch 3.  tools/xenbindgen: Introduce a Xen hypercall IDL generator
> >   Patch 4.  tools/xenbindgen: Add a TOML spec reader
> >   Patch 5.  tools/xenbindgen: Add basic plumbing for the C backend
> >   Patch 6.  tools/xenbindgen: Add xenbindgen's Cargo.lock file
> >   Patch 7.  tools/xenbindgen: Add support for structs in TOML specs
> >   Patch 8.  tools/xenbindgen: Add support for enums in TOML specs
> >   Patch 9.  tools/xenbindgen: Add support for bitmaps in TOML specs
> >   Patch 10. tools/xenbindgen: Add support for includes in the TOML specs
> > 
> > Patch 11 goes a step beyond and validates the ABI has no implicit padding and
> > that all names are unique. In the future, when we define rules for stable ABIs,
> > all of those can be checked here, at generation time.
> > 
> >   Patch 11. tools/xenbindgen: Validate ABI rules at generation time
> > 
> > Patches 12 to 19 replace current items in the C headers with autogenerated
> > versions. They should all be mechanical translations.
> > 
> >   Patch 12. xen: Replace sysctl/readconsole with autogenerated version
> >   Patch 13. xen: Replace hand-crafted altp2m_mode descriptions with
> >             autogenerated ones
> >   Patch 14. xen: Replace common bitmaps in domctl.createdomain with
> >             autogenerated versions
> >   Patch 15. xen/arm: Replace hand-crafted xen_arch_domainconfig with
> >             autogenerated one
>
> I feel like you write "hand-crafted" in those patch description as if it
> is a bad thing. Yet, you replace the hand-crafted C headers by
> hand-crafted IDL. I think a better title could be "Translate
> xen_arch_domainconfig into IDL" to avoid what I feel like is a
> pejorative term.

Far from my intent. I merely meant "non-autogenerated". But point taken.

>
> Also, would it be possible to separate changes to the existing API from
> the patch that introduce the newly generated headers? I think it would
> be much easier to review that the generated headers don't introduce
> any changes over the current one.
>
> Cheers,

Sure, I can do that. createdomainflags is particularly nasty in that sense :/

Cheers,
Alejandro


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

* Re: [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs
  2024-11-22 10:52   ` Teddy Astie
@ 2024-11-22 13:26     ` Alejandro Vallejo
  0 siblings, 0 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-22 13:26 UTC (permalink / raw)
  To: Teddy Astie, Anthony PERARD; +Cc: xen-devel

On Fri Nov 22, 2024 at 10:52 AM GMT, Teddy Astie wrote:
> Le 21/11/2024 à 18:46, Anthony PERARD a écrit :
> > Instead of creating your own IDL specification, did you look for
> > existing project that would do just that? That is been able to describe
> > the existing ABI in IDL and use an existing project to generate C and
> > Rust headers.
> >
> > I kind of look into this, but there's quite a few project to explore and
> > I didn't really spend enough time. Also, there's probably quite a lot
> > that are for client-server interfaces rather than syscall/hypercalls, or
> > they impose a data format.
> >
>
> I think a such IDL would be C headers, but it's easy to make C headers
> that are hard to deal with in other languages.

Well, that's how x86_64 and x86_32 came to have different ABIs. Have a look at
xen/include/public/ and xen/include/compat/

As it turns out, C is very deceptive. And the AST doesn't codify many
invariants we'd like to preserve and write down so languages capable of
enforcing them can do so. One example I'm working on now is evtchn_status. It
contains a tagged union with a external status field (used as the union tag).
In C this relationship is basically unenforced and stated via comments. For
other languages to know about it it ought to be formalized.

IOW, if we were to simply transpile C it's impossible to restrict C to only use
safe constructs in other languages.

> I checked briefly, and
> there is Fuchsia IDL that could be interesting in that matter but is
> much more complex than what we may be looking for.

Fuchsia IDL in in the same camp as Protocol Buffers, Smithy and others, I
think. It's a protocol specification rather than an ABI specification, with the
specific twist that it's tailored for Zircon channels. I don't think it creates
structs.

>
> >
> > Next, on the file format choice, is TOML the best for describing an ABI,
> > or would other existing file format make it a bit easier to read, like
> > JSON or YAML? (I quite like using YAML so I have a bias toward it 🙂,
> > and that's the format used for the CI). I don't think it mater much for
> > Serde which file format is used.
>
> It can be decided by making examples of IDL files in various formats and
> deciding on which one would be the most readable/easy to deal with.

Yeah, I'll probably do that.

>
> Teddy
>
>
> Teddy Astie | Vates XCP-ng Developer
>
> XCP-ng & Xen Orchestra - Vates solutions
>
> web: https://vates.tech

Cheers,
Alejandro


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

* Re: [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs
  2024-11-22 13:12   ` Alejandro Vallejo
@ 2024-11-22 16:34     ` Anthony PERARD
  0 siblings, 0 replies; 51+ messages in thread
From: Anthony PERARD @ 2024-11-22 16:34 UTC (permalink / raw)
  To: Alejandro Vallejo
  Cc: xen-devel, Juergen Gross, Julien Grall, Andrew Cooper,
	Jan Beulich, Stefano Stabellini, Christian Lindig, David Scott,
	Marek Marczykowski-Górecki, Bertrand Marquis, Michal Orzel,
	Volodymyr Babchuk, Roger Pau Monné, Samuel Thibault,
	Daniel P. Smith, Tim Deegan, Lukasz Hawrylko, Mateusz Mówka,
	Doug Goldstein, Teddy Astie, Yann Dirson

On Fri, Nov 22, 2024 at 01:12:24PM +0000, Alejandro Vallejo wrote:
> On Thu Nov 21, 2024 at 5:47 PM GMT, Anthony PERARD wrote:
> > On Fri, Nov 15, 2024 at 11:51:29AM +0000, Alejandro Vallejo wrote:
> > > This series is the result of my "Interfacing Rust with Xen" talk in Xen Summit.
> > > It adds a hypercall ABI IDL parser and generator to the xen tree, replaces a
> > > couple of existing hypercalls, creates a Rust crate with autogenerated contents
> > > an creates a CI job to ensure nothing goes out of sync.
> > >
> > > The changes are fairly invasive because the various autogenerated items appear
> > > in many places (specially the domaincreate flags). However, the changes to the
> > > hypervisor are all mechanical and not functional (not intentionally so, at
> > > least).
> >
> > I tried to build QEMU with this series applied, and the build failed. In
> > this case nothing important, the "autogen" directory just need to be
> > installed. But I fear the changes introduce to the API (like change
> > of case for the flags) will also be done to other API that project
> > outside of the xen repo use, and thus introduce unneeded breakage.
> 
> That's bizarre, I run the series in CI and it came out green.
> 
>   https://gitlab.com/xen-project/people/agvallejo/xen/-/pipelines/1543402100
> 
> And I can do `make dist` without issues locally.
> 
> There might be some flaky dependency somewhere. I admit I'm not sure how the
> headers are installed for the QEMU build.

So, I'm pretty sure the CI have QEMU been built via Xen's build system.
As such, we set $PKG_CONFIG_PATH to "tools/pkg-config". And I think
QEMU's build system will just use that pkgconfig and exctract the
include path from it, and it point to the in-tree include directory,
which has the "autogen" symlink.

What I often do is `make dist`, and then build QEMU with that created
dist directory. It's almost like installing Xen on my system and trying
to build QEMU.

> > Should the changes also introduce a compatibility with the previous API?
> 
> Jan mentioned something to that effect when I first proposed the change to
> grant_opts, but at the time the why was a bit lacking in substance. I then sent
> this whole thing to show the why in context.

Yes, I've seen that other series after this one, and it help to explain
why some change help. Like the one changing the case of the flags.

> A more compatible alternative would be to retroactively widen the single
> subfield inside *_opts to occupy the whole field. Then we can suitably extend
> the masking macros to u32, keep them around for compatibility (outside the
> autogenerated stuff; say, in xen.h) and the API would be preserved.
> 
> Does that sound like a better approach?

I don't know. For flags, having macro/define/const with the old name
would be fairly easy to provide. For new fields on the other end, it
might just be better to break the build and require some adjustment.

> That said, I was under the impression the API to be maintained was in libxl and
> everything else was fair game so long as libxc et al. were suitably updated.
> 
> What do we actually promise externally?

I don't know to be honest, breaking the API might be ok. Quite often,
whenever we want to interface with Xen, we copy the Xen's header into
that project (OVMF for sure, Linux and FreeBSD I guess). For QEMU,
there's also header been copied, for the PV devices. I don't know why
QEMU includes domctl.h from outside the project (this is how I
discovered autogen directory was missing). It might just be included via
the header of one of the library.

> > > I've split the generator in reasonably small pieces, but it's still not a small
> > > tool. The Rust backend remains monolithic in a single patch until the RFC goes
> > > further. It mirrors the C backend for the most part.
> > > 
> > > The hypercall ABI is specified in a schema of TOML. Most of it should be fairly
> > > obvious as to what it does and means, with the possible exception of the "typ"
> > > field. That has the look of a dictionary because that helps the deserializer to
> > > automatically resolve the typ to a convenient Rust enum type (Typ). In time,
> > > that will become something nicer to write, but that's fairly far in my list of
> > > priorities at the moment.
> >
> > Instead of creating your own IDL specification, did you look for
> > existing project that would do just that? That is been able to describe
> > the existing ABI in IDL and use an existing project to generate C and
> > Rust headers.
> >
> > I kind of look into this, but there's quite a few project to explore and
> > I didn't really spend enough time. Also, there's probably quite a lot
> > that are for client-server interfaces rather than syscall/hypercalls, or
> > they impose a data format.
> >
> 
> I looked a fair bit. Alas, the biggest case for this is web microservices, so
> the overwhelming majority of IDL projects focus on end-to-end RPC. That is,
> given pairs of functions for producers/consumers and a byte-based comms channel
> (typically a socket), they create their own ABI serialising on one side and
> deserialising on the other. That's not adequate here because we care about the
> precise semantics of the ABI at the hypercall boundary to avoid pushing a
> deserialiser in the hypervisor.
> 
> Protocol buffers, flatbuffers and Cap'n Proto all fall in this category, and
> gRPC is a higher level construct using protocol buffers or flatbuffers. So all
> those are off the table, and virtually all others suffer from the same sin.
> 
> A notable exception is Kaitai Struct (https://kaitai.io/), because it was
> designed to represent binary formats. I really wanted to use it, but Rust is
> not officially supported and the last release dates from 2022. All in all, it
> doesn't sound like something alive enough for use in a serious existing
> project.

Thanks!

Yeah, Kaitai looks almost like it could do the job, but it doesn't look
to be available in Debian repo. So yes, xenbindgen sounds like a better
candidate. At least, it gives us an other example on a way to describe
binary struct, and it's YAML :-), more or less.

But I'm all in for xenbindgen now.

> >
> > Next, on the file format choice, is TOML the best for describing an ABI,
> > or would other existing file format make it a bit easier to read, like
> > JSON or YAML? (I quite like using YAML so I have a bias toward it :-),
> > and that's the format used for the CI). I don't think it mater much for
> > Serde which file format is used.
> 
> Sure. I don't really care which. I can use serde to convert anything to
> anything else anyway. I happened to already have something set up for TOML, so
> I shamelessly reused it. But I'm happy to use something else.
> 
> I'm halfway through formalising evtchn atm (with a few addition to the
> generator), but I'll try migrating the specs to YAML and JSON to see how they
> look like.
> 
> I'm only frontally opposed to XML :)

:-), I agree.

I'm not going to be the primary consumer of those files so I don't mind
too much. It just that I don't like having to repeat
'[[structs.fields]]' sooo many times, I'm not familiar enough with TOML
to know if it is a limitation of the format, or not. I would think that
in YAML or JSON, we could avoid this repeats, with something like:

    structs:
    - name: xen_sysctl_readconsole
      description: "..."
      fields:
        - name: clear
          description: "..."
          typ: u8
        - name: incremental
          typ: u8
        - name: buffer
          typ:
            tag: ptr
            args: u8

Not sure it's valid YAML for "buffer", but otherwise, we can probably
something similar in JSON, with just a few {} and loads of "".

> > > After the series sysctl::readconsole and domctl::createdomain are autogenerated
> > > from their formalized forms. In the course of formalizing the ABI it became
> > > apparent readconsole has a different ABI in 32 and 64 bits. While benign in
> > > that particular case, it's yet one more reason to formalize the ABI in a
> > > language agnostic way and have it machine-checked.
> > > 
> > > ======== The Plan ===========
> > > 
> > > So, the idea of the series is to adjust 2 meaningful hypercalls to TOML-based
> > > specifications (sysctl::readconsole and domctl::createdomain). The series is
> > > organised in the following chunks of work
> > > 
> > >   1. Sanitise domctl::createdomain to remove packed subfields.
> > >   2. Introduce xenbindgen (IDL parser and generator for C).
> > >   3. Specify hypercalls in TOML, and replace the hand-crafted public bits.
> > >   4. Introduce Rust generator for xenbindgen.
> > >   5. Introduce a xen-sys crate, with the autogenerated Rust constructs.
> > >   6. Introduce CI checks for Rust linters, ABI validation and autogenerated
> > >      file consistency.
> > > 
> > > Future work involves migrating more hypercalls, in the same way patch 12 does.
> > > Most hypercalls should not take the amount of churn createdomain did. With the
> > > foundations laid down the involved work should be simple.
> > > 
> > > I have considered integrating the hypercall generation in the build process.
> > > That forces the Rust toolchain to be in the list of build dependencies for
> > > downstreams, which might be complicated or annoying. For the time being, I
> > > think checking in the autogenerated files and confirming in CI that they are
> > > in-sync is (imo) more than enough.
> >
> > Having the generated header files been committed sound like a good idea
> > for now. For better or for worth we've got a few of those already, so
> > it isn't a first.
> 
> So long as CI checks for consistency (and it does here), it shouldn't be a
> problem and helps a lot with review. I have noticed a few times regressions
> while developing merely because it became apparent in `git status`.

Having CI check from the start is a good idea. I kind of tried to do
that for the autoconf and the *.gen.go files, but that not done (and I
think I've sent something to the list).

> > But the way the different pieces are spread out in the repository in
> > this patch series will make it difficult for future contributor to update
> > the hypercall ABI. They'll be meet with an "autogenerated file, don't
> > modify" with little clue as to how actually regenerate them. For that I
> > think it would be better to have the IDL description (TOML files) in
> > that "xen/public/include" directory or at the very least in "xen/".
> 
> I can move the specs to <root>/xen/abi, or something like that. Having it in
> the include folder might risk installing them on the targets, and while that
> shouldn't matter it's better if we only ship .h files there.
> 
> Regardless of this, I should add a bit more context to the message in the
> headers they reference where the spec lives and some README.

Sounds good.

> > Second, with "xenbindgen" been in in "tools/", this introduce a soft
> > dependency of "xen" on "tools", which should be avoided even if the
> > build system of "xen/" doesn't call into xenbindgen today. So I think it
> > would be better to have xenbindgen either live in "xen/" or in a
> > different directory at the root of the repo. There's already Kconfig in
> > "xen/" so xenbindgen isn't going to be the first parser/generator in
> > "xen/" directory.
> 
> I don't disagree, but what do I do with xen-sys then? Should I put it with the
> hypervisor somewhere in <root>/xen? <root>/xen/rust/xen-sys, maybe?
> 
> Otherwise the same coupling exists between xen and tools, except in the other
> direction.

Coupling in one direction is fine, but going back and fort is not.
Unless we had a single non-recursive build system, but that not the
case, will never be, as the build system for "xen/" is fine and doesn't
need to be shared with anything else (or at least that my point of view).

As for "xen-sys", that just another "tools/libs", so that can live in
"tools/".

Cheers,

-- 

Anthony Perard | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech


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

* Re: [RFC PATCH 12/25] xen: Replace sysctl/readconsole with autogenerated version
  2024-11-15 11:51 ` [RFC PATCH 12/25] xen: Replace sysctl/readconsole with autogenerated version Alejandro Vallejo
@ 2024-11-25 12:05   ` Jan Beulich
  2024-11-25 18:51     ` Alejandro Vallejo
  0 siblings, 1 reply; 51+ messages in thread
From: Jan Beulich @ 2024-11-25 12:05 UTC (permalink / raw)
  To: Alejandro Vallejo
  Cc: Anthony PERARD, Samuel Thibault, Andrew Cooper, Julien Grall,
	Stefano Stabellini, Daniel P. Smith, xen-devel

On 15.11.2024 12:51, Alejandro Vallejo wrote:
> Describe sysctl/readconsole as a TOML specification, remove old
> hand-coded version and replace it with autogenerated file.
> 
> While at it, transform the console driver to use uint8_t rather than
> char in order to mandate the type to be unsigned and ensure the ABI is
> not defined with regards to C-specific types.

Yet the derived C representation imo then should still be using char, not
uint8_t. In particular it would be a good sign if the Xen sources wouldn't
need to change, unlike happens here (altering types of a few internals of
the console machinery).

> Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
> ---
>  stubdom/Makefile                              |  2 +-
>  tools/rust/Makefile                           | 19 ++++++++
>  .../xenbindgen/extra/sysctl/readconsole.toml  | 43 +++++++++++++++++++
>  xen/drivers/char/console.c                    | 12 +++---
>  xen/include/public/autogen/sysctl.h           | 35 +++++++++++++++

In the build tree, having an autogen subdir under public/ _may_ be okay
(personally I dislike even that). I didn't manage to spot adjustments to
how files are eventually installed, yet at that point there clearly
shouldn't be any autogen subdir(s) anymore. How the individual files come
into existence is, imo, nothing consumers of the interface ought to (need
to) care about.

> --- /dev/null
> +++ b/tools/rust/xenbindgen/extra/sysctl/readconsole.toml
> @@ -0,0 +1,43 @@
> +[[structs]]
> +name = "xen_sysctl_readconsole"
> +description = "Read console content from Xen buffer ring."
> +
> +[[structs.fields]]
> +name = "clear"
> +description = "IN: Non-zero -> clear after reading."
> +typ = { tag = "u8" }
> +
> +[[structs.fields]]
> +name = "incremental"
> +description = "IN: Non-zero -> start index specified by `index` field."
> +typ = { tag = "u8" }
> +
> +[[structs.fields]]
> +name = "_pad"
> +description = "Unused."
> +typ = { tag = "u16" }
> +
> +[[structs.fields]]
> +name = "index"
> +description = """
> +IN:  Start index for consuming from ring buffer (if @incremental);
> +OUT: End index after consuming from ring buffer."""
> +typ = { tag = "u32" }
> +
> +[[structs.fields]]
> +name = "buffer"
> +description = """
> +IN: Virtual address to write console data.
> +
> +NOTE: The pointer itself is IN, but the contents of the buffer are OUT."""
> +typ = { tag = "ptr", args = { tag = "u8" } }
> +
> +[[structs.fields]]
> +name = "count"
> +description = "IN: Size of buffer; OUT: Bytes written to buffer."
> +typ = { tag = "u32" }
> +
> +[[structs.fields]]
> +name = "rsvd0_a"
> +description = "Tail padding reserved to zero."
> +typ = { tag = "u32" }

Up to here I wasn't able to spot any documentation on what it to be written
in which way. I already struggle with the double square brackets. The TOML
doc I found when searching the web doesn't have such. Taking just the example
above also doesn't allow me to conclude how e.g. nested structures would be
specified. Really, when talk was of some form of IDL, I expected to see
something IDLish (im particular closer to typical programming languages we
use). Whereas TOML, aiui, is more an easy language for config files of all
sorts.

What I have in mind wouldn't allow for descriptions, yet I'm not sure that's
relevant. The description ought to, first of all, live in the primary source
(i.e. the IDL itself) anyway. Commentary there might be possible to extract
into proper (machine generated/derived) documentation.

> --- a/xen/drivers/char/console.c
> +++ b/xen/drivers/char/console.c
> @@ -42,6 +42,8 @@
>  #include <asm/vpl011.h>
>  #endif
>  
> +#include <public/xen.h>

Why would this be needed all of the sudden?

> --- /dev/null
> +++ b/xen/include/public/autogen/sysctl.h
> @@ -0,0 +1,35 @@
> +/*
> + * sysctl
> + *
> + * AUTOGENERATED. DO NOT MODIFY
> + */
> +#ifndef __XEN_AUTOGEN_SYSCTL_H
> +#define __XEN_AUTOGEN_SYSCTL_H
> +
> +/* Read console content from Xen buffer ring. */
> +struct xen_sysctl_readconsole {
> +    /* IN: Non-zero -> clear after reading. */
> +    uint8_t clear;
> +    /* IN: Non-zero -> start index specified by `index` field. */
> +    uint8_t incremental;
> +    /* Unused. */
> +    uint16_t _pad;
> +    /*
> +     * IN:  Start index for consuming from ring buffer (if @incremental);
> +     * OUT: End index after consuming from ring buffer.
> +     */
> +    uint32_t index;
> +    /*
> +     * IN: Virtual address to write console data.
> +     *
> +     * NOTE: The pointer itself is IN, but the contents of the buffer are OUT.
> +     */
> +    XEN_GUEST_HANDLE_64(uint8) buffer;
> +    /* IN: Size of buffer; OUT: Bytes written to buffer. */
> +    uint32_t count;
> +    /* Tail padding reserved to zero. */
> +    uint32_t rsvd0_a;
> +};
> +
> +#endif /* __XEN_AUTOGEN_SYSCTL_H */
> +

If this file is auto-generated, why would it need committing? And yes, there
is the connected question: Will everyone then need to have a Rust compiler
available?

Nit: For anything that is committed, it would be nice if those files were as
tidy as possible style-wise. Most of the above looks entirely okay, just
that there is an unnecessary trailing blank line.

Jan


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

* Re: [RFC PATCH 16/25] xen/x86: Replace hand-crafted xen_arch_domainconfig with autogenerated one
  2024-11-15 11:51 ` [RFC PATCH 16/25] xen/x86: " Alejandro Vallejo
@ 2024-11-25 12:09   ` Jan Beulich
  2024-11-25 18:53     ` Alejandro Vallejo
  0 siblings, 1 reply; 51+ messages in thread
From: Jan Beulich @ 2024-11-25 12:09 UTC (permalink / raw)
  To: Alejandro Vallejo
  Cc: Anthony PERARD, Juergen Gross, Andrew Cooper, Julien Grall,
	Stefano Stabellini, Christian Lindig, David Scott,
	Roger Pau Monné, xen-devel

On 15.11.2024 12:51, Alejandro Vallejo wrote:
> Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
> ---
>  tools/libs/light/libxl_x86.c                  |  4 +-
>  tools/ocaml/libs/xc/xenctrl_stubs.c           |  4 +-
>  .../extra/arch-x86/domainconfig.toml          | 87 +++++++++++++++++++
>  .../xenbindgen/extra/domctl/createdomain.toml |  6 ++
>  xen/arch/x86/domain.c                         |  8 +-
>  xen/arch/x86/include/asm/domain.h             |  4 +-
>  xen/arch/x86/setup.c                          |  2 +-
>  xen/include/public/arch-x86/xen.h             | 51 -----------
>  xen/include/public/autogen/arch_x86.h         | 52 +++++++++++

Nit: If at all possible, please avoid underscores in the names of new files.

Jan


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

* Re: [RFC PATCH 07/25] tools/xenbindgen: Add support for structs in TOML specs
  2024-11-15 11:51 ` [RFC PATCH 07/25] tools/xenbindgen: Add support for structs in TOML specs Alejandro Vallejo
@ 2024-11-25 12:39   ` Teddy Astie
  2024-11-25 17:07     ` Alejandro Vallejo
  2024-11-25 15:03   ` Teddy Astie
  1 sibling, 1 reply; 51+ messages in thread
From: Teddy Astie @ 2024-11-25 12:39 UTC (permalink / raw)
  To: Alejandro Vallejo, xen-devel; +Cc: Anthony PERARD, Yann Dirson

Hi Alejandro,

Le 15/11/2024 à 12:51, Alejandro Vallejo a écrit :
> Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
> ---
>   tools/rust/xenbindgen/src/c_lang.rs | 56 ++++++++++++++++++++++++-
>   tools/rust/xenbindgen/src/spec.rs   | 64 ++++++++++++++++++++++++++++-
>   2 files changed, 117 insertions(+), 3 deletions(-)
>
> diff --git a/tools/rust/xenbindgen/src/c_lang.rs b/tools/rust/xenbindgen/src/c_lang.rs
> index f05e36bb362f..597e0ed41362 100644
> --- a/tools/rust/xenbindgen/src/c_lang.rs
> +++ b/tools/rust/xenbindgen/src/c_lang.rs
> @@ -17,9 +17,10 @@
>
>   use std::fmt::Write;
>
> -use crate::spec::OutFileDef;
> +use crate::spec::{OutFileDef, StructDef, Typ};
>
>   use convert_case::{Case, Casing};
> +use log::{debug, trace};
>
>   /// An abstract indentation level. 0 is no indentation, 1 is [`INDENT_WIDTH`]
>   /// and so on.
> @@ -29,6 +30,39 @@ struct Indentation(usize);
>   /// Default width of each level of indentation
>   const INDENT_WIDTH: usize = 4;
>
> +/// Create a C-compatible struct field. Without the terminating semicolon.
> +fn structfield(typ: &Typ, name: &str) -> String {
> +    match typ {
> +        Typ::Ptr(x) => {
> +            let t: &Typ = x;
> +            format!(
> +                "XEN_GUEST_HANDLE_64({}) {name}",
> +                match t {
> +                    Typ::U8 => "uint8",
> +                    Typ::U16 => "uint16",
> +                    Typ::U32 => "uint32",
> +                    Typ::U64 => "uint64_aligned_t",
> +                    Typ::I8 => "int8",
> +                    Typ::I16 => "int16",
> +                    Typ::I32 => "int32",
> +                    Typ::I64 => "int64_aligned_t",
> +                    _ => panic!("foo {t:?}"),
> +                }
> +            )
> +        }
> +        Typ::Struct(x) => format!("struct {x} {name}"),
> +        Typ::Array(x, len) => format!("{}{name}[{len}]", structfield(x, "")),
> +        Typ::U8 => format!("uint8_t {name}"),
> +        Typ::U16 => format!("uint16_t {name}"),
> +        Typ::U32 => format!("uint32_t {name}"),
> +        Typ::U64 => format!("uint64_aligned_t {name}"),
> +        Typ::I8 => format!("int8_t {name}"),
> +        Typ::I16 => format!("int16_t {name}"),
> +        Typ::I32 => format!("int32_t {name}"),
> +        Typ::I64 => format!("int64_aligned_t {name}"),
> +    }
> +}
> +

I think _t are missing in the Ptr cases (we are currently generating
XEN_GUEST_HANDLE_64(uint8) which I don't think is valid).
Aside that, wouldn't it be better to have a separate function for
converting the type to its C representation ?

Something like

impl Typ { // or blanket trait
     fn c_repr(&self) -> String {
         match self {
             /* ... */
         }
     }
}

fn structfield(typ: &Typ, name: &str) -> String {
     format!("{} {name}", typ.c_repr());
}

We can also consider Typ::Struct or Typ::Array cases to call recursively
to c_repr on its inner type to get its representation.

That way, we can have XEN_GUEST_HANDLE_64(struct something).

Cheers

Teddy



Teddy Astie | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech



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

* Re: [RFC PATCH 07/25] tools/xenbindgen: Add support for structs in TOML specs
  2024-11-15 11:51 ` [RFC PATCH 07/25] tools/xenbindgen: Add support for structs in TOML specs Alejandro Vallejo
  2024-11-25 12:39   ` Teddy Astie
@ 2024-11-25 15:03   ` Teddy Astie
  2024-11-25 17:16     ` Alejandro Vallejo
  1 sibling, 1 reply; 51+ messages in thread
From: Teddy Astie @ 2024-11-25 15:03 UTC (permalink / raw)
  To: Alejandro Vallejo, xen-devel; +Cc: Anthony PERARD, Yann Dirson

Hi,

> +/// An IDL type. A type may be a primitive integer, a pointer to an IDL type,
> +/// an array of IDL types or a struct composed of IDL types. Every integer must
> +/// be aligned to its size.
> +///
> +/// FIXME: This enumerated type is recovered as-is from the `typ` field in the
> +/// TOML files. Ideally, that representation should be more ergonomic and the
> +/// parser instructed to deal with it.
> +#[allow(clippy::missing_docs_in_private_items)]
> +#[derive(Debug, serde::Deserialize, PartialEq)]
> +#[serde(rename_all = "lowercase", tag = "tag", content = "args")]
> +pub enum Typ {
> +    Struct(String),
> +    U8,
> +    U16,
> +    U32,
> +    U64,
> +    I8,
> +    I16,
> +    I32,
> +    I64,
> +    Ptr(Box<Typ>),
> +    Array(Box<Typ>, usize),
> +}
> +

I think we can name it Type (it doesn't clash with a keyword actually)

> +
> +/// Deserialized form of a field within a hypercall struct (see [`StructDef`])
> +#[derive(Debug, serde::Deserialize)]
> +pub struct FieldDef {
> +    /// Name of the field
> +    pub name: String,
> +    /// Description of what the field is for. This string is added as a comment
> +    /// on top of the autogenerated field.
> +    pub description: String,
> +    /// Type of the field.
> +    pub typ: Typ,
> +}
> +

regarding this "typ" name, we can either use the "raw identifier" syntax 
with r#type to have it "technically" named 'type' or use
#[serde(rename = "type")]
to have it named "type" during deserialization even if the field is 
still "typ"

Cheers
Teddy


Teddy Astie | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech


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

* Re: [RFC PATCH 04/25] tools/xenbindgen: Add a TOML spec reader
  2024-11-15 11:51 ` [RFC PATCH 04/25] tools/xenbindgen: Add a TOML spec reader Alejandro Vallejo
@ 2024-11-25 15:13   ` Teddy Astie
  2024-11-25 16:51     ` Alejandro Vallejo
  0 siblings, 1 reply; 51+ messages in thread
From: Teddy Astie @ 2024-11-25 15:13 UTC (permalink / raw)
  To: Alejandro Vallejo, xen-devel; +Cc: Anthony PERARD, Yann Dirson

Hi,

> +    let _specification = match spec::Spec::new(&cli.indir) {
> +        Ok(x) => x,
> +        Err(spec::Error::Toml(x)) => {
> +            error!("TOML parsing error:");
> +            error!("{x:#?}");
> +            std::process::exit(1);
> +        }
> +        Err(spec::Error::Io(x)) => {
> +            error!("IO error:");
> +            error!("{x:#?}");
> +            std::process::exit(1);
> +        }
> +    };

I think it can be replaced with .unwrap() (or making the main function 
returns a Result<T, E>) as long as our internal error implements Display.

> +/// Internal error type for every error spec parsing could encounter
> +#[derive(Debug)]
> +pub enum Error {
> +    /// Wrapper around IO errors
> +    Io(std::io::Error),
> +    /// Wrapper around deserialization errors
> +    Toml(toml::de::Error),
> +}
> +
> +/// Maps an [`std::io::Error`] onto a [`Error`] type for easier propagation
> +fn from_ioerr<T>(t: std::io::Result<T>) -> Result<T, Error> {
> +    t.map_err(Error::Io)
> +}
> +

May be worth a
impl From<std::io::Error> for super::Error
such as ? operator can automatically convert it to our internal error type

Cheers
Teddy


Teddy Astie | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech


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

* Re: [RFC PATCH 08/25] tools/xenbindgen: Add support for enums in TOML specs
  2024-11-15 11:51 ` [RFC PATCH 08/25] tools/xenbindgen: Add support for enums " Alejandro Vallejo
@ 2024-11-25 16:39   ` Teddy Astie
  2024-11-25 17:18     ` Alejandro Vallejo
  0 siblings, 1 reply; 51+ messages in thread
From: Teddy Astie @ 2024-11-25 16:39 UTC (permalink / raw)
  To: Alejandro Vallejo, xen-devel; +Cc: Anthony PERARD, Yann Dirson

Hello,

> +
>   /// A language-agnostic specification.
>   #[derive(Debug, serde::Deserialize)]
>   struct InFileDef {
>       /// List of structs described in this input specification.
>       structs: Option<Vec<StructDef>>,
> +    /// List of lang-agnostic enumerated descriptions.
> +    enums: Option<Vec<EnumDef>>,
>   }
>   

Alike for struct/..., I think we can merge that with OutFileDef using 
the default attribute in serde :
#[serde(default)]
https://serde.rs/field-attrs.html#default

That way, when there is no structs/... entry in the file, it is parsed 
as a empty vec![] instead of failing which allows us to remove this 
wrapper struct.

Cheers

Teddy



Teddy Astie | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech


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

* Re: [RFC PATCH 04/25] tools/xenbindgen: Add a TOML spec reader
  2024-11-25 15:13   ` Teddy Astie
@ 2024-11-25 16:51     ` Alejandro Vallejo
  0 siblings, 0 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-25 16:51 UTC (permalink / raw)
  To: Teddy Astie, xen-devel; +Cc: Anthony PERARD, Yann Dirson

On Mon Nov 25, 2024 at 3:13 PM GMT, Teddy Astie wrote:
> Hi,
>
> > +    let _specification = match spec::Spec::new(&cli.indir) {
> > +        Ok(x) => x,
> > +        Err(spec::Error::Toml(x)) => {
> > +            error!("TOML parsing error:");
> > +            error!("{x:#?}");
> > +            std::process::exit(1);
> > +        }
> > +        Err(spec::Error::Io(x)) => {
> > +            error!("IO error:");
> > +            error!("{x:#?}");
> > +            std::process::exit(1);
> > +        }
> > +    };
>
> I think it can be replaced with .unwrap() (or making the main function 
> returns a Result<T, E>) as long as our internal error implements Display.

Oh, I wasn't aware E: Display was honoured on exit. I thought it always used E:
Debug. That ought to be a lot nicer.

>
> > +/// Internal error type for every error spec parsing could encounter
> > +#[derive(Debug)]
> > +pub enum Error {
> > +    /// Wrapper around IO errors
> > +    Io(std::io::Error),
> > +    /// Wrapper around deserialization errors
> > +    Toml(toml::de::Error),
> > +}
> > +
> > +/// Maps an [`std::io::Error`] onto a [`Error`] type for easier propagation
> > +fn from_ioerr<T>(t: std::io::Result<T>) -> Result<T, Error> {
> > +    t.map_err(Error::Io)
> > +}
> > +
>
> May be worth a
> impl From<std::io::Error> for super::Error
> such as ? operator can automatically convert it to our internal error type
>
> Cheers
> Teddy
>
>
> Teddy Astie | Vates XCP-ng Developer
>
> XCP-ng & Xen Orchestra - Vates solutions
>
> web: https://vates.tech

Yes, I replaced all this faff in my internal branch with From<std::io::Error>
and From<toml::de::Error> shortly after sending the RFC. It is indeed a lot
tidier.

Cheers,
Alejandro



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

* Re: [RFC PATCH 07/25] tools/xenbindgen: Add support for structs in TOML specs
  2024-11-25 12:39   ` Teddy Astie
@ 2024-11-25 17:07     ` Alejandro Vallejo
  0 siblings, 0 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-25 17:07 UTC (permalink / raw)
  To: Teddy Astie, xen-devel; +Cc: Anthony PERARD, Yann Dirson

On Mon Nov 25, 2024 at 12:39 PM GMT, Teddy Astie wrote:
> Hi Alejandro,
>
> Le 15/11/2024 à 12:51, Alejandro Vallejo a écrit :
> > Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
> > ---
> >   tools/rust/xenbindgen/src/c_lang.rs | 56 ++++++++++++++++++++++++-
> >   tools/rust/xenbindgen/src/spec.rs   | 64 ++++++++++++++++++++++++++++-
> >   2 files changed, 117 insertions(+), 3 deletions(-)
> >
> > diff --git a/tools/rust/xenbindgen/src/c_lang.rs b/tools/rust/xenbindgen/src/c_lang.rs
> > index f05e36bb362f..597e0ed41362 100644
> > --- a/tools/rust/xenbindgen/src/c_lang.rs
> > +++ b/tools/rust/xenbindgen/src/c_lang.rs
> > @@ -17,9 +17,10 @@
> >
> >   use std::fmt::Write;
> >
> > -use crate::spec::OutFileDef;
> > +use crate::spec::{OutFileDef, StructDef, Typ};
> >
> >   use convert_case::{Case, Casing};
> > +use log::{debug, trace};
> >
> >   /// An abstract indentation level. 0 is no indentation, 1 is [`INDENT_WIDTH`]
> >   /// and so on.
> > @@ -29,6 +30,39 @@ struct Indentation(usize);
> >   /// Default width of each level of indentation
> >   const INDENT_WIDTH: usize = 4;
> >
> > +/// Create a C-compatible struct field. Without the terminating semicolon.
> > +fn structfield(typ: &Typ, name: &str) -> String {
> > +    match typ {
> > +        Typ::Ptr(x) => {
> > +            let t: &Typ = x;
> > +            format!(
> > +                "XEN_GUEST_HANDLE_64({}) {name}",
> > +                match t {
> > +                    Typ::U8 => "uint8",
> > +                    Typ::U16 => "uint16",
> > +                    Typ::U32 => "uint32",
> > +                    Typ::U64 => "uint64_aligned_t",
> > +                    Typ::I8 => "int8",
> > +                    Typ::I16 => "int16",
> > +                    Typ::I32 => "int32",
> > +                    Typ::I64 => "int64_aligned_t",
> > +                    _ => panic!("foo {t:?}"),
> > +                }
> > +            )
> > +        }
> > +        Typ::Struct(x) => format!("struct {x} {name}"),
> > +        Typ::Array(x, len) => format!("{}{name}[{len}]", structfield(x, "")),
> > +        Typ::U8 => format!("uint8_t {name}"),
> > +        Typ::U16 => format!("uint16_t {name}"),
> > +        Typ::U32 => format!("uint32_t {name}"),
> > +        Typ::U64 => format!("uint64_aligned_t {name}"),
> > +        Typ::I8 => format!("int8_t {name}"),
> > +        Typ::I16 => format!("int16_t {name}"),
> > +        Typ::I32 => format!("int32_t {name}"),
> > +        Typ::I64 => format!("int64_aligned_t {name}"),
> > +    }
> > +}
> > +
>
> I think _t are missing in the Ptr cases (we are currently generating
> XEN_GUEST_HANDLE_64(uint8) which I don't think is valid).

It is intentional. The handles are presently missing those _t in Xen's public
headers, but that's something I'll be changing in the interest of sanity. That
way we can just recurse to the inner type.


> Aside that, wouldn't it be better to have a separate function for
> converting the type to its C representation ?
>
> Something like
>
> impl Typ { // or blanket trait
>      fn c_repr(&self) -> String {
>          match self {
>              /* ... */
>          }
>      }
> }

That's roughhly what typ_rs() does, and indeed what typ_c() used to do. There's
a complication though...

>
> fn structfield(typ: &Typ, name: &str) -> String {
>      format!("{} {name}", typ.c_repr());
> }
>
> We can also consider Typ::Struct or Typ::Array cases to call recursively
> to c_repr on its inner type to get its representation.
>
> That way, we can have XEN_GUEST_HANDLE_64(struct something).

Initially structfield() was typ_c() (like the Rust backend). Then arrays
happened... Size and typename surround the name of the field (e.g: uint8_t
handle[16]) so I stopped doing it like that because I thought I couldn't.

I have since then noticed I can cheat! The following two fields are identical.
Except the first one is a heck of a lot simpler to generate.

  __typeof__(uint8_t[16]) handle;
  uint8_t handle[16];

My latest branch simplifies all this by s/structfield/typ_c/ and using that
typeof trick.

>
> Cheers
>
> Teddy
>
>
>
> Teddy Astie | Vates XCP-ng Developer
>
> XCP-ng & Xen Orchestra - Vates solutions
>
> web: https://vates.tech

Cheers,
Alejandro


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

* Re: [RFC PATCH 07/25] tools/xenbindgen: Add support for structs in TOML specs
  2024-11-25 15:03   ` Teddy Astie
@ 2024-11-25 17:16     ` Alejandro Vallejo
  0 siblings, 0 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-25 17:16 UTC (permalink / raw)
  To: Teddy Astie, xen-devel; +Cc: Anthony PERARD, Yann Dirson

On Mon Nov 25, 2024 at 3:03 PM GMT, Teddy Astie wrote:
> Hi,
>
> > +/// An IDL type. A type may be a primitive integer, a pointer to an IDL type,
> > +/// an array of IDL types or a struct composed of IDL types. Every integer must
> > +/// be aligned to its size.
> > +///
> > +/// FIXME: This enumerated type is recovered as-is from the `typ` field in the
> > +/// TOML files. Ideally, that representation should be more ergonomic and the
> > +/// parser instructed to deal with it.
> > +#[allow(clippy::missing_docs_in_private_items)]
> > +#[derive(Debug, serde::Deserialize, PartialEq)]
> > +#[serde(rename_all = "lowercase", tag = "tag", content = "args")]

FYI, this serde config is something I've also changed since the RFC. The
explicit tag and content are gone, because they complicate things and they are
actively harmful

Before (with explicit tag+content):

  typ = { tag = "u16" }
  typ = { tag = "struct", content = "foobar" }
  typ = { tag = "ptr", content = { tag = "u8" } }
  typ = { tag = "ptr", content = { tag = "struct", content = "foobar" } }

After (without explicit tag+content):

  typ = "u16"
  typ = { struct = "foobar" }
  typ = { ptr = "u8" }
  typ = { ptr = { struct = "foobar" } }

> > +pub enum Typ {
> > +    Struct(String),
> > +    U8,
> > +    U16,
> > +    U32,
> > +    U64,
> > +    I8,
> > +    I16,
> > +    I32,
> > +    I64,
> > +    Ptr(Box<Typ>),
> > +    Array(Box<Typ>, usize),
> > +}
> > +
>
> I think we can name it Type (it doesn't clash with a keyword actually)

Sure. I just wanted it to mirror the field name (because `type` is reserved).
In the big scheme of things it's not terribly important to do so.

>
> > +
> > +/// Deserialized form of a field within a hypercall struct (see [`StructDef`])
> > +#[derive(Debug, serde::Deserialize)]
> > +pub struct FieldDef {
> > +    /// Name of the field
> > +    pub name: String,
> > +    /// Description of what the field is for. This string is added as a comment
> > +    /// on top of the autogenerated field.
> > +    pub description: String,
> > +    /// Type of the field.
> > +    pub typ: Typ,
> > +}
> > +
>
> regarding this "typ" name, we can either use the "raw identifier" syntax 
> with r#type to have it "technically" named 'type' or use

I'd really rather not. Feels like playing with hot fire.

> #[serde(rename = "type")]
> to have it named "type" during deserialization even if the field is 
> still "typ"

This I like. I forgot I could do that.

>
> Cheers
> Teddy
>
>
> Teddy Astie | Vates XCP-ng Developer
>
> XCP-ng & Xen Orchestra - Vates solutions
>
> web: https://vates.tech

Cheers,
Alejandro


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

* Re: [RFC PATCH 08/25] tools/xenbindgen: Add support for enums in TOML specs
  2024-11-25 16:39   ` Teddy Astie
@ 2024-11-25 17:18     ` Alejandro Vallejo
  0 siblings, 0 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-25 17:18 UTC (permalink / raw)
  To: Teddy Astie, xen-devel; +Cc: Anthony PERARD, Yann Dirson

On Mon Nov 25, 2024 at 4:39 PM GMT, Teddy Astie wrote:
> Hello,
>
> > +
> >   /// A language-agnostic specification.
> >   #[derive(Debug, serde::Deserialize)]
> >   struct InFileDef {
> >       /// List of structs described in this input specification.
> >       structs: Option<Vec<StructDef>>,
> > +    /// List of lang-agnostic enumerated descriptions.
> > +    enums: Option<Vec<EnumDef>>,
> >   }
> >   
>
> Alike for struct/..., I think we can merge that with OutFileDef using 
> the default attribute in serde :
> #[serde(default)]
> https://serde.rs/field-attrs.html#default
>
> That way, when there is no structs/... entry in the file, it is parsed 
> as a empty vec![] instead of failing which allows us to remove this 
> wrapper struct.

I didn't know about that setting. Option<T> was indeed a clutch to avoid having
to define enums = [] explicitly. I like your suggestion better.

>
> Cheers
>
> Teddy
>
>
>
> Teddy Astie | Vates XCP-ng Developer
>
> XCP-ng & Xen Orchestra - Vates solutions
>
> web: https://vates.tech

Cheers,
Alejandro


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

* Re: [RFC PATCH 12/25] xen: Replace sysctl/readconsole with autogenerated version
  2024-11-25 12:05   ` Jan Beulich
@ 2024-11-25 18:51     ` Alejandro Vallejo
  2024-11-26  9:40       ` Jan Beulich
  0 siblings, 1 reply; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-25 18:51 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Anthony PERARD, Samuel Thibault, Andrew Cooper, Julien Grall,
	Stefano Stabellini, Daniel P. Smith, xen-devel

Hi Jan,

Thanks for having a look.

On Mon Nov 25, 2024 at 12:05 PM GMT, Jan Beulich wrote:
> On 15.11.2024 12:51, Alejandro Vallejo wrote:
> > Describe sysctl/readconsole as a TOML specification, remove old
> > hand-coded version and replace it with autogenerated file.
> > 
> > While at it, transform the console driver to use uint8_t rather than
> > char in order to mandate the type to be unsigned and ensure the ABI is
> > not defined with regards to C-specific types.
>
> Yet the derived C representation imo then should still be using char, not
> uint8_t.

There's 2 issued addressed by this patch.

  1. The removal of char from the external headers (and the Xen driver).
  2. The replacement of the existing struct by the autogenerated one.

(1) wants doing irrespective of (2). char has neither a fixed width nor a fixed
sign. Which is irrelevant for ABI purposes in this case because what we really
meant is "give me a pointer" in this hypercall, but it may be important in
other cases.

IOW, char should've never made it to the definition of the public ABI, and I'm
merely taking the chance to take it out. Happy to extract this patch and send
it separately.

> In particular it would be a good sign if the Xen sources wouldn't
> need to change, unlike happens here (altering types of a few internals of
> the console machinery).

And that would be the case if Xen had uniform naming conventions and its ABI
was fully unambiguous. The process of uniformizing the naming convention and
disambiguating the ABI is bound to cause (non-functional) changes, mostly in
the naming conventions side of things.

Naming conventions can be _MOSTLY_ sorted by creating compat #defines and
typedefs that match the old types. I can do that, but note that even then some
code would have to change in order to i.e: s/struct OLD_NAME/NEW_NAME_T/

If this is deemed important for backporting changes, I can do it for invasive
replacements, like the createdomain flags.

On the topic of changing types, The present case is an ABI inconsistency case.
My intention is to keep the ABI fixed as a matter of principle (if anything,
because the domU ABI cannot be changed). However, changing the way C represents
said ABI is a requirement if the current definition is ambiguous. In those
cases we ought to change C to ensure there's one and only one way of
interpreting it.

>
> > Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
> > ---
> >  stubdom/Makefile                              |  2 +-
> >  tools/rust/Makefile                           | 19 ++++++++
> >  .../xenbindgen/extra/sysctl/readconsole.toml  | 43 +++++++++++++++++++
> >  xen/drivers/char/console.c                    | 12 +++---
> >  xen/include/public/autogen/sysctl.h           | 35 +++++++++++++++
>
> In the build tree, having an autogen subdir under public/ _may_ be okay
> (personally I dislike even that). I didn't manage to spot adjustments to
> how files are eventually installed, yet at that point there clearly
> shouldn't be any autogen subdir(s) anymore. How the individual files come
> into existence is, imo, nothing consumers of the interface ought to (need
> to) care about.

Anthony already mentioned an error while building QEMU, which I'm guessing
comes from the same problem. The stitching is definitely up for discussion. I
got far enough to allow the compilation of `dist` to go through, but didn't
think incredibly hard about the finer details (like the install targets).

In principle, renaming `autogen` to `abi` and adding its contents to the list of
installed headers ought to sort that particular concern? 

>
> > --- /dev/null
> > +++ b/tools/rust/xenbindgen/extra/sysctl/readconsole.toml
> > @@ -0,0 +1,43 @@
> > +[[structs]]
> > +name = "xen_sysctl_readconsole"
> > +description = "Read console content from Xen buffer ring."
> > +
> > +[[structs.fields]]
> > +name = "clear"
> > +description = "IN: Non-zero -> clear after reading."
> > +typ = { tag = "u8" }
> > +
> > +[[structs.fields]]
> > +name = "incremental"
> > +description = "IN: Non-zero -> start index specified by `index` field."
> > +typ = { tag = "u8" }
> > +
> > +[[structs.fields]]
> > +name = "_pad"
> > +description = "Unused."
> > +typ = { tag = "u16" }
> > +
> > +[[structs.fields]]
> > +name = "index"
> > +description = """
> > +IN:  Start index for consuming from ring buffer (if @incremental);
> > +OUT: End index after consuming from ring buffer."""
> > +typ = { tag = "u32" }
> > +
> > +[[structs.fields]]
> > +name = "buffer"
> > +description = """
> > +IN: Virtual address to write console data.
> > +
> > +NOTE: The pointer itself is IN, but the contents of the buffer are OUT."""
> > +typ = { tag = "ptr", args = { tag = "u8" } }
> > +
> > +[[structs.fields]]
> > +name = "count"
> > +description = "IN: Size of buffer; OUT: Bytes written to buffer."
> > +typ = { tag = "u32" }
> > +
> > +[[structs.fields]]
> > +name = "rsvd0_a"
> > +description = "Tail padding reserved to zero."
> > +typ = { tag = "u32" }
>
> Up to here I wasn't able to spot any documentation on what it to be written
> in which way.

You're right that the specification is not itself specified. I neglected to do
so to avoid having to rewrite it should we settle on a different markup
language.

Much of your confusion seems to stem from simultanuously looking at a new
markup language and a new schema for it. Let me try to unpick some of that...

> I already struggle with the double square brackets. The TOML
> doc I found when searching the web doesn't have such. Taking just the example
> above also doesn't allow me to conclude how e.g. nested structures would be
> specified.

The schema is represented by the contents of `spec.rs`. All structs with a
Deserialize attribute (i.e: #[derive(Foo, Bar, Deserialize)]) map to some
"table" in TOML.

When I say "struct" now I mean a struct inside the generator that represents
the input file (_NOT_ a struct representing a hypercall).

The rules are as follows. The whole file is deserialized in a single struct
(InFileDef). When there's a single square bracket (which I don't think I've
required yet), that means that what follows is a "table" with the name between
the brackets. There's several ways to represent table

    Regular tables:           [foo]
                              bar = "some_bar"
                              baz = "some_baz"

                              [foo2]
                              bar = "blergh"

    Inline tables:            foo = { bar = "some_bar", baz = "some_baz" }
                              foo2 = { bar = "blergh" }

Both of those deserialize to the same thing (it's C for ease of explaining it
here, but it's actually Rust in the generator).

                struct infiledef {
                    struct {
                        char *bar; // points to "some_bar"
                        char *baz; // points to "some_baz"
                    } foo;
                    struct {
                        char *bar; // points to "blergh"
                    } foo2;
                };

The double brackets are adding one more element to a "list"

That is. This TOML...

                             [[foos]]
                             bar = "some_bar"
                             baz = "some_baz"

                             [[foos]]
                             bar = "some_bar"
                             baz = "some_baz"

... deserializes to...

                struct foodef {
                    char *bar;
                    char *baz;
                }

                struct infiledef {
                    struct foodef *foos;
                };

The last bit of relevant information is that you can identify which table you
want to add to with dots. So [[structs.fields]] is saying "Add this field to
the list of fields of the current hypercall struct".

The "typ" field is a bit quirky (I have a solution to simplify it), but that
uses inline tables.

> Really, when talk was of some form of IDL, I expected to see
> something IDLish (im particular closer to typical programming languages we
> use). Whereas TOML, aiui, is more an easy language for config files of all
> sorts.

I might've been unclear in the talk. One of my goals is to _not_ define a new
language. Or I'll just exchange one problem for two. Maybe I should've called
it an Interface Definition Schema, rather than Language.

The key benefit here is that, while the generators can be tricky, the parser is
all done and strictly specified. We can experiment with YAML (Anthony already
asked about it). But it really is a matter of getting used to. TOML is
fantastic for saving horizontal space. And multi-line comments are neatly
organized.

>
> What I have in mind wouldn't allow for descriptions, yet I'm not sure that's
> relevant. The description ought to, first of all, live in the primary source
> (i.e. the IDL itself) anyway. Commentary there might be possible to extract
> into proper (machine generated/derived) documentation.

Not sure I follow, these TOML files _are_ the IDL itself.

The descriptions here are propagated to the generated code, so they are
infinitely helpful when reaching the type via e.g: cscope, LSPs, etc.

>
> > --- a/xen/drivers/char/console.c
> > +++ b/xen/drivers/char/console.c
> > @@ -42,6 +42,8 @@
> >  #include <asm/vpl011.h>
> >  #endif
> >  
> > +#include <public/xen.h>
>
> Why would this be needed all of the sudden?
>

Because of the new XEN_GUEST_HANDLE_64(uint8) type. The macro is quite ugly and
requires being declared ahead.

> > --- /dev/null
> > +++ b/xen/include/public/autogen/sysctl.h
> > @@ -0,0 +1,35 @@
> > +/*
> > + * sysctl
> > + *
> > + * AUTOGENERATED. DO NOT MODIFY
> > + */
> > +#ifndef __XEN_AUTOGEN_SYSCTL_H
> > +#define __XEN_AUTOGEN_SYSCTL_H
> > +
> > +/* Read console content from Xen buffer ring. */
> > +struct xen_sysctl_readconsole {
> > +    /* IN: Non-zero -> clear after reading. */
> > +    uint8_t clear;
> > +    /* IN: Non-zero -> start index specified by `index` field. */
> > +    uint8_t incremental;
> > +    /* Unused. */
> > +    uint16_t _pad;
> > +    /*
> > +     * IN:  Start index for consuming from ring buffer (if @incremental);
> > +     * OUT: End index after consuming from ring buffer.
> > +     */
> > +    uint32_t index;
> > +    /*
> > +     * IN: Virtual address to write console data.
> > +     *
> > +     * NOTE: The pointer itself is IN, but the contents of the buffer are OUT.
> > +     */
> > +    XEN_GUEST_HANDLE_64(uint8) buffer;
> > +    /* IN: Size of buffer; OUT: Bytes written to buffer. */
> > +    uint32_t count;
> > +    /* Tail padding reserved to zero. */
> > +    uint32_t rsvd0_a;
> > +};
> > +
> > +#endif /* __XEN_AUTOGEN_SYSCTL_H */
> > +
>
> If this file is auto-generated, why would it need committing? And yes, there
> is the connected question: Will everyone then need to have a Rust compiler
> available?

Committing it is required precisely so that no one needs to have a Rust
compiler available. The last patch in the series checks the generated code
matches the specs byte by byte. It has the nice benefit that you can git-grep
for it and tags work even without compiling first. You also get all
architectures upfront and it's a lot easier to review changes to the generator
because CI will scream to you if the outputs diverge.

>
> Nit: For anything that is committed, it would be nice if those files were as
> tidy as possible style-wise. Most of the above looks entirely okay, just
> that there is an unnecessary trailing blank line.

I did go out of my way to prettify the output.

The trailing newline was intentional to make it C++03-compatible. I can get rid
of it, as it doesn't matter a whole lot.

>
> Jan

Cheers,
Alejandro


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

* Re: [RFC PATCH 16/25] xen/x86: Replace hand-crafted xen_arch_domainconfig with autogenerated one
  2024-11-25 12:09   ` Jan Beulich
@ 2024-11-25 18:53     ` Alejandro Vallejo
  0 siblings, 0 replies; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-25 18:53 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Anthony PERARD, Juergen Gross, Andrew Cooper, Julien Grall,
	Stefano Stabellini, Christian Lindig, David Scott,
	Roger Pau Monné, xen-devel

On Mon Nov 25, 2024 at 12:09 PM GMT, Jan Beulich wrote:
> On 15.11.2024 12:51, Alejandro Vallejo wrote:
> > Signed-off-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
> > ---
> >  tools/libs/light/libxl_x86.c                  |  4 +-
> >  tools/ocaml/libs/xc/xenctrl_stubs.c           |  4 +-
> >  .../extra/arch-x86/domainconfig.toml          | 87 +++++++++++++++++++
> >  .../xenbindgen/extra/domctl/createdomain.toml |  6 ++
> >  xen/arch/x86/domain.c                         |  8 +-
> >  xen/arch/x86/include/asm/domain.h             |  4 +-
> >  xen/arch/x86/setup.c                          |  2 +-
> >  xen/include/public/arch-x86/xen.h             | 51 -----------
> >  xen/include/public/autogen/arch_x86.h         | 52 +++++++++++
>
> Nit: If at all possible, please avoid underscores in the names of new files.
>
> Jan

Sure, re-casing it is easy.

Cheers,
Alejandro


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

* Re: [RFC PATCH 12/25] xen: Replace sysctl/readconsole with autogenerated version
  2024-11-25 18:51     ` Alejandro Vallejo
@ 2024-11-26  9:40       ` Jan Beulich
  2024-11-26 12:27         ` Alejandro Vallejo
  0 siblings, 1 reply; 51+ messages in thread
From: Jan Beulich @ 2024-11-26  9:40 UTC (permalink / raw)
  To: Alejandro Vallejo
  Cc: Anthony PERARD, Samuel Thibault, Andrew Cooper, Julien Grall,
	Stefano Stabellini, Daniel P. Smith, xen-devel

On 25.11.2024 19:51, Alejandro Vallejo wrote:
> On Mon Nov 25, 2024 at 12:05 PM GMT, Jan Beulich wrote:
>> On 15.11.2024 12:51, Alejandro Vallejo wrote:
>>> Describe sysctl/readconsole as a TOML specification, remove old
>>> hand-coded version and replace it with autogenerated file.
>>>
>>> While at it, transform the console driver to use uint8_t rather than
>>> char in order to mandate the type to be unsigned and ensure the ABI is
>>> not defined with regards to C-specific types.
>>
>> Yet the derived C representation imo then should still be using char, not
>> uint8_t.
> 
> There's 2 issued addressed by this patch.
> 
>   1. The removal of char from the external headers (and the Xen driver).
>   2. The replacement of the existing struct by the autogenerated one.
> 
> (1) wants doing irrespective of (2). char has neither a fixed width nor a fixed
> sign. Which is irrelevant for ABI purposes in this case because what we really
> meant is "give me a pointer" in this hypercall, but it may be important in
> other cases.
> 
> IOW, char should've never made it to the definition of the public ABI, and I'm
> merely taking the chance to take it out. Happy to extract this patch and send
> it separately.

Well, work towards fully getting char out of the public headers may indeed be
worthwhile. Otoh with char being the basic addressing granularity, I think
the ABI is pretty much tied to sizeof(char) == 1, imo limiting the
worthwhile-ness quite a bit.

Signed-ness of plain char doesn't really matter as long as it's used only for
what really are characters (or strings thereof). And that looks the be pretty
much the case throughout the public headers.

>> In particular it would be a good sign if the Xen sources wouldn't
>> need to change, unlike happens here (altering types of a few internals of
>> the console machinery).
> 
> And that would be the case if Xen had uniform naming conventions and its ABI
> was fully unambiguous. The process of uniformizing the naming convention and
> disambiguating the ABI is bound to cause (non-functional) changes, mostly in
> the naming conventions side of things.
> 
> Naming conventions can be _MOSTLY_ sorted by creating compat #defines and
> typedefs that match the old types. I can do that, but note that even then some
> code would have to change in order to i.e: s/struct OLD_NAME/NEW_NAME_T/

Here we already disagree: I think we'd better avoid any typedef-s in the public
interface when they're not strictly needed (e.g. in order to declare associated
handles). Imo we simply shouldn't introduce more into the name space than
actually required.

> If this is deemed important for backporting changes, I can do it for invasive
> replacements, like the createdomain flags.
> 
> On the topic of changing types, The present case is an ABI inconsistency case.
> My intention is to keep the ABI fixed as a matter of principle (if anything,
> because the domU ABI cannot be changed). However, changing the way C represents
> said ABI is a requirement if the current definition is ambiguous. In those
> cases we ought to change C to ensure there's one and only one way of
> interpreting it.

I wonder what concrete cases of ambiguity you're thinking of here.

>>>  xen/include/public/autogen/sysctl.h           | 35 +++++++++++++++
>>
>> In the build tree, having an autogen subdir under public/ _may_ be okay
>> (personally I dislike even that). I didn't manage to spot adjustments to
>> how files are eventually installed, yet at that point there clearly
>> shouldn't be any autogen subdir(s) anymore. How the individual files come
>> into existence is, imo, nothing consumers of the interface ought to (need
>> to) care about.
> 
> Anthony already mentioned an error while building QEMU, which I'm guessing
> comes from the same problem. The stitching is definitely up for discussion. I
> got far enough to allow the compilation of `dist` to go through, but didn't
> think incredibly hard about the finer details (like the install targets).
> 
> In principle, renaming `autogen` to `abi` and adding its contents to the list of
> installed headers ought to sort that particular concern? 

Not really, no. That only gives the child a different name. Imo the original
tree structure shouldn't change. By the end of the conversion work, all-
generated stuff would simply replace all-hand-written stuff.

>>> --- /dev/null
>>> +++ b/tools/rust/xenbindgen/extra/sysctl/readconsole.toml
>>> @@ -0,0 +1,43 @@
>>> +[[structs]]
>>> +name = "xen_sysctl_readconsole"
>>> +description = "Read console content from Xen buffer ring."
>>> +
>>> +[[structs.fields]]
>>> +name = "clear"
>>> +description = "IN: Non-zero -> clear after reading."
>>> +typ = { tag = "u8" }
>>> +
>>> +[[structs.fields]]
>>> +name = "incremental"
>>> +description = "IN: Non-zero -> start index specified by `index` field."
>>> +typ = { tag = "u8" }
>>> +
>>> +[[structs.fields]]
>>> +name = "_pad"
>>> +description = "Unused."
>>> +typ = { tag = "u16" }
>>> +
>>> +[[structs.fields]]
>>> +name = "index"
>>> +description = """
>>> +IN:  Start index for consuming from ring buffer (if @incremental);
>>> +OUT: End index after consuming from ring buffer."""
>>> +typ = { tag = "u32" }
>>> +
>>> +[[structs.fields]]
>>> +name = "buffer"
>>> +description = """
>>> +IN: Virtual address to write console data.
>>> +
>>> +NOTE: The pointer itself is IN, but the contents of the buffer are OUT."""
>>> +typ = { tag = "ptr", args = { tag = "u8" } }
>>> +
>>> +[[structs.fields]]
>>> +name = "count"
>>> +description = "IN: Size of buffer; OUT: Bytes written to buffer."
>>> +typ = { tag = "u32" }
>>> +
>>> +[[structs.fields]]
>>> +name = "rsvd0_a"
>>> +description = "Tail padding reserved to zero."
>>> +typ = { tag = "u32" }
>>
>> Up to here I wasn't able to spot any documentation on what it to be written
>> in which way.
> 
> You're right that the specification is not itself specified. I neglected to do
> so to avoid having to rewrite it should we settle on a different markup
> language.
> 
> Much of your confusion seems to stem from simultanuously looking at a new
> markup language and a new schema for it. Let me try to unpick some of that...
> 
>> I already struggle with the double square brackets. The TOML
>> doc I found when searching the web doesn't have such. Taking just the example
>> above also doesn't allow me to conclude how e.g. nested structures would be
>> specified.
> 
> The schema is represented by the contents of `spec.rs`. All structs with a
> Deserialize attribute (i.e: #[derive(Foo, Bar, Deserialize)]) map to some
> "table" in TOML.
> 
> When I say "struct" now I mean a struct inside the generator that represents
> the input file (_NOT_ a struct representing a hypercall).
> 
> The rules are as follows. The whole file is deserialized in a single struct
> (InFileDef). When there's a single square bracket (which I don't think I've
> required yet), that means that what follows is a "table" with the name between
> the brackets. There's several ways to represent table
> 
>     Regular tables:           [foo]
>                               bar = "some_bar"
>                               baz = "some_baz"
> 
>                               [foo2]
>                               bar = "blergh"
> 
>     Inline tables:            foo = { bar = "some_bar", baz = "some_baz" }
>                               foo2 = { bar = "blergh" }
> 
> Both of those deserialize to the same thing (it's C for ease of explaining it
> here, but it's actually Rust in the generator).
> 
>                 struct infiledef {
>                     struct {
>                         char *bar; // points to "some_bar"
>                         char *baz; // points to "some_baz"
>                     } foo;
>                     struct {
>                         char *bar; // points to "blergh"
>                     } foo2;
>                 };
> 
> The double brackets are adding one more element to a "list"
> 
> That is. This TOML...
> 
>                              [[foos]]
>                              bar = "some_bar"
>                              baz = "some_baz"
> 
>                              [[foos]]
>                              bar = "some_bar"
>                              baz = "some_baz"
> 
> ... deserializes to...
> 
>                 struct foodef {
>                     char *bar;
>                     char *baz;
>                 }
> 
>                 struct infiledef {
>                     struct foodef *foos;
>                 };
> 
> The last bit of relevant information is that you can identify which table you
> want to add to with dots. So [[structs.fields]] is saying "Add this field to
> the list of fields of the current hypercall struct".
> 
> The "typ" field is a bit quirky (I have a solution to simplify it), but that
> uses inline tables.
> 
>> Really, when talk was of some form of IDL, I expected to see
>> something IDLish (im particular closer to typical programming languages we
>> use). Whereas TOML, aiui, is more an easy language for config files of all
>> sorts.
> 
> I might've been unclear in the talk. One of my goals is to _not_ define a new
> language. Or I'll just exchange one problem for two. Maybe I should've called
> it an Interface Definition Schema, rather than Language.
> 
> The key benefit here is that, while the generators can be tricky, the parser is
> all done and strictly specified. We can experiment with YAML (Anthony already
> asked about it). But it really is a matter of getting used to. TOML is
> fantastic for saving horizontal space. And multi-line comments are neatly
> organized.

It may indeed be a matter of getting used to, yet I'm afraid your explanations
above make the situation yet more confusing, at least for the moment. Just to
explain my expectations some: I don't really speak e.g. Python or Perl, but the
languages are self-explanatory above that I can at least roughly follow not
overly involved pieces of code written therein. An interface specification imo
certainly falls in the group of "not overly involved". Yet the (so far small)
pieces of TOML that there aren't as self-explanatory as I'd have expected them
to be.

>> What I have in mind wouldn't allow for descriptions, yet I'm not sure that's
>> relevant. The description ought to, first of all, live in the primary source
>> (i.e. the IDL itself) anyway. Commentary there might be possible to extract
>> into proper (machine generated/derived) documentation.
> 
> Not sure I follow, these TOML files _are_ the IDL itself.
> 
> The descriptions here are propagated to the generated code, so they are
> infinitely helpful when reaching the type via e.g: cscope, LSPs, etc.

Yet they are full-fledged attributes, when normally I'd expect such to be
comments (thus clearly separating "code" from "non-code").

As to propagating to generated code - hmm, yes, for use of cscope and alike
it may indeed be helpful to propagate, if such tools can't associate back
the generated files to their origins. My general take though is that
generated code is something you look at as a human only when actually
dealing with their generation. For all other purposes one would prefer the
"original" source.

>>> --- a/xen/drivers/char/console.c
>>> +++ b/xen/drivers/char/console.c
>>> @@ -42,6 +42,8 @@
>>>  #include <asm/vpl011.h>
>>>  #endif
>>>  
>>> +#include <public/xen.h>
>>
>> Why would this be needed all of the sudden?
>>
> 
> Because of the new XEN_GUEST_HANDLE_64(uint8) type. The macro is quite ugly and
> requires being declared ahead.

How's that different from the earlier XEN_GUEST_HANDLE_PARAM(char)?

>>> --- /dev/null
>>> +++ b/xen/include/public/autogen/sysctl.h
>>> @@ -0,0 +1,35 @@
>>> +/*
>>> + * sysctl
>>> + *
>>> + * AUTOGENERATED. DO NOT MODIFY
>>> + */
>>> +#ifndef __XEN_AUTOGEN_SYSCTL_H
>>> +#define __XEN_AUTOGEN_SYSCTL_H
>>> +
>>> +/* Read console content from Xen buffer ring. */
>>> +struct xen_sysctl_readconsole {
>>> +    /* IN: Non-zero -> clear after reading. */
>>> +    uint8_t clear;
>>> +    /* IN: Non-zero -> start index specified by `index` field. */
>>> +    uint8_t incremental;
>>> +    /* Unused. */
>>> +    uint16_t _pad;
>>> +    /*
>>> +     * IN:  Start index for consuming from ring buffer (if @incremental);
>>> +     * OUT: End index after consuming from ring buffer.
>>> +     */
>>> +    uint32_t index;
>>> +    /*
>>> +     * IN: Virtual address to write console data.
>>> +     *
>>> +     * NOTE: The pointer itself is IN, but the contents of the buffer are OUT.
>>> +     */
>>> +    XEN_GUEST_HANDLE_64(uint8) buffer;
>>> +    /* IN: Size of buffer; OUT: Bytes written to buffer. */
>>> +    uint32_t count;
>>> +    /* Tail padding reserved to zero. */
>>> +    uint32_t rsvd0_a;
>>> +};
>>> +
>>> +#endif /* __XEN_AUTOGEN_SYSCTL_H */
>>> +
>>
>> If this file is auto-generated, why would it need committing? And yes, there
>> is the connected question: Will everyone then need to have a Rust compiler
>> available?
> 
> Committing it is required precisely so that no one needs to have a Rust
> compiler available.

How would that work? If I make a change to what currently is a public header,
I'd still need to have one available, wouldn't I?

> The last patch in the series checks the generated code
> matches the specs byte by byte. It has the nice benefit that you can git-grep
> for it and tags work even without compiling first. You also get all
> architectures upfront and it's a lot easier to review changes to the generator
> because CI will scream to you if the outputs diverge.
> 
>>
>> Nit: For anything that is committed, it would be nice if those files were as
>> tidy as possible style-wise. Most of the above looks entirely okay, just
>> that there is an unnecessary trailing blank line.
> 
> I did go out of my way to prettify the output.
> 
> The trailing newline was intentional to make it C++03-compatible. I can get rid
> of it, as it doesn't matter a whole lot.

I haven't followed the development of C++ very closely; my experience with it
is mostly from far more than 20 years ago. What's that C++03 compatibility
requirement?

Jan


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

* Re: [RFC PATCH 12/25] xen: Replace sysctl/readconsole with autogenerated version
  2024-11-26  9:40       ` Jan Beulich
@ 2024-11-26 12:27         ` Alejandro Vallejo
  2024-11-26 13:20           ` Jan Beulich
  0 siblings, 1 reply; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-26 12:27 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Anthony PERARD, Samuel Thibault, Andrew Cooper, Julien Grall,
	Stefano Stabellini, Daniel P. Smith, xen-devel

On Tue Nov 26, 2024 at 9:40 AM GMT, Jan Beulich wrote:
> On 25.11.2024 19:51, Alejandro Vallejo wrote:
> > On Mon Nov 25, 2024 at 12:05 PM GMT, Jan Beulich wrote:
> >> On 15.11.2024 12:51, Alejandro Vallejo wrote:
> >>> Describe sysctl/readconsole as a TOML specification, remove old
> >>> hand-coded version and replace it with autogenerated file.
> >>>
> >>> While at it, transform the console driver to use uint8_t rather than
> >>> char in order to mandate the type to be unsigned and ensure the ABI is
> >>> not defined with regards to C-specific types.
> >>
> >> Yet the derived C representation imo then should still be using char, not
> >> uint8_t.
> > 
> > There's 2 issued addressed by this patch.
> > 
> >   1. The removal of char from the external headers (and the Xen driver).
> >   2. The replacement of the existing struct by the autogenerated one.
> > 
> > (1) wants doing irrespective of (2). char has neither a fixed width nor a fixed
> > sign. Which is irrelevant for ABI purposes in this case because what we really
> > meant is "give me a pointer" in this hypercall, but it may be important in
> > other cases.
> > 
> > IOW, char should've never made it to the definition of the public ABI, and I'm
> > merely taking the chance to take it out. Happy to extract this patch and send
> > it separately.
>
> Well, work towards fully getting char out of the public headers may indeed be
> worthwhile. Otoh with char being the basic addressing granularity, I think
> the ABI is pretty much tied to sizeof(char) == 1, imo limiting the
> worthwhile-ness quite a bit.

Let me put it another way. If I were to create a separate patch stripping char
and using uint8_t instead, what are my chances of getting an Acked-by? Or not a
NAK, at least. (there's other maintainers that I need that from, but one step
at a time).

>
> Signed-ness of plain char doesn't really matter as long as it's used only for
> what really are characters (or strings thereof). And that looks the be pretty
> much the case throughout the public headers.

Maybe. Still, as a general principle caller and callee ought to agree on size,
alignment and sign for every type. I'd rather not make exceptions for that
invariant unless truly well motivated. And in this case it's a case of
requiring trivial non-functional changes.

>
> >> In particular it would be a good sign if the Xen sources wouldn't
> >> need to change, unlike happens here (altering types of a few internals of
> >> the console machinery).
> > 
> > And that would be the case if Xen had uniform naming conventions and its ABI
> > was fully unambiguous. The process of uniformizing the naming convention and
> > disambiguating the ABI is bound to cause (non-functional) changes, mostly in
> > the naming conventions side of things.
> > 
> > Naming conventions can be _MOSTLY_ sorted by creating compat #defines and
> > typedefs that match the old types. I can do that, but note that even then some
> > code would have to change in order to i.e: s/struct OLD_NAME/NEW_NAME_T/
>
> Here we already disagree: I think we'd better avoid any typedef-s in the public
> interface when they're not strictly needed (e.g. in order to declare associated
> handles). Imo we simply shouldn't introduce more into the name space than
> actually required.

I really don't want to pollute the spec files with tidbits of how C happened to
case its identifiers originally.

> > If this is deemed important for backporting changes, I can do it for invasive
> > replacements, like the createdomain flags.
> > 
> > On the topic of changing types, The present case is an ABI inconsistency case.
> > My intention is to keep the ABI fixed as a matter of principle (if anything,
> > because the domU ABI cannot be changed). However, changing the way C represents
> > said ABI is a requirement if the current definition is ambiguous. In those
> > cases we ought to change C to ensure there's one and only one way of
> > interpreting it.
>
> I wonder what concrete cases of ambiguity you're thinking of here.
>

Anything where the size, alignment or sign of a type might not be up for
interpretation. This "char" case is one. So are things like xen_sysctl_meminfo
due to using raw uint64_t rather than uint64_aligned_t.

> >>>  xen/include/public/autogen/sysctl.h           | 35 +++++++++++++++
> >>
> >> In the build tree, having an autogen subdir under public/ _may_ be okay
> >> (personally I dislike even that). I didn't manage to spot adjustments to
> >> how files are eventually installed, yet at that point there clearly
> >> shouldn't be any autogen subdir(s) anymore. How the individual files come
> >> into existence is, imo, nothing consumers of the interface ought to (need
> >> to) care about.
> > 
> > Anthony already mentioned an error while building QEMU, which I'm guessing
> > comes from the same problem. The stitching is definitely up for discussion. I
> > got far enough to allow the compilation of `dist` to go through, but didn't
> > think incredibly hard about the finer details (like the install targets).
> > 
> > In principle, renaming `autogen` to `abi` and adding its contents to the list of
> > installed headers ought to sort that particular concern? 
>
> Not really, no. That only gives the child a different name. Imo the original
> tree structure shouldn't change. By the end of the conversion work, all-
> generated stuff would simply replace all-hand-written stuff.

I'm afraid that introduces a lot of undue complexity. Putting everything
autogenerated in the same folder where only autogenerated headers live (from
the same generator) provides for easy ways of checking whether files are stale
or not. Trying to surgically replace C would require either a C parser or magic
tokens in the header (yuck!).

I want to avoid anyone having to explicitly include the new headers, but they
do definitely want to be installed in the targets alongside the rest of the
public headers. Because they are public headers.

>
> >>> --- /dev/null
> >>> +++ b/tools/rust/xenbindgen/extra/sysctl/readconsole.toml
> >>> @@ -0,0 +1,43 @@
> >>> +[[structs]]
> >>> +name = "xen_sysctl_readconsole"
> >>> +description = "Read console content from Xen buffer ring."
> >>> +
> >>> +[[structs.fields]]
> >>> +name = "clear"
> >>> +description = "IN: Non-zero -> clear after reading."
> >>> +typ = { tag = "u8" }
> >>> +
> >>> +[[structs.fields]]
> >>> +name = "incremental"
> >>> +description = "IN: Non-zero -> start index specified by `index` field."
> >>> +typ = { tag = "u8" }
> >>> +
> >>> +[[structs.fields]]
> >>> +name = "_pad"
> >>> +description = "Unused."
> >>> +typ = { tag = "u16" }
> >>> +
> >>> +[[structs.fields]]
> >>> +name = "index"
> >>> +description = """
> >>> +IN:  Start index for consuming from ring buffer (if @incremental);
> >>> +OUT: End index after consuming from ring buffer."""
> >>> +typ = { tag = "u32" }
> >>> +
> >>> +[[structs.fields]]
> >>> +name = "buffer"
> >>> +description = """
> >>> +IN: Virtual address to write console data.
> >>> +
> >>> +NOTE: The pointer itself is IN, but the contents of the buffer are OUT."""
> >>> +typ = { tag = "ptr", args = { tag = "u8" } }
> >>> +
> >>> +[[structs.fields]]
> >>> +name = "count"
> >>> +description = "IN: Size of buffer; OUT: Bytes written to buffer."
> >>> +typ = { tag = "u32" }
> >>> +
> >>> +[[structs.fields]]
> >>> +name = "rsvd0_a"
> >>> +description = "Tail padding reserved to zero."
> >>> +typ = { tag = "u32" }
> >>
> >> Up to here I wasn't able to spot any documentation on what it to be written
> >> in which way.
> > 
> > You're right that the specification is not itself specified. I neglected to do
> > so to avoid having to rewrite it should we settle on a different markup
> > language.
> > 
> > Much of your confusion seems to stem from simultanuously looking at a new
> > markup language and a new schema for it. Let me try to unpick some of that...
> > 
> >> I already struggle with the double square brackets. The TOML
> >> doc I found when searching the web doesn't have such. Taking just the example
> >> above also doesn't allow me to conclude how e.g. nested structures would be
> >> specified.
> > 
> > The schema is represented by the contents of `spec.rs`. All structs with a
> > Deserialize attribute (i.e: #[derive(Foo, Bar, Deserialize)]) map to some
> > "table" in TOML.
> > 
> > When I say "struct" now I mean a struct inside the generator that represents
> > the input file (_NOT_ a struct representing a hypercall).
> > 
> > The rules are as follows. The whole file is deserialized in a single struct
> > (InFileDef). When there's a single square bracket (which I don't think I've
> > required yet), that means that what follows is a "table" with the name between
> > the brackets. There's several ways to represent table
> > 
> >     Regular tables:           [foo]
> >                               bar = "some_bar"
> >                               baz = "some_baz"
> > 
> >                               [foo2]
> >                               bar = "blergh"
> > 
> >     Inline tables:            foo = { bar = "some_bar", baz = "some_baz" }
> >                               foo2 = { bar = "blergh" }
> > 
> > Both of those deserialize to the same thing (it's C for ease of explaining it
> > here, but it's actually Rust in the generator).
> > 
> >                 struct infiledef {
> >                     struct {
> >                         char *bar; // points to "some_bar"
> >                         char *baz; // points to "some_baz"
> >                     } foo;
> >                     struct {
> >                         char *bar; // points to "blergh"
> >                     } foo2;
> >                 };
> > 
> > The double brackets are adding one more element to a "list"
> > 
> > That is. This TOML...
> > 
> >                              [[foos]]
> >                              bar = "some_bar"
> >                              baz = "some_baz"
> > 
> >                              [[foos]]
> >                              bar = "some_bar"
> >                              baz = "some_baz"
> > 
> > ... deserializes to...
> > 
> >                 struct foodef {
> >                     char *bar;
> >                     char *baz;
> >                 }
> > 
> >                 struct infiledef {
> >                     struct foodef *foos;
> >                 };
> > 
> > The last bit of relevant information is that you can identify which table you
> > want to add to with dots. So [[structs.fields]] is saying "Add this field to
> > the list of fields of the current hypercall struct".
> > 
> > The "typ" field is a bit quirky (I have a solution to simplify it), but that
> > uses inline tables.
> > 
> >> Really, when talk was of some form of IDL, I expected to see
> >> something IDLish (im particular closer to typical programming languages we
> >> use). Whereas TOML, aiui, is more an easy language for config files of all
> >> sorts.
> > 
> > I might've been unclear in the talk. One of my goals is to _not_ define a new
> > language. Or I'll just exchange one problem for two. Maybe I should've called
> > it an Interface Definition Schema, rather than Language.
> > 
> > The key benefit here is that, while the generators can be tricky, the parser is
> > all done and strictly specified. We can experiment with YAML (Anthony already
> > asked about it). But it really is a matter of getting used to. TOML is
> > fantastic for saving horizontal space. And multi-line comments are neatly
> > organized.
>
> It may indeed be a matter of getting used to, yet I'm afraid your explanations
> above make the situation yet more confusing, at least for the moment. Just to
> explain my expectations some: I don't really speak e.g. Python or Perl, but the
> languages are self-explanatory above that I can at least roughly follow not
> overly involved pieces of code written therein. An interface specification imo
> certainly falls in the group of "not overly involved". Yet the (so far small)
> pieces of TOML that there aren't as self-explanatory as I'd have expected them
> to be.

That's fair. I'll have it translated to YAML for comparison, as  I suspect
it'll be easier on the eye.

>
> >> What I have in mind wouldn't allow for descriptions, yet I'm not sure that's
> >> relevant. The description ought to, first of all, live in the primary source
> >> (i.e. the IDL itself) anyway. Commentary there might be possible to extract
> >> into proper (machine generated/derived) documentation.
> > 
> > Not sure I follow, these TOML files _are_ the IDL itself.
> > 
> > The descriptions here are propagated to the generated code, so they are
> > infinitely helpful when reaching the type via e.g: cscope, LSPs, etc.
>
> Yet they are full-fledged attributes, when normally I'd expect such to be
> comments (thus clearly separating "code" from "non-code").

A comment in TOML (or YAML) would stay at the markup because the parser would
never see it. It must be an attribute so it's brought to it's intended
destination (the .h/.rs files). While it'd be desirable to have a connection
between the spec files and their generated counterparts at the LSP-level, I'm
not aware of any way of doing so. And by and large, unless you're actively
adding another hypercall, you really shouldn't care.

>
> As to propagating to generated code - hmm, yes, for use of cscope and alike
> it may indeed be helpful to propagate, if such tools can't associate back
> the generated files to their origins. My general take though is that
> generated code is something you look at as a human only when actually
> dealing with their generation. For all other purposes one would prefer the
> "original" source.

I'd say it's the other way around. I only look at the source material when
working on the generation. In general, I care about what was generated (if
anything, because that's where cscope took me while traversing the tree.

Of course, all this assumes all information in the source file has been
propagated to the generated file. And that's the case here.

>
> >>> --- a/xen/drivers/char/console.c
> >>> +++ b/xen/drivers/char/console.c
> >>> @@ -42,6 +42,8 @@
> >>>  #include <asm/vpl011.h>
> >>>  #endif
> >>>  
> >>> +#include <public/xen.h>
> >>
> >> Why would this be needed all of the sudden?
> >>
> > 
> > Because of the new XEN_GUEST_HANDLE_64(uint8) type. The macro is quite ugly and
> > requires being declared ahead.
>
> How's that different from the earlier XEN_GUEST_HANDLE_PARAM(char)?

I'll have a go at removing it. I wrote that a while ago and I no longer
remember the specifics of why it was required.

>
> >>> --- /dev/null
> >>> +++ b/xen/include/public/autogen/sysctl.h
> >>> @@ -0,0 +1,35 @@
> >>> +/*
> >>> + * sysctl
> >>> + *
> >>> + * AUTOGENERATED. DO NOT MODIFY
> >>> + */
> >>> +#ifndef __XEN_AUTOGEN_SYSCTL_H
> >>> +#define __XEN_AUTOGEN_SYSCTL_H
> >>> +
> >>> +/* Read console content from Xen buffer ring. */
> >>> +struct xen_sysctl_readconsole {
> >>> +    /* IN: Non-zero -> clear after reading. */
> >>> +    uint8_t clear;
> >>> +    /* IN: Non-zero -> start index specified by `index` field. */
> >>> +    uint8_t incremental;
> >>> +    /* Unused. */
> >>> +    uint16_t _pad;
> >>> +    /*
> >>> +     * IN:  Start index for consuming from ring buffer (if @incremental);
> >>> +     * OUT: End index after consuming from ring buffer.
> >>> +     */
> >>> +    uint32_t index;
> >>> +    /*
> >>> +     * IN: Virtual address to write console data.
> >>> +     *
> >>> +     * NOTE: The pointer itself is IN, but the contents of the buffer are OUT.
> >>> +     */
> >>> +    XEN_GUEST_HANDLE_64(uint8) buffer;
> >>> +    /* IN: Size of buffer; OUT: Bytes written to buffer. */
> >>> +    uint32_t count;
> >>> +    /* Tail padding reserved to zero. */
> >>> +    uint32_t rsvd0_a;
> >>> +};
> >>> +
> >>> +#endif /* __XEN_AUTOGEN_SYSCTL_H */
> >>> +
> >>
> >> If this file is auto-generated, why would it need committing? And yes, there
> >> is the connected question: Will everyone then need to have a Rust compiler
> >> available?
> > 
> > Committing it is required precisely so that no one needs to have a Rust
> > compiler available.
>
> How would that work? If I make a change to what currently is a public header,
> I'd still need to have one available, wouldn't I?

If you want to make a change to the public ABI, then yes. But that's reasonaly
rare. What I want to avoid is _everyone_ needing a Rust compiler just to build,
or indeed pushing the Rust dependency as a build-dependency on every
downstream. That might come to pass, as the efforts to Rust-ify the toolstack
come to fruition, but we're not there yet.

As for one-off changes, it's actually fairly easy to determine what a new field
in the spec would look like in the final file. You could even write it by hand.
CI will validate the C headers match the spec outputs.

When they don't match, CI tells you the diff.

>
> > The last patch in the series checks the generated code
> > matches the specs byte by byte. It has the nice benefit that you can git-grep
> > for it and tags work even without compiling first. You also get all
> > architectures upfront and it's a lot easier to review changes to the generator
> > because CI will scream to you if the outputs diverge.
> > 
> >>
> >> Nit: For anything that is committed, it would be nice if those files were as
> >> tidy as possible style-wise. Most of the above looks entirely okay, just
> >> that there is an unnecessary trailing blank line.
> > 
> > I did go out of my way to prettify the output.
> > 
> > The trailing newline was intentional to make it C++03-compatible. I can get rid
> > of it, as it doesn't matter a whole lot.
>
> I haven't followed the development of C++ very closely; my experience with it
> is mostly from far more than 20 years ago. What's that C++03 compatibility
> requirement?
>
> Jan

It's really unimportant. -Wnewline-eof, I think it was. There's a pedantic
paragraph in the C++ spec from 2003 that states that if a file is not
newline-terminated it's UB to parse it. I tend to newline-terminate my files
for easy `cat`-ing them together in the rare occasions where that's useful for
something.

Regardless, it's trully unimportant, I'll just get rid of that final newline.

Cheers,
Alejandro


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

* Re: [RFC PATCH 12/25] xen: Replace sysctl/readconsole with autogenerated version
  2024-11-26 12:27         ` Alejandro Vallejo
@ 2024-11-26 13:20           ` Jan Beulich
  2024-11-26 14:36             ` Alejandro Vallejo
  2024-11-26 14:39             ` Teddy Astie
  0 siblings, 2 replies; 51+ messages in thread
From: Jan Beulich @ 2024-11-26 13:20 UTC (permalink / raw)
  To: Alejandro Vallejo
  Cc: Anthony PERARD, Samuel Thibault, Andrew Cooper, Julien Grall,
	Stefano Stabellini, Daniel P. Smith, xen-devel

On 26.11.2024 13:27, Alejandro Vallejo wrote:
> On Tue Nov 26, 2024 at 9:40 AM GMT, Jan Beulich wrote:
>> On 25.11.2024 19:51, Alejandro Vallejo wrote:
>>> On Mon Nov 25, 2024 at 12:05 PM GMT, Jan Beulich wrote:
>>>> On 15.11.2024 12:51, Alejandro Vallejo wrote:
>>>>> Describe sysctl/readconsole as a TOML specification, remove old
>>>>> hand-coded version and replace it with autogenerated file.
>>>>>
>>>>> While at it, transform the console driver to use uint8_t rather than
>>>>> char in order to mandate the type to be unsigned and ensure the ABI is
>>>>> not defined with regards to C-specific types.
>>>>
>>>> Yet the derived C representation imo then should still be using char, not
>>>> uint8_t.
>>>
>>> There's 2 issued addressed by this patch.
>>>
>>>   1. The removal of char from the external headers (and the Xen driver).
>>>   2. The replacement of the existing struct by the autogenerated one.
>>>
>>> (1) wants doing irrespective of (2). char has neither a fixed width nor a fixed
>>> sign. Which is irrelevant for ABI purposes in this case because what we really
>>> meant is "give me a pointer" in this hypercall, but it may be important in
>>> other cases.
>>>
>>> IOW, char should've never made it to the definition of the public ABI, and I'm
>>> merely taking the chance to take it out. Happy to extract this patch and send
>>> it separately.
>>
>> Well, work towards fully getting char out of the public headers may indeed be
>> worthwhile. Otoh with char being the basic addressing granularity, I think
>> the ABI is pretty much tied to sizeof(char) == 1, imo limiting the
>> worthwhile-ness quite a bit.
> 
> Let me put it another way. If I were to create a separate patch stripping char
> and using uint8_t instead, what are my chances of getting an Acked-by? Or not a
> NAK, at least. (there's other maintainers that I need that from, but one step
> at a time).

That would to some degree depend on what other maintainers think. Not a straight
NAK in any event.

>> Signed-ness of plain char doesn't really matter as long as it's used only for
>> what really are characters (or strings thereof). And that looks the be pretty
>> much the case throughout the public headers.
> 
> Maybe. Still, as a general principle caller and callee ought to agree on size,
> alignment and sign for every type. I'd rather not make exceptions for that
> invariant unless truly well motivated. And in this case it's a case of
> requiring trivial non-functional changes.

In how far they're non-functional will need to be seen. You also need to keep
consumers in mind: They may face sudden type disagreement that compilers may
complain about. Yet "stable" for the public headers means not just the ABI
itself being stable, but updated headers also being usable as drop-in
replacements for older versions.

>>>> Nit: For anything that is committed, it would be nice if those files were as
>>>> tidy as possible style-wise. Most of the above looks entirely okay, just
>>>> that there is an unnecessary trailing blank line.
>>>
>>> I did go out of my way to prettify the output.
>>>
>>> The trailing newline was intentional to make it C++03-compatible. I can get rid
>>> of it, as it doesn't matter a whole lot.
>>
>> I haven't followed the development of C++ very closely; my experience with it
>> is mostly from far more than 20 years ago. What's that C++03 compatibility
>> requirement?
> 
> It's really unimportant. -Wnewline-eof, I think it was. There's a pedantic
> paragraph in the C++ spec from 2003 that states that if a file is not
> newline-terminated it's UB to parse it. I tend to newline-terminate my files
> for easy `cat`-ing them together in the rare occasions where that's useful for
> something.

Unimportant or not - there must then be some misunderstanding on either my
side or yours. Even the assembler insists on a final newline, as does plain
C. Yet that means one newline, not two (i.e. not a trailing blank line).

Jan


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

* Re: [RFC PATCH 12/25] xen: Replace sysctl/readconsole with autogenerated version
  2024-11-26 13:20           ` Jan Beulich
@ 2024-11-26 14:36             ` Alejandro Vallejo
  2024-11-26 16:30               ` Jan Beulich
  2024-11-26 14:39             ` Teddy Astie
  1 sibling, 1 reply; 51+ messages in thread
From: Alejandro Vallejo @ 2024-11-26 14:36 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Anthony PERARD, Samuel Thibault, Andrew Cooper, Julien Grall,
	Stefano Stabellini, Daniel P. Smith, xen-devel

On Tue Nov 26, 2024 at 1:20 PM GMT, Jan Beulich wrote:
> On 26.11.2024 13:27, Alejandro Vallejo wrote:
> > On Tue Nov 26, 2024 at 9:40 AM GMT, Jan Beulich wrote:
> >> On 25.11.2024 19:51, Alejandro Vallejo wrote:
> >>> On Mon Nov 25, 2024 at 12:05 PM GMT, Jan Beulich wrote:
> >>>> On 15.11.2024 12:51, Alejandro Vallejo wrote:
> >>>>> Describe sysctl/readconsole as a TOML specification, remove old
> >>>>> hand-coded version and replace it with autogenerated file.
> >>>>>
> >>>>> While at it, transform the console driver to use uint8_t rather than
> >>>>> char in order to mandate the type to be unsigned and ensure the ABI is
> >>>>> not defined with regards to C-specific types.
> >>>>
> >>>> Yet the derived C representation imo then should still be using char, not
> >>>> uint8_t.
> >>>
> >>> There's 2 issued addressed by this patch.
> >>>
> >>>   1. The removal of char from the external headers (and the Xen driver).
> >>>   2. The replacement of the existing struct by the autogenerated one.
> >>>
> >>> (1) wants doing irrespective of (2). char has neither a fixed width nor a fixed
> >>> sign. Which is irrelevant for ABI purposes in this case because what we really
> >>> meant is "give me a pointer" in this hypercall, but it may be important in
> >>> other cases.
> >>>
> >>> IOW, char should've never made it to the definition of the public ABI, and I'm
> >>> merely taking the chance to take it out. Happy to extract this patch and send
> >>> it separately.
> >>
> >> Well, work towards fully getting char out of the public headers may indeed be
> >> worthwhile. Otoh with char being the basic addressing granularity, I think
> >> the ABI is pretty much tied to sizeof(char) == 1, imo limiting the
> >> worthwhile-ness quite a bit.
> > 
> > Let me put it another way. If I were to create a separate patch stripping char
> > and using uint8_t instead, what are my chances of getting an Acked-by? Or not a
> > NAK, at least. (there's other maintainers that I need that from, but one step
> > at a time).
>
> That would to some degree depend on what other maintainers think. Not a straight
> NAK in any event.
>
> >> Signed-ness of plain char doesn't really matter as long as it's used only for
> >> what really are characters (or strings thereof). And that looks the be pretty
> >> much the case throughout the public headers.
> > 
> > Maybe. Still, as a general principle caller and callee ought to agree on size,
> > alignment and sign for every type. I'd rather not make exceptions for that
> > invariant unless truly well motivated. And in this case it's a case of
> > requiring trivial non-functional changes.
>
> In how far they're non-functional will need to be seen. You also need to keep
> consumers in mind: They may face sudden type disagreement that compilers may
> complain about. Yet "stable" for the public headers means not just the ABI
> itself being stable, but updated headers also being usable as drop-in
> replacements for older versions.

Would it be fair to say that users of the Xen low-level API strictly go via
xenctrl et al? So long as it's only those libraries being affected the effects
should not be externally visible. It's just the hypercall boundary that is
adjusted, not the external API.

>
> >>>> Nit: For anything that is committed, it would be nice if those files were as
> >>>> tidy as possible style-wise. Most of the above looks entirely okay, just
> >>>> that there is an unnecessary trailing blank line.
> >>>
> >>> I did go out of my way to prettify the output.
> >>>
> >>> The trailing newline was intentional to make it C++03-compatible. I can get rid
> >>> of it, as it doesn't matter a whole lot.
> >>
> >> I haven't followed the development of C++ very closely; my experience with it
> >> is mostly from far more than 20 years ago. What's that C++03 compatibility
> >> requirement?
> > 
> > It's really unimportant. -Wnewline-eof, I think it was. There's a pedantic
> > paragraph in the C++ spec from 2003 that states that if a file is not
> > newline-terminated it's UB to parse it. I tend to newline-terminate my files
> > for easy `cat`-ing them together in the rare occasions where that's useful for
> > something.
>
> Unimportant or not - there must then be some misunderstanding on either my
> side or yours. Even the assembler insists on a final newline, as does plain
> C. Yet that means one newline, not two (i.e. not a trailing blank line).
>
> Jan

Ok, I see what you mean now (only after doing `xxd <file>`). There's indeed an
extra trailing newline. My $EDITOR led me astray.

Cheers,
Alejandro


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

* Re: [RFC PATCH 12/25] xen: Replace sysctl/readconsole with autogenerated version
  2024-11-26 13:20           ` Jan Beulich
  2024-11-26 14:36             ` Alejandro Vallejo
@ 2024-11-26 14:39             ` Teddy Astie
  2024-11-26 16:28               ` Jan Beulich
  1 sibling, 1 reply; 51+ messages in thread
From: Teddy Astie @ 2024-11-26 14:39 UTC (permalink / raw)
  To: Jan Beulich, Alejandro Vallejo
  Cc: Anthony PERARD, Samuel Thibault, Andrew Cooper, Julien Grall,
	Stefano Stabellini, Daniel P. Smith, xen-devel

Hello,

Le 26/11/2024 à 14:20, Jan Beulich a écrit :
>>> Signed-ness of plain char doesn't really matter as long as it's used only for
>>> what really are characters (or strings thereof). And that looks the be pretty
>>> much the case throughout the public headers.
>> Maybe. Still, as a general principle caller and callee ought to agree on size,
>> alignment and sign for every type. I'd rather not make exceptions for that
>> invariant unless truly well motivated. And in this case it's a case of
>> requiring trivial non-functional changes.
> In how far they're non-functional will need to be seen. You also need to keep
> consumers in mind: They may face sudden type disagreement that compilers may
> complain about. Yet "stable" for the public headers means not just the ABI
> itself being stable, but updated headers also being usable as drop-in
> replacements for older versions.

I don't think we currently enforce stability on all Xen headers
(especially not those control-domain related).
For instance

Commit 21e3ef57e0406b6b9a783f721f29df8f91a00f99
x86: Rename {domctl,sysctl}.cpu_policy.{cpuid,msr}_policy fields

actually modifies the name of some fields in a struct of sysctl.h, so I
suppose modifying the type of fields with more defined variants is
acceptable.

One thing remain is that if the user is not careful of this change and
char is silently replaced by uint8_t, could that break something by
possibly changing the signed-ness ?

Teddy


Teddy Astie | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech



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

* Re: [RFC PATCH 12/25] xen: Replace sysctl/readconsole with autogenerated version
  2024-11-26 14:39             ` Teddy Astie
@ 2024-11-26 16:28               ` Jan Beulich
  0 siblings, 0 replies; 51+ messages in thread
From: Jan Beulich @ 2024-11-26 16:28 UTC (permalink / raw)
  To: Teddy Astie
  Cc: Anthony PERARD, Samuel Thibault, Andrew Cooper, Julien Grall,
	Stefano Stabellini, Daniel P. Smith, xen-devel, Alejandro Vallejo

On 26.11.2024 15:39, Teddy Astie wrote:
> Le 26/11/2024 à 14:20, Jan Beulich a écrit :
>>>> Signed-ness of plain char doesn't really matter as long as it's used only for
>>>> what really are characters (or strings thereof). And that looks the be pretty
>>>> much the case throughout the public headers.
>>> Maybe. Still, as a general principle caller and callee ought to agree on size,
>>> alignment and sign for every type. I'd rather not make exceptions for that
>>> invariant unless truly well motivated. And in this case it's a case of
>>> requiring trivial non-functional changes.
>> In how far they're non-functional will need to be seen. You also need to keep
>> consumers in mind: They may face sudden type disagreement that compilers may
>> complain about. Yet "stable" for the public headers means not just the ABI
>> itself being stable, but updated headers also being usable as drop-in
>> replacements for older versions.
> 
> I don't think we currently enforce stability on all Xen headers 
> (especially not those control-domain related).
> For instance
> 
> Commit 21e3ef57e0406b6b9a783f721f29df8f91a00f99
> x86: Rename {domctl,sysctl}.cpu_policy.{cpuid,msr}_policy fields
> 
> actually modifies the name of some fields in a struct of sysctl.h, so I 
> suppose modifying the type of fields with more defined variants is 
> acceptable.

Context shifted away from what the subject says, towards doing replacement
on _all_ public headers. For domctl/sysctl and other toolstack-only ones
the transformation would indeed be less problematic (it would be mainly us
who need to adjust the wrapper functions in the libraries).

> One thing remain is that if the user is not careful of this change and 
> char is silently replaced by uint8_t, could that break something by 
> possibly changing the signed-ness ?

Well, sure, such a risk exists. Much would depend on how the wrapper
functions were adjusted.

Jan


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

* Re: [RFC PATCH 12/25] xen: Replace sysctl/readconsole with autogenerated version
  2024-11-26 14:36             ` Alejandro Vallejo
@ 2024-11-26 16:30               ` Jan Beulich
  0 siblings, 0 replies; 51+ messages in thread
From: Jan Beulich @ 2024-11-26 16:30 UTC (permalink / raw)
  To: Alejandro Vallejo
  Cc: Anthony PERARD, Samuel Thibault, Andrew Cooper, Julien Grall,
	Stefano Stabellini, Daniel P. Smith, xen-devel

On 26.11.2024 15:36, Alejandro Vallejo wrote:
> On Tue Nov 26, 2024 at 1:20 PM GMT, Jan Beulich wrote:
>> On 26.11.2024 13:27, Alejandro Vallejo wrote:
>>> On Tue Nov 26, 2024 at 9:40 AM GMT, Jan Beulich wrote:
>>>> On 25.11.2024 19:51, Alejandro Vallejo wrote:
>>>>> On Mon Nov 25, 2024 at 12:05 PM GMT, Jan Beulich wrote:
>>>>>> On 15.11.2024 12:51, Alejandro Vallejo wrote:
>>>>>>> Describe sysctl/readconsole as a TOML specification, remove old
>>>>>>> hand-coded version and replace it with autogenerated file.
>>>>>>>
>>>>>>> While at it, transform the console driver to use uint8_t rather than
>>>>>>> char in order to mandate the type to be unsigned and ensure the ABI is
>>>>>>> not defined with regards to C-specific types.
>>>>>>
>>>>>> Yet the derived C representation imo then should still be using char, not
>>>>>> uint8_t.
>>>>>
>>>>> There's 2 issued addressed by this patch.
>>>>>
>>>>>   1. The removal of char from the external headers (and the Xen driver).
>>>>>   2. The replacement of the existing struct by the autogenerated one.
>>>>>
>>>>> (1) wants doing irrespective of (2). char has neither a fixed width nor a fixed
>>>>> sign. Which is irrelevant for ABI purposes in this case because what we really
>>>>> meant is "give me a pointer" in this hypercall, but it may be important in
>>>>> other cases.
>>>>>
>>>>> IOW, char should've never made it to the definition of the public ABI, and I'm
>>>>> merely taking the chance to take it out. Happy to extract this patch and send
>>>>> it separately.
>>>>
>>>> Well, work towards fully getting char out of the public headers may indeed be
>>>> worthwhile. Otoh with char being the basic addressing granularity, I think
>>>> the ABI is pretty much tied to sizeof(char) == 1, imo limiting the
>>>> worthwhile-ness quite a bit.
>>>
>>> Let me put it another way. If I were to create a separate patch stripping char
>>> and using uint8_t instead, what are my chances of getting an Acked-by? Or not a
>>> NAK, at least. (there's other maintainers that I need that from, but one step
>>> at a time).
>>
>> That would to some degree depend on what other maintainers think. Not a straight
>> NAK in any event.
>>
>>>> Signed-ness of plain char doesn't really matter as long as it's used only for
>>>> what really are characters (or strings thereof). And that looks the be pretty
>>>> much the case throughout the public headers.
>>>
>>> Maybe. Still, as a general principle caller and callee ought to agree on size,
>>> alignment and sign for every type. I'd rather not make exceptions for that
>>> invariant unless truly well motivated. And in this case it's a case of
>>> requiring trivial non-functional changes.
>>
>> In how far they're non-functional will need to be seen. You also need to keep
>> consumers in mind: They may face sudden type disagreement that compilers may
>> complain about. Yet "stable" for the public headers means not just the ABI
>> itself being stable, but updated headers also being usable as drop-in
>> replacements for older versions.
> 
> Would it be fair to say that users of the Xen low-level API strictly go via
> xenctrl et al?

No - recall we're meanwhile talking about all public headers, not just ones
limited to toolstack use. Kernels (and alike, e.g. xtf) obviously won't use
xenctrl.

Jan


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

* Re: [RFC PATCH 19/25] xen: Replace hand-crafted domctl/createdomain with autogenerated version
  2024-11-15 11:51 ` [RFC PATCH 19/25] xen: Replace hand-crafted domctl/createdomain with autogenerated version Alejandro Vallejo
@ 2024-12-04 14:48   ` Teddy Astie
  0 siblings, 0 replies; 51+ messages in thread
From: Teddy Astie @ 2024-12-04 14:48 UTC (permalink / raw)
  To: Alejandro Vallejo, xen-devel
  Cc: Anthony PERARD, Andrew Cooper, Jan Beulich, Julien Grall,
	Stefano Stabellini, Daniel P. Smith

Hello,

There is a alternative relevant way of representing "handle" (keeping  :

> +[[structs.fields]]
> +name = "handle"
> +description = "IN: Unique identifier for this guest given by the toolstack."
> +typ = { tag = "array", args = [{ tag = "u8" }, 16]  }
> +

We can introduce a "guest_handle" type which is represented either as :
- C: xen_guest_handle_t (basically uint8_t[16])
- Rust: uuid::Uuid (which is uuid::Bytes thus [u8; 16]) [1]
(we would need to add uuid = "1" as a dependency on xen-sys)

The toolstack currently uses and represents this handle as a UUID, so I 
suppose we can keep this representation and being able to manipulate 
those as Uuid as well (and having new_v4 functions and similar).

[1] https://docs.rs/uuid/1.11.0/uuid/struct.Uuid.html#abi

Cheers
Teddy


Teddy Astie | Vates XCP-ng Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech


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

end of thread, other threads:[~2024-12-04 14:48 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-11-15 11:51 [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Alejandro Vallejo
2024-11-15 11:51 ` [RFC PATCH 01/25] xen/domctl: Refine grant_opts into max_grant_version Alejandro Vallejo
2024-11-15 11:51 ` [RFC PATCH 02/25] xen/domctl: Replace altp2m_opts with altp2m_mode Alejandro Vallejo
2024-11-15 11:51 ` [RFC PATCH 03/25] tools/xenbindgen: Introduce a Xen hypercall IDL generator Alejandro Vallejo
2024-11-15 11:51 ` [RFC PATCH 04/25] tools/xenbindgen: Add a TOML spec reader Alejandro Vallejo
2024-11-25 15:13   ` Teddy Astie
2024-11-25 16:51     ` Alejandro Vallejo
2024-11-15 11:51 ` [RFC PATCH 05/25] tools/xenbindgen: Add basic plumbing for the C backend Alejandro Vallejo
2024-11-15 11:51 ` [RFC PATCH 06/25] tools/xenbindgen: Add xenbindgen's Cargo.lock file Alejandro Vallejo
2024-11-15 11:51 ` [RFC PATCH 07/25] tools/xenbindgen: Add support for structs in TOML specs Alejandro Vallejo
2024-11-25 12:39   ` Teddy Astie
2024-11-25 17:07     ` Alejandro Vallejo
2024-11-25 15:03   ` Teddy Astie
2024-11-25 17:16     ` Alejandro Vallejo
2024-11-15 11:51 ` [RFC PATCH 08/25] tools/xenbindgen: Add support for enums " Alejandro Vallejo
2024-11-25 16:39   ` Teddy Astie
2024-11-25 17:18     ` Alejandro Vallejo
2024-11-15 11:51 ` [RFC PATCH 09/25] tools/xenbindgen: Add support for bitmaps " Alejandro Vallejo
2024-11-15 11:51 ` [RFC PATCH 10/25] tools/xenbindgen: Add support for includes in the " Alejandro Vallejo
2024-11-15 11:51 ` [RFC PATCH 11/25] tools/xenbindgen: Validate ABI rules at generation time Alejandro Vallejo
2024-11-15 11:51 ` [RFC PATCH 12/25] xen: Replace sysctl/readconsole with autogenerated version Alejandro Vallejo
2024-11-25 12:05   ` Jan Beulich
2024-11-25 18:51     ` Alejandro Vallejo
2024-11-26  9:40       ` Jan Beulich
2024-11-26 12:27         ` Alejandro Vallejo
2024-11-26 13:20           ` Jan Beulich
2024-11-26 14:36             ` Alejandro Vallejo
2024-11-26 16:30               ` Jan Beulich
2024-11-26 14:39             ` Teddy Astie
2024-11-26 16:28               ` Jan Beulich
2024-11-15 11:51 ` [RFC PATCH 13/25] xen: Replace hand-crafted altp2m_mode descriptions with autogenerated ones Alejandro Vallejo
2024-11-15 11:51 ` [RFC PATCH 14/25] xen: Replace common bitmaps in domctl.createdomain with autogenerated versions Alejandro Vallejo
2024-11-15 11:51 ` [RFC PATCH 15/25] xen/arm: Replace hand-crafted xen_arch_domainconfig with autogenerated one Alejandro Vallejo
2024-11-15 11:51 ` [RFC PATCH 16/25] xen/x86: " Alejandro Vallejo
2024-11-25 12:09   ` Jan Beulich
2024-11-25 18:53     ` Alejandro Vallejo
2024-11-15 11:51 ` [RFC PATCH 17/25] xen/ppc: Replace empty " Alejandro Vallejo
2024-11-15 11:51 ` [RFC PATCH 18/25] xen/riscv: " Alejandro Vallejo
2024-11-15 11:51 ` [RFC PATCH 19/25] xen: Replace hand-crafted domctl/createdomain with autogenerated version Alejandro Vallejo
2024-12-04 14:48   ` Teddy Astie
2024-11-15 11:51 ` [RFC PATCH 20/25] tools/xen-sys: Create a crate with autogenerated Rust constructs Alejandro Vallejo
2024-11-15 11:51 ` [RFC PATCH 21/25] tools/xenbindgen: Add Rust backend to xenbindgen Alejandro Vallejo
2024-11-15 11:51 ` [RFC PATCH 22/25] tools/xen-sys: Add autogenerated Rust files Alejandro Vallejo
2024-11-15 11:51 ` [RFC PATCH 23/25] licence: Add Unicode-DFS-2016 to the list of licences Alejandro Vallejo
2024-11-15 11:51 ` [RFC PATCH 24/25] tools/rust: Add deny.toml Alejandro Vallejo
2024-11-15 11:51 ` [RFC PATCH 25/25] ci: Add a CI checker for Rust-related helpful properties Alejandro Vallejo
2024-11-21 17:46 ` [RFC PATCH 00/25] Introduce xenbindgen to autogen hypercall structs Anthony PERARD
2024-11-22 10:52   ` Teddy Astie
2024-11-22 13:26     ` Alejandro Vallejo
2024-11-22 13:12   ` Alejandro Vallejo
2024-11-22 16:34     ` Anthony PERARD

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.