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