@@ -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,46 @@ impl<'a> BootInformation<'a> {
251
259
252
260
Ok ( Self ( mbi) )
253
261
}
262
+ }
263
+
264
+ impl BootInformation < & mut BootInformationInner > {
265
+ /// [`load`], but mutably.
266
+ pub unsafe fn load_mut ( ptr : * mut BootInformationHeader ) -> Result < Self , MbiLoadError > {
267
+ // null or not aligned
268
+ if ptr. is_null ( ) || ptr. align_offset ( 8 ) != 0 {
269
+ return Err ( MbiLoadError :: IllegalAddress ) ;
270
+ }
271
+
272
+ // mbi: reference to basic header
273
+ let mbi = & * ptr;
274
+
275
+ // Check if total size is not 0 and a multiple of 8.
276
+ if mbi. total_size == 0 || mbi. total_size & 0b111 != 0 {
277
+ return Err ( MbiLoadError :: IllegalTotalSize ( mbi. total_size ) ) ;
278
+ }
254
279
280
+ let slice_size = mbi. total_size as usize - size_of :: < BootInformationHeader > ( ) ;
281
+ // mbi: reference to full mbi
282
+ let mbi = ptr_meta:: from_raw_parts_mut :: < BootInformationInner > ( ptr. cast ( ) , slice_size) ;
283
+ let mbi = & mut * mbi;
284
+
285
+ if !mbi. has_valid_end_tag ( ) {
286
+ return Err ( MbiLoadError :: NoEndTag ) ;
287
+ }
288
+
289
+ Ok ( Self ( mbi) )
290
+ }
291
+ }
292
+
293
+ impl < T : AsRef < BootInformationInner > > BootInformation < T > {
255
294
/// Get the start address of the boot info.
256
295
pub fn start_address ( & self ) -> usize {
257
296
self . as_ptr ( ) as usize
258
297
}
259
298
260
299
/// Get the start address of the boot info as pointer.
261
300
pub fn as_ptr ( & self ) -> * const ( ) {
262
- core:: ptr:: addr_of!( * self . 0 ) . cast ( )
301
+ core:: ptr:: addr_of!( * self . 0 . as_ref ( ) ) . cast ( )
263
302
}
264
303
265
304
/// Get the end address of the boot info.
@@ -276,7 +315,7 @@ impl<'a> BootInformation<'a> {
276
315
277
316
/// Get the total size of the boot info struct.
278
317
pub fn total_size ( & self ) -> usize {
279
- self . 0 . header . total_size as usize
318
+ self . 0 . as_ref ( ) . header . total_size as usize
280
319
}
281
320
282
321
/// Search for the basic memory info tag.
@@ -454,10 +493,10 @@ impl<'a> BootInformation<'a> {
454
493
/// .unwrap();
455
494
/// assert_eq!(tag.name(), Ok("name"));
456
495
/// ```
457
- pub fn get_tag < TagT : TagTrait + ?Sized + ' a , TagType : Into < TagTypeId > > (
458
- & ' a self ,
496
+ pub fn get_tag < TagT : TagTrait + ?Sized , TagType : Into < TagTypeId > > (
497
+ & self ,
459
498
typ : TagType ,
460
- ) -> Option < & ' a TagT > {
499
+ ) -> Option < & TagT > {
461
500
let typ = typ. into ( ) ;
462
501
self . tags ( )
463
502
. find ( |tag| tag. typ == typ)
@@ -466,15 +505,36 @@ impl<'a> BootInformation<'a> {
466
505
467
506
/// Returns an iterator over all tags.
468
507
fn tags ( & self ) -> TagIter {
469
- TagIter :: new ( & self . 0 . tags )
508
+ TagIter :: new ( & self . 0 . as_ref ( ) . tags )
509
+ }
510
+ }
511
+
512
+ impl < T : AsRef < BootInformationInner > + AsMut < BootInformationInner > > BootInformation < T > {
513
+ /// Search for the Memory map tag, return a mutable reference.
514
+ pub fn memory_map_tag_mut ( & mut self ) -> Option < & mut MemoryMapTag > {
515
+ self . get_tag_mut :: < MemoryMapTag , _ > ( TagType :: Mmap )
516
+ }
517
+
518
+ fn get_tag_mut < TagT : TagTrait + ?Sized , TagType : Into < TagTypeId > > (
519
+ & mut self ,
520
+ typ : TagType ,
521
+ ) -> Option < & mut TagT > {
522
+ let typ = typ. into ( ) ;
523
+ self . tags_mut ( )
524
+ . find ( |tag| tag. typ == typ)
525
+ . map ( |tag| tag. cast_tag_mut :: < TagT > ( ) )
526
+ }
527
+
528
+ fn tags_mut ( & mut self ) -> TagIterMut {
529
+ TagIterMut :: new ( & mut self . 0 . as_mut ( ) . tags )
470
530
}
471
531
}
472
532
473
533
// SAFETY: BootInformation contains a const ptr to memory that is never mutated.
474
534
// Sending this pointer to other threads is sound.
475
- unsafe impl Send for BootInformation < ' _ > { }
535
+ unsafe impl < T : AsRef < BootInformationInner > > Send for BootInformation < T > { }
476
536
477
- impl fmt:: Debug for BootInformation < ' _ > {
537
+ impl < T : AsRef < BootInformationInner > > fmt:: Debug for BootInformation < T > {
478
538
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
479
539
/// Limit how many Elf-Sections should be debug-formatted.
480
540
/// Can be thousands of sections for a Rust binary => this is useless output.
@@ -557,6 +617,19 @@ pub trait TagTrait: Pointee {
557
617
let ptr = ptr_meta:: from_raw_parts ( ptr. cast ( ) , Self :: dst_size ( tag) ) ;
558
618
& * ptr
559
619
}
620
+
621
+ /// Creates a mutable reference to a (dynamically sized) tag type in a safe way.
622
+ /// DST tags need to implement a proper [`Self::dst_size`] implementation.
623
+ ///
624
+ /// # Safety
625
+ /// Callers must be sure that the "size" field of the provided [`Tag`] is
626
+ /// sane and the underlying memory valid. The implementation of this trait
627
+ /// **must have** a correct [`Self::dst_size`] implementation.
628
+ unsafe fn from_base_tag_mut < ' a > ( tag : & mut Tag ) -> & ' a mut Self {
629
+ let ptr = core:: ptr:: addr_of_mut!( * tag) ;
630
+ let ptr = ptr_meta:: from_raw_parts_mut ( ptr. cast ( ) , Self :: dst_size ( tag) ) ;
631
+ & mut * ptr
632
+ }
560
633
}
561
634
562
635
// All sized tags automatically have a Pointee implementation where
@@ -1280,7 +1353,7 @@ mod tests {
1280
1353
1281
1354
/// Helper for [`grub2`].
1282
1355
fn test_grub2_boot_info (
1283
- bi : & BootInformation ,
1356
+ bi : & BootInformation < & BootInformationInner > ,
1284
1357
addr : usize ,
1285
1358
string_addr : u64 ,
1286
1359
bytes : & [ u8 ] ,
0 commit comments