Skip to main content

strat9_abi/
boot.rs

1//! Bootloader-to-kernel handoff ABI.
2//!
3//! This module defines the data structures passed from the bootloader
4//! (Limine) to the kernel at entry point. The kernel reads these structures
5//! to discover memory layout, ACPI tables, framebuffer configuration, and
6//! kernel modules.
7//!
8//! # Boot flow
9//!
10//! ```text
11//! BIOS/UEFI → Limine bootloader → kernel_main(KernelArgs)
12//! ```
13//!
14//! The bootloader populates `KernelArgs` on the initial stack or in a
15//! reserved memory region, then jumps to the kernel entry point with a
16//! pointer to this structure in a register (typically RDI on x86_64).
17//!
18//! # ABI stability
19//!
20//! The `KernelArgs` layout is frozen per ABI version. Changing the layout
21//! requires bumping [`STRAT9_BOOT_ABI_VERSION`] and updating both
22//! bootloader and kernel simultaneously.
23//!
24//! # Example (kernel side)
25//!
26//! ```ignore
27//! // In kernel_main():
28//! unsafe fn kernel_main(args: *const KernelArgs) -> ! {
29//!     let args = &*args;
30//!
31//!     // Validate magic number
32//!     assert_eq!(args.magic, STRAT9_BOOT_MAGIC);
33//!
34//!     // Validate ABI version
35//!     assert_eq!(args.abi_version, STRAT9_BOOT_ABI_VERSION);
36//!
37//!     // Use memory map to initialize buddy allocator
38//!     let mmap = core::slice::from_raw_parts(
39//!         args.memory_map_base as *const MemoryRegion,
40//!         args.memory_map_size as usize / core::mem::size_of::<MemoryRegion>(),
41//!     );
42//!
43//!     // Use ACPI RSDP to find ACPI tables
44//!     let rsdp = args.acpi_rsdp_base;
45//!
46//!     // Use framebuffer for early console
47//!     let fb_addr = args.framebuffer_addr;
48//!     let fb_w = args.framebuffer_width;
49//!     let fb_h = args.framebuffer_height;
50//! }
51//! ```
52
53use zerocopy::{FromBytes, IntoBytes};
54
55/// ABI version for the boot handoff structure.
56///
57/// Increment this when `KernelArgs` layout changes.
58pub const STRAT9_BOOT_ABI_VERSION: u32 = 1;
59
60/// Magic number validating the boot handoff (`"ST9B"` in ASCII).
61///
62/// The kernel must check this value before trusting any `KernelArgs` data.
63pub const STRAT9_BOOT_MAGIC: u32 = 0x5354_3942; // "ST9B"
64
65/// Bootloader-to-kernel handoff structure.
66///
67/// Passed by the bootloader to the kernel at entry point.
68/// Layout is `#[repr(C)]` for natural alignment across all fields.
69/// Total size: 160 bytes, alignment: 8 bytes.
70///
71/// # Field groups
72///
73/// ## Identity (8 bytes)
74/// - `magic`: must equal [`STRAT9_BOOT_MAGIC`] (`0x5354_3942`)
75/// - `abi_version`: must equal [`STRAT9_BOOT_ABI_VERSION`] (currently `1`)
76///
77/// ## Kernel memory (16 bytes)
78/// - `kernel_base`: physical address of the kernel ELF image
79/// - `kernel_size`: size of the kernel image in bytes
80///
81/// ## Boot stack (16 bytes)
82/// - `stack_base`: physical address of the initial kernel stack
83/// - `stack_size`: size of the initial stack in bytes
84///
85/// ## Environment (16 bytes)
86/// - `env_base`: physical address of the environment block
87/// - `env_size`: size of the environment block in bytes
88///
89/// ## ACPI (16 bytes)
90/// - `acpi_rsdp_base`: physical address of the RSDP (Root System Description Pointer)
91/// - `acpi_rsdp_size`: size of the RSDP in bytes (typically 36 or 276)
92///
93/// ## Memory map (16 bytes)
94/// - `memory_map_base`: physical address of the memory map array
95/// - `memory_map_size`: total size of the memory map in bytes
96///
97/// ## Init filesystem (16 bytes)
98/// - `initfs_base`: physical address of the init filesystem (cpio/tar archive)
99/// - `initfs_size`: size of the init filesystem in bytes
100///
101/// ## Framebuffer (32 bytes)
102/// - `framebuffer_addr`: physical address of the linear framebuffer
103/// - `framebuffer_width`: width in pixels
104/// - `framebuffer_height`: height in pixels
105/// - `framebuffer_stride`: bytes per row (may include padding)
106/// - `framebuffer_bpp`: bits per pixel (15, 16, 24, or 32)
107/// - `framebuffer_*_mask_size/shift`: RGB channel mask layout
108///
109/// ## HHDM (8 bytes)
110/// - `hhdm_offset`: Higher Half Direct Map offset (physical-to-virtual)
111///
112/// ## Command line (16 bytes)
113/// - `cmdline_ptr`: pointer to null-terminated kernel command line string
114/// - `cmdline_len`: length of the command line (including null terminator)
115#[derive(Debug, FromBytes, IntoBytes)]
116#[repr(C)]
117pub struct KernelArgs {
118    pub magic: u32,
119    pub abi_version: u32,
120    pub kernel_base: u64,
121    pub kernel_size: u64,
122    pub stack_base: u64,
123    pub stack_size: u64,
124    pub env_base: u64,
125    pub env_size: u64,
126    pub acpi_rsdp_base: u64,
127    pub acpi_rsdp_size: u64,
128    pub memory_map_base: u64,
129    pub memory_map_size: u64,
130    pub initfs_base: u64,
131    pub initfs_size: u64,
132    pub framebuffer_addr: u64,
133    pub framebuffer_width: u32,
134    pub framebuffer_height: u32,
135    pub framebuffer_stride: u32,
136    pub framebuffer_bpp: u16,
137    pub framebuffer_red_mask_size: u8,
138    pub framebuffer_red_mask_shift: u8,
139    pub framebuffer_green_mask_size: u8,
140    pub framebuffer_green_mask_shift: u8,
141    pub framebuffer_blue_mask_size: u8,
142    pub framebuffer_blue_mask_shift: u8,
143    pub _padding1: [u8; 4], // Align hhdm_offset to 8-byte boundary
144    pub hhdm_offset: u64,
145    /// Pointer to the kernel command line string (null-terminated C string).
146    pub cmdline_ptr: u64,
147    /// Length of the kernel command line string (including null terminator).
148    pub cmdline_len: u64,
149}
150
151/// Memory region descriptor for the bootloader memory map.
152///
153/// The memory map is an array of these descriptors, passed via
154/// `KernelArgs::memory_map_base` and `KernelArgs::memory_map_size`.
155/// Each descriptor is 24 bytes (aligned to 8).
156///
157/// # Example
158///
159/// ```text
160/// Region 1: base=0x0000_0000, size=0x0009_F000, kind=Free     (conventional memory)
161/// Region 2: base=0x0010_0000, size=0x7EF0_0000, kind=Free     (extended memory)
162/// Region 3: base=0xFD00_0000, size=0x0200_0000, kind=Reserved (MMIO, framebuffer)
163/// Region 4: base=0x7FE0_0000, size=0x0020_0000, kind=Reserved (ACPI NVS)
164/// ```
165#[derive(Debug, Clone, Copy, FromBytes, IntoBytes)]
166#[repr(C)]
167pub struct MemoryRegion {
168    /// Physical base address of the region.
169    pub base: u64,
170    /// Size of the region in bytes.
171    pub size: u64,
172    /// Region type (see [`MemoryKind`]).
173    pub kind: MemoryKind,
174}
175
176/// Memory region type identifier.
177///
178/// Used by the bootloader to communicate the memory map to the kernel.
179/// The kernel uses this to decide which regions can be used for the
180/// buddy allocator, which are reserved for hardware, etc.
181///
182/// # Example
183///
184/// ```ignore
185/// let regions = /* from KernelArgs */;
186/// for region in regions {
187///     match region.kind {
188///         MemoryKind::Free => {
189///             // Add to buddy allocator
190///             buddy_init_region(region.base, region.size);
191///         }
192///         MemoryKind::Reserved => {
193///             // Skip — hardware MMIO (framebuffer, APIC, etc.)
194///         }
195///         MemoryKind::Reclaim => {
196///             // Bootloader code — can be freed after init
197///             reclaim_region(region.base, region.size);
198///         }
199///         _ => {}
200///     }
201/// }
202/// ```
203#[derive(Clone, Copy, Debug, PartialEq, Eq, FromBytes, IntoBytes)]
204#[repr(transparent)]
205pub struct MemoryKind(pub u64);
206
207#[allow(non_upper_case_globals)]
208impl MemoryKind {
209    /// Null/invalid region (should not appear in the memory map).
210    pub const Null: Self = Self(0);
211
212    /// Free usable memory — available for kernel allocation.
213    pub const Free: Self = Self(1);
214
215    /// Bootloader-reclaimable memory — free after boot, before first use.
216    pub const Reclaim: Self = Self(2);
217
218    /// Reserved memory — hardware MMIO, firmware, ACPI NVS, etc.
219    /// Kernel must not allocate from these regions.
220    pub const Reserved: Self = Self(3);
221}
222
223// ABI size assertions for bootloader structures
224static_assertions::assert_eq_size!(KernelArgs, [u8; 160]);
225static_assertions::const_assert_eq!(core::mem::align_of::<KernelArgs>(), 8);
226static_assertions::assert_eq_size!(MemoryRegion, [u8; 24]);
227static_assertions::const_assert_eq!(core::mem::align_of::<MemoryRegion>(), 8);
228static_assertions::assert_eq_size!(MemoryKind, [u8; 8]);