|  | 
| 4 | 4 | //! | 
| 5 | 5 | //! The main value-add of this crate is to abstract away the parsing and | 
| 6 | 6 | //! 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. | 
| 8 | 9 | //! | 
| 9 | 10 | //! The abstractions provided by this crate serve as the base to work with the | 
| 10 |  | -//! following structures: | 
|  | 11 | +//! following structures in interaction: | 
| 11 | 12 | //! - multiboot2: | 
| 12 |  | -//!   - boot information structure (whole) | 
|  | 13 | +//!   - boot information | 
|  | 14 | +//!   - boot information header (the fixed sized begin portion of a boot | 
|  | 15 | +//!     information) | 
| 13 | 16 | //!   - boot information tags | 
|  | 17 | +//!   - boot information tag header (the fixed sized begin portion of a tag) | 
| 14 | 18 | //! - multiboot2-header: | 
| 15 |  | -//!   - header structure (whole) | 
|  | 19 | +//!   - header | 
|  | 20 | +//!   - header header (the fixed sized begin portion of a header) | 
| 16 | 21 | //!   - header tags | 
|  | 22 | +//!   - header tag header (the fixed sized begin portion of a tag) | 
| 17 | 23 | //! | 
| 18 |  | -//! # Solved Problem & Difficulties Along the Way | 
|  | 24 | +//! # TL;DR: Specific Example | 
| 19 | 25 | //! | 
| 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. | 
| 24 | 58 | //! | 
| 25 | 59 | //! ## Multiboot2 Structures | 
| 26 | 60 | //! | 
|  | 
| 83 | 117 | //! | 
| 84 | 118 | //! The overall common abstractions needed to solve the problems mentioned in | 
| 85 | 119 | //! 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. | 
| 88 | 123 | //! | 
| 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: | 
| 92 | 127 | //! | 
| 93 | 128 | //! ```rust,ignore | 
| 94 | 129 | //! /// ABI-compatible tag for parsing. | 
|  | 130 | +//! #[repr(C)] | 
| 95 | 131 | //! pub struct MemoryMapTag { | 
| 96 | 132 | //!     header: TagHeader, | 
| 97 | 133 | //!     entry_size: u32, | 
|  | 
| 112 | 148 | //! | 
| 113 | 149 | //! ## Creating Fat Pointers with [`ptr_meta`] | 
| 114 | 150 | //! | 
|  | 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 | +//! | 
| 115 | 158 | //! To create fat pointers with [`ptr_meta`], each tag needs a `Metadata` type | 
| 116 | 159 | //! 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`]. | 
| 118 | 161 | //! | 
| 119 | 162 | //! ## Multiboot2 Requirements | 
| 120 | 163 | //! | 
| 121 | 164 | //! All tags must be 8-byte aligned. The actual payload of tags may be followed | 
| 122 | 165 | //! by padding zeroes to fill the gap until the next alignment boundary, if | 
| 123 | 166 | //! 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. | 
| 125 | 168 | //! | 
| 126 | 169 | //! ## Rustc Requirements | 
| 127 | 170 | //! | 
|  | 
| 141 | 184 | //! [`Layout`] for the underlying type equals the one we manually used for the | 
| 142 | 185 | //! allocation. | 
| 143 | 186 | //! | 
| 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 |  | -//! | 
| 154 | 187 | //! ## Parsing and Casting | 
| 155 | 188 | //! | 
|  | 189 | +//! The general idea of parsing is that the lifetime of the original byte slice | 
|  | 190 | +//! propagates through to references of target types. | 
|  | 191 | +//! | 
| 156 | 192 | //! First, we need byte slices which are guaranteed to be aligned and are a | 
| 157 | 193 | //! multiple of the alignment. We have [`BytesRef`] for that. With that, we can | 
| 158 | 194 | //! 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 { | 
| 256 | 292 | } | 
| 257 | 293 | 
 | 
| 258 | 294 | /// 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. | 
| 260 | 296 | /// | 
| 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. | 
| 264 | 301 | /// | 
| 265 | 302 | /// 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). | 
| 267 | 307 | /// | 
| 268 | 308 | /// # ABI | 
| 269 | 309 | /// This type uses the C ABI. The fixed [`Header`] portion is always there. | 
| 270 | 310 | /// Further, there is a variable amount of payload bytes. Thus, this type can | 
| 271 | 311 | /// 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`]. | 
| 273 | 313 | /// | 
| 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, | 
| 275 | 315 | /// `size_of_val(&self)` might report additional padding bytes that are not | 
| 276 | 316 | /// 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. | 
| 278 | 319 | #[derive(Debug, PartialEq, Eq, ptr_meta::Pointee)] | 
| 279 | 320 | #[repr(C, align(8))] | 
| 280 | 321 | pub struct DynSizedStructure<H: Header> { | 
| @@ -363,13 +404,16 @@ impl<H: Header> DynSizedStructure<H> { | 
| 363 | 404 |     /// | 
| 364 | 405 |     /// [`size_of_val`]: mem::size_of_val | 
| 365 | 406 |     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. | 
| 366 | 409 |         let base_ptr = ptr::addr_of!(*self); | 
| 367 | 410 | 
 | 
| 368 | 411 |         // This should be a compile-time assertion. However, this is the best | 
| 369 | 412 |         // location to place it for now. | 
| 370 | 413 |         assert!(T::BASE_SIZE >= mem::size_of::<H>()); | 
| 371 | 414 | 
 | 
| 372 | 415 |         let t_dst_size = T::dst_len(self.header()); | 
|  | 416 | +        // Creates thin or fat pointer, depending on type. | 
| 373 | 417 |         let t_ptr = ptr_meta::from_raw_parts(base_ptr.cast(), t_dst_size); | 
| 374 | 418 |         let t_ref = unsafe { &*t_ptr }; | 
| 375 | 419 | 
 | 
|  | 
0 commit comments