diff --git a/.typos.toml b/.typos.toml index 6947ea6e..1a9fcd8b 100644 --- a/.typos.toml +++ b/.typos.toml @@ -2,7 +2,7 @@ [files] extend-exclude = [ - # "uefi/src/table/boot.rs" + "*.drawio.xml" ] [default.extend-words] diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..5d848768 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +Please see: + +- [multiboot2/CHANGELOG.md](multiboot2/CHANGELOG.md) +- [multiboot2-header/CHANGELOG.md](multiboot2-header/CHANGELOG.md) +- [multiboot2-common/CHANGELOG.md](multiboot2-common/CHANGELOG.md) diff --git a/Cargo.lock b/Cargo.lock index 9010edda..40ee3afd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,7 +27,7 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "multiboot2" -version = "0.22.1" +version = "0.22.2" dependencies = [ "bitflags", "derive_more", @@ -39,7 +39,7 @@ dependencies = [ [[package]] name = "multiboot2-common" -version = "0.1.1" +version = "0.1.2" dependencies = [ "derive_more", "ptr_meta", @@ -47,7 +47,7 @@ dependencies = [ [[package]] name = "multiboot2-header" -version = "0.5.0" +version = "0.5.1" dependencies = [ "derive_more", "log", diff --git a/Cargo.toml b/Cargo.toml index 57e82c6b..49bd0ea7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,8 @@ exclude = [ bitflags = "2.6.0" derive_more = { version = "~0.99.18", default-features = false, features = ["display"] } log = { version = "~0.4", default-features = false } +multiboot2 = { version = "0.22.2", default-features = false } +multiboot2-common = { version = "0.1.2", default-features = false } ptr_meta = { version = "~0.2", default-features = false } # This way, the corresponding crate dependency can be normalley referenced by @@ -21,3 +23,4 @@ ptr_meta = { version = "~0.2", default-features = false } [patch.crates-io] multiboot2 = { path = "multiboot2" } multiboot2-common = { path = "multiboot2-common" } +multiboot2-header = { path = "multiboot2-header" } diff --git a/Changelog.md b/Changelog.md deleted file mode 100644 index bac17705..00000000 --- a/Changelog.md +++ /dev/null @@ -1,3 +0,0 @@ -Please see: -- [multiboot2/Changelog.md](multiboot2/Changelog.md) -- [multiboot2-header/Changelog.md](multiboot2-header/Changelog.md) diff --git a/README.md b/README.md index 012308f6..1ce60e83 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,10 @@ -# Multiboot2: MBI + Header +# Rusty Wrappers for Multiboot2 -This repository contains the crates `multiboot2` and `multiboot2-header`. -Please check their individual README-files ([multiboot2](multiboot2/README.md), -[multiboot2-header](multiboot2-header/README.md)). +## Repository Overview -The `multiboot2` crate helps to parse the Multiboot2 information structure -(MBI) and is relevant in kernels, that get booted by a bootloader such as -GRUB, for example. `multiboot2-header` helps you to either build -Multiboot2-headers yourself, or to parse Multiboot2 headers in custom bootloader -or similar applications. +- [`multiboot2`](./multiboot2/README.md) +- [`multiboot2-header`](./multiboot2-header/README.md) +- [`multiboot2-common`](./multiboot2-common/README.md) ## License @@ -22,6 +18,6 @@ at your option. ### Contribution -Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the -work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any -additional terms or conditions. +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/integration-test/bins/Cargo.lock b/integration-test/bins/Cargo.lock index 7d718dc6..dff4de92 100644 --- a/integration-test/bins/Cargo.lock +++ b/integration-test/bins/Cargo.lock @@ -96,7 +96,7 @@ dependencies = [ [[package]] name = "multiboot2" -version = "0.22.1" +version = "0.22.2" dependencies = [ "bitflags 2.6.0", "derive_more", @@ -108,7 +108,7 @@ dependencies = [ [[package]] name = "multiboot2-common" -version = "0.1.1" +version = "0.1.2" dependencies = [ "derive_more", "ptr_meta", @@ -116,7 +116,7 @@ dependencies = [ [[package]] name = "multiboot2-header" -version = "0.5.0" +version = "0.5.1" dependencies = [ "derive_more", "log", diff --git a/multiboot2-common/CHANGELOG.md b/multiboot2-common/CHANGELOG.md new file mode 100644 index 00000000..d2ecb870 --- /dev/null +++ b/multiboot2-common/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog for Crate `multiboot2-common` + +## v0.1.2 (2024-08-24) + +- Documentation improvements +- + +## 0.1.0 / 0.1.1 (2024-08-20) + +Initial release. diff --git a/multiboot2-common/Cargo.toml b/multiboot2-common/Cargo.toml index 8ad25231..5ea30f70 100644 --- a/multiboot2-common/Cargo.toml +++ b/multiboot2-common/Cargo.toml @@ -3,7 +3,7 @@ name = "multiboot2-common" description = """ Common helpers for the `multiboot2` and `multiboot2-header` crates. """ -version = "0.1.1" +version = "0.1.2" authors = [ "Philipp Schuster " ] diff --git a/multiboot2-common/Changelog.md b/multiboot2-common/Changelog.md deleted file mode 100644 index 8d3f3905..00000000 --- a/multiboot2-common/Changelog.md +++ /dev/null @@ -1,5 +0,0 @@ -# CHANGELOG for crate `multiboot2` - -## 0.1.0 / 0.1.1 (2024-08-20) - -Initial release. diff --git a/multiboot2-common/README.md b/multiboot2-common/README.md index 3a4cd576..7a2282ed 100644 --- a/multiboot2-common/README.md +++ b/multiboot2-common/README.md @@ -5,6 +5,23 @@ Common helpers for the `multiboot2` and `multiboot2-header` crates. +## Architecture + +The following figures, not displayable in `lib.rs` / on `docs.rs` unfortunately, +outline the design of this crate: + +![Overview Multiboot2 Structures](./overview-multiboot2-structures.drawio.png "Overview Multiboot2 Structures") + +Overview of Multiboot2 structures: Multiboot2 boot information, boot +information tags, Multiboot2 headers, and Multiboot2 header tags all share the +same technical foundation: They have a common header and a possible dynamic +size, depending on the header. + +![Crate Architecture Overview](./architecture.drawio.png "Crate Architecture Overview") + +Overview of how raw bytes are modelled to be representable by high-level +ABI-compatible rusty types. + ## MSRV The MSRV is 1.70.0 stable. diff --git a/multiboot2-common/architecture.drawio.png b/multiboot2-common/architecture.drawio.png new file mode 100644 index 00000000..a3d0e18c Binary files /dev/null and b/multiboot2-common/architecture.drawio.png differ diff --git a/multiboot2-common/architecture.drawio.xml b/multiboot2-common/architecture.drawio.xml new file mode 100644 index 00000000..1e87a57d --- /dev/null +++ b/multiboot2-common/architecture.drawio.xml @@ -0,0 +1,217 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/multiboot2-common/overview-multiboot2-structures.drawio.png b/multiboot2-common/overview-multiboot2-structures.drawio.png new file mode 100644 index 00000000..f8971427 Binary files /dev/null and b/multiboot2-common/overview-multiboot2-structures.drawio.png differ diff --git a/multiboot2-common/overview-multiboot2-structures.drawio.xml b/multiboot2-common/overview-multiboot2-structures.drawio.xml new file mode 100644 index 00000000..898f0633 --- /dev/null +++ b/multiboot2-common/overview-multiboot2-structures.drawio.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/multiboot2-common/src/lib.rs b/multiboot2-common/src/lib.rs index 6f01e285..5bc7d5e9 100644 --- a/multiboot2-common/src/lib.rs +++ b/multiboot2-common/src/lib.rs @@ -15,7 +15,12 @@ //! - header structure (whole) //! - header tags //! -//! # The Problem / Difficulties +//! # Solved Problem & Difficulties Along the Way +//! +//! Firstly, the design choice to have ABI-compatible rusty types influenced the +//! requirements and difficulties along the way. They, on the other side, +//! influenced the design. The outcome is what we perceive as the optimal rusty +//! and convenient solution. //! //! ## Multiboot2 Structures //! @@ -34,7 +39,9 @@ //! //! 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. +//! header contains Multiboot2 header tags - both are itself **dynamically +//! sized** structures. This means, you can know the size (and amount of +//! elements) **only at runtime!** //! //! 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 @@ -42,7 +49,11 @@ //! are a language feature currently not constructable with stable Rust. //! Luckily, we can utilize [`ptr_meta`]. //! -//! ## Dynamic and Sized Structs +//! Figure 1 in the [README](https://crates.io/crates/multiboot2-common) +//! (currently not embeddable in lib.rs unfortunately) provides an overview of +//! Multiboot2 structures. +//! +//! ## Dynamic and Sized Structs in Rust //! //! Note that we also have structures (tags) in Multiboot2 that looks like this: //! @@ -68,7 +79,38 @@ //! } //! ``` //! -//! ## Fat Pointer Requirements +//! ## Chosen Design +//! +//! The overall common abstractions needed to solve the problems mentioned in +//! this section are also mainly influenced by the fact that the `multiboot2` +//! and `multiboot2-header` crates use a **zero-copy** design for parsing +//! the corresponding structures. +//! +//! Further, by having **ABI-compatible types** that fully represent the +//! reality, we can use the same type for parsing **and** for construction, +//! as modelled in the following simplified example: +//! +//! ```rust,ignore +//! /// ABI-compatible tag for parsing. +//! pub struct MemoryMapTag { +//! header: TagHeader, +//! entry_size: u32, +//! entry_version: u32, +//! areas: [MemoryArea], +//! } +//! +//! impl MemoryMapTag { +//! // We can also create an ABI-compatible structure of that type. +//! pub fn new(areas: &[MemoryArea]) -> Box { +//! // omitted +//! } +//! } +//! ``` +//! +//! Hence, the structures can also be build at runtime. This is what we +//! consider **idiomatic and rusty**. +//! +//! ## Creating Fat Pointers with [`ptr_meta`] //! //! 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 @@ -76,22 +118,35 @@ //! //! ## 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. +//! All tags must be 8-byte aligned. The actual payload of tags may be followed +//! by padding zeroes to fill the gap until the next alignment boundary, if +//! necessary. These zeroes are not reflected in the tag's size, but for Rust, +//! must be reflected in the memory allocation size. //! //! ## Rustc Requirements //! -//! The allocation space that Rust requires for types is a multiple of the +//! The required allocation space that Rust uses 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]` +//! types, Rust doesn't just see the "trimmed down actual payload" defined by +//! struct members, but also any necessary, but hidden, padding bytes. If we +//! don't guarantee the correct is not the case, for example we cast the bytes +//! from a `&[u8; 15]` to an 8-byte aligned struct, Miri will complain as it +//! expects `&[u8; 16]`. //! //! See for information. //! -//! # Provided Abstractions +//! Further, this also means that we can't cast references to smaller structs +//! to bigger ones. Also, once we construct a `Box` on the heap and construct +//! it using the [`new_boxed`] helper, we must ensure that the default +//! [`Layout`] for the underlying type equals the one we manually used for the +//! allocation. +//! +//! # Architecture & Provided Abstractions +//! +//! Figure 2 in the [README](https://crates.io/crates/multiboot2-common) +//! (currently not embeddable in lib.rs unfortunately) provides an overview of +//! the parsing of Multiboot2 structures and how the definitions from this +//! crate are used. //! //! ## Parsing and Casting //! @@ -122,6 +177,8 @@ //! # No Public API //! //! Not meant as stable public API for others outside Multiboot2. +//! +//! [`Layout`]: core::alloc::Layout #![no_std] #![cfg_attr(feature = "unstable", feature(error_in_core))] @@ -270,10 +327,17 @@ impl DynSizedStructure { &self.payload } - /// Casts the structure tag to a specific [`MaybeDynSized`] implementation which - /// may be a ZST or DST typed tag. The output type will have the exact same - /// size as `*self`. The target type must be sufficient for that. If not, - /// the function will panic. + /// Performs a memory-safe same-size cast from the base-structure to a + /// specific [`MaybeDynSized`]. The idea here is to cast the generic + /// mostly semantic-free version to a specific type with fields that have + /// a semantic. + /// + /// The provided `T` of type [`MaybeDynSized`] might be may be sized type + /// or DST. This depends on the type. + /// + /// # Panic + /// Panics if base assumptions are violated. For example, the + /// `T` of type [`MaybeDynSized`] must allow a proper casting to it. /// /// # Safety /// This function is safe due to various sanity checks and the overall diff --git a/multiboot2-common/src/tag.rs b/multiboot2-common/src/tag.rs index 2ff85104..29a4da53 100644 --- a/multiboot2-common/src/tag.rs +++ b/multiboot2-common/src/tag.rs @@ -10,7 +10,8 @@ use ptr_meta::Pointee; /// [`DynSizedStructure::cast`]. /// /// Structs that are a DST must provide a **correct** -/// [`MaybeDynSized::dst_len`] implementation. +/// [`MaybeDynSized::dst_len`] implementation. Further, implementors **must** +/// use `#[repr(C)]`. /// /// [`ID`]: Tag::ID /// [`DynSizedStructure`]: crate::DynSizedStructure diff --git a/multiboot2-header/Changelog.md b/multiboot2-header/CHANGELOG.md similarity index 96% rename from multiboot2-header/Changelog.md rename to multiboot2-header/CHANGELOG.md index bf67ee82..d18a5953 100644 --- a/multiboot2-header/Changelog.md +++ b/multiboot2-header/CHANGELOG.md @@ -1,4 +1,8 @@ -# CHANGELOG for crate `multiboot2-header` +# Changelog for Crate `multiboot2-header` + +## v0.5.1 (2024-08-24) + +- Documentation improvements ## v0.5.0 (2024-05-20) diff --git a/multiboot2-header/Cargo.toml b/multiboot2-header/Cargo.toml index 20321308..c8ca8787 100644 --- a/multiboot2-header/Cargo.toml +++ b/multiboot2-header/Cargo.toml @@ -1,10 +1,12 @@ [package] name = "multiboot2-header" description = """ -Library with type definitions and parsing functions for Multiboot2 headers. -This library is `no_std` and can be used in bootloaders. +Convenient and safe parsing of Multiboot2 Header structures and the +contained header tags. Usable in no_std environments, such as a +bootloader. An optional builder feature also allows the construction of +the corresponding structures. """ -version = "0.5.0" +version = "0.5.1" authors = [ "Philipp Schuster " ] @@ -43,9 +45,9 @@ unstable = [] [dependencies] derive_more.workspace = true log.workspace = true +multiboot2-common.workspace = true +multiboot2.workspace = true ptr_meta.workspace = true -multiboot2 = { version = "0.22.1", default-features = false } -multiboot2-common = "0.1.1" [package.metadata.docs.rs] all-features = true diff --git a/multiboot2-header/README.md b/multiboot2-header/README.md index eebac8d0..b33cfb92 100644 --- a/multiboot2-header/README.md +++ b/multiboot2-header/README.md @@ -4,9 +4,18 @@ [![crates.io](https://img.shields.io/crates/v/multiboot2-header.svg)](https://crates.io/crates/multiboot2-header) [![docs](https://docs.rs/multiboot2-header/badge.svg)](https://docs.rs/multiboot2-header/) -Rust library with type definitions and parsing functions for Multiboot2 headers, -as well as a builder to build them at runtime. This library is `no_std` and can -be used in bootloaders. +Convenient and safe parsing of Multiboot2 Header structures and the +contained header tags. Usable in `no_std` environments, such as a +bootloader. An optional `builder` feature also allows the construction of +the corresponding structures. + +## Design + +For every Multiboot2 header structure, there is an ABI-compatible rusty type. +This enables a zero-copying parsing design while also enabling the creation of +these structures via convenient constructors for the corresponding types. + +## Use-Cases What this library is good for: diff --git a/multiboot2-header/src/lib.rs b/multiboot2-header/src/lib.rs index f9dd25d4..e2121b68 100644 --- a/multiboot2-header/src/lib.rs +++ b/multiboot2-header/src/lib.rs @@ -1,6 +1,13 @@ -//! Rust library with type definitions and parsing functions for Multiboot2 -//! headers, as well as a builder to build them at runtime. This library is -//! `no_std` and can be used in bootloaders. +//! Convenient and safe parsing of Multiboot2 Header structures and the +//! contained header tags. Usable in `no_std` environments, such as a +//! bootloader. An optional builder feature also allows the construction of +//! the corresponding structures. +//! +//! ## Design +//! +//! For every Multiboot2 header structure, there is an ABI-compatible rusty type. +//! This enables a zero-copying parsing design while also enabling the creation +//! of these structures via convenient constructors on the corresponding types. //! //! # Example: Parsing a Header //! diff --git a/multiboot2/Changelog.md b/multiboot2/CHANGELOG.md similarity index 99% rename from multiboot2/Changelog.md rename to multiboot2/CHANGELOG.md index 5c4faa82..6a875fe4 100644 --- a/multiboot2/Changelog.md +++ b/multiboot2/CHANGELOG.md @@ -1,7 +1,8 @@ -# CHANGELOG for crate `multiboot2` +# Changelog for Crate `multiboot2` -## Unreleased +## v0.22.2 (2024-08-24) +- Documentation improvements - Improve debug formatting for EFIMemoryMapTag ## v0.22.1 (2024-08-20) diff --git a/multiboot2/Cargo.toml b/multiboot2/Cargo.toml index 0f7e61b9..05ff43cb 100644 --- a/multiboot2/Cargo.toml +++ b/multiboot2/Cargo.toml @@ -6,7 +6,7 @@ structures and the contained information tags. Usable in `no_std` environments, such as a kernel. An optional builder feature also allows the construction of the corresponding structures. """ -version = "0.22.1" +version = "0.22.2" authors = [ "Philipp Oppermann ", "Calvin Lee ", @@ -46,8 +46,7 @@ bitflags.workspace = true derive_more.workspace = true log.workspace = true ptr_meta.workspace = true -multiboot2-common = { version = "0.1.1", default-features = false } - +multiboot2-common.workspace = true # We only use a very basic type definition from this crate. To prevent MSRV # bumps from uefi-raw, I restrict this here. Upstream users are likely to have # two versions of this library in it, which is no problem, as we only use the diff --git a/multiboot2/README.md b/multiboot2/README.md index 9d65d1c1..5c15d837 100644 --- a/multiboot2/README.md +++ b/multiboot2/README.md @@ -5,13 +5,19 @@ Convenient and safe parsing of Multiboot2 Boot Information (MBI) structures and the contained information tags. Usable in `no_std` environments, -such as a kernel. An optional builder feature also allows the construction of +such as a kernel. An optional `builder` feature also allows the construction of the corresponding structures. It follows the Multiboot 2.0 specification at https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html and the ELF 64 specification at http://www.uclibc.org/docs/elf-64-gen.pdf. +## Design + +For every Multiboot2 structure, there is an ABI-compatible rusty type. This +enables a zero-copying parsing design while also enabling the creation of these +structures via convenient constructors on the corresponding types. + ## Features and `no_std` Compatibility This library is always `no_std` without `alloc`. However, the default `builder`- diff --git a/multiboot2/src/lib.rs b/multiboot2/src/lib.rs index cc8f7f40..8027c79a 100644 --- a/multiboot2/src/lib.rs +++ b/multiboot2/src/lib.rs @@ -17,15 +17,16 @@ #![deny(rustdoc::all)] // --- END STYLE CHECKS --- -//! Library that assists parsing the Multiboot2 Information Structure (MBI) from -//! Multiboot2-compliant bootloaders, such as GRUB. It supports all tags from the -//! specification including full support for the sections of ELF files. This library -//! is `no_std` and can be used in a Multiboot2-kernel. +//! Convenient and safe parsing of Multiboot2 Boot Information (MBI) structures +//! and the contained information tags. Usable in `no_std` environments, such as +//! a kernel. An optional builder feature also allows the construction of +//! the corresponding structures. //! -//! The GNU Multiboot(2) specification aims to provide a standardised -//! method of sharing commonly used information about the host machine at -//! boot time and give the payload, i.e. a kernel, a well defined machine -//! state. +//! ## Design +//! +//! For every Multiboot2 structure, there is an ABI-compatible rusty type. This +//! enables a zero-copying parsing design while also enabling the creation of +//! these structures via convenient constructors on the corresponding types. //! //! ## Example //!