Skip to content

Commit 690c84a

Browse files
committed
multiboot2: Support setting the EFI memory map tag
1 parent 79646bb commit 690c84a

File tree

3 files changed

+96
-18
lines changed

3 files changed

+96
-18
lines changed

multiboot2/src/builder/information.rs

+14-2
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

-10
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

+82-6
Original file line numberDiff line numberDiff line change
@@ -233,38 +233,71 @@ impl Debug for BasicMemoryInfoTag {
233233
}
234234
}
235235

236+
const EFI_METADATA_SIZE: usize = mem::size_of::<TagTypeId>() + 3 * mem::size_of::<u32>();
237+
236238
/// EFI memory map as per EFI specification.
237-
#[derive(Debug)]
239+
#[derive(Debug, ptr_meta::Pointee)]
238240
#[repr(C)]
239241
pub struct EFIMemoryMapTag {
240242
typ: TagTypeId,
241243
size: u32,
242244
desc_size: u32,
243245
desc_version: u32,
244-
first_desc: [EFIMemoryDesc; 0],
246+
descs: [EFIMemoryDesc],
245247
}
246248

247249
impl EFIMemoryMapTag {
250+
#[cfg(feature = "builder")]
251+
/// Create a new EFI memory map tag with the given memory descriptors.
252+
/// Version and size can't be set because you're passing a slice of
253+
/// EFIMemoryDescs, not the ones you might have gotten from the firmware.
254+
pub fn new(descs: &[EFIMemoryDesc]) -> Box<Self> {
255+
// update this when updating EFIMemoryDesc
256+
const MEMORY_DESCRIPTOR_VERSION: u32 = 1;
257+
let mut bytes = [
258+
(mem::size_of::<EFIMemoryDesc>() as u32).to_le_bytes(),
259+
MEMORY_DESCRIPTOR_VERSION.to_le_bytes(),
260+
]
261+
.concat();
262+
for desc in descs {
263+
bytes.extend(desc.struct_as_bytes());
264+
}
265+
boxed_dst_tag(TagType::EfiMmap, bytes.as_slice())
266+
}
267+
248268
/// Return an iterator over ALL marked memory areas.
249269
///
250270
/// This differs from `MemoryMapTag` as for UEFI, the OS needs some non-
251271
/// available memory areas for tables and such.
252272
pub fn memory_areas(&self) -> EFIMemoryAreaIter {
253273
let self_ptr = self as *const EFIMemoryMapTag;
254-
let start_area = self.first_desc.as_ptr();
274+
let start_area = (&self.descs[0]) as *const EFIMemoryDesc;
255275
EFIMemoryAreaIter {
256276
current_area: start_area as u64,
257277
// NOTE: `last_area` is only a bound, it doesn't necessarily point exactly to the last element
258-
last_area: (self_ptr as u64
259-
+ (self.size as u64 - core::mem::size_of::<EFIMemoryMapTag>() as u64)),
278+
last_area: (self_ptr as *const () as u64 + self.size as u64),
260279
entry_size: self.desc_size,
261280
phantom: PhantomData,
262281
}
263282
}
264283
}
265284

285+
impl TagTrait for EFIMemoryMapTag {
286+
fn dst_size(base_tag: &Tag) -> usize {
287+
assert!(base_tag.size as usize >= EFI_METADATA_SIZE);
288+
base_tag.size as usize - EFI_METADATA_SIZE
289+
}
290+
}
291+
292+
#[cfg(feature = "builder")]
293+
impl StructAsBytes for EFIMemoryMapTag {
294+
fn byte_size(&self) -> usize {
295+
self.size.try_into().unwrap()
296+
}
297+
}
298+
266299
/// EFI Boot Memory Map Descriptor
267-
#[derive(Debug)]
300+
#[derive(Debug, Clone)]
268301
#[repr(C)]
269302
pub struct EFIMemoryDesc {
270303
typ: u32,
@@ -275,6 +308,13 @@ pub struct EFIMemoryDesc {
275308
attr: u64,
276309
}
277310

311+
#[cfg(feature = "builder")]
312+
impl StructAsBytes for EFIMemoryDesc {
313+
fn byte_size(&self) -> usize {
314+
mem::size_of::<Self>()
315+
}
316+
}
317+
278318
/// An enum of possible reported region types.
279319
#[derive(Debug, PartialEq, Eq)]
280320
pub enum EFIMemoryAreaType {
@@ -329,6 +369,29 @@ pub enum EFIMemoryAreaType {
329369
EfiUnknown,
330370
}
331371

372+
impl From<EFIMemoryAreaType> for u32 {
373+
fn from(area: EFIMemoryAreaType) -> Self {
374+
match area {
375+
EFIMemoryAreaType::EfiReservedMemoryType => 0,
376+
EFIMemoryAreaType::EfiLoaderCode => 1,
377+
EFIMemoryAreaType::EfiLoaderData => 2,
378+
EFIMemoryAreaType::EfiBootServicesCode => 3,
379+
EFIMemoryAreaType::EfiBootServicesData => 4,
380+
EFIMemoryAreaType::EfiRuntimeServicesCode => 5,
381+
EFIMemoryAreaType::EfiRuntimeServicesData => 6,
382+
EFIMemoryAreaType::EfiConventionalMemory => 7,
383+
EFIMemoryAreaType::EfiUnusableMemory => 8,
384+
EFIMemoryAreaType::EfiACPIReclaimMemory => 9,
385+
EFIMemoryAreaType::EfiACPIMemoryNVS => 10,
386+
EFIMemoryAreaType::EfiMemoryMappedIO => 11,
387+
EFIMemoryAreaType::EfiMemoryMappedIOPortSpace => 12,
388+
EFIMemoryAreaType::EfiPalCode => 13,
389+
EFIMemoryAreaType::EfiPersistentMemory => 14,
390+
EFIMemoryAreaType::EfiUnknown => panic!("unknown type"),
391+
}
392+
}
393+
}
394+
332395
impl EFIMemoryDesc {
333396
/// The physical address of the memory region.
334397
pub fn physical_address(&self) -> u64 {
@@ -369,6 +432,19 @@ impl EFIMemoryDesc {
369432
}
370433
}
371434

435+
impl Default for EFIMemoryDesc {
436+
fn default() -> Self {
437+
Self {
438+
typ: EFIMemoryAreaType::EfiReservedMemoryType.into(),
439+
_padding: 0,
440+
phys_addr: 0,
441+
virt_addr: 0,
442+
num_pages: 0,
443+
attr: 0,
444+
}
445+
}
446+
}
447+
372448
/// EFI ExitBootServices was not called
373449
#[derive(Debug)]
374450
#[repr(C)]

0 commit comments

Comments
 (0)