|
| 1 | +use core::mem; |
| 2 | + |
| 3 | +use crate::{ |
| 4 | + common, |
| 5 | + fat::{Error, Read}, |
| 6 | + mem::MemoryRegion, |
| 7 | +}; |
| 8 | + |
| 9 | +// Common data needed for all boot paths |
| 10 | +pub trait Info { |
| 11 | + fn rsdp_addr(&self) -> u64; |
| 12 | + fn cmdline(&self) -> &str; |
| 13 | + fn num_entries(&self) -> u8; |
| 14 | + fn entry(&self, idx: u8) -> E820Entry; |
| 15 | +} |
| 16 | + |
| 17 | +#[derive(Clone, Copy, Debug)] |
| 18 | +#[repr(C, packed(4))] |
| 19 | +pub struct E820Entry { |
| 20 | + pub addr: u64, |
| 21 | + pub size: u64, |
| 22 | + pub entry_type: u32, |
| 23 | +} |
| 24 | + |
| 25 | +impl E820Entry { |
| 26 | + pub const RAM_TYPE: u32 = 1; |
| 27 | +} |
| 28 | + |
| 29 | +// The so-called "zeropage" |
| 30 | +#[derive(Clone, Copy)] |
| 31 | +#[repr(C, align(4096))] |
| 32 | +pub struct Params { |
| 33 | + screen_info: ScreenInfo, // 0x000 |
| 34 | + apm_bios_info: ApmBiosInfo, // 0x040 |
| 35 | + _pad2: [u8; 4], // 0x054 |
| 36 | + tboot_addr: u64, // 0x058 |
| 37 | + ist_info: IstInfo, // 0x060 |
| 38 | + pub acpi_rsdp_addr: u64, // 0x070 |
| 39 | + _pad3: [u8; 8], // 0x078 |
| 40 | + hd0_info: HdInfo, // 0x080 - obsolete |
| 41 | + hd1_info: HdInfo, // 0x090 - obsolete |
| 42 | + sys_desc_table: SysDescTable, // 0x0a0 - obsolete |
| 43 | + olpc_ofw_header: OlpcOfwHeader, // 0x0b0 |
| 44 | + ext_ramdisk_image: u32, // 0x0c0 |
| 45 | + ext_ramdisk_size: u32, // 0x0c4 |
| 46 | + ext_cmd_line_ptr: u32, // 0x0c8 |
| 47 | + _pad4: [u8; 0x74], // 0x0cc |
| 48 | + edd_info: EdidInfo, // 0x140 |
| 49 | + efi_info: EfiInfo, // 0x1c0 |
| 50 | + alt_mem_k: u32, // 0x1e0 |
| 51 | + scratch: u32, // 0x1e4 |
| 52 | + e820_entries: u8, // 0x1e8 |
| 53 | + eddbuf_entries: u8, // 0x1e9 |
| 54 | + edd_mbr_sig_buf_entries: u8, // 0x1ea |
| 55 | + kbd_status: u8, // 0x1eb |
| 56 | + secure_boot: u8, // 0x1ec |
| 57 | + _pad5: [u8; 2], // 0x1ed |
| 58 | + sentinel: u8, // 0x1ef |
| 59 | + pub hdr: Header, // 0x1f0 |
| 60 | + _pad7: [u8; 0x290 - HEADER_END], |
| 61 | + edd_mbr_sig_buffer: [u32; 16], // 0x290 |
| 62 | + e820_table: [E820Entry; 128], // 0x2d0 |
| 63 | + _pad8: [u8; 0x30], // 0xcd0 |
| 64 | + eddbuf: [EddInfo; 6], // 0xd00 |
| 65 | + _pad9: [u8; 0x114], // 0xeec |
| 66 | +} |
| 67 | + |
| 68 | +impl Params { |
| 69 | + pub fn new() -> Self { |
| 70 | + // SAFETY: Struct consists entirely of primitive integral types. |
| 71 | + unsafe { mem::zeroed() } |
| 72 | + } |
| 73 | + pub fn set_entries(&mut self, info: &dyn Info) { |
| 74 | + self.e820_entries = info.num_entries(); |
| 75 | + for i in 0..self.e820_entries { |
| 76 | + self.e820_table[i as usize] = info.entry(i); |
| 77 | + } |
| 78 | + } |
| 79 | +} |
| 80 | + |
| 81 | +impl Info for Params { |
| 82 | + fn rsdp_addr(&self) -> u64 { |
| 83 | + self.acpi_rsdp_addr |
| 84 | + } |
| 85 | + fn cmdline(&self) -> &str { |
| 86 | + unsafe { common::from_cstring(self.hdr.cmd_line_ptr as u64) } |
| 87 | + } |
| 88 | + fn num_entries(&self) -> u8 { |
| 89 | + self.e820_entries |
| 90 | + } |
| 91 | + fn entry(&self, idx: u8) -> E820Entry { |
| 92 | + assert!(idx < self.num_entries()); |
| 93 | + self.e820_table[idx as usize] |
| 94 | + } |
| 95 | +} |
| 96 | + |
| 97 | +// The normal Linux setup_header has an offset of 0x1f1 in BootParams and the |
| 98 | +// kernel image. We use an additonal padding field, so that the structure is |
| 99 | +// properly aligned, meaning this structure uses an offset of 0x1f0. |
| 100 | +const HEADER_START: usize = 0x1f0; |
| 101 | +const HEADER_END: usize = HEADER_START + mem::size_of::<Header>(); |
| 102 | + |
| 103 | +#[derive(Clone, Copy, Debug)] |
| 104 | +#[repr(C)] |
| 105 | +pub struct Header { |
| 106 | + _pad6: u8, |
| 107 | + pub setup_sects: u8, |
| 108 | + pub root_flags: u16, |
| 109 | + pub syssize: u32, |
| 110 | + pub ram_size: u16, |
| 111 | + pub vid_mode: u16, |
| 112 | + pub root_dev: u16, |
| 113 | + pub boot_flag: u16, |
| 114 | + pub jump: u16, |
| 115 | + pub header: [u8; 4], |
| 116 | + pub version: u16, |
| 117 | + pub realmode_swtch: u32, |
| 118 | + pub start_sys_seg: u16, |
| 119 | + pub kernel_version: u16, |
| 120 | + pub type_of_loader: u8, |
| 121 | + pub loadflags: u8, |
| 122 | + pub setup_move_size: u16, |
| 123 | + pub code32_start: u32, |
| 124 | + pub ramdisk_image: u32, |
| 125 | + pub ramdisk_size: u32, |
| 126 | + pub bootsect_kludge: u32, |
| 127 | + pub heap_end_ptr: u16, |
| 128 | + pub ext_loader_ver: u8, |
| 129 | + pub ext_loader_type: u8, |
| 130 | + pub cmd_line_ptr: u32, |
| 131 | + pub initrd_addr_max: u32, |
| 132 | + pub kernel_alignment: u32, |
| 133 | + pub relocatable_kernel: u8, |
| 134 | + pub min_alignment: u8, |
| 135 | + pub xloadflags: u16, |
| 136 | + pub cmdline_size: u32, |
| 137 | + pub hardware_subarch: u32, |
| 138 | + pub hardware_subarch_data: u64, |
| 139 | + pub payload_offset: u32, |
| 140 | + pub payload_length: u32, |
| 141 | + pub setup_data: u64, |
| 142 | + pub pref_address: u64, |
| 143 | + pub init_size: u32, |
| 144 | + pub handover_offset: u32, |
| 145 | +} |
| 146 | + |
| 147 | +impl Header { |
| 148 | + pub fn from_file(f: &mut dyn Read) -> Result<Self, Error> { |
| 149 | + let mut data: [u8; 1024] = [0; 1024]; |
| 150 | + let mut region = MemoryRegion::from_bytes(&mut data); |
| 151 | + |
| 152 | + f.seek(0)?; |
| 153 | + f.load_file(&mut region)?; |
| 154 | + |
| 155 | + #[repr(C)] |
| 156 | + struct HeaderData { |
| 157 | + before: [u8; HEADER_START], |
| 158 | + hdr: Header, |
| 159 | + after: [u8; 1024 - HEADER_END], |
| 160 | + } |
| 161 | + // SAFETY: Struct consists entirely of primitive integral types. |
| 162 | + Ok(unsafe { mem::transmute::<_, HeaderData>(data) }.hdr) |
| 163 | + } |
| 164 | +} |
| 165 | + |
| 166 | +// Right now the stucts below are unused, so we only need them to be the correct |
| 167 | +// size. Update test_size_and_offset if a struct's real definition is added. |
| 168 | +#[derive(Clone, Copy)] |
| 169 | +#[repr(C, align(4))] |
| 170 | +struct ScreenInfo([u8; 0x40]); |
| 171 | +#[derive(Clone, Copy)] |
| 172 | +#[repr(C, align(4))] |
| 173 | +struct ApmBiosInfo([u8; 0x14]); |
| 174 | +#[derive(Clone, Copy)] |
| 175 | +#[repr(C, align(4))] |
| 176 | +struct IstInfo([u8; 0x10]); |
| 177 | +#[derive(Clone, Copy)] |
| 178 | +#[repr(C, align(16))] |
| 179 | +struct HdInfo([u8; 0x10]); |
| 180 | +#[derive(Clone, Copy)] |
| 181 | +#[repr(C, align(2))] |
| 182 | +struct SysDescTable([u8; 0x10]); |
| 183 | +#[derive(Clone, Copy)] |
| 184 | +#[repr(C, align(4))] |
| 185 | +struct OlpcOfwHeader([u8; 0x10]); |
| 186 | +#[derive(Clone, Copy)] |
| 187 | +#[repr(C, align(4))] |
| 188 | +struct EdidInfo([u8; 0x80]); |
| 189 | +#[derive(Clone, Copy)] |
| 190 | +#[repr(C, align(4))] |
| 191 | +struct EfiInfo([u8; 0x20]); |
| 192 | +#[derive(Clone, Copy)] |
| 193 | +#[repr(C, align(2))] |
| 194 | +struct EddInfo([u8; 0x52]); |
| 195 | + |
| 196 | +#[cfg(test)] |
| 197 | +mod tests { |
| 198 | + use super::*; |
| 199 | + #[test] |
| 200 | + fn test_size_and_offset() { |
| 201 | + assert_eq!(mem::size_of::<Header>(), 120); |
| 202 | + assert_eq!(mem::size_of::<E820Entry>(), 20); |
| 203 | + assert_eq!(mem::size_of::<Params>(), 4096); |
| 204 | + |
| 205 | + assert_eq!(offset_of!(Params, hdr), HEADER_START); |
| 206 | + } |
| 207 | +} |
0 commit comments