Skip to content

Add a builder to multiboot2 #133

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Jun 19, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
152c985
multiboot2: Add basic information builder
YtvwlD Mar 6, 2023
544e1ca
multiboot2: Implement setting the command line
YtvwlD Mar 6, 2023
535c9e7
multiboot2: Implement adding module tags
YtvwlD Mar 7, 2023
41428fb
multiboot2: Implement setting ELF section tag
YtvwlD Mar 7, 2023
08df6c2
multiboot2: Implement setting boot loader name
YtvwlD Mar 7, 2023
bb21998
multiboot2: Implement setting the framebuffer tag
YtvwlD Mar 8, 2023
0320148
multiboot2: Implement setting the BasicMemoryInfoTag
YtvwlD Mar 8, 2023
d198dce
multiboot2: Implement setting memory map tag
YtvwlD Mar 8, 2023
122fc9c
multiboot2: Implement building the multiboot2 information
YtvwlD Mar 8, 2023
6379b42
multiboot2: Implement Debug and PartialEq for packed structs
YtvwlD Mar 14, 2023
d5e99f7
multiboot2: Support passing the EFI System Table
YtvwlD Mar 27, 2023
888dd27
multiboot2: Allow setting the SMBIOS tag
YtvwlD Mar 28, 2023
79646bb
multiboot2: Allow setting the RSDP tags
YtvwlD Mar 28, 2023
690c84a
multiboot2: Support setting the EFI memory map tag
YtvwlD Apr 3, 2023
12f4642
multiboot2: Support setting Boot Services not exited tag
YtvwlD Apr 3, 2023
ed316cb
multiboot2: Support setting the image handle pointer
YtvwlD Apr 4, 2023
cbc47ab
multiboot2: Support setting the image load address
YtvwlD Apr 4, 2023
2f2a058
multiboot2: Improve builder test
YtvwlD Jun 4, 2023
09de523
multiboot2-header: Improve builder test
YtvwlD Jun 4, 2023
69630b3
multiboot2: Don't require an offset for the ELF sections
YtvwlD Jun 19, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion multiboot2/src/builder/information.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Exports item [`Multiboot2InformationBuilder`].
use crate::{builder::traits::StructAsBytes, CommandLineTag, ModuleTag};
use crate::builder::traits::StructAsBytes;
use crate::{CommandLineTag, ElfSectionsTag, ModuleTag};

use alloc::boxed::Box;
use alloc::vec::Vec;
Expand All @@ -10,13 +11,15 @@ use alloc::vec::Vec;
#[derive(Debug)]
pub struct Multiboot2InformationBuilder {
command_line_tag: Option<Box<CommandLineTag>>,
elf_sections_tag: Option<Box<ElfSectionsTag>>,
module_tags: Vec<Box<ModuleTag>>,
}

impl Multiboot2InformationBuilder {
pub const fn new() -> Self {
Self {
command_line_tag: None,
elf_sections_tag: None,
module_tags: Vec::new(),
}
}
Expand All @@ -25,6 +28,10 @@ impl Multiboot2InformationBuilder {
self.command_line_tag = Some(command_line_tag);
}

pub fn elf_sections_tag(&mut self, elf_sections_tag: Box<ElfSectionsTag>) {
self.elf_sections_tag = Some(elf_sections_tag);
}

pub fn add_module_tag(&mut self, module_tag: Box<ModuleTag>) {
self.module_tags.push(module_tag);
}
Expand Down
71 changes: 40 additions & 31 deletions multiboot2/src/elf_sections.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,42 @@
use crate::tag_type::Tag;
use crate::TagType;
use crate::{Tag, TagTrait, TagType, TagTypeId};

use core::fmt::{Debug, Formatter};
use core::mem::size_of;
use core::str::Utf8Error;

#[cfg(feature = "builder")]
use {crate::builder::boxed_dst_tag, alloc::boxed::Box};

const METADATA_SIZE: usize = size_of::<TagTypeId>() + 4 * size_of::<u32>();

/// This tag contains section header table from an ELF kernel.
///
/// The sections iterator is provided via the `sections` method.
#[derive(Debug)]
#[derive(Debug, ptr_meta::Pointee)]
#[repr(C, packed)]
pub struct ElfSectionsTag {
inner: *const ElfSectionsTagInner,
offset: usize,
}

pub unsafe fn elf_sections_tag(tag: &Tag, offset: usize) -> ElfSectionsTag {
assert_eq!(TagType::ElfSections.val(), tag.typ);
let es = ElfSectionsTag {
inner: (tag as *const Tag).offset(1) as *const ElfSectionsTagInner,
offset,
};
assert!((es.get().entry_size * es.get().shndx) <= tag.size);
es
}

#[derive(Clone, Copy, Debug)]
#[repr(C, packed)] // only repr(C) would add unwanted padding at the end
struct ElfSectionsTagInner {
typ: TagTypeId,
pub(crate) size: u32,
number_of_sections: u32,
entry_size: u32,
shndx: u32, // string table
pub(crate) entry_size: u32,
pub(crate) shndx: u32, // string table
sections: [u8],
}

impl ElfSectionsTag {
/// Create a new ElfSectionsTag with the given data.
#[cfg(feature = "builder")]
pub fn new(number_of_sections: u32, entry_size: u32, shndx: u32, sections: &[u8]) -> Box<Self> {
let mut bytes = [
number_of_sections.to_le_bytes(),
entry_size.to_le_bytes(),
shndx.to_le_bytes(),
]
.concat();
bytes.extend_from_slice(sections);
boxed_dst_tag(TagType::ElfSections, &bytes)
}

/// Get an iterator of loaded ELF sections.
///
/// # Examples
Expand All @@ -39,31 +45,34 @@ impl ElfSectionsTag {
/// # let boot_info = unsafe { multiboot2::load(0xdeadbeef).unwrap() };
/// if let Some(elf_tag) = boot_info.elf_sections_tag() {
/// let mut total = 0;
/// for section in elf_tag.sections() {
/// for section in elf_tag.sections(0) {
/// println!("Section: {:?}", section);
/// total += 1;
/// }
/// }
/// ```
pub fn sections(&self) -> ElfSectionIter {
let string_section_offset = (self.get().shndx * self.get().entry_size) as isize;
pub fn sections(&self, offset: usize) -> ElfSectionIter {
let string_section_offset = (self.shndx * self.entry_size) as isize;
let string_section_ptr =
unsafe { self.first_section().offset(string_section_offset) as *const _ };
ElfSectionIter {
current_section: self.first_section(),
remaining_sections: self.get().number_of_sections,
entry_size: self.get().entry_size,
remaining_sections: self.number_of_sections,
entry_size: self.entry_size,
string_section: string_section_ptr,
offset: self.offset,
offset,
}
}

fn first_section(&self) -> *const u8 {
(unsafe { self.inner.offset(1) }) as *const _
&(self.sections[0]) as *const _
}
}

fn get(&self) -> &ElfSectionsTagInner {
unsafe { &*self.inner }
impl TagTrait for ElfSectionsTag {
fn dst_size(base_tag: &Tag) -> usize {
assert!(base_tag.size as usize >= METADATA_SIZE);
base_tag.size as usize - METADATA_SIZE
}
}

Expand Down
27 changes: 10 additions & 17 deletions multiboot2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,12 @@ impl BootInformation {
}

/// Search for the ELF Sections tag.
pub fn elf_sections_tag(&self) -> Option<ElfSectionsTag> {
self.get_tag::<Tag, _>(TagType::ElfSections)
.map(|tag| unsafe { elf_sections::elf_sections_tag(tag, self.offset) })
pub fn elf_sections_tag(&self) -> Option<&ElfSectionsTag> {
let tag = self.get_tag::<ElfSectionsTag, _>(TagType::ElfSections);
if let Some(t) = tag {
assert!((t.entry_size * t.shndx) <= t.size);
}
tag
}

/// Search for the Memory map tag.
Expand Down Expand Up @@ -445,7 +448,7 @@ impl fmt::Debug for BootInformation {

let elf_sections_tag_entries_count = self
.elf_sections_tag()
.map(|x| x.sections().count())
.map(|x| x.sections(self.offset).count())
.unwrap_or(0);

if elf_sections_tag_entries_count > ELF_SECTIONS_LIMIT {
Expand All @@ -455,7 +458,7 @@ impl fmt::Debug for BootInformation {
"elf_sections_tags",
&self
.elf_sections_tag()
.map(|x| x.sections())
.map(|x| x.sections(self.offset))
.unwrap_or_default(),
);
}
Expand Down Expand Up @@ -1262,7 +1265,7 @@ mod tests {
assert_eq!(addr + bytes.len(), bi.end_address());
assert_eq!(bytes.len(), bi.total_size());
let es = bi.elf_sections_tag().unwrap();
let mut s = es.sections();
let mut s = es.sections(bi.offset);
let s1 = s.next().expect("Should have one more section");
assert_eq!(".rodata", s1.name().expect("Should be valid utf-8"));
assert_eq!(0xFFFF_8000_0010_0000, s1.start_address());
Expand Down Expand Up @@ -1447,7 +1450,7 @@ mod tests {
assert_eq!(addr + bytes.0.len(), bi.end_address());
assert_eq!(bytes.0.len(), bi.total_size());
let es = bi.elf_sections_tag().unwrap();
let mut s = es.sections();
let mut s = es.sections(bi.offset);
let s1 = s.next().expect("Should have one more section");
assert_eq!(".shstrtab", s1.name().expect("Should be valid utf-8"));
assert_eq!(string_addr, s1.start_address());
Expand All @@ -1458,16 +1461,6 @@ mod tests {
assert!(s.next().is_none());
}

#[test]
/// Compile time test for `ElfSectionsTag`.
fn elf_sections_tag_size() {
use super::ElfSectionsTag;
unsafe {
// `ElfSectionsTagInner` is 12 bytes + 4 in the offset.
core::mem::transmute::<[u8; 16], ElfSectionsTag>([0u8; 16]);
}
}

#[test]
fn efi_memory_map() {
use memory_map::EFIMemoryAreaType;
Expand Down