Skip to content

Commit 763feed

Browse files
committed
multiboot2: foundation for mutable reference to tags
1 parent 4078c90 commit 763feed

File tree

4 files changed

+61
-37
lines changed

4 files changed

+61
-37
lines changed

multiboot2/src/boot_loader_name.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ impl BootLoaderNameTag {
3939
///
4040
/// ```rust,no_run
4141
/// # use multiboot2::{BootInformation, BootInformationHeader};
42-
/// # let ptr = 0xdeadbeef as *const BootInformationHeader;
42+
/// # let ptr = 0xdeadbeef as *mut BootInformationHeader;
4343
/// # let boot_info = unsafe { BootInformation::load(ptr).unwrap() };
4444
/// if let Some(tag) = boot_info.boot_loader_name_tag() {
4545
/// assert_eq!(Ok("GRUB 2.02~beta3-5"), tag.name());

multiboot2/src/builder/information.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ mod tests {
448448
let mb2i_data = create_builder().build();
449449

450450
// Step 2/2: Test the built MBI
451-
let mb2i = unsafe { BootInformation::load(mb2i_data.as_ptr().cast()) }
451+
let mb2i = unsafe { BootInformation::load(mb2i_data.as_ptr().cast_mut().cast()) }
452452
.expect("generated information should be readable");
453453

454454
assert_eq!(mb2i.basic_memory_info_tag().unwrap().memory_lower(), 640);

multiboot2/src/command_line.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ impl CommandLineTag {
4848
///
4949
/// ```rust,no_run
5050
/// # use multiboot2::{BootInformation, BootInformationHeader};
51-
/// # let ptr = 0xdeadbeef as *const BootInformationHeader;
51+
/// # let ptr = 0xdeadbeef as *mut BootInformationHeader;
5252
/// # let boot_info = unsafe { BootInformation::load(ptr).unwrap() };
5353
/// if let Some(tag) = boot_info.command_line_tag() {
5454
/// let command_line = tag.cmdline();

multiboot2/src/lib.rs

Lines changed: 58 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
//!
2727
//! fn kernel_entry(mb_magic: u32, mbi_ptr: u32) {
2828
//! if mb_magic == multiboot2::MAGIC {
29-
//! let boot_info = unsafe { BootInformation::load(mbi_ptr as *const BootInformationHeader).unwrap() };
29+
//! let boot_info = unsafe { BootInformation::load(mbi_ptr as *mut BootInformationHeader).unwrap() };
3030
//! let _cmd = boot_info.command_line_tag();
3131
//! } else { /* Panic or use multiboot1 flow. */ }
3232
//! }
@@ -91,7 +91,9 @@ pub use vbe_info::{
9191
};
9292

9393
use core::fmt;
94+
use core::marker::PhantomData;
9495
use core::mem::size_of;
96+
use core::ptr::NonNull;
9597
use derive_more::Display;
9698
// Must be public so that custom tags can be DSTs.
9799
#[cfg(feature = "builder")]
@@ -177,8 +179,16 @@ impl BootInformationInner {
177179
}
178180

179181
/// A Multiboot 2 Boot Information (MBI) accessor.
182+
///
183+
/// This type acts like it owns the memory of the MBI. It allows reading all
184+
/// kind of tags. Furthermore, it gives you mutable access to a certain degree
185+
/// to some tags, in case you want to modify them. The latter is most likely
186+
/// only relevant in niche cases.
180187
#[repr(transparent)]
181-
pub struct BootInformation<'a>(&'a BootInformationInner);
188+
pub struct BootInformation<'a> {
189+
ptr: NonNull<BootInformationInner>,
190+
_phantom: PhantomData<&'a mut BootInformationInner>,
191+
}
182192

183193
impl<'a> BootInformation<'a> {
184194
/// Loads the [`BootInformation`] from a pointer. The pointer must be valid
@@ -191,7 +201,7 @@ impl<'a> BootInformation<'a> {
191201
///
192202
/// fn kernel_entry(mb_magic: u32, mbi_ptr: u32) {
193203
/// if mb_magic == multiboot2::MAGIC {
194-
/// let boot_info = unsafe { BootInformation::load(mbi_ptr as *const BootInformationHeader).unwrap() };
204+
/// let boot_info = unsafe { BootInformation::load(mbi_ptr as *mut BootInformationHeader).unwrap() };
195205
/// let _cmd = boot_info.command_line_tag();
196206
/// } else { /* Panic or use multiboot1 flow. */ }
197207
/// }
@@ -204,7 +214,7 @@ impl<'a> BootInformation<'a> {
204214
/// boot environments, such as UEFI.
205215
/// * The memory at `ptr` must not be modified after calling `load` or the
206216
/// program may observe unsynchronized mutation.
207-
pub unsafe fn load(ptr: *const BootInformationHeader) -> Result<Self, MbiLoadError> {
217+
pub unsafe fn load(ptr: *mut BootInformationHeader) -> Result<Self, MbiLoadError> {
208218
// null or not aligned
209219
if ptr.is_null() || ptr.align_offset(8) != 0 {
210220
return Err(MbiLoadError::IllegalAddress);
@@ -220,24 +230,36 @@ impl<'a> BootInformation<'a> {
220230

221231
let slice_size = mbi.total_size as usize - size_of::<BootInformationHeader>();
222232
// mbi: reference to full mbi
223-
let mbi = ptr_meta::from_raw_parts::<BootInformationInner>(ptr.cast(), slice_size);
224-
let mbi = &*mbi;
233+
let mbi_ptr = ptr_meta::from_raw_parts_mut::<BootInformationInner>(ptr.cast(), slice_size);
234+
let mbi_ref = &*mbi_ptr;
225235

226-
if !mbi.has_valid_end_tag() {
236+
if !mbi_ref.has_valid_end_tag() {
227237
return Err(MbiLoadError::NoEndTag);
228238
}
229239

230-
Ok(Self(mbi))
240+
Ok(Self {
241+
// Safety: checked earlier that this is not null
242+
ptr: NonNull::new_unchecked(mbi_ptr),
243+
_phantom: PhantomData,
244+
})
231245
}
232246

233-
/// Get the start address of the boot info.
234-
pub fn start_address(&self) -> usize {
235-
self.as_ptr() as usize
247+
fn inner(&self) -> &BootInformationInner {
248+
unsafe { self.ptr.as_ref() }
249+
}
250+
251+
fn inner_mut(&mut self) -> &mut BootInformationInner {
252+
unsafe { self.ptr.as_mut() }
236253
}
237254

238255
/// Get the start address of the boot info as pointer.
239-
pub fn as_ptr(&self) -> *const () {
240-
core::ptr::addr_of!(*self.0).cast()
256+
pub fn as_ptr(&self) -> *const BootInformationHeader {
257+
self.ptr.as_ptr().cast()
258+
}
259+
260+
/// Get the start address of the boot info.
261+
pub fn start_address(&self) -> usize {
262+
self.as_ptr() as usize
241263
}
242264

243265
/// Get the end address of the boot info.
@@ -246,7 +268,7 @@ impl<'a> BootInformation<'a> {
246268
///
247269
/// ```rust,no_run
248270
/// # use multiboot2::{BootInformation, BootInformationHeader};
249-
/// # let ptr = 0xdeadbeef as *const BootInformationHeader;
271+
/// # let ptr = 0xdeadbeef as *mut BootInformationHeader;
250272
/// # let boot_info = unsafe { BootInformation::load(ptr).unwrap() };
251273
/// let end_addr = boot_info.start_address() + boot_info.total_size();
252274
/// ```
@@ -256,7 +278,7 @@ impl<'a> BootInformation<'a> {
256278

257279
/// Get the total size of the boot info struct.
258280
pub fn total_size(&self) -> usize {
259-
self.0.header.total_size as usize
281+
self.inner().header.total_size as usize
260282
}
261283

262284
// ######################################################
@@ -332,7 +354,7 @@ impl<'a> BootInformation<'a> {
332354
///
333355
/// ```rust,no_run
334356
/// # use multiboot2::{BootInformation, BootInformationHeader};
335-
/// # let ptr = 0xdeadbeef as *const BootInformationHeader;
357+
/// # let ptr = 0xdeadbeef as *mut BootInformationHeader;
336358
/// # let boot_info = unsafe { BootInformation::load(ptr).unwrap() };
337359
/// if let Some(sections) = boot_info.elf_sections() {
338360
/// let mut total = 0;
@@ -448,7 +470,7 @@ impl<'a> BootInformation<'a> {
448470
/// Tag::get_dst_str_slice(&self.name)
449471
/// }
450472
/// }
451-
/// let mbi_ptr = 0xdeadbeef as *const BootInformationHeader;
473+
/// let mbi_ptr = 0xdeadbeef as *mut BootInformationHeader;
452474
/// let mbi = unsafe { BootInformation::load(mbi_ptr).unwrap() };
453475
///
454476
/// let tag = mbi
@@ -464,7 +486,7 @@ impl<'a> BootInformation<'a> {
464486

465487
/// Returns an iterator over all tags.
466488
fn tags(&self) -> TagIter {
467-
TagIter::new(&self.0.tags)
489+
TagIter::new(&self.inner().tags)
468490
}
469491
}
470492

@@ -477,8 +499,10 @@ impl fmt::Debug for BootInformation<'_> {
477499

478500
let mut debug = f.debug_struct("Multiboot2BootInformation");
479501
debug
480-
.field("start_address", &self.start_address())
481-
.field("end_address", &self.end_address())
502+
.field("start_address", &self.as_ptr())
503+
.field("end_address", unsafe {
504+
&self.as_ptr().cast::<u8>().add(self.total_size())
505+
})
482506
.field("total_size", &self.total_size())
483507
// now tags in alphabetical order
484508
.field("basic_memory_info", &(self.basic_memory_info_tag()))
@@ -560,7 +584,7 @@ mod tests {
560584
]);
561585
let ptr = bytes.0.as_ptr();
562586
let addr = ptr as usize;
563-
let bi = unsafe { BootInformation::load(ptr.cast()) };
587+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
564588
let bi = bi.unwrap();
565589
assert_eq!(addr, bi.start_address());
566590
assert_eq!(addr + bytes.0.len(), bi.end_address());
@@ -585,7 +609,7 @@ mod tests {
585609
]);
586610
let ptr = bytes.0.as_ptr();
587611
let addr = ptr as usize;
588-
let bi = unsafe { BootInformation::load(ptr.cast()) };
612+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
589613
let bi = bi.unwrap();
590614
assert_eq!(addr, bi.start_address());
591615
assert_eq!(addr + bytes.0.len(), bi.end_address());
@@ -610,7 +634,7 @@ mod tests {
610634
]);
611635
let ptr = bytes.0.as_ptr();
612636
let addr = ptr as usize;
613-
let bi = unsafe { BootInformation::load(ptr.cast()) };
637+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
614638
let bi = bi.unwrap();
615639
assert_eq!(addr, bi.start_address());
616640
assert_eq!(addr + bytes.0.len(), bi.end_address());
@@ -639,7 +663,7 @@ mod tests {
639663
]);
640664
let ptr = bytes.0.as_ptr();
641665
let addr = ptr as usize;
642-
let bi = unsafe { BootInformation::load(ptr.cast()) };
666+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
643667
let bi = bi.unwrap();
644668
assert_eq!(addr, bi.start_address());
645669
assert_eq!(addr + bytes.0.len(), bi.end_address());
@@ -683,7 +707,7 @@ mod tests {
683707
]);
684708
let ptr = bytes.0.as_ptr();
685709
let addr = ptr as usize;
686-
let bi = unsafe { BootInformation::load(ptr.cast()) };
710+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
687711
let bi = bi.unwrap();
688712
assert_eq!(addr, bi.start_address());
689713
assert_eq!(addr + bytes.0.len(), bi.end_address());
@@ -744,7 +768,7 @@ mod tests {
744768
]);
745769
let ptr = bytes.0.as_ptr();
746770
let addr = ptr as usize;
747-
let bi = unsafe { BootInformation::load(ptr.cast()) };
771+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
748772
let bi = bi.unwrap();
749773
assert_eq!(addr, bi.start_address());
750774
assert_eq!(addr + bytes.0.len(), bi.end_address());
@@ -862,7 +886,7 @@ mod tests {
862886

863887
let ptr = bytes.0.as_ptr();
864888
let addr = ptr as usize;
865-
let bi = unsafe { BootInformation::load(ptr.cast()) };
889+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
866890
let bi = bi.unwrap();
867891
assert_eq!(addr, bi.start_address());
868892
assert_eq!(addr + bytes.0.len(), bi.end_address());
@@ -1222,7 +1246,7 @@ mod tests {
12221246
}
12231247
let ptr = bytes.0.as_ptr();
12241248
let addr = ptr as usize;
1225-
let bi = unsafe { BootInformation::load(ptr.cast()) };
1249+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
12261250
let bi = bi.unwrap();
12271251
test_grub2_boot_info(&bi, addr, string_addr, &bytes.0, &string_bytes.0);
12281252

@@ -1429,7 +1453,7 @@ mod tests {
14291453
}
14301454
let ptr = bytes.0.as_ptr();
14311455
let addr = ptr as usize;
1432-
let bi = unsafe { BootInformation::load(ptr.cast()) };
1456+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
14331457
let bi = bi.unwrap();
14341458
assert_eq!(addr, bi.start_address());
14351459
assert_eq!(addr + bytes.0.len(), bi.end_address());
@@ -1473,7 +1497,7 @@ mod tests {
14731497
]);
14741498
let ptr = bytes.0.as_ptr();
14751499
let addr = ptr as usize;
1476-
let bi = unsafe { BootInformation::load(ptr.cast()) };
1500+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
14771501
let bi = bi.unwrap();
14781502
assert_eq!(addr, bi.start_address());
14791503
assert_eq!(addr + bytes.0.len(), bi.end_address());
@@ -1509,7 +1533,7 @@ mod tests {
15091533
0, 0, 0, 0, // end tag type.
15101534
8, 0, 0, 0, // end tag size.
15111535
]);
1512-
let bi = unsafe { BootInformation::load(bytes2.0.as_ptr().cast()) };
1536+
let bi = unsafe { BootInformation::load(bytes2.0.as_ptr().cast_mut().cast()) };
15131537
let bi = bi.unwrap();
15141538
let efi_mmap = bi.efi_memory_map_tag();
15151539
assert!(efi_mmap.is_none());
@@ -1579,7 +1603,7 @@ mod tests {
15791603
]);
15801604
let ptr = bytes.0.as_ptr();
15811605
let addr = ptr as usize;
1582-
let bi = unsafe { BootInformation::load(ptr.cast()) };
1606+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
15831607
let bi = bi.unwrap();
15841608
assert_eq!(addr, bi.start_address());
15851609
assert_eq!(addr + bytes.0.len(), bi.end_address());
@@ -1657,7 +1681,7 @@ mod tests {
16571681
]);
16581682
let ptr = bytes.0.as_ptr();
16591683
let addr = ptr as usize;
1660-
let bi = unsafe { BootInformation::load(ptr.cast()) };
1684+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
16611685
let bi = bi.unwrap();
16621686
assert_eq!(addr, bi.start_address());
16631687
assert_eq!(addr + bytes.0.len(), bi.end_address());
@@ -1709,7 +1733,7 @@ mod tests {
17091733
]);
17101734

17111735
let ptr = bytes.0.as_ptr();
1712-
let bi = unsafe { BootInformation::load(ptr.cast()) };
1736+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
17131737
let bi = bi.unwrap();
17141738

17151739
let _tag = bi.get_tag::<CommandLineTag>().unwrap();

0 commit comments

Comments
 (0)