diff mbox series

[RFC,09/25] tools/xenbindgen: Add support for bitmaps in TOML specs

Message ID 20241115115200.2824-10-alejandro.vallejo@cloud.com (mailing list archive)
State New
Headers show
Series Introduce xenbindgen to autogen hypercall structs | expand

Commit Message

Alejandro Vallejo Nov. 15, 2024, 11:51 a.m. UTC
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 mbox series

Patch

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)