[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [RFC PATCH 0/6] xen/abi: On wide bitfields inside primitive types


  • To: Alejandro Vallejo <alejandro.vallejo@xxxxxxxxx>
  • From: Jan Beulich <jbeulich@xxxxxxxx>
  • Date: Thu, 31 Oct 2024 08:57:49 +0100
  • Autocrypt: addr=jbeulich@xxxxxxxx; keydata= xsDiBFk3nEQRBADAEaSw6zC/EJkiwGPXbWtPxl2xCdSoeepS07jW8UgcHNurfHvUzogEq5xk hu507c3BarVjyWCJOylMNR98Yd8VqD9UfmX0Hb8/BrA+Hl6/DB/eqGptrf4BSRwcZQM32aZK 7Pj2XbGWIUrZrd70x1eAP9QE3P79Y2oLrsCgbZJfEwCgvz9JjGmQqQkRiTVzlZVCJYcyGGsD /0tbFCzD2h20ahe8rC1gbb3K3qk+LpBtvjBu1RY9drYk0NymiGbJWZgab6t1jM7sk2vuf0Py O9Hf9XBmK0uE9IgMaiCpc32XV9oASz6UJebwkX+zF2jG5I1BfnO9g7KlotcA/v5ClMjgo6Gl MDY4HxoSRu3i1cqqSDtVlt+AOVBJBACrZcnHAUSuCXBPy0jOlBhxPqRWv6ND4c9PH1xjQ3NP nxJuMBS8rnNg22uyfAgmBKNLpLgAGVRMZGaGoJObGf72s6TeIqKJo/LtggAS9qAUiuKVnygo 3wjfkS9A3DRO+SpU7JqWdsveeIQyeyEJ/8PTowmSQLakF+3fote9ybzd880fSmFuIEJldWxp Y2ggPGpiZXVsaWNoQHN1c2UuY29tPsJgBBMRAgAgBQJZN5xEAhsDBgsJCAcDAgQVAggDBBYC AwECHgECF4AACgkQoDSui/t3IH4J+wCfQ5jHdEjCRHj23O/5ttg9r9OIruwAn3103WUITZee e7Sbg12UgcQ5lv7SzsFNBFk3nEQQCACCuTjCjFOUdi5Nm244F+78kLghRcin/awv+IrTcIWF hUpSs1Y91iQQ7KItirz5uwCPlwejSJDQJLIS+QtJHaXDXeV6NI0Uef1hP20+y8qydDiVkv6l IreXjTb7DvksRgJNvCkWtYnlS3mYvQ9NzS9PhyALWbXnH6sIJd2O9lKS1Mrfq+y0IXCP10eS FFGg+Av3IQeFatkJAyju0PPthyTqxSI4lZYuJVPknzgaeuJv/2NccrPvmeDg6Coe7ZIeQ8Yj t0ARxu2xytAkkLCel1Lz1WLmwLstV30g80nkgZf/wr+/BXJW/oIvRlonUkxv+IbBM3dX2OV8 AmRv1ySWPTP7AAMFB/9PQK/VtlNUJvg8GXj9ootzrteGfVZVVT4XBJkfwBcpC/XcPzldjv+3 HYudvpdNK3lLujXeA5fLOH+Z/G9WBc5pFVSMocI71I8bT8lIAzreg0WvkWg5V2WZsUMlnDL9 mpwIGFhlbM3gfDMs7MPMu8YQRFVdUvtSpaAs8OFfGQ0ia3LGZcjA6Ik2+xcqscEJzNH+qh8V m5jjp28yZgaqTaRbg3M/+MTbMpicpZuqF4rnB0AQD12/3BNWDR6bmh+EkYSMcEIpQmBM51qM EKYTQGybRCjpnKHGOxG0rfFY1085mBDZCH5Kx0cl0HVJuQKC+dV2ZY5AqjcKwAxpE75MLFkr wkkEGBECAAkFAlk3nEQCGwwACgkQoDSui/t3IH7nnwCfcJWUDUFKdCsBH/E5d+0ZnMQi+G0A nAuWpQkjM1ASeQwSHEeAWPgskBQL
  • Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>, Julien Grall <julien@xxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>, Juergen Gross <jgross@xxxxxxxx>, Anthony PERARD <anthony.perard@xxxxxxxxxx>, Marek Marczykowski-Górecki <marmarek@xxxxxxxxxxxxxxxxxxxxxx>, Christian Lindig <christian.lindig@xxxxxxxxxx>, David Scott <dave@xxxxxxxxxx>, Bertrand Marquis <bertrand.marquis@xxxxxxx>, Michal Orzel <michal.orzel@xxxxxxx>, Volodymyr Babchuk <Volodymyr_Babchuk@xxxxxxxx>, Roger Pau Monné <roger.pau@xxxxxxxxxx>, xen-devel@xxxxxxxxxxxxxxxxxxxx
  • Delivery-date: Thu, 31 Oct 2024 07:58:17 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

On 30.10.2024 16:08, Alejandro Vallejo wrote:
> 
> In the course of preparing this answer I just noticed that altp2m_opts suffers
> from the exact same annoyance, with the exact same fix. I just noticed while
> rebasing my Rust branch.

Hardly the only other one. See GTF_type_mask or XEN_DOMCTL_PFINFO_LTAB_MASK.

> On Wed Oct 30, 2024 at 9:14 AM GMT, Jan Beulich wrote:
>> On 29.10.2024 19:16, Alejandro Vallejo wrote:
>>> Non-boolean bitfields in the hypercall ABI make it fairly inconvenient to
>>> create bindings for any language because (a) they are always ad-hoc and are
>>> subject to restrictions regular fields are not (b) require boilerplate that
>>> regular fields do not and (c) might not even be part of the core language,
>>> forcing avoidable external libraries into any sort of generic library.
>>>
>>> This patch (it's a series merely to split roughly by maintainer) is one such
>>> case that I happened to spot while playing around. It's the grant_version
>>> field, buried under an otherwise empty grant_opts.
>>>
>>> The invariant I'd like to (slowly) introduce and discuss is that fields may
>>> have bitflags (e.g: a packed array of booleans indexed by some enumerated
>>> type), but not be mixed with wider fields in the same primitive type. This
>>> ensures any field containing an integer of any kind can be referred by 
>>> pointer
>>> and treated the same way as any other with regards to sizeof() and the like.
>>
>> While I don't strictly mind, I'm also not really seeing why taking addresses
>> or applying sizeof() would be commonly necessary. Can you perhaps provide a
>> concrete example of where the present way of dealing with grant max version
>> is getting in the way? After all your use of the term "bitfield" doesn't
>> really mean C's understanding of it, so especially (c) above escapes me to a
>> fair degree.
> 
> Wall of text ahead, but I'll try to stay on point. The rationale should become
> a lot clearer after I send an RFC series with initial code to autogenerate 
> some
> hypercall payloads from markup. The biggest question is: Can I create a
> definition language such that (a) it precisely represents the Xen ABI and (b)
> is fully type-safe under modern strongly-typed languages?
> 
> I already have a backbone I can define the ABI in, so my options when I hit
> some impedance mismatch are:
> 
>   1. Change the ABI so it matches better my means of defining it.
>   2. Change the means to define so it captures the existing ABI better.
> 
> Most of the work I've done has moved in the (2) direction so far, but I found 
> a
> number of pain points when mapping the existing ABI to Rust that, while not
> impossible to work around, are quite annoying for no clear benefit. If
> possible, I'd like to simplify the cognitive load involved in defining, using
> and updating hypercalls rather than bending over backwards to support a
> construct that provides no real benefit. IOW: If I can define an ABI that is
> _simpler_, it follows that it's also easier to not make mistakes and it's
> easier to generate code for it.
> 
> The use of packed fields is one such case. Even in C, we create extra macros
> for creating a field, modifying it, fetching it, etc. Patches 2-6 are strict
> code removals. And even in the most extreme cases the space savings are 
> largely
> irrelevant because the hypercall has a fixed size. We do want to pack _flags_
> as otherwise the payload size would explode pretty quickly on hypercalls with
> tons of boolean options, but I'm not aware of that being problematic for wider
> subfields (like the grant max version).
> 
> Now, being more concrete...
> 
> ##################################################################
> # IDL is simpler if the size is a property of the type
> ##################################################################
> 
> Consider the definition of the (new) max_grant_version type under the IDL I'm
> working on (it's TOML, but I don't particularly care about which markup we end
> up using).
> 
>   [[enums]]
>   name = "xen_domaincreate_max_grant_version"
>   description = "Content of the `max_grant_version` field of the domain 
> creation hypercall."
>   typ = { tag = "u8" }
> 
>   [[enums.variants]]
>   name = "off"
>   description = "Must be used with gnttab support compiled out"
>   value = 0
> 
>   [[enums.variants]]
>   name = "v1"
>   description = "Allow the domain to use up to gnttab_v1"
>   value = 1
> 
>   [[enums.variants]]
>   name = "v2"
>   description = "Allow the domain to use up to gnttab_v2"
>   value = 2
> 
> Note that I can define a type being enumerated, can choose its specific
> variants and its width is a property of the type itself. With bitfields you're
> always in a weird position of the width not being part of the type that goes
> into it.
> 
> Should I need it as a field somewhere, then...
> 
>   [[structs.fields]]
>   name = "max_grant_version"
>   description = "Maximum grant table version the domain may be bumped to"
>   typ = { tag = "enum", args = "xen_domaincreate_max_grant_version" }
> 
> ... at which point the size of the field is given by an intrinsic property of
> the type (the typ property on the enums table) I previously defined. It's
> extensible, composable and allows me to generate readable code in both C and
> Rust.
> 
> Should I need to support full bitfields I would require a means of stating the
> start and end bits of every field, which is very bad for the sanity of whoever
> wants to maintain coherency in the ABI.
> 
> ##################################################################
> # Rust and Go don't like bitfields...
> ##################################################################
> 
> ... and neither does C, even if for historic reasons they do exist in the
> standard.

I don't think that's just for historic reasons. To interface with hardware,
alternative approaches are often more cumbersome. See how we're (slowly)
moving to using bitfields more in Xen, in favor of tons of #define-s and
more or less open-coded masking operations.

> On a slight tangent, neither Rust nor Go support bitfields in the
> core language. This was a deliberate design decision of their respective
> designers. I can't speak for Go as I'm not a Go developer, but Rust does have 
> a
> very well-known, well-supported and very common external crate ("bitflags")
> that allows very ergonomic semantics for definition of packed booleans. As an
> example here's the flags for domain create, as spitted out by the generator I
> have.
> 
> (comments removed for brevity). This defines a bitmap indexed by the flags
> type, represented by a 32bit primitive. It's type-safe from the PoV that I
> can't just write 1 << 15 to a variable of this type and expect anything but
> screams from the compiler.
> 
>   bitflags! {
>       #[repr(C)]
>       #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
>       pub struct XenDomaincreateFlags: u32 {
>           const Hvm = 1 << 0;
>           const Hap = 1 << 1;
>           const S3Integrity = 1 << 2;
>           const OosOff = 1 << 3;
>           const XsDomain = 1 << 4;
>           const Iommu = 1 << 5;
>           const NestedVirt = 1 << 6;
>           const Vpmu = 1 << 7;
>       }
>   }
> 
> This enables callers to have type-safe variables in a pretty ergonomic 
> fashion:
> 
>   let flags = XenDomainCreateFlags::Hvm |
>               XenDomainCreateFlags::Hap |
>               XenDomainCreateFlags::Iommu;
> 
> and assignments to its related struct would follow regular assignment rules.
> 
> ##################################################################
> # IOW
> ##################################################################
> 
> Supporting general bitfields is annoying, even in C. Adding support in IDL for
> them is a headache if we want the descriptions to help us catch mistakes and
> language support is poor using this constructs (at best).
> 
> Can we please get rid of them?

I remain undecided. If we set forth as a goal to avoid such in the new ABI
that has been mentioned for many years, that would be a more clear cut.

Just taking the example of the gnttab max version: By switching to

    uint8_t max_grant_version;
    uint8_t rsvd0[3];

you actively make it more cumbersome to re-use the rest of the 32-bit field
as (boolean) flags. It may reasonably work for the first 8, with early
provisions it may also work for 16, yet it'll be harder / uglier for more
than that. Allowing such is, after all, the idea behind the present
"packing". (The issue would similarly exist in the new ABI, yet we could
simply decide up front that we're willing to pay that price, perhaps even
outlining up front how to best limit undesirable effects when doing so.)

Just to mention it - you didn't really answer the sizeof() / address-taking
question I raised. You provided a lot of other _useful_ background though.

Jan



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.