11//! Module for [`BootInformation`].
22
3- #[ cfg( feature = "builder" ) ]
4- use crate :: builder:: AsBytes ;
53use crate :: framebuffer:: UnknownFramebufferType ;
6- use crate :: tag:: { TagHeader , TagIter } ;
4+ use crate :: tag:: TagHeader ;
75use crate :: {
86 module, BasicMemoryInfoTag , BootLoaderNameTag , CommandLineTag , EFIBootServicesNotExitedTag ,
97 EFIImageHandle32Tag , EFIImageHandle64Tag , EFIMemoryMapTag , EFISdt32Tag , EFISdt64Tag ,
108 ElfSectionIter , ElfSectionsTag , EndTag , FramebufferTag , ImageLoadPhysAddrTag , MemoryMapTag ,
11- ModuleIter , RsdpV1Tag , RsdpV2Tag , SmbiosTag , TagTrait , VBEInfoTag ,
9+ ModuleIter , RsdpV1Tag , RsdpV2Tag , SmbiosTag , TagIter , TagType , VBEInfoTag ,
1210} ;
1311use core:: fmt;
1412use core:: mem;
15- use core:: ptr;
13+ use core:: ptr:: NonNull ;
1614use derive_more:: Display ;
15+ use multiboot2_common:: { DynSizedStructure , Header , MaybeDynSized , MemoryError , Tag } ;
1716
1817/// Error type that describes errors while loading/parsing a multiboot2 information structure
1918/// from a given address.
2019#[ derive( Display , Copy , Clone , Debug , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
2120pub enum MbiLoadError {
22- /// The address is invalid. Make sure that the address is 8-byte aligned,
23- /// according to the spec.
24- #[ display( fmt = "The address is invalid" ) ]
25- IllegalAddress ,
26- /// The total size of the multiboot2 information structure must be not zero
27- /// and a multiple of 8.
28- #[ display( fmt = "The size of the MBI is unexpected" ) ]
29- IllegalTotalSize ( u32 ) ,
30- /// Missing end tag. Each multiboot2 boot information requires to have an
31- /// end tag.
32- #[ display( fmt = "There is no end tag" ) ]
21+ /// See [`MemoryError`].
22+ Memory ( MemoryError ) ,
23+ /// Missing mandatory end tag.
3324 NoEndTag ,
3425}
3526
@@ -62,40 +53,19 @@ impl BootInformationHeader {
6253 }
6354}
6455
65- #[ cfg( feature = "builder" ) ]
66- impl AsBytes for BootInformationHeader { }
67-
68- /// This type holds the whole data of the MBI. This helps to better satisfy miri
69- /// when it checks for memory issues.
70- #[ derive( ptr_meta:: Pointee ) ]
71- #[ repr( C , align( 8 ) ) ]
72- struct BootInformationInner {
73- header : BootInformationHeader ,
74- tags : [ u8 ] ,
75- }
76-
77- impl BootInformationInner {
78- /// Checks if the MBI has a valid end tag by checking the end of the mbi's
79- /// bytes.
80- fn has_valid_end_tag ( & self ) -> bool {
81- let self_ptr = ptr:: addr_of!( * self ) ;
82-
83- let end_tag_ptr = unsafe {
84- self_ptr
85- . cast :: < u8 > ( )
86- . add ( self . header . total_size as usize )
87- . sub ( mem:: size_of :: < EndTag > ( ) )
88- . cast :: < TagHeader > ( )
89- } ;
90- let end_tag = unsafe { & * end_tag_ptr } ;
56+ impl Header for BootInformationHeader {
57+ fn payload_len ( & self ) -> usize {
58+ self . total_size as usize - mem:: size_of :: < Self > ( )
59+ }
9160
92- end_tag. typ == EndTag :: ID && end_tag. size as usize == mem:: size_of :: < EndTag > ( )
61+ fn set_size ( & mut self , total_size : usize ) {
62+ self . total_size = total_size as u32 ;
9363 }
9464}
9565
9666/// A Multiboot 2 Boot Information (MBI) accessor.
9767#[ repr( transparent) ]
98- pub struct BootInformation < ' a > ( & ' a BootInformationInner ) ;
68+ pub struct BootInformation < ' a > ( & ' a DynSizedStructure < BootInformationHeader > ) ;
9969
10070impl < ' a > BootInformation < ' a > {
10171 /// Loads the [`BootInformation`] from a pointer. The pointer must be valid
@@ -115,36 +85,38 @@ impl<'a> BootInformation<'a> {
11585 /// ```
11686 ///
11787 /// ## Safety
118- /// * `ptr` must be valid for reading. Otherwise this function might cause
88+ /// * `ptr` must be valid for reading. Otherwise, this function might cause
11989 /// invalid machine state or crash your binary (kernel). This can be the
12090 /// case in environments with standard environment (segfault), but also in
12191 /// boot environments, such as UEFI.
12292 /// * The memory at `ptr` must not be modified after calling `load` or the
12393 /// program may observe unsynchronized mutation.
12494 pub unsafe fn load ( ptr : * const BootInformationHeader ) -> Result < Self , MbiLoadError > {
125- // null or not aligned
126- if ptr. is_null ( ) || ptr. align_offset ( 8 ) != 0 {
127- return Err ( MbiLoadError :: IllegalAddress ) ;
128- }
129-
130- // mbi: reference to basic header
131- let mbi = & * ptr;
95+ let ptr = NonNull :: new ( ptr. cast_mut ( ) ) . ok_or ( MbiLoadError :: Memory ( MemoryError :: Null ) ) ?;
96+ let inner = DynSizedStructure :: ref_from_ptr ( ptr) . map_err ( MbiLoadError :: Memory ) ?;
13297
133- // Check if total size is not 0 and a multiple of 8.
134- if mbi. total_size == 0 || mbi. total_size & 0b111 != 0 {
135- return Err ( MbiLoadError :: IllegalTotalSize ( mbi. total_size ) ) ;
136- }
137-
138- let slice_size = mbi. total_size as usize - mem:: size_of :: < BootInformationHeader > ( ) ;
139- // mbi: reference to full mbi
140- let mbi = ptr_meta:: from_raw_parts :: < BootInformationInner > ( ptr. cast ( ) , slice_size) ;
141- let mbi = & * mbi;
142-
143- if !mbi. has_valid_end_tag ( ) {
98+ let this = Self ( inner) ;
99+ if !this. has_valid_end_tag ( ) {
144100 return Err ( MbiLoadError :: NoEndTag ) ;
145101 }
102+ Ok ( this)
103+ }
104+
105+ /// Checks if the MBI has a valid end tag by checking the end of the mbi's
106+ /// bytes.
107+ fn has_valid_end_tag ( & self ) -> bool {
108+ let header = self . 0 . header ( ) ;
109+ let end_tag_ptr = unsafe {
110+ self . 0
111+ . payload ( )
112+ . as_ptr ( )
113+ . add ( header. payload_len ( ) )
114+ . sub ( mem:: size_of :: < EndTag > ( ) )
115+ . cast :: < TagHeader > ( )
116+ } ;
117+ let end_tag = unsafe { & * end_tag_ptr } ;
146118
147- Ok ( Self ( mbi ) )
119+ end_tag . typ == EndTag :: ID && end_tag . size as usize == mem :: size_of :: < EndTag > ( )
148120 }
149121
150122 /// Get the start address of the boot info.
@@ -177,7 +149,7 @@ impl<'a> BootInformation<'a> {
177149 /// Get the total size of the boot info struct.
178150 #[ must_use]
179151 pub const fn total_size ( & self ) -> usize {
180- self . 0 . header . total_size as usize
152+ self . 0 . header ( ) . total_size as usize
181153 }
182154
183155 // ######################################################
@@ -279,7 +251,7 @@ impl<'a> BootInformation<'a> {
279251 pub fn elf_sections ( & self ) -> Option < ElfSectionIter > {
280252 let tag = self . get_tag :: < ElfSectionsTag > ( ) ;
281253 tag. map ( |t| {
282- assert ! ( ( t. entry_size( ) * t. shndx( ) ) <= t. size ( ) as u32 ) ;
254+ assert ! ( ( t. entry_size( ) * t. shndx( ) ) <= t. header ( ) . size ) ;
283255 t. sections_iter ( )
284256 } )
285257 }
@@ -289,10 +261,12 @@ impl<'a> BootInformation<'a> {
289261 #[ must_use]
290262 pub fn framebuffer_tag ( & self ) -> Option < Result < & FramebufferTag , UnknownFramebufferType > > {
291263 self . get_tag :: < FramebufferTag > ( )
292- . map ( |tag| match tag. buffer_type ( ) {
293- Ok ( _) => Ok ( tag) ,
294- Err ( e) => Err ( e) ,
295- } )
264+ // TODO temporarily. Someone needs to fix the framebuffer thingy.
265+ . map ( Ok )
266+ /*.map(|tag| match tag.buffer_type() {
267+ Ok(_) => Ok(tag),
268+ Err(e) => Err(e),
269+ })*/
296270 }
297271
298272 /// Search for the Image Load Base Physical Address tag.
@@ -361,34 +335,44 @@ impl<'a> BootInformation<'a> {
361335 /// special handling is required. This is reflected by code-comments.
362336 ///
363337 /// ```no_run
364- /// use multiboot2::{BootInformation, BootInformationHeader, parse_slice_as_string, StringError, TagHeader, TagTrait, TagType, TagTypeId};
338+ /// use std::mem;
339+ /// use multiboot2::{BootInformation, BootInformationHeader, parse_slice_as_string, StringError, TagHeader, TagType, TagTypeId}; ///
340+ /// use multiboot2_common::{MaybeDynSized, Tag};
365341 ///
366342 /// #[repr(C)]
367343 /// #[derive(multiboot2::Pointee)] // Only needed for DSTs.
368344 /// struct CustomTag {
369- /// tag: TagTypeId ,
370- /// size : u32,
371- /// // begin of inline string
345+ /// header: TagHeader ,
346+ /// some_other_prop : u32,
347+ /// // Begin of C string, for example.
372348 /// name: [u8],
373349 /// }
374350 ///
375- /// // This implementation is only necessary for tags that are DSTs.
376- /// impl TagTrait for CustomTag {
377- /// const ID: TagType = TagType::Custom(0x1337);
351+ /// impl CustomTag {
352+ /// fn name(&self) -> Result<&str, StringError> {
353+ /// parse_slice_as_string(&self.name)
354+ /// }
355+ /// }
356+ ///
357+ /// // Give the library hints how big this tag is.
358+ /// impl MaybeDynSized for CustomTag {
359+ /// type Header = TagHeader;
360+ /// const BASE_SIZE: usize = mem::size_of::<TagHeader>() + mem::size_of::<u32>();
378361 ///
362+ /// // This differs for DSTs and normal structs. See function
363+ /// // documentation.
379364 /// fn dst_len(header: &TagHeader) -> usize {
380- /// // The size of the sized portion of the custom tag.
381- /// let tag_base_size = 8; // id + size is 8 byte in size
382- /// assert!(header.size >= 8);
383- /// header.size as usize - tag_base_size
365+ /// assert!(header.size >= Self::BASE_SIZE as u32);
366+ /// header.size as usize - Self::BASE_SIZE
384367 /// }
385368 /// }
386369 ///
387- /// impl CustomTag {
388- /// fn name(&self) -> Result<&str, StringError> {
389- /// parse_slice_as_string(&self.name)
390- /// }
370+ /// // Make the Tag identifiable.
371+ /// impl Tag for CustomTag {
372+ /// type IDType = TagType;
373+ /// const ID: TagType = TagType::Custom(0x1337);
391374 /// }
375+ ///
392376 /// let mbi_ptr = 0xdeadbeef as *const BootInformationHeader;
393377 /// let mbi = unsafe { BootInformation::load(mbi_ptr).unwrap() };
394378 ///
@@ -400,15 +384,17 @@ impl<'a> BootInformation<'a> {
400384 ///
401385 /// [`TagType`]: crate::TagType
402386 #[ must_use]
403- pub fn get_tag < TagT : TagTrait + ?Sized + ' a > ( & ' a self ) -> Option < & ' a TagT > {
387+ pub fn get_tag < T : Tag < IDType = TagType , Header = TagHeader > + ?Sized + ' a > (
388+ & ' a self ,
389+ ) -> Option < & ' a T > {
404390 self . tags ( )
405- . find ( |tag| tag. header ( ) . typ == TagT :: ID )
406- . map ( |tag| tag. cast :: < TagT > ( ) )
391+ . find ( |tag| tag. header ( ) . typ == T :: ID )
392+ . map ( |tag| tag. cast :: < T > ( ) )
407393 }
408394
409395 /// Returns an iterator over all tags.
410- fn tags ( & self ) -> TagIter {
411- TagIter :: new ( & self . 0 . tags )
396+ pub ( crate ) fn tags ( & self ) -> TagIter {
397+ TagIter :: new ( self . 0 . payload ( ) )
412398 }
413399}
414400
0 commit comments