Skip to content

Commit 1e67e42

Browse files
committed
multiboot2: foundation for mutable reference to tags
1 parent cf29802 commit 1e67e42

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

@@ -481,8 +503,10 @@ impl fmt::Debug for BootInformation<'_> {
481503

482504
let mut debug = f.debug_struct("Multiboot2BootInformation");
483505
debug
484-
.field("start_address", &self.start_address())
485-
.field("end_address", &self.end_address())
506+
.field("start_address", &self.as_ptr())
507+
.field("end_address", unsafe {
508+
&self.as_ptr().cast::<u8>().add(self.total_size())
509+
})
486510
.field("total_size", &self.total_size())
487511
// now tags in alphabetical order
488512
.field("basic_memory_info", &(self.basic_memory_info_tag()))
@@ -540,7 +564,7 @@ mod tests {
540564
]);
541565
let ptr = bytes.0.as_ptr();
542566
let addr = ptr as usize;
543-
let bi = unsafe { BootInformation::load(ptr.cast()) };
567+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
544568
let bi = bi.unwrap();
545569
assert_eq!(addr, bi.start_address());
546570
assert_eq!(addr + bytes.0.len(), bi.end_address());
@@ -565,7 +589,7 @@ mod tests {
565589
]);
566590
let ptr = bytes.0.as_ptr();
567591
let addr = ptr as usize;
568-
let bi = unsafe { BootInformation::load(ptr.cast()) };
592+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
569593
let bi = bi.unwrap();
570594
assert_eq!(addr, bi.start_address());
571595
assert_eq!(addr + bytes.0.len(), bi.end_address());
@@ -590,7 +614,7 @@ mod tests {
590614
]);
591615
let ptr = bytes.0.as_ptr();
592616
let addr = ptr as usize;
593-
let bi = unsafe { BootInformation::load(ptr.cast()) };
617+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
594618
let bi = bi.unwrap();
595619
assert_eq!(addr, bi.start_address());
596620
assert_eq!(addr + bytes.0.len(), bi.end_address());
@@ -619,7 +643,7 @@ mod tests {
619643
]);
620644
let ptr = bytes.0.as_ptr();
621645
let addr = ptr as usize;
622-
let bi = unsafe { BootInformation::load(ptr.cast()) };
646+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
623647
let bi = bi.unwrap();
624648
assert_eq!(addr, bi.start_address());
625649
assert_eq!(addr + bytes.0.len(), bi.end_address());
@@ -663,7 +687,7 @@ mod tests {
663687
]);
664688
let ptr = bytes.0.as_ptr();
665689
let addr = ptr as usize;
666-
let bi = unsafe { BootInformation::load(ptr.cast()) };
690+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
667691
let bi = bi.unwrap();
668692
assert_eq!(addr, bi.start_address());
669693
assert_eq!(addr + bytes.0.len(), bi.end_address());
@@ -724,7 +748,7 @@ mod tests {
724748
]);
725749
let ptr = bytes.0.as_ptr();
726750
let addr = ptr as usize;
727-
let bi = unsafe { BootInformation::load(ptr.cast()) };
751+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
728752
let bi = bi.unwrap();
729753
assert_eq!(addr, bi.start_address());
730754
assert_eq!(addr + bytes.0.len(), bi.end_address());
@@ -842,7 +866,7 @@ mod tests {
842866

843867
let ptr = bytes.0.as_ptr();
844868
let addr = ptr as usize;
845-
let bi = unsafe { BootInformation::load(ptr.cast()) };
869+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
846870
let bi = bi.unwrap();
847871
assert_eq!(addr, bi.start_address());
848872
assert_eq!(addr + bytes.0.len(), bi.end_address());
@@ -1202,7 +1226,7 @@ mod tests {
12021226
}
12031227
let ptr = bytes.0.as_ptr();
12041228
let addr = ptr as usize;
1205-
let bi = unsafe { BootInformation::load(ptr.cast()) };
1229+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
12061230
let bi = bi.unwrap();
12071231
test_grub2_boot_info(&bi, addr, string_addr, &bytes.0, &string_bytes.0);
12081232

@@ -1409,7 +1433,7 @@ mod tests {
14091433
}
14101434
let ptr = bytes.0.as_ptr();
14111435
let addr = ptr as usize;
1412-
let bi = unsafe { BootInformation::load(ptr.cast()) };
1436+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
14131437
let bi = bi.unwrap();
14141438
assert_eq!(addr, bi.start_address());
14151439
assert_eq!(addr + bytes.0.len(), bi.end_address());
@@ -1453,7 +1477,7 @@ mod tests {
14531477
]);
14541478
let ptr = bytes.0.as_ptr();
14551479
let addr = ptr as usize;
1456-
let bi = unsafe { BootInformation::load(ptr.cast()) };
1480+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
14571481
let bi = bi.unwrap();
14581482
assert_eq!(addr, bi.start_address());
14591483
assert_eq!(addr + bytes.0.len(), bi.end_address());
@@ -1489,7 +1513,7 @@ mod tests {
14891513
0, 0, 0, 0, // end tag type.
14901514
8, 0, 0, 0, // end tag size.
14911515
]);
1492-
let bi = unsafe { BootInformation::load(bytes2.0.as_ptr().cast()) };
1516+
let bi = unsafe { BootInformation::load(bytes2.0.as_ptr().cast_mut().cast()) };
14931517
let bi = bi.unwrap();
14941518
let efi_mmap = bi.efi_memory_map_tag();
14951519
assert!(efi_mmap.is_none());
@@ -1559,7 +1583,7 @@ mod tests {
15591583
]);
15601584
let ptr = bytes.0.as_ptr();
15611585
let addr = ptr as usize;
1562-
let bi = unsafe { BootInformation::load(ptr.cast()) };
1586+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
15631587
let bi = bi.unwrap();
15641588
assert_eq!(addr, bi.start_address());
15651589
assert_eq!(addr + bytes.0.len(), bi.end_address());
@@ -1637,7 +1661,7 @@ mod tests {
16371661
]);
16381662
let ptr = bytes.0.as_ptr();
16391663
let addr = ptr as usize;
1640-
let bi = unsafe { BootInformation::load(ptr.cast()) };
1664+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
16411665
let bi = bi.unwrap();
16421666
assert_eq!(addr, bi.start_address());
16431667
assert_eq!(addr + bytes.0.len(), bi.end_address());
@@ -1689,7 +1713,7 @@ mod tests {
16891713
]);
16901714

16911715
let ptr = bytes.0.as_ptr();
1692-
let bi = unsafe { BootInformation::load(ptr.cast()) };
1716+
let bi = unsafe { BootInformation::load(ptr.cast_mut().cast()) };
16931717
let bi = bi.unwrap();
16941718

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

0 commit comments

Comments
 (0)