1*db7c782aSLoGin //! Multiboot v1 library 2*db7c782aSLoGin //! 3*db7c782aSLoGin //! This crate is partitially modified from `https://github.com/gz/rust-multiboot` && asterinas 4*db7c782aSLoGin //! 5*db7c782aSLoGin //! The main structs to interact with are [`Multiboot`] for the Multiboot information 6*db7c782aSLoGin //! passed from the bootloader to the kernel at runtime and [`Header`] for the static 7*db7c782aSLoGin //! information passed from the kernel to the bootloader in the kernel image. 8*db7c782aSLoGin //! 9*db7c782aSLoGin //! 10*db7c782aSLoGin //! # Additional documentation 11*db7c782aSLoGin //! * https://www.gnu.org/software/grub/manual/multiboot/multiboot.html 12*db7c782aSLoGin //! * http://git.savannah.gnu.org/cgit/grub.git/tree/doc/multiboot.texi?h=multiboot 13*db7c782aSLoGin //! 14*db7c782aSLoGin //! [`Multiboot`]: information/struct.Multiboot.html 15*db7c782aSLoGin //! [`Header`]: header/struct.Header.html 16*db7c782aSLoGin #![no_std] 17*db7c782aSLoGin 18*db7c782aSLoGin use core::ffi::CStr; 19*db7c782aSLoGin 20*db7c782aSLoGin pub const MAGIC: u32 = 0x2BADB002; 21*db7c782aSLoGin 22*db7c782aSLoGin /// The ‘boot_device’ field. 23*db7c782aSLoGin /// 24*db7c782aSLoGin /// Partition numbers always start from zero. Unused partition 25*db7c782aSLoGin /// bytes must be set to 0xFF. For example, if the disk is partitioned 26*db7c782aSLoGin /// using a simple one-level DOS partitioning scheme, then 27*db7c782aSLoGin /// ‘part’ contains the DOS partition number, and ‘part2’ and ‘part3’ 28*db7c782aSLoGin /// are both 0xFF. As another example, if a disk is partitioned first into 29*db7c782aSLoGin /// DOS partitions, and then one of those DOS partitions is subdivided 30*db7c782aSLoGin /// into several BSD partitions using BSD's disklabel strategy, then ‘part1’ 31*db7c782aSLoGin /// contains the DOS partition number, ‘part2’ contains the BSD sub-partition 32*db7c782aSLoGin /// within that DOS partition, and ‘part3’ is 0xFF. 33*db7c782aSLoGin /// 34*db7c782aSLoGin #[derive(Debug, Clone, Copy)] 35*db7c782aSLoGin #[repr(C)] 36*db7c782aSLoGin pub struct BootDevice { 37*db7c782aSLoGin /// Contains the bios drive number as understood by 38*db7c782aSLoGin /// the bios INT 0x13 low-level disk interface: e.g. 0x00 for the 39*db7c782aSLoGin /// first floppy disk or 0x80 for the first hard disk. 40*db7c782aSLoGin pub drive: u8, 41*db7c782aSLoGin /// Specifies the top-level partition number. 42*db7c782aSLoGin pub partition1: u8, 43*db7c782aSLoGin /// Specifies a sub-partition in the top-level partition 44*db7c782aSLoGin pub partition2: u8, 45*db7c782aSLoGin /// Specifies a sub-partition in the 2nd-level partition 46*db7c782aSLoGin pub partition3: u8, 47*db7c782aSLoGin } 48*db7c782aSLoGin 49*db7c782aSLoGin impl BootDevice { 50*db7c782aSLoGin /// Is partition1 a valid partition? partition1_is_valid(&self) -> bool51*db7c782aSLoGin pub fn partition1_is_valid(&self) -> bool { 52*db7c782aSLoGin self.partition1 != 0xff 53*db7c782aSLoGin } 54*db7c782aSLoGin 55*db7c782aSLoGin /// Is partition2 a valid partition? partition2_is_valid(&self) -> bool56*db7c782aSLoGin pub fn partition2_is_valid(&self) -> bool { 57*db7c782aSLoGin self.partition2 != 0xff 58*db7c782aSLoGin } 59*db7c782aSLoGin 60*db7c782aSLoGin /// Is partition3 a valid partition? partition3_is_valid(&self) -> bool61*db7c782aSLoGin pub fn partition3_is_valid(&self) -> bool { 62*db7c782aSLoGin self.partition3 != 0xff 63*db7c782aSLoGin } 64*db7c782aSLoGin } 65*db7c782aSLoGin 66*db7c782aSLoGin impl Default for BootDevice { default() -> Self67*db7c782aSLoGin fn default() -> Self { 68*db7c782aSLoGin Self { 69*db7c782aSLoGin drive: 0xff, 70*db7c782aSLoGin partition1: 0xff, 71*db7c782aSLoGin partition2: 0xff, 72*db7c782aSLoGin partition3: 0xff, 73*db7c782aSLoGin } 74*db7c782aSLoGin } 75*db7c782aSLoGin } 76*db7c782aSLoGin 77*db7c782aSLoGin /// Representation of Multiboot Information according to specification. 78*db7c782aSLoGin /// 79*db7c782aSLoGin /// Reference: https://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Boot-information-format 80*db7c782aSLoGin /// 81*db7c782aSLoGin ///```text 82*db7c782aSLoGin /// +-------------------+ 83*db7c782aSLoGin /// 0 | flags | (required) 84*db7c782aSLoGin /// +-------------------+ 85*db7c782aSLoGin /// 4 | mem_lower | (present if flags[0] is set) 86*db7c782aSLoGin /// 8 | mem_upper | (present if flags[0] is set) 87*db7c782aSLoGin /// +-------------------+ 88*db7c782aSLoGin /// 12 | boot_device | (present if flags[1] is set) 89*db7c782aSLoGin /// +-------------------+ 90*db7c782aSLoGin /// 16 | cmdline | (present if flags[2] is set) 91*db7c782aSLoGin /// +-------------------+ 92*db7c782aSLoGin /// 20 | mods_count | (present if flags[3] is set) 93*db7c782aSLoGin /// 24 | mods_addr | (present if flags[3] is set) 94*db7c782aSLoGin /// +-------------------+ 95*db7c782aSLoGin /// 28 - 40 | syms | (present if flags[4] or 96*db7c782aSLoGin /// | | flags[5] is set) 97*db7c782aSLoGin /// +-------------------+ 98*db7c782aSLoGin /// 44 | mmap_length | (present if flags[6] is set) 99*db7c782aSLoGin /// 48 | mmap_addr | (present if flags[6] is set) 100*db7c782aSLoGin /// +-------------------+ 101*db7c782aSLoGin /// 52 | drives_length | (present if flags[7] is set) 102*db7c782aSLoGin /// 56 | drives_addr | (present if flags[7] is set) 103*db7c782aSLoGin /// +-------------------+ 104*db7c782aSLoGin /// 60 | config_table | (present if flags[8] is set) 105*db7c782aSLoGin /// +-------------------+ 106*db7c782aSLoGin /// 64 | boot_loader_name | (present if flags[9] is set) 107*db7c782aSLoGin /// +-------------------+ 108*db7c782aSLoGin /// 68 | apm_table | (present if flags[10] is set) 109*db7c782aSLoGin /// +-------------------+ 110*db7c782aSLoGin /// 72 | vbe_control_info | (present if flags[11] is set) 111*db7c782aSLoGin /// 76 | vbe_mode_info | 112*db7c782aSLoGin /// 80 | vbe_mode | 113*db7c782aSLoGin /// 82 | vbe_interface_seg | 114*db7c782aSLoGin /// 84 | vbe_interface_off | 115*db7c782aSLoGin /// 86 | vbe_interface_len | 116*db7c782aSLoGin /// +-------------------+ 117*db7c782aSLoGin /// 88 | framebuffer_addr | (present if flags[12] is set) 118*db7c782aSLoGin /// 96 | framebuffer_pitch | 119*db7c782aSLoGin /// 100 | framebuffer_width | 120*db7c782aSLoGin /// 104 | framebuffer_height| 121*db7c782aSLoGin /// 108 | framebuffer_bpp | 122*db7c782aSLoGin /// 109 | framebuffer_type | 123*db7c782aSLoGin /// 110-115 | color_info | 124*db7c782aSLoGin /// +-------------------+ 125*db7c782aSLoGin ///``` 126*db7c782aSLoGin /// 127*db7c782aSLoGin #[allow(dead_code)] 128*db7c782aSLoGin #[derive(Debug, Copy, Clone)] 129*db7c782aSLoGin #[repr(C, packed)] 130*db7c782aSLoGin pub struct MultibootInfo { 131*db7c782aSLoGin /// Indicate whether the below field exists. 132*db7c782aSLoGin flags: u32, 133*db7c782aSLoGin 134*db7c782aSLoGin /// Physical memory low. 135*db7c782aSLoGin mem_lower: u32, 136*db7c782aSLoGin /// Physical memory high. 137*db7c782aSLoGin mem_upper: u32, 138*db7c782aSLoGin 139*db7c782aSLoGin /// Indicates which BIOS disk device the boot loader loaded the OS image from. 140*db7c782aSLoGin boot_device: BootDevice, 141*db7c782aSLoGin 142*db7c782aSLoGin /// Command line passed to kernel. 143*db7c782aSLoGin cmdline: u32, 144*db7c782aSLoGin 145*db7c782aSLoGin /// Modules count. 146*db7c782aSLoGin pub mods_count: u32, 147*db7c782aSLoGin /// The start address of modules list, each module structure format: 148*db7c782aSLoGin /// ```text 149*db7c782aSLoGin /// +-------------------+ 150*db7c782aSLoGin /// 0 | mod_start | 151*db7c782aSLoGin /// 4 | mod_end | 152*db7c782aSLoGin /// +-------------------+ 153*db7c782aSLoGin /// 8 | string | 154*db7c782aSLoGin /// +-------------------+ 155*db7c782aSLoGin /// 12 | reserved (0) | 156*db7c782aSLoGin /// +-------------------+ 157*db7c782aSLoGin /// ``` 158*db7c782aSLoGin mods_paddr: u32, 159*db7c782aSLoGin 160*db7c782aSLoGin /// If flags[4] = 1, then the field starting at byte 28 are valid: 161*db7c782aSLoGin /// ```text 162*db7c782aSLoGin /// +-------------------+ 163*db7c782aSLoGin /// 28 | tabsize | 164*db7c782aSLoGin /// 32 | strsize | 165*db7c782aSLoGin /// 36 | addr | 166*db7c782aSLoGin /// 40 | reserved (0) | 167*db7c782aSLoGin /// +-------------------+ 168*db7c782aSLoGin /// ``` 169*db7c782aSLoGin /// These indicate where the symbol table from kernel image can be found. 170*db7c782aSLoGin /// 171*db7c782aSLoGin /// If flags[5] = 1, then the field starting at byte 28 are valid: 172*db7c782aSLoGin /// ```text 173*db7c782aSLoGin /// +-------------------+ 174*db7c782aSLoGin /// 28 | num | 175*db7c782aSLoGin /// 32 | size | 176*db7c782aSLoGin /// 36 | addr | 177*db7c782aSLoGin /// 40 | shndx | 178*db7c782aSLoGin /// +-------------------+ 179*db7c782aSLoGin /// ``` 180*db7c782aSLoGin /// These indicate where the section header table from an ELF kernel is, 181*db7c782aSLoGin /// the size of each entry, number of entries, and the string table used as the index of names. 182*db7c782aSLoGin symbols: [u8; 16], 183*db7c782aSLoGin 184*db7c782aSLoGin memory_map_len: u32, 185*db7c782aSLoGin memory_map_paddr: u32, 186*db7c782aSLoGin 187*db7c782aSLoGin drives_length: u32, 188*db7c782aSLoGin drives_addr: u32, 189*db7c782aSLoGin 190*db7c782aSLoGin config_table: u32, 191*db7c782aSLoGin 192*db7c782aSLoGin /// bootloader name paddr 193*db7c782aSLoGin pub boot_loader_name: u32, 194*db7c782aSLoGin 195*db7c782aSLoGin apm_table: u32, 196*db7c782aSLoGin 197*db7c782aSLoGin vbe_table: VbeInfo, 198*db7c782aSLoGin 199*db7c782aSLoGin pub framebuffer_table: FramebufferTable, 200*db7c782aSLoGin } 201*db7c782aSLoGin 202*db7c782aSLoGin impl MultibootInfo { 203*db7c782aSLoGin /// If true, then the `mem_upper` and `mem_lower` fields are valid. 204*db7c782aSLoGin pub const FLAG_MEMORY_BOUNDS: u32 = 1 << 0; 205*db7c782aSLoGin /// If true, then the `boot_device` field is valid. 206*db7c782aSLoGin pub const FLAG_BOOT_DEVICE: u32 = 1 << 1; 207*db7c782aSLoGin /// If true, then the `cmdline` field is valid. 208*db7c782aSLoGin pub const FLAG_CMDLINE: u32 = 1 << 2; 209*db7c782aSLoGin /// If true, then the `mods_count` and `mods_addr` fields are valid. 210*db7c782aSLoGin pub const FLAG_MODULES: u32 = 1 << 3; 211*db7c782aSLoGin /// If true, then the `symbols` field is valid. 212*db7c782aSLoGin pub const FLAG_SYMBOLS: u32 = 1 << 4; 213*db7c782aSLoGin memory_map(&self, ops: &'static dyn MultibootOps) -> MemoryEntryIter214*db7c782aSLoGin pub unsafe fn memory_map(&self, ops: &'static dyn MultibootOps) -> MemoryEntryIter { 215*db7c782aSLoGin let mmap_addr = ops.phys_2_virt(self.memory_map_paddr as usize); 216*db7c782aSLoGin let mmap_len = self.memory_map_len as usize; 217*db7c782aSLoGin MemoryEntryIter { 218*db7c782aSLoGin cur_ptr: mmap_addr, 219*db7c782aSLoGin region_end_vaddr: mmap_addr + mmap_len, 220*db7c782aSLoGin } 221*db7c782aSLoGin } 222*db7c782aSLoGin modules(&self, ops: &'static dyn MultibootOps) -> Option<ModulesIter>223*db7c782aSLoGin pub unsafe fn modules(&self, ops: &'static dyn MultibootOps) -> Option<ModulesIter> { 224*db7c782aSLoGin if !self.has_modules() { 225*db7c782aSLoGin return None; 226*db7c782aSLoGin } 227*db7c782aSLoGin 228*db7c782aSLoGin let mods_addr = ops.phys_2_virt(self.mods_paddr as usize); 229*db7c782aSLoGin let end = mods_addr + (self.mods_count as usize) * core::mem::size_of::<MBModule>(); 230*db7c782aSLoGin Some(ModulesIter { 231*db7c782aSLoGin cur_ptr: mods_addr, 232*db7c782aSLoGin region_end_vaddr: end, 233*db7c782aSLoGin }) 234*db7c782aSLoGin } 235*db7c782aSLoGin cmdline(&self, ops: &'static dyn MultibootOps) -> Option<&str>236*db7c782aSLoGin pub unsafe fn cmdline(&self, ops: &'static dyn MultibootOps) -> Option<&str> { 237*db7c782aSLoGin if !self.has_cmdline() { 238*db7c782aSLoGin return None; 239*db7c782aSLoGin } 240*db7c782aSLoGin 241*db7c782aSLoGin let cmdline_vaddr = ops.phys_2_virt(self.cmdline as usize); 242*db7c782aSLoGin 243*db7c782aSLoGin let cstr = CStr::from_ptr(cmdline_vaddr as *const i8); 244*db7c782aSLoGin cstr.to_str().ok() 245*db7c782aSLoGin } 246*db7c782aSLoGin 247*db7c782aSLoGin #[inline] has_memory_bounds(&self) -> bool248*db7c782aSLoGin pub fn has_memory_bounds(&self) -> bool { 249*db7c782aSLoGin self.flags & Self::FLAG_MEMORY_BOUNDS != 0 250*db7c782aSLoGin } 251*db7c782aSLoGin 252*db7c782aSLoGin #[inline] has_boot_device(&self) -> bool253*db7c782aSLoGin pub fn has_boot_device(&self) -> bool { 254*db7c782aSLoGin self.flags & Self::FLAG_BOOT_DEVICE != 0 255*db7c782aSLoGin } 256*db7c782aSLoGin 257*db7c782aSLoGin #[inline] has_cmdline(&self) -> bool258*db7c782aSLoGin pub fn has_cmdline(&self) -> bool { 259*db7c782aSLoGin self.flags & Self::FLAG_CMDLINE != 0 260*db7c782aSLoGin } 261*db7c782aSLoGin 262*db7c782aSLoGin #[inline] has_modules(&self) -> bool263*db7c782aSLoGin pub fn has_modules(&self) -> bool { 264*db7c782aSLoGin self.flags & Self::FLAG_MODULES != 0 265*db7c782aSLoGin } 266*db7c782aSLoGin 267*db7c782aSLoGin #[inline] has_symbols(&self) -> bool268*db7c782aSLoGin pub fn has_symbols(&self) -> bool { 269*db7c782aSLoGin self.flags & Self::FLAG_SYMBOLS != 0 270*db7c782aSLoGin } 271*db7c782aSLoGin } 272*db7c782aSLoGin 273*db7c782aSLoGin pub trait MultibootOps { phys_2_virt(&self, paddr: usize) -> usize274*db7c782aSLoGin fn phys_2_virt(&self, paddr: usize) -> usize; 275*db7c782aSLoGin } 276*db7c782aSLoGin 277*db7c782aSLoGin #[derive(Debug, Copy, Clone)] 278*db7c782aSLoGin #[repr(C, packed)] 279*db7c782aSLoGin pub struct VbeInfo { 280*db7c782aSLoGin pub control_info: u32, 281*db7c782aSLoGin pub mode_info: u32, 282*db7c782aSLoGin pub mode: u16, 283*db7c782aSLoGin pub interface_seg: u16, 284*db7c782aSLoGin pub interface_off: u16, 285*db7c782aSLoGin pub interface_len: u16, 286*db7c782aSLoGin } 287*db7c782aSLoGin 288*db7c782aSLoGin #[derive(Debug, Copy, Clone)] 289*db7c782aSLoGin #[repr(C, packed)] 290*db7c782aSLoGin pub struct FramebufferTable { 291*db7c782aSLoGin pub paddr: u64, 292*db7c782aSLoGin pub pitch: u32, 293*db7c782aSLoGin pub width: u32, 294*db7c782aSLoGin pub height: u32, 295*db7c782aSLoGin pub bpp: u8, 296*db7c782aSLoGin pub typ: u8, 297*db7c782aSLoGin color_info: ColorInfo, 298*db7c782aSLoGin } 299*db7c782aSLoGin 300*db7c782aSLoGin impl FramebufferTable { 301*db7c782aSLoGin /// Get the color info from this table. color_info(&self) -> Option<ColorInfoType>302*db7c782aSLoGin pub fn color_info(&self) -> Option<ColorInfoType> { 303*db7c782aSLoGin unsafe { 304*db7c782aSLoGin match self.typ { 305*db7c782aSLoGin 0 => Some(ColorInfoType::Palette(self.color_info.palette)), 306*db7c782aSLoGin 1 => Some(ColorInfoType::Rgb(self.color_info.rgb)), 307*db7c782aSLoGin 2 => Some(ColorInfoType::Text), 308*db7c782aSLoGin _ => None, 309*db7c782aSLoGin } 310*db7c782aSLoGin } 311*db7c782aSLoGin } 312*db7c782aSLoGin } 313*db7c782aSLoGin 314*db7c782aSLoGin /// Safe wrapper for `ColorInfo` 315*db7c782aSLoGin #[derive(Debug)] 316*db7c782aSLoGin pub enum ColorInfoType { 317*db7c782aSLoGin Palette(ColorInfoPalette), 318*db7c782aSLoGin Rgb(ColorInfoRgb), 319*db7c782aSLoGin Text, 320*db7c782aSLoGin } 321*db7c782aSLoGin 322*db7c782aSLoGin /// Multiboot format for the frambuffer color info 323*db7c782aSLoGin /// 324*db7c782aSLoGin /// According to the spec, if type == 0, it's indexed color and 325*db7c782aSLoGin ///<rawtext> 326*db7c782aSLoGin /// +----------------------------------+ 327*db7c782aSLoGin /// 110 | framebuffer_palette_addr | 328*db7c782aSLoGin /// 114 | framebuffer_palette_num_colors | 329*db7c782aSLoGin /// +----------------------------------+ 330*db7c782aSLoGin ///</rawtext> 331*db7c782aSLoGin /// The address points to an array of `ColorDescriptor`s. 332*db7c782aSLoGin /// If type == 1, it's RGB and 333*db7c782aSLoGin ///<rawtext> 334*db7c782aSLoGin /// +----------------------------------+ 335*db7c782aSLoGin ///110 | framebuffer_red_field_position | 336*db7c782aSLoGin ///111 | framebuffer_red_mask_size | 337*db7c782aSLoGin ///112 | framebuffer_green_field_position | 338*db7c782aSLoGin ///113 | framebuffer_green_mask_size | 339*db7c782aSLoGin ///114 | framebuffer_blue_field_position | 340*db7c782aSLoGin ///115 | framebuffer_blue_mask_size | 341*db7c782aSLoGin /// +----------------------------------+ 342*db7c782aSLoGin ///</rawtext> 343*db7c782aSLoGin /// (If type == 2, it's just text.) 344*db7c782aSLoGin #[repr(C)] 345*db7c782aSLoGin #[derive(Clone, Copy)] 346*db7c782aSLoGin union ColorInfo { 347*db7c782aSLoGin palette: ColorInfoPalette, 348*db7c782aSLoGin rgb: ColorInfoRgb, 349*db7c782aSLoGin _union_align: [u32; 2usize], 350*db7c782aSLoGin } 351*db7c782aSLoGin 352*db7c782aSLoGin impl core::fmt::Debug for ColorInfo { fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result353*db7c782aSLoGin fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 354*db7c782aSLoGin unsafe { 355*db7c782aSLoGin f.debug_struct("ColorInfo") 356*db7c782aSLoGin .field("palette", &self.palette) 357*db7c782aSLoGin .field("rgb", &self.rgb) 358*db7c782aSLoGin .finish() 359*db7c782aSLoGin } 360*db7c782aSLoGin } 361*db7c782aSLoGin } 362*db7c782aSLoGin 363*db7c782aSLoGin // default type is 0, so indexed color 364*db7c782aSLoGin impl Default for ColorInfo { default() -> Self365*db7c782aSLoGin fn default() -> Self { 366*db7c782aSLoGin Self { 367*db7c782aSLoGin palette: ColorInfoPalette { 368*db7c782aSLoGin palette_addr: 0, 369*db7c782aSLoGin palette_num_colors: 0, 370*db7c782aSLoGin }, 371*db7c782aSLoGin } 372*db7c782aSLoGin } 373*db7c782aSLoGin } 374*db7c782aSLoGin 375*db7c782aSLoGin /// Information for indexed color mode 376*db7c782aSLoGin #[repr(C)] 377*db7c782aSLoGin #[derive(Debug, Clone, Copy)] 378*db7c782aSLoGin pub struct ColorInfoPalette { 379*db7c782aSLoGin palette_addr: u32, 380*db7c782aSLoGin palette_num_colors: u16, 381*db7c782aSLoGin } 382*db7c782aSLoGin 383*db7c782aSLoGin /// Information for direct RGB color mode 384*db7c782aSLoGin #[repr(C)] 385*db7c782aSLoGin #[derive(Debug, Clone, Copy)] 386*db7c782aSLoGin pub struct ColorInfoRgb { 387*db7c782aSLoGin pub red_field_position: u8, 388*db7c782aSLoGin pub red_mask_size: u8, 389*db7c782aSLoGin pub green_field_position: u8, 390*db7c782aSLoGin pub green_mask_size: u8, 391*db7c782aSLoGin pub blue_field_position: u8, 392*db7c782aSLoGin pub blue_mask_size: u8, 393*db7c782aSLoGin } 394*db7c782aSLoGin 395*db7c782aSLoGin /// Types that define if the memory is usable or not. 396*db7c782aSLoGin #[derive(Debug, PartialEq, Eq)] 397*db7c782aSLoGin pub enum MemoryType { 398*db7c782aSLoGin /// memory, available to OS 399*db7c782aSLoGin Available = 1, 400*db7c782aSLoGin /// reserved, not available (rom, mem map dev) 401*db7c782aSLoGin Reserved = 2, 402*db7c782aSLoGin /// ACPI Reclaim Memory 403*db7c782aSLoGin ACPI = 3, 404*db7c782aSLoGin /// ACPI NVS Memory 405*db7c782aSLoGin NVS = 4, 406*db7c782aSLoGin /// defective RAM modules 407*db7c782aSLoGin Defect = 5, 408*db7c782aSLoGin } 409*db7c782aSLoGin 410*db7c782aSLoGin /// A memory entry in the memory map header info region. 411*db7c782aSLoGin /// 412*db7c782aSLoGin /// The memory layout of the entry structure doesn't fit in any scheme 413*db7c782aSLoGin /// provided by Rust: 414*db7c782aSLoGin /// 415*db7c782aSLoGin /// ```text 416*db7c782aSLoGin /// +-------------------+ <- start of the struct pointer 417*db7c782aSLoGin /// -4 | size | 418*db7c782aSLoGin /// +-------------------+ 419*db7c782aSLoGin /// 0 | base_addr | 420*db7c782aSLoGin /// 8 | length | 421*db7c782aSLoGin /// 16 | type | 422*db7c782aSLoGin /// +-------------------+ 423*db7c782aSLoGin /// ``` 424*db7c782aSLoGin /// 425*db7c782aSLoGin /// The start of a entry is not 64-bit aligned. Although the boot 426*db7c782aSLoGin /// protocol may provide the `mmap_addr` 64-bit aligned when added with 427*db7c782aSLoGin /// 4, it is not guaranteed. So we need to use pointer arithmetic to 428*db7c782aSLoGin /// access the fields. 429*db7c782aSLoGin pub struct MemoryEntry { 430*db7c782aSLoGin ptr: usize, 431*db7c782aSLoGin } 432*db7c782aSLoGin 433*db7c782aSLoGin impl MemoryEntry { size(&self) -> u32434*db7c782aSLoGin pub fn size(&self) -> u32 { 435*db7c782aSLoGin // SAFETY: the entry can only be contructed from a valid address. 436*db7c782aSLoGin unsafe { (self.ptr as *const u32).read_unaligned() } 437*db7c782aSLoGin } 438*db7c782aSLoGin base_addr(&self) -> u64439*db7c782aSLoGin pub fn base_addr(&self) -> u64 { 440*db7c782aSLoGin // SAFETY: the entry can only be contructed from a valid address. 441*db7c782aSLoGin unsafe { ((self.ptr + 4) as *const u64).read_unaligned() } 442*db7c782aSLoGin } 443*db7c782aSLoGin length(&self) -> u64444*db7c782aSLoGin pub fn length(&self) -> u64 { 445*db7c782aSLoGin // SAFETY: the entry can only be contructed from a valid address. 446*db7c782aSLoGin unsafe { ((self.ptr + 12) as *const u64).read_unaligned() } 447*db7c782aSLoGin } 448*db7c782aSLoGin memory_type(&self) -> MemoryType449*db7c782aSLoGin pub fn memory_type(&self) -> MemoryType { 450*db7c782aSLoGin let typ_val = unsafe { ((self.ptr + 20) as *const u8).read_unaligned() }; 451*db7c782aSLoGin // The meaning of the values are however documented clearly by the manual. 452*db7c782aSLoGin match typ_val { 453*db7c782aSLoGin 1 => MemoryType::Available, 454*db7c782aSLoGin 2 => MemoryType::Reserved, 455*db7c782aSLoGin 3 => MemoryType::ACPI, 456*db7c782aSLoGin 4 => MemoryType::NVS, 457*db7c782aSLoGin 5 => MemoryType::Defect, 458*db7c782aSLoGin _ => MemoryType::Reserved, 459*db7c782aSLoGin } 460*db7c782aSLoGin } 461*db7c782aSLoGin } 462*db7c782aSLoGin 463*db7c782aSLoGin /// A memory entry iterator in the memory map header info region. 464*db7c782aSLoGin #[derive(Debug, Copy, Clone)] 465*db7c782aSLoGin pub struct MemoryEntryIter { 466*db7c782aSLoGin cur_ptr: usize, 467*db7c782aSLoGin region_end_vaddr: usize, 468*db7c782aSLoGin } 469*db7c782aSLoGin 470*db7c782aSLoGin impl Iterator for MemoryEntryIter { 471*db7c782aSLoGin type Item = MemoryEntry; 472*db7c782aSLoGin next(&mut self) -> Option<Self::Item>473*db7c782aSLoGin fn next(&mut self) -> Option<Self::Item> { 474*db7c782aSLoGin if self.cur_ptr >= self.region_end_vaddr { 475*db7c782aSLoGin return None; 476*db7c782aSLoGin } 477*db7c782aSLoGin let entry = MemoryEntry { ptr: self.cur_ptr }; 478*db7c782aSLoGin self.cur_ptr += entry.size() as usize + 4; 479*db7c782aSLoGin Some(entry) 480*db7c782aSLoGin } 481*db7c782aSLoGin } 482*db7c782aSLoGin 483*db7c782aSLoGin /// Multiboot format to information about module 484*db7c782aSLoGin #[repr(C)] 485*db7c782aSLoGin pub struct MBModule { 486*db7c782aSLoGin /// Start address of module in memory. 487*db7c782aSLoGin start: u32, 488*db7c782aSLoGin 489*db7c782aSLoGin /// End address of module in memory. 490*db7c782aSLoGin end: u32, 491*db7c782aSLoGin 492*db7c782aSLoGin /// The `string` field provides an arbitrary string to be associated 493*db7c782aSLoGin /// with that particular boot module. 494*db7c782aSLoGin /// 495*db7c782aSLoGin /// It is a zero-terminated ASCII string, just like the kernel command line. 496*db7c782aSLoGin /// The `string` field may be 0 if there is no string associated with the module. 497*db7c782aSLoGin /// Typically the string might be a command line (e.g. if the operating system 498*db7c782aSLoGin /// treats boot modules as executable programs), or a pathname 499*db7c782aSLoGin /// (e.g. if the operating system treats boot modules as files in a file system), 500*db7c782aSLoGin /// but its exact use is specific to the operating system. 501*db7c782aSLoGin string: u32, 502*db7c782aSLoGin 503*db7c782aSLoGin /// Must be zero. 504*db7c782aSLoGin reserved: u32, 505*db7c782aSLoGin } 506*db7c782aSLoGin 507*db7c782aSLoGin impl MBModule { 508*db7c782aSLoGin #[inline] start(&self) -> u32509*db7c782aSLoGin pub fn start(&self) -> u32 { 510*db7c782aSLoGin self.start 511*db7c782aSLoGin } 512*db7c782aSLoGin 513*db7c782aSLoGin #[inline] end(&self) -> u32514*db7c782aSLoGin pub fn end(&self) -> u32 { 515*db7c782aSLoGin self.end 516*db7c782aSLoGin } 517*db7c782aSLoGin string(&self) -> u32518*db7c782aSLoGin pub fn string(&self) -> u32 { 519*db7c782aSLoGin self.string 520*db7c782aSLoGin } 521*db7c782aSLoGin reserved(&self) -> u32522*db7c782aSLoGin pub fn reserved(&self) -> u32 { 523*db7c782aSLoGin self.reserved 524*db7c782aSLoGin } 525*db7c782aSLoGin } 526*db7c782aSLoGin 527*db7c782aSLoGin impl core::fmt::Debug for MBModule { fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result528*db7c782aSLoGin fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { 529*db7c782aSLoGin write!( 530*db7c782aSLoGin f, 531*db7c782aSLoGin "MBModule {{ start: {}, end: {}, string: {}, reserved: {} }}", 532*db7c782aSLoGin self.start, self.end, self.string, self.reserved 533*db7c782aSLoGin ) 534*db7c782aSLoGin } 535*db7c782aSLoGin } 536*db7c782aSLoGin 537*db7c782aSLoGin #[derive(Debug, Copy, Clone)] 538*db7c782aSLoGin pub struct ModulesIter { 539*db7c782aSLoGin cur_ptr: usize, 540*db7c782aSLoGin region_end_vaddr: usize, 541*db7c782aSLoGin } 542*db7c782aSLoGin 543*db7c782aSLoGin impl Iterator for ModulesIter { 544*db7c782aSLoGin type Item = MBModule; 545*db7c782aSLoGin next(&mut self) -> Option<Self::Item>546*db7c782aSLoGin fn next(&mut self) -> Option<Self::Item> { 547*db7c782aSLoGin if self.cur_ptr >= self.region_end_vaddr { 548*db7c782aSLoGin return None; 549*db7c782aSLoGin } 550*db7c782aSLoGin let mb_module = unsafe { (self.cur_ptr as *const MBModule).read() }; 551*db7c782aSLoGin 552*db7c782aSLoGin self.cur_ptr += core::mem::size_of::<MBModule>(); 553*db7c782aSLoGin Some(mb_module) 554*db7c782aSLoGin } 555*db7c782aSLoGin } 556