xref: /DragonOS/kernel/crates/multiboot/src/lib.rs (revision db7c782a9aaacb320027167bda4f23751b8f36e1)
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