@@ -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);
}
@@ -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)
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(-)