1
1
//! Module for [`BootInformation`].
2
2
3
- #[ cfg( feature = "builder" ) ]
4
- use crate :: builder:: AsBytes ;
5
3
use crate :: framebuffer:: UnknownFramebufferType ;
6
- use crate :: tag:: { TagHeader , TagIter } ;
4
+ use crate :: tag:: TagHeader ;
7
5
use crate :: {
8
6
module, BasicMemoryInfoTag , BootLoaderNameTag , CommandLineTag , EFIBootServicesNotExitedTag ,
9
7
EFIImageHandle32Tag , EFIImageHandle64Tag , EFIMemoryMapTag , EFISdt32Tag , EFISdt64Tag ,
10
8
ElfSectionIter , ElfSectionsTag , EndTag , FramebufferTag , ImageLoadPhysAddrTag , MemoryMapTag ,
11
- ModuleIter , RsdpV1Tag , RsdpV2Tag , SmbiosTag , TagTrait , VBEInfoTag ,
9
+ ModuleIter , RsdpV1Tag , RsdpV2Tag , SmbiosTag , TagIter , TagType , VBEInfoTag ,
12
10
} ;
13
11
use core:: fmt;
14
12
use core:: mem;
15
- use core:: ptr;
13
+ use core:: ptr:: NonNull ;
16
14
use derive_more:: Display ;
15
+ use multiboot2_common:: { DynSizedStructure , Header , MaybeDynSized , MemoryError , Tag } ;
17
16
18
17
/// Error type that describes errors while loading/parsing a multiboot2 information structure
19
18
/// from a given address.
20
19
#[ derive( Display , Copy , Clone , Debug , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
21
20
pub 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.
33
24
NoEndTag ,
34
25
}
35
26
@@ -62,40 +53,19 @@ impl BootInformationHeader {
62
53
}
63
54
}
64
55
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
+ }
91
60
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 ;
93
63
}
94
64
}
95
65
96
66
/// A Multiboot 2 Boot Information (MBI) accessor.
97
67
#[ repr( transparent) ]
98
- pub struct BootInformation < ' a > ( & ' a BootInformationInner ) ;
68
+ pub struct BootInformation < ' a > ( & ' a DynSizedStructure < BootInformationHeader > ) ;
99
69
100
70
impl < ' a > BootInformation < ' a > {
101
71
/// Loads the [`BootInformation`] from a pointer. The pointer must be valid
@@ -115,36 +85,38 @@ impl<'a> BootInformation<'a> {
115
85
/// ```
116
86
///
117
87
/// ## 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
119
89
/// invalid machine state or crash your binary (kernel). This can be the
120
90
/// case in environments with standard environment (segfault), but also in
121
91
/// boot environments, such as UEFI.
122
92
/// * The memory at `ptr` must not be modified after calling `load` or the
123
93
/// program may observe unsynchronized mutation.
124
94
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 ) ?;
132
97
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 ( ) {
144
100
return Err ( MbiLoadError :: NoEndTag ) ;
145
101
}
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 } ;
146
118
147
- Ok ( Self ( mbi ) )
119
+ end_tag . typ == EndTag :: ID && end_tag . size as usize == mem :: size_of :: < EndTag > ( )
148
120
}
149
121
150
122
/// Get the start address of the boot info.
@@ -177,7 +149,7 @@ impl<'a> BootInformation<'a> {
177
149
/// Get the total size of the boot info struct.
178
150
#[ must_use]
179
151
pub const fn total_size ( & self ) -> usize {
180
- self . 0 . header . total_size as usize
152
+ self . 0 . header ( ) . total_size as usize
181
153
}
182
154
183
155
// ######################################################
@@ -279,7 +251,7 @@ impl<'a> BootInformation<'a> {
279
251
pub fn elf_sections ( & self ) -> Option < ElfSectionIter > {
280
252
let tag = self . get_tag :: < ElfSectionsTag > ( ) ;
281
253
tag. map ( |t| {
282
- assert ! ( ( t. entry_size( ) * t. shndx( ) ) <= t. size ( ) as u32 ) ;
254
+ assert ! ( ( t. entry_size( ) * t. shndx( ) ) <= t. header ( ) . size ) ;
283
255
t. sections_iter ( )
284
256
} )
285
257
}
@@ -289,10 +261,12 @@ impl<'a> BootInformation<'a> {
289
261
#[ must_use]
290
262
pub fn framebuffer_tag ( & self ) -> Option < Result < & FramebufferTag , UnknownFramebufferType > > {
291
263
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
+ })*/
296
270
}
297
271
298
272
/// Search for the Image Load Base Physical Address tag.
@@ -361,34 +335,44 @@ impl<'a> BootInformation<'a> {
361
335
/// special handling is required. This is reflected by code-comments.
362
336
///
363
337
/// ```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};
365
341
///
366
342
/// #[repr(C)]
367
343
/// #[derive(multiboot2::Pointee)] // Only needed for DSTs.
368
344
/// 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.
372
348
/// name: [u8],
373
349
/// }
374
350
///
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>();
378
361
///
362
+ /// // This differs for DSTs and normal structs. See function
363
+ /// // documentation.
379
364
/// 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
384
367
/// }
385
368
/// }
386
369
///
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);
391
374
/// }
375
+ ///
392
376
/// let mbi_ptr = 0xdeadbeef as *const BootInformationHeader;
393
377
/// let mbi = unsafe { BootInformation::load(mbi_ptr).unwrap() };
394
378
///
@@ -400,15 +384,17 @@ impl<'a> BootInformation<'a> {
400
384
///
401
385
/// [`TagType`]: crate::TagType
402
386
#[ 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 > {
404
390
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 > ( ) )
407
393
}
408
394
409
395
/// 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 ( ) )
412
398
}
413
399
}
414
400
0 commit comments