2222//! ## Example
2323//!
2424//! ```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. */ }
2932//! }
3033//! ```
3134//!
@@ -41,6 +44,7 @@ extern crate alloc;
4144extern crate std;
4245
4346use core:: fmt;
47+ use core:: mem:: size_of;
4448use derive_more:: Display ;
4549// Must be public so that custom tags can be DSTs.
4650pub use ptr_meta:: Pointee ;
@@ -102,7 +106,7 @@ pub const MAGIC: u32 = 0x36d76289;
102106/// Deprecated. Please use BootInformation::load() instead.
103107#[ deprecated = "Please use BootInformation::load() instead." ]
104108pub unsafe fn load < ' a > ( address : usize ) -> Result < BootInformation < ' a > , MbiLoadError > {
105- let ptr = address as * const u8 ;
109+ let ptr = address as * const BootInformationHeader ;
106110 BootInformation :: load ( ptr)
107111}
108112
@@ -139,39 +143,58 @@ pub enum MbiLoadError {
139143#[ cfg( feature = "unstable" ) ]
140144impl core:: error:: Error for MbiLoadError { }
141145
146+ /// The basic header of a boot information.
147+ #[ derive( Copy , Clone , Debug , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
142148#[ repr( C , align( 8 ) ) ]
143- struct BootInformationInner {
149+ pub struct BootInformationHeader {
150+ // size is multiple of 8
144151 total_size : u32 ,
145152 _reserved : u32 ,
146- // followed by various, dynamically sized multiboot2 tags
147- tags : [ Tag ; 0 ] ,
153+ // Followed by the boot information tags.
148154}
149155
150- impl BootInformationInner {
156+ impl BootInformationHeader {
151157 #[ cfg( feature = "builder" ) ]
152158 fn new ( total_size : u32 ) -> Self {
153159 Self {
154160 total_size,
155161 _reserved : 0 ,
156- tags : [ ] ,
157162 }
158163 }
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+ }
159172
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.
160185 fn has_valid_end_tag ( & self ) -> bool {
161186 let end_tag_prototype = EndTag :: default ( ) ;
162187
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 > ( ) ) } ;
166189
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 ) } ;
170196
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
175198 }
176199}
177200
@@ -186,11 +209,11 @@ impl BootInformation<'_> {
186209 /// ## Example
187210 ///
188211 /// ```rust
189- /// use multiboot2::BootInformation;
212+ /// use multiboot2::{ BootInformation, BootInformationHeader} ;
190213 ///
191214 /// fn kernel_entry(mb_magic: u32, mbi_ptr: u32) {
192215 /// 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() };
194217 /// let _cmd = boot_info.command_line_tag();
195218 /// } else { /* Panic or use multiboot1 flow. */ }
196219 /// }
@@ -203,20 +226,26 @@ impl BootInformation<'_> {
203226 /// boot environments, such as UEFI.
204227 /// * The memory at `ptr` must not be modified after calling `load` or the
205228 /// 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 > {
207230 // null or not aligned
208231 if ptr. is_null ( ) || ptr. align_offset ( 8 ) != 0 {
209232 return Err ( MbiLoadError :: IllegalAddress ) ;
210233 }
211234
212- let mbi = & * ptr. cast :: < BootInformationInner > ( ) ;
235+ // mbi: reference to basic header
236+ let mbi = & * ptr;
213237
214238 // Check if total size is a multiple of 8.
215239 // See MbiLoadError::IllegalTotalSize for comments
216240 if mbi. total_size & 0b111 != 0 {
217241 return Err ( MbiLoadError :: IllegalTotalSize ( mbi. total_size ) ) ;
218242 }
219243
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+
220249 if !mbi. has_valid_end_tag ( ) {
221250 return Err ( MbiLoadError :: NoEndTag ) ;
222251 }
@@ -226,7 +255,7 @@ impl BootInformation<'_> {
226255
227256 /// Get the start address of the boot info.
228257 pub fn start_address ( & self ) -> usize {
229- core :: ptr :: addr_of! ( * self . 0 ) as usize
258+ self . as_ptr ( ) as usize
230259 }
231260
232261 /// Get the start address of the boot info as pointer.
@@ -248,7 +277,7 @@ impl BootInformation<'_> {
248277
249278 /// Get the total size of the boot info struct.
250279 pub fn total_size ( & self ) -> usize {
251- self . 0 . total_size as usize
280+ self . 0 . header . total_size as usize
252281 }
253282
254283 /// Search for the basic memory info tag.
@@ -1520,7 +1549,7 @@ mod tests {
15201549 0 , 0 , 0 , 0 , // end tag type.
15211550 8 , 0 , 0 , 0 , // end tag size.
15221551 ] ) ;
1523- let bi = unsafe { BootInformation :: load ( bytes2. 0 . as_ptr ( ) ) } ;
1552+ let bi = unsafe { BootInformation :: load ( bytes2. 0 . as_ptr ( ) . cast ( ) ) } ;
15241553 let bi = bi. unwrap ( ) ;
15251554 let efi_mmap = bi. efi_memory_map_tag ( ) ;
15261555 assert ! ( efi_mmap. is_none( ) ) ;
0 commit comments