|
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