Skip to content

Commit 91d1c38

Browse files
committed
multiboot2: Support setting the EFI memory map tag
1 parent 84c9a6e commit 91d1c38

File tree

3 files changed

+97
-18
lines changed

3 files changed

+97
-18
lines changed

multiboot2/src/builder/information.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! Exports item [`Multiboot2InformationBuilder`].
22
use crate::builder::traits::StructAsBytes;
33
use crate::{
4-
BasicMemoryInfoTag, BootInformationInner, BootLoaderNameTag, CommandLineTag, EFISdt32,
5-
EFISdt64, ElfSectionsTag, EndTag, FramebufferTag, MemoryMapTag, ModuleTag, RsdpV1Tag,
4+
BasicMemoryInfoTag, BootInformationInner, BootLoaderNameTag, CommandLineTag, EFIMemoryMapTag,
5+
EFISdt32, EFISdt64, ElfSectionsTag, EndTag, FramebufferTag, MemoryMapTag, ModuleTag, RsdpV1Tag,
66
RsdpV2Tag, SmbiosTag,
77
};
88

@@ -18,6 +18,7 @@ pub struct Multiboot2InformationBuilder {
1818
basic_memory_info_tag: Option<BasicMemoryInfoTag>,
1919
boot_loader_name_tag: Option<Box<BootLoaderNameTag>>,
2020
command_line_tag: Option<Box<CommandLineTag>>,
21+
efi_memory_map_tag: Option<Box<EFIMemoryMapTag>>,
2122
elf_sections_tag: Option<Box<ElfSectionsTag>>,
2223
framebuffer_tag: Option<Box<FramebufferTag>>,
2324
memory_map_tag: Option<Box<MemoryMapTag>>,
@@ -37,6 +38,7 @@ impl Multiboot2InformationBuilder {
3738
command_line_tag: None,
3839
efisdt32: None,
3940
efisdt64: None,
41+
efi_memory_map_tag: None,
4042
elf_sections_tag: None,
4143
framebuffer_tag: None,
4244
memory_map_tag: None,
@@ -83,6 +85,9 @@ impl Multiboot2InformationBuilder {
8385
if let Some(tag) = &self.efisdt64 {
8486
len += Self::size_or_up_aligned(tag.byte_size())
8587
}
88+
if let Some(tag) = &self.efi_memory_map_tag {
89+
len += Self::size_or_up_aligned(tag.byte_size())
90+
}
8691
if let Some(tag) = &self.elf_sections_tag {
8792
len += Self::size_or_up_aligned(tag.byte_size())
8893
}
@@ -149,6 +154,9 @@ impl Multiboot2InformationBuilder {
149154
if let Some(tag) = self.efisdt64.as_ref() {
150155
Self::build_add_bytes(&mut data, &tag.struct_as_bytes(), false)
151156
}
157+
if let Some(tag) = self.efi_memory_map_tag.as_ref() {
158+
Self::build_add_bytes(&mut data, &tag.struct_as_bytes(), false)
159+
}
152160
if let Some(tag) = self.elf_sections_tag.as_ref() {
153161
Self::build_add_bytes(&mut data, &tag.struct_as_bytes(), false)
154162
}
@@ -196,6 +204,10 @@ impl Multiboot2InformationBuilder {
196204
self.efisdt64 = Some(efisdt64);
197205
}
198206

207+
pub fn efi_memory_map_tag(&mut self, efi_memory_map_tag: Box<EFIMemoryMapTag>) {
208+
self.efi_memory_map_tag = Some(efi_memory_map_tag);
209+
}
210+
199211
pub fn elf_sections_tag(&mut self, elf_sections_tag: Box<ElfSectionsTag>) {
200212
self.elf_sections_tag = Some(elf_sections_tag);
201213
}

multiboot2/src/lib.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1544,16 +1544,6 @@ mod tests {
15441544
assert!(efi_mmap.is_none());
15451545
}
15461546

1547-
#[test]
1548-
/// Compile time test for `EFIMemoryMapTag`.
1549-
fn efi_memory_map_tag_size() {
1550-
use super::EFIMemoryMapTag;
1551-
unsafe {
1552-
// `EFIMemoryMapTag` is 16 bytes without the 1st entry
1553-
core::mem::transmute::<[u8; 16], EFIMemoryMapTag>([0u8; 16]);
1554-
}
1555-
}
1556-
15571547
#[test]
15581548
#[cfg(feature = "unstable")]
15591549
/// This test succeeds if it compiles.

multiboot2/src/memory_map.rs

Lines changed: 83 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -238,38 +238,72 @@ impl Debug for BasicMemoryInfoTag {
238238
}
239239
}
240240

241+
const EFI_METADATA_SIZE: usize = mem::size_of::<TagTypeId>() + 3 * mem::size_of::<u32>();
242+
241243
/// EFI memory map as per EFI specification.
242-
#[derive(Debug)]
244+
#[derive(Debug, ptr_meta::Pointee)]
243245
#[repr(C)]
244246
pub struct EFIMemoryMapTag {
245247
typ: TagTypeId,
246248
size: u32,
247249
desc_size: u32,
248250
desc_version: u32,
249-
first_desc: [EFIMemoryDesc; 0],
251+
descs: [EFIMemoryDesc],
250252
}
251253

252254
impl EFIMemoryMapTag {
255+
#[cfg(feature = "builder")]
256+
/// Create a new EFI memory map tag with the given memory descriptors.
257+
/// Version and size can't be set because you're passing a slice of
258+
/// EFIMemoryDescs, not the ones you might have gotten from the firmware.
259+
pub fn new(descs: &[EFIMemoryDesc]) -> Box<Self> {
260+
// update this when updating EFIMemoryDesc
261+
const MEMORY_DESCRIPTOR_VERSION: u32 = 1;
262+
let mut bytes = [
263+
(mem::size_of::<EFIMemoryDesc>() as u32).to_le_bytes(),
264+
MEMORY_DESCRIPTOR_VERSION.to_le_bytes(),
265+
]
266+
.concat();
267+
for desc in descs {
268+
bytes.extend(desc.struct_as_bytes());
269+
}
270+
let tag = boxed_dst_tag(TagType::EfiMmap.into(), bytes.as_slice());
271+
unsafe { Box::from_raw(Box::into_raw(tag) as *mut Self) }
272+
}
273+
253274
/// Return an iterator over ALL marked memory areas.
254275
///
255276
/// This differs from `MemoryMapTag` as for UEFI, the OS needs some non-
256277
/// available memory areas for tables and such.
257278
pub fn memory_areas(&self) -> EFIMemoryAreaIter {
258279
let self_ptr = self as *const EFIMemoryMapTag;
259-
let start_area = self.first_desc.as_ptr();
280+
let start_area = (&self.descs[0]) as *const EFIMemoryDesc;
260281
EFIMemoryAreaIter {
261282
current_area: start_area as u64,
262283
// NOTE: `last_area` is only a bound, it doesn't necessarily point exactly to the last element
263-
last_area: (self_ptr as u64
264-
+ (self.size as u64 - core::mem::size_of::<EFIMemoryMapTag>() as u64)),
284+
last_area: (self_ptr as *const () as u64 + self.size as u64),
265285
entry_size: self.desc_size,
266286
phantom: PhantomData,
267287
}
268288
}
269289
}
270290

291+
impl TagTrait for EFIMemoryMapTag {
292+
fn dst_size(base_tag: &Tag) -> usize {
293+
assert!(base_tag.size as usize >= EFI_METADATA_SIZE);
294+
base_tag.size as usize - EFI_METADATA_SIZE
295+
}
296+
}
297+
298+
#[cfg(feature = "builder")]
299+
impl StructAsBytes for EFIMemoryMapTag {
300+
fn byte_size(&self) -> usize {
301+
self.size.try_into().unwrap()
302+
}
303+
}
304+
271305
/// EFI Boot Memory Map Descriptor
272-
#[derive(Debug)]
306+
#[derive(Debug, Clone)]
273307
#[repr(C)]
274308
pub struct EFIMemoryDesc {
275309
typ: u32,
@@ -280,6 +314,13 @@ pub struct EFIMemoryDesc {
280314
attr: u64,
281315
}
282316

317+
#[cfg(feature = "builder")]
318+
impl StructAsBytes for EFIMemoryDesc {
319+
fn byte_size(&self) -> usize {
320+
mem::size_of::<Self>()
321+
}
322+
}
323+
283324
/// An enum of possible reported region types.
284325
#[derive(Debug, PartialEq, Eq)]
285326
pub enum EFIMemoryAreaType {
@@ -334,6 +375,29 @@ pub enum EFIMemoryAreaType {
334375
EfiUnknown,
335376
}
336377

378+
impl From<EFIMemoryAreaType> for u32 {
379+
fn from(area: EFIMemoryAreaType) -> Self {
380+
match area {
381+
EFIMemoryAreaType::EfiReservedMemoryType => 0,
382+
EFIMemoryAreaType::EfiLoaderCode => 1,
383+
EFIMemoryAreaType::EfiLoaderData => 2,
384+
EFIMemoryAreaType::EfiBootServicesCode => 3,
385+
EFIMemoryAreaType::EfiBootServicesData => 4,
386+
EFIMemoryAreaType::EfiRuntimeServicesCode => 5,
387+
EFIMemoryAreaType::EfiRuntimeServicesData => 6,
388+
EFIMemoryAreaType::EfiConventionalMemory => 7,
389+
EFIMemoryAreaType::EfiUnusableMemory => 8,
390+
EFIMemoryAreaType::EfiACPIReclaimMemory => 9,
391+
EFIMemoryAreaType::EfiACPIMemoryNVS => 10,
392+
EFIMemoryAreaType::EfiMemoryMappedIO => 11,
393+
EFIMemoryAreaType::EfiMemoryMappedIOPortSpace => 12,
394+
EFIMemoryAreaType::EfiPalCode => 13,
395+
EFIMemoryAreaType::EfiPersistentMemory => 14,
396+
EFIMemoryAreaType::EfiUnknown => panic!("unknown type"),
397+
}
398+
}
399+
}
400+
337401
impl EFIMemoryDesc {
338402
/// The physical address of the memory region.
339403
pub fn physical_address(&self) -> u64 {
@@ -374,6 +438,19 @@ impl EFIMemoryDesc {
374438
}
375439
}
376440

441+
impl Default for EFIMemoryDesc {
442+
fn default() -> Self {
443+
Self {
444+
typ: EFIMemoryAreaType::EfiReservedMemoryType.into(),
445+
_padding: 0,
446+
phys_addr: 0,
447+
virt_addr: 0,
448+
num_pages: 0,
449+
attr: 0,
450+
}
451+
}
452+
}
453+
377454
/// EFI ExitBootServices was not called
378455
#[derive(Debug)]
379456
#[repr(C)]

0 commit comments

Comments
 (0)