@@ -67,8 +67,8 @@ pub use memory_map::{
67
67
pub use module:: { ModuleIter , ModuleTag } ;
68
68
pub use rsdp:: { RsdpV1Tag , RsdpV2Tag } ;
69
69
pub use smbios:: SmbiosTag ;
70
- use tag_type:: TagIter ;
71
70
pub use tag_type:: { EndTag , Tag , TagType , TagTypeId } ;
71
+ use tag_type:: { TagIter , TagIterMut } ;
72
72
pub use vbe_info:: {
73
73
VBECapabilities , VBEControlInfo , VBEDirectColorAttributes , VBEField , VBEInfoTag ,
74
74
VBEMemoryModel , VBEModeAttributes , VBEModeInfo , VBEWindowAttributes ,
@@ -105,8 +105,10 @@ pub const MAGIC: u32 = 0x36d76289;
105
105
/// # Safety
106
106
/// Deprecated. Please use BootInformation::load() instead.
107
107
#[ deprecated = "Please use BootInformation::load() instead." ]
108
- pub unsafe fn load < ' a > ( address : usize ) -> Result < BootInformation < ' a > , MbiLoadError > {
109
- let ptr = address as * const BootInformationHeader ;
108
+ pub unsafe fn load < ' a > (
109
+ address : usize ,
110
+ ) -> Result < BootInformation < & ' a BootInformationInner > , MbiLoadError > {
111
+ let ptr = address as * mut BootInformationHeader ;
110
112
BootInformation :: load ( ptr)
111
113
}
112
114
@@ -116,8 +118,8 @@ pub unsafe fn load<'a>(address: usize) -> Result<BootInformation<'a>, MbiLoadErr
116
118
pub unsafe fn load_with_offset < ' a > (
117
119
address : usize ,
118
120
offset : usize ,
119
- ) -> Result < BootInformation < ' a > , MbiLoadError > {
120
- let ptr = address as * const u8 ;
121
+ ) -> Result < BootInformation < & ' a BootInformationInner > , MbiLoadError > {
122
+ let ptr = address as * mut u8 ;
121
123
let ptr = ptr. add ( offset) ;
122
124
BootInformation :: load ( ptr. cast ( ) )
123
125
}
@@ -172,9 +174,9 @@ impl StructAsBytes for BootInformationHeader {
172
174
173
175
/// This type holds the whole data of the MBI. This helps to better satisfy miri
174
176
/// when it checks for memory issues.
175
- #[ derive( ptr_meta:: Pointee ) ]
177
+ #[ derive( ptr_meta:: Pointee , Debug ) ]
176
178
#[ repr( C ) ]
177
- struct BootInformationInner {
179
+ pub struct BootInformationInner {
178
180
header : BootInformationHeader ,
179
181
tags : [ u8 ] ,
180
182
}
@@ -198,11 +200,17 @@ impl BootInformationInner {
198
200
}
199
201
}
200
202
203
+ impl AsRef < BootInformationInner > for BootInformationInner {
204
+ fn as_ref ( & self ) -> & BootInformationInner {
205
+ self
206
+ }
207
+ }
208
+
201
209
/// A Multiboot 2 Boot Information (MBI) accessor.
202
210
#[ repr( transparent) ]
203
- pub struct BootInformation < ' a > ( & ' a BootInformationInner ) ;
211
+ pub struct BootInformation < T : AsRef < BootInformationInner > > ( T ) ;
204
212
205
- impl < ' a > BootInformation < ' a > {
213
+ impl BootInformation < & BootInformationInner > {
206
214
/// Loads the [`BootInformation`] from a pointer. The pointer must be valid
207
215
/// and aligned to an 8-byte boundary, as defined by the spec.
208
216
///
@@ -251,15 +259,50 @@ impl<'a> BootInformation<'a> {
251
259
252
260
Ok ( Self ( mbi) )
253
261
}
262
+ }
254
263
264
+ impl BootInformation < & mut BootInformationInner > {
265
+ /// [`load`], but mutably.
266
+ ///
267
+ /// # Safety
268
+ /// The same considerations that apply to `load` also apply here, but the
269
+ /// memory can be modified (through the `_mut` methods).
270
+ pub unsafe fn load_mut ( ptr : * mut BootInformationHeader ) -> Result < Self , MbiLoadError > {
271
+ // null or not aligned
272
+ if ptr. is_null ( ) || ptr. align_offset ( 8 ) != 0 {
273
+ return Err ( MbiLoadError :: IllegalAddress ) ;
274
+ }
275
+
276
+ // mbi: reference to basic header
277
+ let mbi = & * ptr;
278
+
279
+ // Check if total size is not 0 and a multiple of 8.
280
+ if mbi. total_size == 0 || mbi. total_size & 0b111 != 0 {
281
+ return Err ( MbiLoadError :: IllegalTotalSize ( mbi. total_size ) ) ;
282
+ }
283
+
284
+ let slice_size = mbi. total_size as usize - size_of :: < BootInformationHeader > ( ) ;
285
+ // mbi: reference to full mbi
286
+ let mbi = ptr_meta:: from_raw_parts_mut :: < BootInformationInner > ( ptr. cast ( ) , slice_size) ;
287
+ let mbi = & mut * mbi;
288
+
289
+ if !mbi. has_valid_end_tag ( ) {
290
+ return Err ( MbiLoadError :: NoEndTag ) ;
291
+ }
292
+
293
+ Ok ( Self ( mbi) )
294
+ }
295
+ }
296
+
297
+ impl < T : AsRef < BootInformationInner > > BootInformation < T > {
255
298
/// Get the start address of the boot info.
256
299
pub fn start_address ( & self ) -> usize {
257
300
self . as_ptr ( ) as usize
258
301
}
259
302
260
303
/// Get the start address of the boot info as pointer.
261
304
pub fn as_ptr ( & self ) -> * const ( ) {
262
- core:: ptr:: addr_of!( * self . 0 ) . cast ( )
305
+ core:: ptr:: addr_of!( * self . 0 . as_ref ( ) ) . cast ( )
263
306
}
264
307
265
308
/// Get the end address of the boot info.
@@ -276,7 +319,7 @@ impl<'a> BootInformation<'a> {
276
319
277
320
/// Get the total size of the boot info struct.
278
321
pub fn total_size ( & self ) -> usize {
279
- self . 0 . header . total_size as usize
322
+ self . 0 . as_ref ( ) . header . total_size as usize
280
323
}
281
324
282
325
/// Search for the basic memory info tag.
@@ -454,10 +497,10 @@ impl<'a> BootInformation<'a> {
454
497
/// .unwrap();
455
498
/// assert_eq!(tag.name(), Ok("name"));
456
499
/// ```
457
- pub fn get_tag < TagT : TagTrait + ?Sized + ' a , TagType : Into < TagTypeId > > (
458
- & ' a self ,
500
+ pub fn get_tag < TagT : TagTrait + ?Sized , TagType : Into < TagTypeId > > (
501
+ & self ,
459
502
typ : TagType ,
460
- ) -> Option < & ' a TagT > {
503
+ ) -> Option < & TagT > {
461
504
let typ = typ. into ( ) ;
462
505
self . tags ( )
463
506
. find ( |tag| tag. typ == typ)
@@ -466,15 +509,36 @@ impl<'a> BootInformation<'a> {
466
509
467
510
/// Returns an iterator over all tags.
468
511
fn tags ( & self ) -> TagIter {
469
- TagIter :: new ( & self . 0 . tags )
512
+ TagIter :: new ( & self . 0 . as_ref ( ) . tags )
513
+ }
514
+ }
515
+
516
+ impl < T : AsRef < BootInformationInner > + AsMut < BootInformationInner > > BootInformation < T > {
517
+ /// Search for the Memory map tag, return a mutable reference.
518
+ pub fn memory_map_tag_mut ( & mut self ) -> Option < & mut MemoryMapTag > {
519
+ self . get_tag_mut :: < MemoryMapTag , _ > ( TagType :: Mmap )
520
+ }
521
+
522
+ fn get_tag_mut < TagT : TagTrait + ?Sized , TagType : Into < TagTypeId > > (
523
+ & mut self ,
524
+ typ : TagType ,
525
+ ) -> Option < & mut TagT > {
526
+ let typ = typ. into ( ) ;
527
+ self . tags_mut ( )
528
+ . find ( |tag| tag. typ == typ)
529
+ . map ( |tag| tag. cast_tag_mut :: < TagT > ( ) )
530
+ }
531
+
532
+ fn tags_mut ( & mut self ) -> TagIterMut {
533
+ TagIterMut :: new ( & mut self . 0 . as_mut ( ) . tags )
470
534
}
471
535
}
472
536
473
537
// SAFETY: BootInformation contains a const ptr to memory that is never mutated.
474
538
// Sending this pointer to other threads is sound.
475
- unsafe impl Send for BootInformation < ' _ > { }
539
+ unsafe impl < T : AsRef < BootInformationInner > > Send for BootInformation < T > { }
476
540
477
- impl fmt:: Debug for BootInformation < ' _ > {
541
+ impl < T : AsRef < BootInformationInner > > fmt:: Debug for BootInformation < T > {
478
542
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
479
543
/// Limit how many Elf-Sections should be debug-formatted.
480
544
/// Can be thousands of sections for a Rust binary => this is useless output.
@@ -557,6 +621,19 @@ pub trait TagTrait: Pointee {
557
621
let ptr = ptr_meta:: from_raw_parts ( ptr. cast ( ) , Self :: dst_size ( tag) ) ;
558
622
& * ptr
559
623
}
624
+
625
+ /// Creates a mutable reference to a (dynamically sized) tag type in a safe way.
626
+ /// DST tags need to implement a proper [`Self::dst_size`] implementation.
627
+ ///
628
+ /// # Safety
629
+ /// Callers must be sure that the "size" field of the provided [`Tag`] is
630
+ /// sane and the underlying memory valid. The implementation of this trait
631
+ /// **must have** a correct [`Self::dst_size`] implementation.
632
+ unsafe fn from_base_tag_mut < ' a > ( tag : & mut Tag ) -> & ' a mut Self {
633
+ let ptr = core:: ptr:: addr_of_mut!( * tag) ;
634
+ let ptr = ptr_meta:: from_raw_parts_mut ( ptr. cast ( ) , Self :: dst_size ( tag) ) ;
635
+ & mut * ptr
636
+ }
560
637
}
561
638
562
639
// All sized tags automatically have a Pointee implementation where
@@ -1280,7 +1357,7 @@ mod tests {
1280
1357
1281
1358
/// Helper for [`grub2`].
1282
1359
fn test_grub2_boot_info (
1283
- bi : & BootInformation ,
1360
+ bi : & BootInformation < & BootInformationInner > ,
1284
1361
addr : usize ,
1285
1362
string_addr : u64 ,
1286
1363
bytes : & [ u8 ] ,
0 commit comments