• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //! Multiboot specification 0.6.96 definitions
6 //!
7 //! <https://www.gnu.org/software/grub/manual/multiboot/multiboot.html>
8 
9 use zerocopy::FromBytes;
10 use zerocopy::Immutable;
11 use zerocopy::IntoBytes;
12 use zerocopy::KnownLayout;
13 
14 /// Magic value stored in EAX to indicate bootloader is Multiboot compliant.
15 pub const MULTIBOOT_BOOTLOADER_MAGIC: u32 = 0x2BADB002;
16 
17 #[derive(Debug, Default, FromBytes, Immutable, IntoBytes, KnownLayout)]
18 #[repr(C, packed)]
19 pub struct MultibootInfo {
20     pub flags: u32,
21 
22     pub mem_lower: u32,
23     pub mem_upper: u32,
24 
25     pub boot_device: u32,
26 
27     pub cmdline: u32,
28 
29     pub mods_count: u32,
30     pub mods_addr: u32,
31 
32     // TODO: add union for ELF + a.out symbols if needed
33     pub syms: [u32; 4],
34 
35     pub mmap_length: u32,
36     pub mmap_addr: u32,
37 
38     pub drives_length: u32,
39     pub drives_addr: u32,
40 
41     pub config_table: u32,
42 
43     pub boot_loader_name: u32,
44 
45     pub apm_table: u32,
46 
47     pub vbe_control_info: u32,
48     pub vbe_mode_info: u32,
49     pub vbe_mode: u16,
50     pub vbe_interface_seg: u16,
51     pub vbe_interface_off: u16,
52     pub vbe_interface_len: u16,
53 
54     pub framebuffer_addr: u64,
55     pub framebuffer_pitch: u32,
56     pub framebuffer_width: u32,
57     pub framebuffer_height: u32,
58     pub framebuffer_bpp: u8,
59     pub framebuffer_type: u8,
60 
61     // TODO: add union for palette + RGB color info if needed
62     pub color_info: [u8; 6],
63 }
64 
65 impl MultibootInfo {
66     pub const F_MEM: u32 = 1 << 0;
67     pub const F_BOOT_DEVICE: u32 = 1 << 1;
68     pub const F_CMDLINE: u32 = 1 << 2;
69     pub const F_MODS: u32 = 1 << 3;
70     pub const F_SYMS_AOUT: u32 = 1 << 4;
71     pub const F_SYMS_ELF: u32 = 1 << 5;
72     pub const F_MMAP: u32 = 1 << 6;
73     pub const F_DRIVES: u32 = 1 << 7;
74     pub const F_CONFIG_TABLE: u32 = 1 << 8;
75     pub const F_BOOT_LOADER_NAME: u32 = 1 << 9;
76     pub const F_APM_TABLE: u32 = 1 << 10;
77     pub const F_VBE: u32 = 1 << 11;
78     pub const F_FRAMEBUFFER: u32 = 1 << 12;
79 }
80 
81 #[derive(Debug, Default, FromBytes, Immutable, IntoBytes, KnownLayout)]
82 #[repr(C, packed)]
83 pub struct MultibootMmapEntry {
84     pub size: u32,
85     pub base_addr: u64,
86     pub length: u64,
87     pub type_: u32,
88 }
89 
90 #[cfg(test)]
91 mod tests {
92     use std::mem::offset_of;
93     use std::mem::size_of;
94 
95     use super::*;
96 
97     #[test]
test_multiboot_info_offsets()98     fn test_multiboot_info_offsets() {
99         // Validate that multiboot_info field offsets match the spec.
100         assert_eq!(0, offset_of!(MultibootInfo, flags));
101         assert_eq!(4, offset_of!(MultibootInfo, mem_lower));
102         assert_eq!(8, offset_of!(MultibootInfo, mem_upper));
103         assert_eq!(8, offset_of!(MultibootInfo, mem_upper));
104         assert_eq!(12, offset_of!(MultibootInfo, boot_device));
105         assert_eq!(16, offset_of!(MultibootInfo, cmdline));
106         assert_eq!(20, offset_of!(MultibootInfo, mods_count));
107         assert_eq!(24, offset_of!(MultibootInfo, mods_addr));
108         assert_eq!(28, offset_of!(MultibootInfo, syms));
109         assert_eq!(44, offset_of!(MultibootInfo, mmap_length));
110         assert_eq!(48, offset_of!(MultibootInfo, mmap_addr));
111         assert_eq!(52, offset_of!(MultibootInfo, drives_length));
112         assert_eq!(56, offset_of!(MultibootInfo, drives_addr));
113         assert_eq!(60, offset_of!(MultibootInfo, config_table));
114         assert_eq!(64, offset_of!(MultibootInfo, boot_loader_name));
115         assert_eq!(68, offset_of!(MultibootInfo, apm_table));
116         assert_eq!(72, offset_of!(MultibootInfo, vbe_control_info));
117         assert_eq!(76, offset_of!(MultibootInfo, vbe_mode_info));
118         assert_eq!(80, offset_of!(MultibootInfo, vbe_mode));
119         assert_eq!(82, offset_of!(MultibootInfo, vbe_interface_seg));
120         assert_eq!(84, offset_of!(MultibootInfo, vbe_interface_off));
121         assert_eq!(86, offset_of!(MultibootInfo, vbe_interface_len));
122         assert_eq!(88, offset_of!(MultibootInfo, framebuffer_addr));
123         assert_eq!(96, offset_of!(MultibootInfo, framebuffer_pitch));
124         assert_eq!(100, offset_of!(MultibootInfo, framebuffer_width));
125         assert_eq!(104, offset_of!(MultibootInfo, framebuffer_height));
126         assert_eq!(108, offset_of!(MultibootInfo, framebuffer_bpp));
127         assert_eq!(109, offset_of!(MultibootInfo, framebuffer_type));
128         assert_eq!(110, offset_of!(MultibootInfo, color_info));
129 
130         assert_eq!(size_of::<MultibootInfo>(), 116);
131     }
132 
133     #[test]
test_multiboot_mmap_entry_offsets()134     fn test_multiboot_mmap_entry_offsets() {
135         // The spec defines the mmap entry structure in a confusing way (`size` at offset -4 and
136         // `base_addr` at offset 0), but this does not match how both bootloaders and kernels have
137         // implemented Multiboot (`size` at offset 0), so this does not exactly match the table in
138         // the spec.
139         assert_eq!(0, offset_of!(MultibootMmapEntry, size));
140         assert_eq!(4, offset_of!(MultibootMmapEntry, base_addr));
141         assert_eq!(12, offset_of!(MultibootMmapEntry, length));
142         assert_eq!(20, offset_of!(MultibootMmapEntry, type_));
143 
144         assert_eq!(size_of::<MultibootMmapEntry>(), 24); // 20-byte e820 data + 4 bytes for size
145     }
146 }
147