|
@@ -0,0 +1,555 @@
|
|
|
+//! Multiboot v1 library
|
|
|
+//!
|
|
|
+//! This crate is partitially modified from `https://github.com/gz/rust-multiboot` && asterinas
|
|
|
+//!
|
|
|
+//! The main structs to interact with are [`Multiboot`] for the Multiboot information
|
|
|
+//! passed from the bootloader to the kernel at runtime and [`Header`] for the static
|
|
|
+//! information passed from the kernel to the bootloader in the kernel image.
|
|
|
+//!
|
|
|
+//!
|
|
|
+//! # Additional documentation
|
|
|
+//! * https://www.gnu.org/software/grub/manual/multiboot/multiboot.html
|
|
|
+//! * http://git.savannah.gnu.org/cgit/grub.git/tree/doc/multiboot.texi?h=multiboot
|
|
|
+//!
|
|
|
+//! [`Multiboot`]: information/struct.Multiboot.html
|
|
|
+//! [`Header`]: header/struct.Header.html
|
|
|
+#![no_std]
|
|
|
+
|
|
|
+use core::ffi::CStr;
|
|
|
+
|
|
|
+pub const MAGIC: u32 = 0x2BADB002;
|
|
|
+
|
|
|
+/// The ‘boot_device’ field.
|
|
|
+///
|
|
|
+/// Partition numbers always start from zero. Unused partition
|
|
|
+/// bytes must be set to 0xFF. For example, if the disk is partitioned
|
|
|
+/// using a simple one-level DOS partitioning scheme, then
|
|
|
+/// ‘part’ contains the DOS partition number, and ‘part2’ and ‘part3’
|
|
|
+/// are both 0xFF. As another example, if a disk is partitioned first into
|
|
|
+/// DOS partitions, and then one of those DOS partitions is subdivided
|
|
|
+/// into several BSD partitions using BSD's disklabel strategy, then ‘part1’
|
|
|
+/// contains the DOS partition number, ‘part2’ contains the BSD sub-partition
|
|
|
+/// within that DOS partition, and ‘part3’ is 0xFF.
|
|
|
+///
|
|
|
+#[derive(Debug, Clone, Copy)]
|
|
|
+#[repr(C)]
|
|
|
+pub struct BootDevice {
|
|
|
+ /// Contains the bios drive number as understood by
|
|
|
+ /// the bios INT 0x13 low-level disk interface: e.g. 0x00 for the
|
|
|
+ /// first floppy disk or 0x80 for the first hard disk.
|
|
|
+ pub drive: u8,
|
|
|
+ /// Specifies the top-level partition number.
|
|
|
+ pub partition1: u8,
|
|
|
+ /// Specifies a sub-partition in the top-level partition
|
|
|
+ pub partition2: u8,
|
|
|
+ /// Specifies a sub-partition in the 2nd-level partition
|
|
|
+ pub partition3: u8,
|
|
|
+}
|
|
|
+
|
|
|
+impl BootDevice {
|
|
|
+ /// Is partition1 a valid partition?
|
|
|
+ pub fn partition1_is_valid(&self) -> bool {
|
|
|
+ self.partition1 != 0xff
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Is partition2 a valid partition?
|
|
|
+ pub fn partition2_is_valid(&self) -> bool {
|
|
|
+ self.partition2 != 0xff
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Is partition3 a valid partition?
|
|
|
+ pub fn partition3_is_valid(&self) -> bool {
|
|
|
+ self.partition3 != 0xff
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl Default for BootDevice {
|
|
|
+ fn default() -> Self {
|
|
|
+ Self {
|
|
|
+ drive: 0xff,
|
|
|
+ partition1: 0xff,
|
|
|
+ partition2: 0xff,
|
|
|
+ partition3: 0xff,
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/// Representation of Multiboot Information according to specification.
|
|
|
+///
|
|
|
+/// Reference: https://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Boot-information-format
|
|
|
+///
|
|
|
+///```text
|
|
|
+/// +-------------------+
|
|
|
+/// 0 | flags | (required)
|
|
|
+/// +-------------------+
|
|
|
+/// 4 | mem_lower | (present if flags[0] is set)
|
|
|
+/// 8 | mem_upper | (present if flags[0] is set)
|
|
|
+/// +-------------------+
|
|
|
+/// 12 | boot_device | (present if flags[1] is set)
|
|
|
+/// +-------------------+
|
|
|
+/// 16 | cmdline | (present if flags[2] is set)
|
|
|
+/// +-------------------+
|
|
|
+/// 20 | mods_count | (present if flags[3] is set)
|
|
|
+/// 24 | mods_addr | (present if flags[3] is set)
|
|
|
+/// +-------------------+
|
|
|
+/// 28 - 40 | syms | (present if flags[4] or
|
|
|
+/// | | flags[5] is set)
|
|
|
+/// +-------------------+
|
|
|
+/// 44 | mmap_length | (present if flags[6] is set)
|
|
|
+/// 48 | mmap_addr | (present if flags[6] is set)
|
|
|
+/// +-------------------+
|
|
|
+/// 52 | drives_length | (present if flags[7] is set)
|
|
|
+/// 56 | drives_addr | (present if flags[7] is set)
|
|
|
+/// +-------------------+
|
|
|
+/// 60 | config_table | (present if flags[8] is set)
|
|
|
+/// +-------------------+
|
|
|
+/// 64 | boot_loader_name | (present if flags[9] is set)
|
|
|
+/// +-------------------+
|
|
|
+/// 68 | apm_table | (present if flags[10] is set)
|
|
|
+/// +-------------------+
|
|
|
+/// 72 | vbe_control_info | (present if flags[11] is set)
|
|
|
+/// 76 | vbe_mode_info |
|
|
|
+/// 80 | vbe_mode |
|
|
|
+/// 82 | vbe_interface_seg |
|
|
|
+/// 84 | vbe_interface_off |
|
|
|
+/// 86 | vbe_interface_len |
|
|
|
+/// +-------------------+
|
|
|
+/// 88 | framebuffer_addr | (present if flags[12] is set)
|
|
|
+/// 96 | framebuffer_pitch |
|
|
|
+/// 100 | framebuffer_width |
|
|
|
+/// 104 | framebuffer_height|
|
|
|
+/// 108 | framebuffer_bpp |
|
|
|
+/// 109 | framebuffer_type |
|
|
|
+/// 110-115 | color_info |
|
|
|
+/// +-------------------+
|
|
|
+///```
|
|
|
+///
|
|
|
+#[allow(dead_code)]
|
|
|
+#[derive(Debug, Copy, Clone)]
|
|
|
+#[repr(C, packed)]
|
|
|
+pub struct MultibootInfo {
|
|
|
+ /// Indicate whether the below field exists.
|
|
|
+ flags: u32,
|
|
|
+
|
|
|
+ /// Physical memory low.
|
|
|
+ mem_lower: u32,
|
|
|
+ /// Physical memory high.
|
|
|
+ mem_upper: u32,
|
|
|
+
|
|
|
+ /// Indicates which BIOS disk device the boot loader loaded the OS image from.
|
|
|
+ boot_device: BootDevice,
|
|
|
+
|
|
|
+ /// Command line passed to kernel.
|
|
|
+ cmdline: u32,
|
|
|
+
|
|
|
+ /// Modules count.
|
|
|
+ pub mods_count: u32,
|
|
|
+ /// The start address of modules list, each module structure format:
|
|
|
+ /// ```text
|
|
|
+ /// +-------------------+
|
|
|
+ /// 0 | mod_start |
|
|
|
+ /// 4 | mod_end |
|
|
|
+ /// +-------------------+
|
|
|
+ /// 8 | string |
|
|
|
+ /// +-------------------+
|
|
|
+ /// 12 | reserved (0) |
|
|
|
+ /// +-------------------+
|
|
|
+ /// ```
|
|
|
+ mods_paddr: u32,
|
|
|
+
|
|
|
+ /// If flags[4] = 1, then the field starting at byte 28 are valid:
|
|
|
+ /// ```text
|
|
|
+ /// +-------------------+
|
|
|
+ /// 28 | tabsize |
|
|
|
+ /// 32 | strsize |
|
|
|
+ /// 36 | addr |
|
|
|
+ /// 40 | reserved (0) |
|
|
|
+ /// +-------------------+
|
|
|
+ /// ```
|
|
|
+ /// These indicate where the symbol table from kernel image can be found.
|
|
|
+ ///
|
|
|
+ /// If flags[5] = 1, then the field starting at byte 28 are valid:
|
|
|
+ /// ```text
|
|
|
+ /// +-------------------+
|
|
|
+ /// 28 | num |
|
|
|
+ /// 32 | size |
|
|
|
+ /// 36 | addr |
|
|
|
+ /// 40 | shndx |
|
|
|
+ /// +-------------------+
|
|
|
+ /// ```
|
|
|
+ /// These indicate where the section header table from an ELF kernel is,
|
|
|
+ /// the size of each entry, number of entries, and the string table used as the index of names.
|
|
|
+ symbols: [u8; 16],
|
|
|
+
|
|
|
+ memory_map_len: u32,
|
|
|
+ memory_map_paddr: u32,
|
|
|
+
|
|
|
+ drives_length: u32,
|
|
|
+ drives_addr: u32,
|
|
|
+
|
|
|
+ config_table: u32,
|
|
|
+
|
|
|
+ /// bootloader name paddr
|
|
|
+ pub boot_loader_name: u32,
|
|
|
+
|
|
|
+ apm_table: u32,
|
|
|
+
|
|
|
+ vbe_table: VbeInfo,
|
|
|
+
|
|
|
+ pub framebuffer_table: FramebufferTable,
|
|
|
+}
|
|
|
+
|
|
|
+impl MultibootInfo {
|
|
|
+ /// If true, then the `mem_upper` and `mem_lower` fields are valid.
|
|
|
+ pub const FLAG_MEMORY_BOUNDS: u32 = 1 << 0;
|
|
|
+ /// If true, then the `boot_device` field is valid.
|
|
|
+ pub const FLAG_BOOT_DEVICE: u32 = 1 << 1;
|
|
|
+ /// If true, then the `cmdline` field is valid.
|
|
|
+ pub const FLAG_CMDLINE: u32 = 1 << 2;
|
|
|
+ /// If true, then the `mods_count` and `mods_addr` fields are valid.
|
|
|
+ pub const FLAG_MODULES: u32 = 1 << 3;
|
|
|
+ /// If true, then the `symbols` field is valid.
|
|
|
+ pub const FLAG_SYMBOLS: u32 = 1 << 4;
|
|
|
+
|
|
|
+ pub unsafe fn memory_map(&self, ops: &'static dyn MultibootOps) -> MemoryEntryIter {
|
|
|
+ let mmap_addr = ops.phys_2_virt(self.memory_map_paddr as usize);
|
|
|
+ let mmap_len = self.memory_map_len as usize;
|
|
|
+ MemoryEntryIter {
|
|
|
+ cur_ptr: mmap_addr,
|
|
|
+ region_end_vaddr: mmap_addr + mmap_len,
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ pub unsafe fn modules(&self, ops: &'static dyn MultibootOps) -> Option<ModulesIter> {
|
|
|
+ if !self.has_modules() {
|
|
|
+ return None;
|
|
|
+ }
|
|
|
+
|
|
|
+ let mods_addr = ops.phys_2_virt(self.mods_paddr as usize);
|
|
|
+ let end = mods_addr + (self.mods_count as usize) * core::mem::size_of::<MBModule>();
|
|
|
+ Some(ModulesIter {
|
|
|
+ cur_ptr: mods_addr,
|
|
|
+ region_end_vaddr: end,
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ pub unsafe fn cmdline(&self, ops: &'static dyn MultibootOps) -> Option<&str> {
|
|
|
+ if !self.has_cmdline() {
|
|
|
+ return None;
|
|
|
+ }
|
|
|
+
|
|
|
+ let cmdline_vaddr = ops.phys_2_virt(self.cmdline as usize);
|
|
|
+
|
|
|
+ let cstr = CStr::from_ptr(cmdline_vaddr as *const i8);
|
|
|
+ cstr.to_str().ok()
|
|
|
+ }
|
|
|
+
|
|
|
+ #[inline]
|
|
|
+ pub fn has_memory_bounds(&self) -> bool {
|
|
|
+ self.flags & Self::FLAG_MEMORY_BOUNDS != 0
|
|
|
+ }
|
|
|
+
|
|
|
+ #[inline]
|
|
|
+ pub fn has_boot_device(&self) -> bool {
|
|
|
+ self.flags & Self::FLAG_BOOT_DEVICE != 0
|
|
|
+ }
|
|
|
+
|
|
|
+ #[inline]
|
|
|
+ pub fn has_cmdline(&self) -> bool {
|
|
|
+ self.flags & Self::FLAG_CMDLINE != 0
|
|
|
+ }
|
|
|
+
|
|
|
+ #[inline]
|
|
|
+ pub fn has_modules(&self) -> bool {
|
|
|
+ self.flags & Self::FLAG_MODULES != 0
|
|
|
+ }
|
|
|
+
|
|
|
+ #[inline]
|
|
|
+ pub fn has_symbols(&self) -> bool {
|
|
|
+ self.flags & Self::FLAG_SYMBOLS != 0
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+pub trait MultibootOps {
|
|
|
+ fn phys_2_virt(&self, paddr: usize) -> usize;
|
|
|
+}
|
|
|
+
|
|
|
+#[derive(Debug, Copy, Clone)]
|
|
|
+#[repr(C, packed)]
|
|
|
+pub struct VbeInfo {
|
|
|
+ pub control_info: u32,
|
|
|
+ pub mode_info: u32,
|
|
|
+ pub mode: u16,
|
|
|
+ pub interface_seg: u16,
|
|
|
+ pub interface_off: u16,
|
|
|
+ pub interface_len: u16,
|
|
|
+}
|
|
|
+
|
|
|
+#[derive(Debug, Copy, Clone)]
|
|
|
+#[repr(C, packed)]
|
|
|
+pub struct FramebufferTable {
|
|
|
+ pub paddr: u64,
|
|
|
+ pub pitch: u32,
|
|
|
+ pub width: u32,
|
|
|
+ pub height: u32,
|
|
|
+ pub bpp: u8,
|
|
|
+ pub typ: u8,
|
|
|
+ color_info: ColorInfo,
|
|
|
+}
|
|
|
+
|
|
|
+impl FramebufferTable {
|
|
|
+ /// Get the color info from this table.
|
|
|
+ pub fn color_info(&self) -> Option<ColorInfoType> {
|
|
|
+ unsafe {
|
|
|
+ match self.typ {
|
|
|
+ 0 => Some(ColorInfoType::Palette(self.color_info.palette)),
|
|
|
+ 1 => Some(ColorInfoType::Rgb(self.color_info.rgb)),
|
|
|
+ 2 => Some(ColorInfoType::Text),
|
|
|
+ _ => None,
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/// Safe wrapper for `ColorInfo`
|
|
|
+#[derive(Debug)]
|
|
|
+pub enum ColorInfoType {
|
|
|
+ Palette(ColorInfoPalette),
|
|
|
+ Rgb(ColorInfoRgb),
|
|
|
+ Text,
|
|
|
+}
|
|
|
+
|
|
|
+/// Multiboot format for the frambuffer color info
|
|
|
+///
|
|
|
+/// According to the spec, if type == 0, it's indexed color and
|
|
|
+///<rawtext>
|
|
|
+/// +----------------------------------+
|
|
|
+/// 110 | framebuffer_palette_addr |
|
|
|
+/// 114 | framebuffer_palette_num_colors |
|
|
|
+/// +----------------------------------+
|
|
|
+///</rawtext>
|
|
|
+/// The address points to an array of `ColorDescriptor`s.
|
|
|
+/// If type == 1, it's RGB and
|
|
|
+///<rawtext>
|
|
|
+/// +----------------------------------+
|
|
|
+///110 | framebuffer_red_field_position |
|
|
|
+///111 | framebuffer_red_mask_size |
|
|
|
+///112 | framebuffer_green_field_position |
|
|
|
+///113 | framebuffer_green_mask_size |
|
|
|
+///114 | framebuffer_blue_field_position |
|
|
|
+///115 | framebuffer_blue_mask_size |
|
|
|
+/// +----------------------------------+
|
|
|
+///</rawtext>
|
|
|
+/// (If type == 2, it's just text.)
|
|
|
+#[repr(C)]
|
|
|
+#[derive(Clone, Copy)]
|
|
|
+union ColorInfo {
|
|
|
+ palette: ColorInfoPalette,
|
|
|
+ rgb: ColorInfoRgb,
|
|
|
+ _union_align: [u32; 2usize],
|
|
|
+}
|
|
|
+
|
|
|
+impl core::fmt::Debug for ColorInfo {
|
|
|
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
|
+ unsafe {
|
|
|
+ f.debug_struct("ColorInfo")
|
|
|
+ .field("palette", &self.palette)
|
|
|
+ .field("rgb", &self.rgb)
|
|
|
+ .finish()
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// default type is 0, so indexed color
|
|
|
+impl Default for ColorInfo {
|
|
|
+ fn default() -> Self {
|
|
|
+ Self {
|
|
|
+ palette: ColorInfoPalette {
|
|
|
+ palette_addr: 0,
|
|
|
+ palette_num_colors: 0,
|
|
|
+ },
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/// Information for indexed color mode
|
|
|
+#[repr(C)]
|
|
|
+#[derive(Debug, Clone, Copy)]
|
|
|
+pub struct ColorInfoPalette {
|
|
|
+ palette_addr: u32,
|
|
|
+ palette_num_colors: u16,
|
|
|
+}
|
|
|
+
|
|
|
+/// Information for direct RGB color mode
|
|
|
+#[repr(C)]
|
|
|
+#[derive(Debug, Clone, Copy)]
|
|
|
+pub struct ColorInfoRgb {
|
|
|
+ pub red_field_position: u8,
|
|
|
+ pub red_mask_size: u8,
|
|
|
+ pub green_field_position: u8,
|
|
|
+ pub green_mask_size: u8,
|
|
|
+ pub blue_field_position: u8,
|
|
|
+ pub blue_mask_size: u8,
|
|
|
+}
|
|
|
+
|
|
|
+/// Types that define if the memory is usable or not.
|
|
|
+#[derive(Debug, PartialEq, Eq)]
|
|
|
+pub enum MemoryType {
|
|
|
+ /// memory, available to OS
|
|
|
+ Available = 1,
|
|
|
+ /// reserved, not available (rom, mem map dev)
|
|
|
+ Reserved = 2,
|
|
|
+ /// ACPI Reclaim Memory
|
|
|
+ ACPI = 3,
|
|
|
+ /// ACPI NVS Memory
|
|
|
+ NVS = 4,
|
|
|
+ /// defective RAM modules
|
|
|
+ Defect = 5,
|
|
|
+}
|
|
|
+
|
|
|
+/// A memory entry in the memory map header info region.
|
|
|
+///
|
|
|
+/// The memory layout of the entry structure doesn't fit in any scheme
|
|
|
+/// provided by Rust:
|
|
|
+///
|
|
|
+/// ```text
|
|
|
+/// +-------------------+ <- start of the struct pointer
|
|
|
+/// -4 | size |
|
|
|
+/// +-------------------+
|
|
|
+/// 0 | base_addr |
|
|
|
+/// 8 | length |
|
|
|
+/// 16 | type |
|
|
|
+/// +-------------------+
|
|
|
+/// ```
|
|
|
+///
|
|
|
+/// The start of a entry is not 64-bit aligned. Although the boot
|
|
|
+/// protocol may provide the `mmap_addr` 64-bit aligned when added with
|
|
|
+/// 4, it is not guaranteed. So we need to use pointer arithmetic to
|
|
|
+/// access the fields.
|
|
|
+pub struct MemoryEntry {
|
|
|
+ ptr: usize,
|
|
|
+}
|
|
|
+
|
|
|
+impl MemoryEntry {
|
|
|
+ pub fn size(&self) -> u32 {
|
|
|
+ // SAFETY: the entry can only be contructed from a valid address.
|
|
|
+ unsafe { (self.ptr as *const u32).read_unaligned() }
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn base_addr(&self) -> u64 {
|
|
|
+ // SAFETY: the entry can only be contructed from a valid address.
|
|
|
+ unsafe { ((self.ptr + 4) as *const u64).read_unaligned() }
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn length(&self) -> u64 {
|
|
|
+ // SAFETY: the entry can only be contructed from a valid address.
|
|
|
+ unsafe { ((self.ptr + 12) as *const u64).read_unaligned() }
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn memory_type(&self) -> MemoryType {
|
|
|
+ let typ_val = unsafe { ((self.ptr + 20) as *const u8).read_unaligned() };
|
|
|
+ // The meaning of the values are however documented clearly by the manual.
|
|
|
+ match typ_val {
|
|
|
+ 1 => MemoryType::Available,
|
|
|
+ 2 => MemoryType::Reserved,
|
|
|
+ 3 => MemoryType::ACPI,
|
|
|
+ 4 => MemoryType::NVS,
|
|
|
+ 5 => MemoryType::Defect,
|
|
|
+ _ => MemoryType::Reserved,
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/// A memory entry iterator in the memory map header info region.
|
|
|
+#[derive(Debug, Copy, Clone)]
|
|
|
+pub struct MemoryEntryIter {
|
|
|
+ cur_ptr: usize,
|
|
|
+ region_end_vaddr: usize,
|
|
|
+}
|
|
|
+
|
|
|
+impl Iterator for MemoryEntryIter {
|
|
|
+ type Item = MemoryEntry;
|
|
|
+
|
|
|
+ fn next(&mut self) -> Option<Self::Item> {
|
|
|
+ if self.cur_ptr >= self.region_end_vaddr {
|
|
|
+ return None;
|
|
|
+ }
|
|
|
+ let entry = MemoryEntry { ptr: self.cur_ptr };
|
|
|
+ self.cur_ptr += entry.size() as usize + 4;
|
|
|
+ Some(entry)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/// Multiboot format to information about module
|
|
|
+#[repr(C)]
|
|
|
+pub struct MBModule {
|
|
|
+ /// Start address of module in memory.
|
|
|
+ start: u32,
|
|
|
+
|
|
|
+ /// End address of module in memory.
|
|
|
+ end: u32,
|
|
|
+
|
|
|
+ /// The `string` field provides an arbitrary string to be associated
|
|
|
+ /// with that particular boot module.
|
|
|
+ ///
|
|
|
+ /// It is a zero-terminated ASCII string, just like the kernel command line.
|
|
|
+ /// The `string` field may be 0 if there is no string associated with the module.
|
|
|
+ /// Typically the string might be a command line (e.g. if the operating system
|
|
|
+ /// treats boot modules as executable programs), or a pathname
|
|
|
+ /// (e.g. if the operating system treats boot modules as files in a file system),
|
|
|
+ /// but its exact use is specific to the operating system.
|
|
|
+ string: u32,
|
|
|
+
|
|
|
+ /// Must be zero.
|
|
|
+ reserved: u32,
|
|
|
+}
|
|
|
+
|
|
|
+impl MBModule {
|
|
|
+ #[inline]
|
|
|
+ pub fn start(&self) -> u32 {
|
|
|
+ self.start
|
|
|
+ }
|
|
|
+
|
|
|
+ #[inline]
|
|
|
+ pub fn end(&self) -> u32 {
|
|
|
+ self.end
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn string(&self) -> u32 {
|
|
|
+ self.string
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn reserved(&self) -> u32 {
|
|
|
+ self.reserved
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl core::fmt::Debug for MBModule {
|
|
|
+ fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
|
|
+ write!(
|
|
|
+ f,
|
|
|
+ "MBModule {{ start: {}, end: {}, string: {}, reserved: {} }}",
|
|
|
+ self.start, self.end, self.string, self.reserved
|
|
|
+ )
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#[derive(Debug, Copy, Clone)]
|
|
|
+pub struct ModulesIter {
|
|
|
+ cur_ptr: usize,
|
|
|
+ region_end_vaddr: usize,
|
|
|
+}
|
|
|
+
|
|
|
+impl Iterator for ModulesIter {
|
|
|
+ type Item = MBModule;
|
|
|
+
|
|
|
+ fn next(&mut self) -> Option<Self::Item> {
|
|
|
+ if self.cur_ptr >= self.region_end_vaddr {
|
|
|
+ return None;
|
|
|
+ }
|
|
|
+ let mb_module = unsafe { (self.cur_ptr as *const MBModule).read() };
|
|
|
+
|
|
|
+ self.cur_ptr += core::mem::size_of::<MBModule>();
|
|
|
+ Some(mb_module)
|
|
|
+ }
|
|
|
+}
|