Skip to main content

linux_boot_params/
lib.rs

1// SPDX-License-Identifier: MPL-2.0
2
3//! The definition of Linux Boot Protocol boot_params struct.
4//!
5//! The bootloader will deliver the address of the `BootParams` struct
6//! as the argument of the kernel entrypoint. So we must define a Linux
7//! ABI compatible struct in Rust, despite that most of the fields are
8//! currently not needed by Asterinas.
9//!
10
11#![cfg_attr(not(test), no_std)]
12
13/// Magic stored in the boot protocol header.
14pub const LINUX_BOOT_HEADER_MAGIC: u32 = 0x53726448;
15
16/// Linux 32/64-bit Boot Protocol parameter struct.
17///
18/// Originally defined in the linux source tree:
19/// `linux/arch/x86/include/uapi/asm/bootparam.h`
20#[repr(C, packed)]
21#[derive(Clone, Copy, Debug)]
22pub struct BootParams {
23    pub screen_info: ScreenInfo,        /* 0x000 */
24    pub apm_bios_info: ApmBiosInfo,     /* 0x040 */
25    pub _pad2: [u8; 4],                 /* 0x054 */
26    pub tboot_addr: u64,                /* 0x058 */
27    pub ist_info: IstInfo,              /* 0x060 */
28    pub acpi_rsdp_addr: u64,            /* 0x070 */
29    pub _pad3: [u8; 8],                 /* 0x078 */
30    pub hd0_info: [u8; 16],             /* obsolete! 0x080 */
31    pub hd1_info: [u8; 16],             /* obsolete! 0x090 */
32    pub sys_desc_table: SysDescTable,   /* obsolete! 0x0a0 */
33    pub olpc_ofw_header: OlpcOfwHeader, /* 0x0b0 */
34    pub ext_ramdisk_image: u32,         /* 0x0c0 */
35    pub ext_ramdisk_size: u32,          /* 0x0c4 */
36    pub ext_cmd_line_ptr: u32,          /* 0x0c8 */
37    pub _pad4: [u8; 112],               /* 0x0cc */
38    pub cc_blob_address: u32,           /* 0x13c */
39    pub edid_info: EdidInfo,            /* 0x140 */
40    pub efi_info: EfiInfo,              /* 0x1c0 */
41    pub alt_mem_k: u32,                 /* 0x1e0 */
42    pub scratch: u32,                   /* Scratch field! 0x1e4 */
43    pub e820_entries: u8,               /* 0x1e8 */
44    pub eddbuf_entries: u8,             /* 0x1e9 */
45    pub edd_mbr_sig_buf_entries: u8,    /* 0x1ea */
46    pub kbd_status: u8,                 /* 0x1eb */
47    pub secure_boot: u8,                /* 0x1ec */
48    pub _pad5: [u8; 2],                 /* 0x1ed */
49    pub sentinel: u8,                   /* 0x1ef */
50    pub _pad6: [u8; 1],                 /* 0x1f0 */
51    pub hdr: SetupHeader,               /* setup header 0x1f1 */
52    pub _pad7: [u8; 0x290 - 0x1f1 - size_of::<SetupHeader>()],
53    pub edd_mbr_sig_buffer: [u32; EDD_MBR_SIG_MAX], /* 0x290 */
54    pub e820_table: [BootE820Entry; E820_MAX_ENTRIES_ZEROPAGE], /* 0x2d0 */
55    pub _pad8: [u8; 48],                            /* 0xcd0 */
56    pub eddbuf: [EddInfo; EDDMAXNR],                /* 0xd00 */
57    pub _pad9: [u8; 276],                           /* 0xeec */
58}
59
60/// Linux Boot Protocol header.
61///
62/// Originally defined in the linux source tree:
63/// `linux/arch/x86/include/uapi/asm/bootparam.h`
64#[repr(C, packed)]
65#[derive(Clone, Copy, Debug)]
66pub struct SetupHeader {
67    pub setup_sects: u8,
68    pub root_flags: u16,
69    pub syssize: u32,
70    pub ram_size: u16,
71    pub vid_mode: u16,
72    pub root_dev: u16,
73    pub boot_flag: u16,
74    pub jump: u16,
75    pub header: u32,
76    pub version: u16,
77    pub realmode_swtch: u32,
78    pub start_sys_seg: u16,
79    pub kernel_version: u16,
80    pub type_of_loader: u8,
81    pub loadflags: u8,
82    pub setup_move_size: u16,
83    pub code32_start: u32,
84    pub ramdisk_image: u32,
85    pub ramdisk_size: u32,
86    pub bootsect_kludge: u32,
87    pub heap_end_ptr: u16,
88    pub ext_loader_ver: u8,
89    pub ext_loader_type: u8,
90    pub cmd_line_ptr: u32,
91    pub initrd_addr_max: u32,
92    pub kernel_alignment: u32,
93    pub relocatable_kernel: u8,
94    pub min_alignment: u8,
95    pub xloadflags: u16,
96    pub cmdline_size: u32,
97    pub hardware_subarch: u32,
98    pub hardware_subarch_data: u64,
99    pub payload_offset: u32,
100    pub payload_length: u32,
101    pub setup_data: u64,
102    pub pref_address: u64,
103    pub init_size: u32,
104    pub handover_offset: u32,
105    pub kernel_info_offset: u32,
106}
107
108#[repr(C, packed)]
109#[derive(Clone, Copy, Debug)]
110pub struct ScreenInfo {
111    pub orig_x: u8,             /* 0x00 */
112    pub orig_y: u8,             /* 0x01 */
113    pub ext_mem_k: u16,         /* 0x02 */
114    pub orig_video_page: u16,   /* 0x04 */
115    pub orig_video_mode: u8,    /* 0x06 */
116    pub orig_video_cols: u8,    /* 0x07 */
117    pub flags: u8,              /* 0x08 */
118    pub unused2: u8,            /* 0x09 */
119    pub orig_video_ega_bx: u16, /* 0x0a */
120    pub unused3: u16,           /* 0x0c */
121    pub orig_video_lines: u8,   /* 0x0e */
122    pub orig_video_is_vga: u8,  /* 0x0f */
123    pub orig_video_points: u16, /* 0x10 */
124
125    /* VESA graphic mode -- linear frame buffer */
126    pub lfb_width: u16,  /* 0x12 */
127    pub lfb_height: u16, /* 0x14 */
128    pub lfb_depth: u16,  /* 0x16 */
129    pub lfb_base: u32,   /* 0x18 */
130    pub lfb_size: u32,   /* 0x1c */
131    pub cl_magic: u16,
132    pub cl_offset: u16,       /* 0x20 */
133    pub lfb_linelength: u16,  /* 0x24 */
134    pub red_size: u8,         /* 0x26 */
135    pub red_pos: u8,          /* 0x27 */
136    pub green_size: u8,       /* 0x28 */
137    pub green_pos: u8,        /* 0x29 */
138    pub blue_size: u8,        /* 0x2a */
139    pub blue_pos: u8,         /* 0x2b */
140    pub rsvd_size: u8,        /* 0x2c */
141    pub rsvd_pos: u8,         /* 0x2d */
142    pub vesapm_seg: u16,      /* 0x2e */
143    pub vesapm_off: u16,      /* 0x30 */
144    pub pages: u16,           /* 0x32 */
145    pub vesa_attributes: u16, /* 0x34 */
146    pub capabilities: u32,    /* 0x36 */
147    pub ext_lfb_base: u32,    /* 0x3a */
148    pub _reserved: [u8; 2],   /* 0x3e */
149}
150
151#[repr(C, packed)]
152#[derive(Clone, Copy, Debug)]
153pub struct ApmBiosInfo {
154    pub version: u16,
155    pub cseg: u16,
156    pub offset: u32,
157    pub cseg_16: u16,
158    pub dseg: u16,
159    pub flags: u16,
160    pub cseg_len: u16,
161    pub cseg_16_len: u16,
162    pub dseg_len: u16,
163}
164
165#[repr(C, packed)]
166#[derive(Clone, Copy, Debug)]
167pub struct IstInfo {
168    pub signature: u32,
169    pub command: u32,
170    pub event: u32,
171    pub perf_level: u32,
172}
173
174#[repr(C, packed)]
175#[derive(Clone, Copy, Debug)]
176pub struct SysDescTable {
177    pub length: u16,
178    pub table: [u8; 14],
179}
180
181#[repr(C, packed)]
182#[derive(Clone, Copy, Debug)]
183pub struct OlpcOfwHeader {
184    pub ofw_magic: u32, /* OFW signature */
185    pub ofw_version: u32,
186    pub cif_handler: u32, /* callback into OFW */
187    pub irq_desc_table: u32,
188}
189
190#[repr(C)]
191#[derive(Clone, Copy, Debug)]
192pub struct EdidInfo {
193    pub dummy: [u8; 128],
194}
195
196#[repr(C)]
197#[derive(Clone, Copy, Debug)]
198pub struct EfiInfo {
199    pub efi_loader_signature: u32,
200    pub efi_systab: u32,
201    pub efi_memdesc_size: u32,
202    pub efi_memdesc_version: u32,
203    pub efi_memmap: u32,
204    pub efi_memmap_size: u32,
205    pub efi_systab_hi: u32,
206    pub efi_memmap_hi: u32,
207}
208
209impl EfiInfo {
210    /// EFI loader signature used by the Intel TDX guest boot path (`AS64`).
211    ///
212    /// With this signature, `efi_systab` holds the physical address of the
213    /// unaccepted-memory table (header and bitmap), or zero if absent, rather
214    /// than an EFI system table. The address is below 4 GiB and
215    /// `efi_systab_hi` is zero.
216    pub const TDX_LOADER_SIGNATURE: u32 = u32::from_le_bytes(*b"AS64");
217}
218
219/// The E820 types known to the kernel.
220///
221/// Originally defined in the linux source tree:
222/// `linux/arch/x86/include/asm/e820/types.h`
223#[repr(transparent)]
224#[derive(Clone, Copy, Debug, Eq, PartialEq)]
225pub struct E820Type(pub u32);
226
227impl E820Type {
228    pub const RAM: Self = Self(1);
229    pub const RESERVED: Self = Self(2);
230    pub const ACPI: Self = Self(3);
231    pub const NVS: Self = Self(4);
232    pub const UNUSABLE: Self = Self(5);
233    pub const PMEM: Self = Self(7);
234    pub const PRAM: Self = Self(12);
235    pub const SOFT_RESERVED: Self = Self(0xefffffff);
236    pub const RESERVED_KERN: Self = Self(128);
237}
238
239#[repr(C, packed)]
240#[derive(Clone, Copy, Debug)]
241pub struct BootE820Entry {
242    pub addr: u64,
243    pub size: u64,
244    pub typ: E820Type,
245}
246
247const E820_MAX_ENTRIES_ZEROPAGE: usize = 128;
248
249#[repr(C, packed)]
250#[derive(Clone, Copy, Debug)]
251pub struct EddDeviceParams {
252    // TODO: We currently have no plans to support the edd device,
253    // and we need unnamed fields (Rust RFC 2102) to implement this
254    // FFI neatly. So we put a dummy implementation here conforming
255    // to the BootParams struct ABI.
256    pub _dummy: [u8; (0xeec - 0xd00) / 6 - 8],
257}
258
259#[repr(C, packed)]
260#[derive(Clone, Copy, Debug)]
261pub struct EddInfo {
262    pub device: u8,
263    pub version: u8,
264    pub interface_support: u16,
265    pub legacy_max_cylinder: u16,
266    pub legacy_max_head: u8,
267    pub legacy_sectors_per_track: u8,
268    pub params: EddDeviceParams,
269}
270
271const EDD_MBR_SIG_MAX: usize = 16;
272const EDDMAXNR: usize = 6;
273
274#[cfg(test)]
275mod tests {
276    use core::mem::offset_of;
277
278    use super::*;
279
280    #[test]
281    fn screen_info_offsets() {
282        assert_eq!(offset_of!(ScreenInfo, orig_x), 0x00);
283        assert_eq!(offset_of!(ScreenInfo, orig_y), 0x01);
284        assert_eq!(offset_of!(ScreenInfo, ext_mem_k), 0x02);
285        assert_eq!(offset_of!(ScreenInfo, orig_video_page), 0x04);
286        assert_eq!(offset_of!(ScreenInfo, orig_video_mode), 0x06);
287        assert_eq!(offset_of!(ScreenInfo, orig_video_cols), 0x07);
288        assert_eq!(offset_of!(ScreenInfo, flags), 0x08);
289        assert_eq!(offset_of!(ScreenInfo, unused2), 0x09);
290        assert_eq!(offset_of!(ScreenInfo, orig_video_ega_bx), 0x0a);
291        assert_eq!(offset_of!(ScreenInfo, unused3), 0x0c);
292        assert_eq!(offset_of!(ScreenInfo, orig_video_lines), 0x0e);
293        assert_eq!(offset_of!(ScreenInfo, orig_video_is_vga), 0x0f);
294        assert_eq!(offset_of!(ScreenInfo, orig_video_points), 0x10);
295        assert_eq!(offset_of!(ScreenInfo, lfb_width), 0x12);
296        assert_eq!(offset_of!(ScreenInfo, lfb_height), 0x14);
297        assert_eq!(offset_of!(ScreenInfo, lfb_depth), 0x16);
298        assert_eq!(offset_of!(ScreenInfo, lfb_base), 0x18);
299        assert_eq!(offset_of!(ScreenInfo, lfb_size), 0x1c);
300        assert_eq!(offset_of!(ScreenInfo, cl_magic), 0x20);
301        assert_eq!(offset_of!(ScreenInfo, cl_offset), 0x22);
302        assert_eq!(offset_of!(ScreenInfo, lfb_linelength), 0x24);
303        assert_eq!(offset_of!(ScreenInfo, red_size), 0x26);
304        assert_eq!(offset_of!(ScreenInfo, red_pos), 0x27);
305        assert_eq!(offset_of!(ScreenInfo, green_size), 0x28);
306        assert_eq!(offset_of!(ScreenInfo, green_pos), 0x29);
307        assert_eq!(offset_of!(ScreenInfo, blue_size), 0x2a);
308        assert_eq!(offset_of!(ScreenInfo, blue_pos), 0x2b);
309        assert_eq!(offset_of!(ScreenInfo, rsvd_size), 0x2c);
310        assert_eq!(offset_of!(ScreenInfo, rsvd_pos), 0x2d);
311        assert_eq!(offset_of!(ScreenInfo, vesapm_seg), 0x2e);
312        assert_eq!(offset_of!(ScreenInfo, vesapm_off), 0x30);
313        assert_eq!(offset_of!(ScreenInfo, pages), 0x32);
314        assert_eq!(offset_of!(ScreenInfo, vesa_attributes), 0x34);
315        assert_eq!(offset_of!(ScreenInfo, capabilities), 0x36);
316        assert_eq!(offset_of!(ScreenInfo, ext_lfb_base), 0x3a);
317    }
318
319    #[test]
320    fn boot_params_offsets() {
321        assert_eq!(offset_of!(BootParams, screen_info), 0x000);
322        assert_eq!(offset_of!(BootParams, apm_bios_info), 0x040);
323        assert_eq!(offset_of!(BootParams, tboot_addr), 0x058);
324        assert_eq!(offset_of!(BootParams, ist_info), 0x060);
325        assert_eq!(offset_of!(BootParams, acpi_rsdp_addr), 0x070);
326        assert_eq!(offset_of!(BootParams, hd0_info), 0x080);
327        assert_eq!(offset_of!(BootParams, hd1_info), 0x090);
328        assert_eq!(offset_of!(BootParams, sys_desc_table), 0x0a0);
329        assert_eq!(offset_of!(BootParams, olpc_ofw_header), 0x0b0);
330        assert_eq!(offset_of!(BootParams, ext_ramdisk_image), 0x0c0);
331        assert_eq!(offset_of!(BootParams, ext_ramdisk_size), 0x0c4);
332        assert_eq!(offset_of!(BootParams, ext_cmd_line_ptr), 0x0c8);
333        assert_eq!(offset_of!(BootParams, cc_blob_address), 0x13c);
334        assert_eq!(offset_of!(BootParams, edid_info), 0x140);
335        assert_eq!(offset_of!(BootParams, efi_info), 0x1c0);
336        assert_eq!(offset_of!(BootParams, alt_mem_k), 0x1e0);
337        assert_eq!(offset_of!(BootParams, scratch), 0x1e4);
338        assert_eq!(offset_of!(BootParams, e820_entries), 0x1e8);
339        assert_eq!(offset_of!(BootParams, eddbuf_entries), 0x1e9);
340        assert_eq!(offset_of!(BootParams, edd_mbr_sig_buf_entries), 0x1ea);
341        assert_eq!(offset_of!(BootParams, kbd_status), 0x1eb);
342        assert_eq!(offset_of!(BootParams, secure_boot), 0x1ec);
343        assert_eq!(offset_of!(BootParams, sentinel), 0x1ef);
344        assert_eq!(offset_of!(BootParams, hdr), 0x1f1);
345        assert_eq!(offset_of!(BootParams, edd_mbr_sig_buffer), 0x290);
346        assert_eq!(offset_of!(BootParams, e820_table), 0x2d0);
347        assert_eq!(offset_of!(BootParams, eddbuf), 0xd00);
348    }
349}