Crate multiboot2_common
source ·Expand description
Common helpers for the multiboot2 and multiboot2-header crates.
§Value-add
The main value-add of this crate is to abstract away the parsing and construction of Multiboot2 structures. This is more complex as it may sound at first due to the difficulties listed below.
The abstractions provided by this crate serve as the base to work with the following structures:
- multiboot2:
- boot information structure (whole)
- boot information tags
- multiboot2-header:
- header structure (whole)
- header tags
§The Problem / Difficulties
§Multiboot2 Structures
Multiboot2 structures are a consecutive chunk of bytes in memory. They use
the “header pattern”, which means a fixed size and known Header type
indicates the total size of the structure. This is roughly translated to the
following rusty base type:
#[repr(C, align(8))]
struct DynStructure {
header: MyHeader,
payload: [u8]
}Note that these structures can also be nested. So for example, the Multiboot2 boot information contains Multiboot2 tags, and the Multiboot2 header contains Multiboot2 header tags - both are itself dynamic structures.
A final [u8] field in the structs is the most rusty way to model this.
However, this makes the type a Dynamically Sized Type (DST). To create
references to these types from a byte slice, one needs fat pointers. They
are a language feature currently not constructable with stable Rust.
Luckily, we can utilize ptr_meta.
§Dynamic and Sized Structs
Note that we also have structures (tags) in Multiboot2 that looks like this:
#[repr(C, align(8))]
struct DynStructure {
header: MyHeader,
// Not just [`u8`]
payload: [SomeType]
}or
#[repr(C, align(8))]
struct CommandLineTag {
header: TagHeader,
start: u32,
end: u32,
// More than just the base header before the dynamic portion
data: [u8]
}§Fat Pointer Requirements
To create fat pointers with ptr_meta, each tag needs a Metadata type
which is either usize (for DSTs) or (). A trait is needed to abstract
above sized or unsized types.
§Multiboot2 Requirements
All tags must be 8-byte aligned. Space between multiple tags may be filled with zeroes if necessary. These zeroes are not reflected in the previous tag’s size.
§Rustc Requirements
The allocation space that Rust requires for types is a multiple of the
alignment. This means that if we cast between byte slices and specific
types, Rust doesn’t just see the size reported by the header but also
any necessary padding bytes. If this is not the case, for example we
cast to a structure from a &[u8; 15], Miri will complain as it expects
&[u8; 16]
See https://doc.rust-lang.org/reference/type-layout.html for information.
§Provided Abstractions
§Parsing and Casting
First, we need byte slices which are guaranteed to be aligned and are a
multiple of the alignment. We have BytesRef for that. With that, we can
create a DynSizedStructure. This is a rusty type that owns all the bytes
it owns, according to the size reported by its header. Using this type
and with the help of MaybeDynSized, we can call
DynSizedStructure::cast to cast this to arbitrary sized or unsized
struct types fulfilling the corresponding requirements.
This way, one can create nice rusty structs modeling the structure of the
tags, and we only need a single “complicated” type, namely
DynSizedStructure.
§Iterating Tags
To iterate over the tags of a structure, use TagIter.
§Memory Guarantees and Safety Promises
For the parsing and construction of Multiboot2 structures, the alignment and necessary padding bytes as discussed above are guaranteed. When types are constructed, they return Results with appropriate error types. If during runtime something goes wrong, for example due to malformed tags, panics guarantee that no UB will happen.
§No Public API
Not meant as stable public API for others outside Multiboot2.
Modules§
- Various test utilities.
Structs§
- Wraps a byte slice representing a Multiboot2 structure including an optional terminating padding, if necessary. It guarantees that the memory requirements promised in the crates description are respected.
- Iterates over the tags (modelled by
DynSizedStructure) of the underlying byte slice. Each tag is expected to have the same commonHeader.
Enums§
- Errors that may occur when working with memory.
Constants§
- The alignment of all Multiboot2 data structures.
Traits§
- A sized header type for
DynSizedStructure. Note thatheaderrefers to the header pattern. Thus, depending on the use case, this is not just a tag header. Instead, it refers to all bytes that are fixed and not part of any optional terminating dynamic[u8]slice in aDynSizedStructure. - A trait to abstract sized and unsized structures (DSTs). It enables casting a
DynSizedStructureto sized or unsized structures usingDynSizedStructure::cast. - Extension of
MaybeDynSizedfor Tags.
Functions§
- Clones a
MaybeDynSizedby callingnew_boxed. - Increases the given size to the next alignment boundary, if it is not a multiple of the alignment yet. This is relevant as in Rust’s type layout, the allocated size of a type is always a multiple of the alignment, even if the type is smaller.
- Creates a new tag implementing
MaybeDynSizedon the heap. This works for sized and unsized tags. However, it only makes sense to use this for tags that are DSTs (unsized). For regular sized structs, you can just create a typical constructor and box the result.