Skip to content

Commit 951dea9

Browse files
committed
multiboot2-common: improve doc
1 parent f6991f9 commit 951dea9

8 files changed

+466
-82
lines changed

multiboot2-common/README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,14 @@ manner. The `BytesRef` wrapper ensures basic memory guarantees for the
2222
underlying `&[u8]` slice, while `DynSizedStructure` can then be used to
2323
safely cast to the target type.
2424

25-
![Parsing flow overview](./parsing-flow.drawio.png "Parsing flow overview: From raw bytes to specific structures")
25+
![Generic parsing flow overview](./parsing-flow-generic.drawio.png "Generic parsing flow overview: From raw bytes to specific structures")
26+
27+
The next figure is like the previous figure, but shows a more specific parsing
28+
flow by using types of the `multiboot2` crate. Green shows the raw memory.
29+
Purple boxes refers to logic in `multiboot2-common`. Red components show structs
30+
from the `multiboot2` crate.
31+
32+
![Specific parsing flow overview](./parsing-flow-specific.drawio.png "Specific parsing flow overview: From raw bytes to multiboot2 structures")
2633

2734
The last complex figure shows all traits and structs from `multiboot2-common`,
2835
their internal relation, and how consumers (`multiboot2` and
Loading

multiboot2-common/overview-multiboot2-structures.drawio.xml

Lines changed: 68 additions & 47 deletions
Large diffs are not rendered by default.
Loading

multiboot2-common/parsing-flow-specific.drawio.xml

Lines changed: 312 additions & 0 deletions
Large diffs are not rendered by default.

multiboot2-common/src/lib.rs

Lines changed: 78 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,57 @@
44
//!
55
//! The main value-add of this crate is to abstract away the parsing and
66
//! construction of Multiboot2 structures. This is more complex as it may sound
7-
//! at first due to the difficulties listed below.
7+
//! at first due to the difficulties listed below. Further, functionality for
8+
//! the iteration of tags are provided.
89
//!
910
//! The abstractions provided by this crate serve as the base to work with the
10-
//! following structures:
11+
//! following structures in interaction:
1112
//! - multiboot2:
12-
//! - boot information structure (whole)
13+
//! - boot information
14+
//! - boot information header (the fixed sized begin portion of a boot
15+
//! information)
1316
//! - boot information tags
17+
//! - boot information tag header (the fixed sized begin portion of a tag)
1418
//! - multiboot2-header:
15-
//! - header structure (whole)
19+
//! - header
20+
//! - header header (the fixed sized begin portion of a header)
1621
//! - header tags
22+
//! - header tag header (the fixed sized begin portion of a tag)
1723
//!
18-
//! # Solved Problem & Difficulties Along the Way
24+
//! # TL;DR: Specific Example
1925
//!
20-
//! Firstly, the design choice to have ABI-compatible rusty types influenced the
21-
//! requirements and difficulties along the way. They, on the other side,
22-
//! influenced the design. The outcome is what we perceive as the optimal rusty
23-
//! and convenient solution.
26+
//! To name a specific example, the `multiboot2` crate just needs the following
27+
//! types:
28+
//!
29+
//! - `BootInformationHeader` implementing [`Header`]
30+
//! - `BootInformation` wrapping [`DynSizedStructure`]
31+
//! - `type TagIter<'a> = multiboot2_common::TagIter<'a, TagHeader>`
32+
//! ([`TagIter`])
33+
//! - `TagHeader` implementing [`Header`]
34+
//! - Structs for each tag, each implementing [`MaybeDynSized`]
35+
//!
36+
//! Then, all the magic using the [`TagIter`] and [`DynSizedStructure::cast`]
37+
//! can easily be utilized.
38+
//!
39+
//! The same correspondingly applies to the structures in `multiboot2-header`.
40+
//!
41+
//! # Design, Solved Problem, and Difficulties along the Way
42+
//!
43+
//! Firstly, the design choice to have ABI-compatible rusty types in
44+
//! `multiboot2` and `multiboot2-header` mainly influenced the requirements and
45+
//! difficulties along the way. These obstacles on the other side, influenced
46+
//! the design. The outcome is what we perceive as the optimal rusty and
47+
//! convenient solution.
48+
//!
49+
//! ## Architecture Diagrams
50+
//!
51+
//! The figures in the [README](https://crates.io/crates/multiboot2-common)
52+
//! (currently not embeddable in lib.rs unfortunately) provides an overview of
53+
//! the parsing of Multiboot2 structures and how the definitions from this
54+
//! crate are used.
55+
//!
56+
//! Note that although the diagrams seem complex, most logic is in
57+
//! `multiboot2-common`. For downstream users, the usage is quite simple.
2458
//!
2559
//! ## Multiboot2 Structures
2660
//!
@@ -83,15 +117,17 @@
83117
//!
84118
//! The overall common abstractions needed to solve the problems mentioned in
85119
//! this section are also mainly influenced by the fact that the `multiboot2`
86-
//! and `multiboot2-header` crates use a **zero-copy** design for parsing
87-
//! the corresponding structures.
120+
//! and `multiboot2-header` crates use a **zero-copy** design by parsing
121+
//! the corresponding raw bytes with **ABI-compatible types** owning all their
122+
//! memory.
88123
//!
89-
//! Further, by having **ABI-compatible types** that fully represent the
90-
//! reality, we can use the same type for parsing **and** for construction,
91-
//! as modelled in the following simplified example:
124+
//! Further, by having ABI-compatible types that fully represent the reality, we
125+
//! can use the same type for parsing **and** for construction, as modelled in
126+
//! the following simplified example:
92127
//!
93128
//! ```rust,ignore
94129
//! /// ABI-compatible tag for parsing.
130+
//! #[repr(C)]
95131
//! pub struct MemoryMapTag {
96132
//! header: TagHeader,
97133
//! entry_size: u32,
@@ -112,16 +148,23 @@
112148
//!
113149
//! ## Creating Fat Pointers with [`ptr_meta`]
114150
//!
151+
//! Fat pointers are a language feature and the base for references to
152+
//! dynamically sized types, such as `&str`, `&[T]`, `dyn T` or
153+
//! `&DynamicallySizedStruct`.
154+
//!
155+
//! Currently, they can't be created using the standard library, but
156+
//! [`ptr_meta`] can be utilized.
157+
//!
115158
//! To create fat pointers with [`ptr_meta`], each tag needs a `Metadata` type
116159
//! which is either `usize` (for DSTs) or `()`. A trait is needed to abstract
117-
//! above sized or unsized types.
160+
//! above sized or unsized types. This is done by [`MaybeDynSized`].
118161
//!
119162
//! ## Multiboot2 Requirements
120163
//!
121164
//! All tags must be 8-byte aligned. The actual payload of tags may be followed
122165
//! by padding zeroes to fill the gap until the next alignment boundary, if
123166
//! necessary. These zeroes are not reflected in the tag's size, but for Rust,
124-
//! must be reflected in the memory allocation size.
167+
//! must be reflected in the type's memory allocation.
125168
//!
126169
//! ## Rustc Requirements
127170
//!
@@ -141,18 +184,11 @@
141184
//! [`Layout`] for the underlying type equals the one we manually used for the
142185
//! allocation.
143186
//!
144-
//! # Architecture & Provided Abstractions
145-
//!
146-
//! The figures in the [README](https://crates.io/crates/multiboot2-common)
147-
//! (currently not embeddable in lib.rs unfortunately) provides an overview of
148-
//! the parsing of Multiboot2 structures and how the definitions from this
149-
//! crate are used.
150-
//!
151-
//! Note that although the diagrams seem complex, most logic is in
152-
//! `multiboot2-common`. For downstream users, the usage is quite simple.
153-
//!
154187
//! ## Parsing and Casting
155188
//!
189+
//! The general idea of parsing is that the lifetime of the original byte slice
190+
//! propagates through to references of target types.
191+
//!
156192
//! First, we need byte slices which are guaranteed to be aligned and are a
157193
//! multiple of the alignment. We have [`BytesRef`] for that. With that, we can
158194
//! create a [`DynSizedStructure`]. This is a rusty type that owns all the bytes
@@ -256,25 +292,30 @@ pub trait Header: Clone + Sized + PartialEq + Eq + Debug {
256292
}
257293

258294
/// An C ABI-compatible dynamically sized type with a common sized [`Header`]
259-
/// and a dynamic amount of bytes.
295+
/// and a dynamic amount of bytes without hidden implicit padding.
260296
///
261-
/// This structures owns all its bytes, unlike [`Header`]. Instances guarantees
262-
/// that the memory requirements promised in the crates description are
263-
/// respected.
297+
/// This structures combines a [`Header`] with the logically owned data by
298+
/// that header according to the reported [`Header::payload_len`]. Instances
299+
/// guarantees that the memory requirements promised in the crates description
300+
/// are respected.
264301
///
265302
/// This can be a Multiboot2 header tag, information tag, boot information, or
266-
/// a Multiboot2 header. Depending on the context, the [`Header`] is different.
303+
/// a Multiboot2 header. It is the base for **same-size casts** to these
304+
/// corresponding structures using [`DynSizedStructure::cast`]. Depending on the
305+
/// context, the [`Header`] is different (header header, boot information
306+
/// header, header tag header, or boot information tag header).
267307
///
268308
/// # ABI
269309
/// This type uses the C ABI. The fixed [`Header`] portion is always there.
270310
/// Further, there is a variable amount of payload bytes. Thus, this type can
271311
/// only exist on the heap or references to it can be made by cast via fat
272-
/// pointers.
312+
/// pointers. The main constructor is [`DynSizedStructure::ref_from_bytes`].
273313
///
274-
/// As there might be padding necessary for the proper Rust layout,
314+
/// As terminating padding might be necessary for the proper Rust type layout,
275315
/// `size_of_val(&self)` might report additional padding bytes that are not
276316
/// reflected by the actual payload. These additional padding bytes however
277-
/// will be reflected in corresponding [`BytesRef`] instances.
317+
/// will be reflected in corresponding [`BytesRef`] instances from that this
318+
/// structure was created.
278319
#[derive(Debug, PartialEq, Eq, ptr_meta::Pointee)]
279320
#[repr(C, align(8))]
280321
pub struct DynSizedStructure<H: Header> {
@@ -363,13 +404,16 @@ impl<H: Header> DynSizedStructure<H> {
363404
///
364405
/// [`size_of_val`]: mem::size_of_val
365406
pub fn cast<T: MaybeDynSized<Header = H> + ?Sized>(&self) -> &T {
407+
// Thin or fat pointer, depending on type.
408+
// However, only thin ptr is needed.
366409
let base_ptr = ptr::addr_of!(*self);
367410

368411
// This should be a compile-time assertion. However, this is the best
369412
// location to place it for now.
370413
assert!(T::BASE_SIZE >= mem::size_of::<H>());
371414

372415
let t_dst_size = T::dst_len(self.header());
416+
// Creates thin or fat pointer, depending on type.
373417
let t_ptr = ptr_meta::from_raw_parts(base_ptr.cast(), t_dst_size);
374418
let t_ref = unsafe { &*t_ptr };
375419

0 commit comments

Comments
 (0)