22
22
//! ## Example
23
23
//!
24
24
//! ```rust
25
- //! use multiboot2::BootInformation;
26
- //! fn kmain(multiboot_info_ptr: u32) {
27
- //! let boot_info = unsafe { BootInformation::load(multiboot_info_ptr as *const u8).unwrap() };
28
- //! println!("{:?}", boot_info);
25
+ //! use multiboot2::{BootInformation, BootInformationHeader};
26
+ //!
27
+ //! fn kernel_entry(mb_magic: u32, mbi_ptr: u32) {
28
+ //! if mb_magic == multiboot2::MAGIC {
29
+ //! let boot_info = unsafe { BootInformation::load(mbi_ptr as *const BootInformationHeader).unwrap() };
30
+ //! let _cmd = boot_info.command_line_tag();
31
+ //! } else { /* Panic or use multiboot1 flow. */ }
29
32
//! }
30
33
//! ```
31
34
//!
@@ -41,6 +44,7 @@ extern crate alloc;
41
44
extern crate std;
42
45
43
46
use core:: fmt;
47
+ use core:: mem:: size_of;
44
48
use derive_more:: Display ;
45
49
// Must be public so that custom tags can be DSTs.
46
50
pub use ptr_meta:: Pointee ;
@@ -102,7 +106,7 @@ pub const MAGIC: u32 = 0x36d76289;
102
106
/// Deprecated. Please use BootInformation::load() instead.
103
107
#[ deprecated = "Please use BootInformation::load() instead." ]
104
108
pub unsafe fn load < ' a > ( address : usize ) -> Result < BootInformation < ' a > , MbiLoadError > {
105
- let ptr = address as * const u8 ;
109
+ let ptr = address as * const BootInformationHeader ;
106
110
BootInformation :: load ( ptr)
107
111
}
108
112
@@ -139,58 +143,77 @@ pub enum MbiLoadError {
139
143
#[ cfg( feature = "unstable" ) ]
140
144
impl core:: error:: Error for MbiLoadError { }
141
145
146
+ /// The basic header of a boot information.
147
+ #[ derive( Copy , Clone , Debug , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
142
148
#[ repr( C , align( 8 ) ) ]
143
- struct BootInformationInner {
149
+ pub struct BootInformationHeader {
150
+ // size is multiple of 8
144
151
total_size : u32 ,
145
152
_reserved : u32 ,
146
- // followed by various, dynamically sized multiboot2 tags
147
- tags : [ Tag ; 0 ] ,
153
+ // Followed by the boot information tags.
148
154
}
149
155
150
- impl BootInformationInner {
156
+ impl BootInformationHeader {
151
157
#[ cfg( feature = "builder" ) ]
152
158
fn new ( total_size : u32 ) -> Self {
153
159
Self {
154
160
total_size,
155
161
_reserved : 0 ,
156
- tags : [ ] ,
157
162
}
158
163
}
164
+ }
165
+
166
+ #[ cfg( feature = "builder" ) ]
167
+ impl StructAsBytes for BootInformationHeader {
168
+ fn byte_size ( & self ) -> usize {
169
+ core:: mem:: size_of :: < Self > ( )
170
+ }
171
+ }
159
172
173
+ /// This type holds the whole data of the MBI. This helps to better satisfy miri
174
+ /// when it checks for memory issues.
175
+ #[ derive( ptr_meta:: Pointee ) ]
176
+ #[ repr( C ) ]
177
+ struct BootInformationInner {
178
+ header : BootInformationHeader ,
179
+ tags : [ u8 ] ,
180
+ }
181
+
182
+ impl BootInformationInner {
183
+ /// Checks if the MBI has a valid end tag by checking the end of the mbi's
184
+ /// bytes.
160
185
fn has_valid_end_tag ( & self ) -> bool {
161
186
let end_tag_prototype = EndTag :: default ( ) ;
162
187
163
- let self_ptr = self as * const _ ;
164
- let end_tag_addr = self_ptr as usize + ( self . total_size - end_tag_prototype. size ) as usize ;
165
- let end_tag = unsafe { & * ( end_tag_addr as * const Tag ) } ;
188
+ let self_ptr = unsafe { self . tags . as_ptr ( ) . sub ( size_of :: < BootInformationHeader > ( ) ) } ;
166
189
167
- end_tag. typ == end_tag_prototype. typ && end_tag. size == end_tag_prototype. size
168
- }
169
- }
190
+ let end_tag_ptr = unsafe {
191
+ self_ptr
192
+ . add ( self . header . total_size as usize )
193
+ . sub ( size_of :: < EndTag > ( ) )
194
+ } ;
195
+ let end_tag = unsafe { & * ( end_tag_ptr as * const EndTag ) } ;
170
196
171
- #[ cfg( feature = "builder" ) ]
172
- impl StructAsBytes for BootInformationInner {
173
- fn byte_size ( & self ) -> usize {
174
- core:: mem:: size_of :: < Self > ( )
197
+ end_tag. typ == end_tag_prototype. typ && end_tag. size == end_tag_prototype. size
175
198
}
176
199
}
177
200
178
201
/// A Multiboot 2 Boot Information (MBI) accessor.
179
202
#[ repr( transparent) ]
180
203
pub struct BootInformation < ' a > ( & ' a BootInformationInner ) ;
181
204
182
- impl BootInformation < ' _ > {
205
+ impl < ' a > BootInformation < ' a > {
183
206
/// Loads the [`BootInformation`] from a pointer. The pointer must be valid
184
207
/// and aligned to an 8-byte boundary, as defined by the spec.
185
208
///
186
209
/// ## Example
187
210
///
188
211
/// ```rust
189
- /// use multiboot2::BootInformation;
212
+ /// use multiboot2::{ BootInformation, BootInformationHeader} ;
190
213
///
191
214
/// fn kernel_entry(mb_magic: u32, mbi_ptr: u32) {
192
215
/// if mb_magic == multiboot2::MAGIC {
193
- /// let boot_info = unsafe { BootInformation::load(mbi_ptr as *const u8 ).unwrap() };
216
+ /// let boot_info = unsafe { BootInformation::load(mbi_ptr as *const BootInformationHeader ).unwrap() };
194
217
/// let _cmd = boot_info.command_line_tag();
195
218
/// } else { /* Panic or use multiboot1 flow. */ }
196
219
/// }
@@ -203,20 +226,26 @@ impl BootInformation<'_> {
203
226
/// boot environments, such as UEFI.
204
227
/// * The memory at `ptr` must not be modified after calling `load` or the
205
228
/// program may observe unsynchronized mutation.
206
- pub unsafe fn load ( ptr : * const u8 ) -> Result < Self , MbiLoadError > {
229
+ pub unsafe fn load ( ptr : * const BootInformationHeader ) -> Result < Self , MbiLoadError > {
207
230
// null or not aligned
208
231
if ptr. is_null ( ) || ptr. align_offset ( 8 ) != 0 {
209
232
return Err ( MbiLoadError :: IllegalAddress ) ;
210
233
}
211
234
212
- let mbi = & * ptr. cast :: < BootInformationInner > ( ) ;
235
+ // mbi: reference to basic header
236
+ let mbi = & * ptr;
213
237
214
238
// Check if total size is a multiple of 8.
215
239
// See MbiLoadError::IllegalTotalSize for comments
216
240
if mbi. total_size & 0b111 != 0 {
217
241
return Err ( MbiLoadError :: IllegalTotalSize ( mbi. total_size ) ) ;
218
242
}
219
243
244
+ let slice_size = mbi. total_size as usize - size_of :: < BootInformationHeader > ( ) ;
245
+ // mbi: reference to full mbi
246
+ let mbi = ptr_meta:: from_raw_parts :: < BootInformationInner > ( ptr. cast ( ) , slice_size) ;
247
+ let mbi = & * mbi;
248
+
220
249
if !mbi. has_valid_end_tag ( ) {
221
250
return Err ( MbiLoadError :: NoEndTag ) ;
222
251
}
@@ -226,7 +255,7 @@ impl BootInformation<'_> {
226
255
227
256
/// Get the start address of the boot info.
228
257
pub fn start_address ( & self ) -> usize {
229
- core :: ptr :: addr_of! ( * self . 0 ) as usize
258
+ self . as_ptr ( ) as usize
230
259
}
231
260
232
261
/// Get the start address of the boot info as pointer.
@@ -248,7 +277,7 @@ impl BootInformation<'_> {
248
277
249
278
/// Get the total size of the boot info struct.
250
279
pub fn total_size ( & self ) -> usize {
251
- self . 0 . total_size as usize
280
+ self . 0 . header . total_size as usize
252
281
}
253
282
254
283
/// Search for the basic memory info tag.
@@ -425,20 +454,19 @@ impl BootInformation<'_> {
425
454
/// .unwrap();
426
455
/// assert_eq!(tag.name(), Ok("name"));
427
456
/// ```
428
- pub fn get_tag < TagT : TagTrait + ?Sized , TagType : Into < TagTypeId > > (
429
- & self ,
457
+ pub fn get_tag < TagT : TagTrait + ?Sized + ' a , TagType : Into < TagTypeId > > (
458
+ & ' a self ,
430
459
typ : TagType ,
431
- ) -> Option < & TagT > {
460
+ ) -> Option < & ' a TagT > {
432
461
let typ = typ. into ( ) ;
433
462
self . tags ( )
434
463
. find ( |tag| tag. typ == typ)
435
464
. map ( |tag| tag. cast_tag :: < TagT > ( ) )
436
465
}
437
466
467
+ /// Returns an iterator over all tags.
438
468
fn tags ( & self ) -> TagIter {
439
- // The first tag starts 8 bytes after the begin of the boot info header
440
- let ptr = core:: ptr:: addr_of!( self . 0 . tags) . cast ( ) ;
441
- TagIter :: new ( ptr)
469
+ TagIter :: new ( & self . 0 . tags )
442
470
}
443
471
}
444
472
@@ -525,8 +553,8 @@ pub trait TagTrait: Pointee {
525
553
/// sane and the underlying memory valid. The implementation of this trait
526
554
/// **must have** a correct [`Self::dst_size`] implementation.
527
555
unsafe fn from_base_tag < ' a > ( tag : & Tag ) -> & ' a Self {
528
- let ptr = tag as * const _ as * const ( ) ;
529
- let ptr = ptr_meta:: from_raw_parts ( ptr, Self :: dst_size ( tag) ) ;
556
+ let ptr = core :: ptr :: addr_of! ( * tag ) ;
557
+ let ptr = ptr_meta:: from_raw_parts ( ptr. cast ( ) , Self :: dst_size ( tag) ) ;
530
558
& * ptr
531
559
}
532
560
}
@@ -1520,7 +1548,7 @@ mod tests {
1520
1548
0 , 0 , 0 , 0 , // end tag type.
1521
1549
8 , 0 , 0 , 0 , // end tag size.
1522
1550
] ) ;
1523
- let bi = unsafe { BootInformation :: load ( bytes2. 0 . as_ptr ( ) ) } ;
1551
+ let bi = unsafe { BootInformation :: load ( bytes2. 0 . as_ptr ( ) . cast ( ) ) } ;
1524
1552
let bi = bi. unwrap ( ) ;
1525
1553
let efi_mmap = bi. efi_memory_map_tag ( ) ;
1526
1554
assert ! ( efi_mmap. is_none( ) ) ;
0 commit comments