@@ -99,7 +99,7 @@ use derive_more::Display;
99
99
#[ cfg( feature = "builder" ) ]
100
100
use crate :: builder:: AsBytes ;
101
101
use crate :: framebuffer:: UnknownFramebufferType ;
102
- use tag:: TagIter ;
102
+ use tag:: { TagIter , TagIterMut } ;
103
103
104
104
/// Magic number that a Multiboot2-compliant boot loader will use to identify
105
105
/// the handoff. The location depends on the architecture and the targeted
@@ -152,9 +152,9 @@ impl AsBytes for BootInformationHeader {}
152
152
153
153
/// This type holds the whole data of the MBI. This helps to better satisfy miri
154
154
/// when it checks for memory issues.
155
- #[ derive( ptr_meta:: Pointee ) ]
155
+ #[ derive( ptr_meta:: Pointee , Debug ) ]
156
156
#[ repr( C ) ]
157
- struct BootInformationInner {
157
+ pub struct BootInformationInner {
158
158
header : BootInformationHeader ,
159
159
tags : [ u8 ] ,
160
160
}
@@ -178,11 +178,22 @@ impl BootInformationInner {
178
178
}
179
179
}
180
180
181
+ impl AsRef < BootInformationInner > for BootInformationInner {
182
+ fn as_ref ( & self ) -> & BootInformationInner {
183
+ self
184
+ }
185
+ }
186
+
187
+ impl AsMut < BootInformationInner > for BootInformationInner {
188
+ fn as_mut ( & mut self ) -> & mut BootInformationInner {
189
+ self
190
+ }
191
+ }
181
192
/// A Multiboot 2 Boot Information (MBI) accessor.
182
193
#[ repr( transparent) ]
183
- pub struct BootInformation < ' a > ( & ' a BootInformationInner ) ;
194
+ pub struct BootInformation < T : AsRef < BootInformationInner > > ( T ) ;
184
195
185
- impl < ' a > BootInformation < ' a > {
196
+ impl BootInformation < & BootInformationInner > {
186
197
/// Loads the [`BootInformation`] from a pointer. The pointer must be valid
187
198
/// and aligned to an 8-byte boundary, as defined by the spec.
188
199
///
@@ -231,15 +242,50 @@ impl<'a> BootInformation<'a> {
231
242
232
243
Ok ( Self ( mbi) )
233
244
}
245
+ }
246
+
247
+ impl BootInformation < & mut BootInformationInner > {
248
+ /// `BootInformation::load`, but mutably.
249
+ ///
250
+ /// # Safety
251
+ /// The same considerations that apply to `load` also apply here, but the
252
+ /// memory can be modified (through the `_mut` methods).
253
+ pub unsafe fn load_mut ( ptr : * mut BootInformationHeader ) -> Result < Self , MbiLoadError > {
254
+ // null or not aligned
255
+ if ptr. is_null ( ) || ptr. align_offset ( 8 ) != 0 {
256
+ return Err ( MbiLoadError :: IllegalAddress ) ;
257
+ }
258
+
259
+ // mbi: reference to basic header
260
+ let mbi = & * ptr;
261
+
262
+ // Check if total size is not 0 and a multiple of 8.
263
+ if mbi. total_size == 0 || mbi. total_size & 0b111 != 0 {
264
+ return Err ( MbiLoadError :: IllegalTotalSize ( mbi. total_size ) ) ;
265
+ }
234
266
267
+ let slice_size = mbi. total_size as usize - size_of :: < BootInformationHeader > ( ) ;
268
+ // mbi: reference to full mbi
269
+ let mbi = ptr_meta:: from_raw_parts_mut :: < BootInformationInner > ( ptr. cast ( ) , slice_size) ;
270
+ let mbi = & mut * mbi;
271
+
272
+ if !mbi. has_valid_end_tag ( ) {
273
+ return Err ( MbiLoadError :: NoEndTag ) ;
274
+ }
275
+
276
+ Ok ( Self ( mbi) )
277
+ }
278
+ }
279
+
280
+ impl < T : AsRef < BootInformationInner > > BootInformation < T > {
235
281
/// Get the start address of the boot info.
236
282
pub fn start_address ( & self ) -> usize {
237
283
self . as_ptr ( ) as usize
238
284
}
239
285
240
286
/// Get the start address of the boot info as pointer.
241
287
pub fn as_ptr ( & self ) -> * const ( ) {
242
- core:: ptr:: addr_of!( * self . 0 ) . cast ( )
288
+ core:: ptr:: addr_of!( * self . 0 . as_ref ( ) ) . cast ( )
243
289
}
244
290
245
291
/// Get the end address of the boot info.
@@ -258,7 +304,7 @@ impl<'a> BootInformation<'a> {
258
304
259
305
/// Get the total size of the boot info struct.
260
306
pub fn total_size ( & self ) -> usize {
261
- self . 0 . header . total_size as usize
307
+ self . 0 . as_ref ( ) . header . total_size as usize
262
308
}
263
309
264
310
// ######################################################
@@ -458,19 +504,44 @@ impl<'a> BootInformation<'a> {
458
504
/// .unwrap();
459
505
/// assert_eq!(tag.name(), Ok("name"));
460
506
/// ```
461
- pub fn get_tag < TagT : TagTrait + ?Sized + ' a > ( & ' a self ) -> Option < & ' a TagT > {
507
+ pub fn get_tag < TagT : TagTrait + ?Sized > ( & self ) -> Option < & TagT > {
462
508
self . tags ( )
463
509
. find ( |tag| tag. typ == TagT :: ID )
464
510
. map ( |tag| tag. cast_tag :: < TagT > ( ) )
465
511
}
466
512
467
513
/// Returns an iterator over all tags.
468
514
fn tags ( & self ) -> TagIter {
469
- TagIter :: new ( & self . 0 . tags )
515
+ TagIter :: new ( & self . 0 . as_ref ( ) . tags )
470
516
}
471
517
}
472
518
473
- impl fmt:: Debug for BootInformation < ' _ > {
519
+ impl < T : AsRef < BootInformationInner > + AsMut < BootInformationInner > > BootInformation < T > {
520
+ /// Search for the Memory map tag, return a mutable reference.
521
+ pub fn memory_map_tag_mut ( & mut self ) -> Option < & mut MemoryMapTag > {
522
+ self . get_tag_mut :: < MemoryMapTag , _ > ( TagType :: Mmap )
523
+ }
524
+
525
+ fn get_tag_mut < TagT : TagTrait + ?Sized , TagType : Into < TagTypeId > > (
526
+ & mut self ,
527
+ typ : TagType ,
528
+ ) -> Option < & mut TagT > {
529
+ let typ = typ. into ( ) ;
530
+ self . tags_mut ( )
531
+ . find ( |tag| tag. typ == typ)
532
+ . map ( |tag| tag. cast_tag_mut :: < TagT > ( ) )
533
+ }
534
+
535
+ fn tags_mut ( & mut self ) -> TagIterMut {
536
+ TagIterMut :: new ( & mut self . 0 . as_mut ( ) . tags )
537
+ }
538
+ }
539
+
540
+ // SAFETY: BootInformation contains a const ptr to memory that is never mutated.
541
+ // Sending this pointer to other threads is sound.
542
+ unsafe impl < T : AsRef < BootInformationInner > > Send for BootInformation < T > { }
543
+
544
+ impl < T : AsRef < BootInformationInner > > fmt:: Debug for BootInformation < T > {
474
545
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
475
546
/// Limit how many Elf-Sections should be debug-formatted.
476
547
/// Can be thousands of sections for a Rust binary => this is useless output.
@@ -1235,7 +1306,7 @@ mod tests {
1235
1306
1236
1307
/// Helper for [`grub2`].
1237
1308
fn test_grub2_boot_info (
1238
- bi : & BootInformation ,
1309
+ bi : & BootInformation < & BootInformationInner > ,
1239
1310
addr : usize ,
1240
1311
string_addr : u64 ,
1241
1312
bytes : & [ u8 ] ,
0 commit comments