98 lines
4.0 KiB
Zig
98 lines
4.0 KiB
Zig
//! Shared definitions that form the contract between the bootloader
|
|
//! (src/efi.zig, built as BOOTX64.efi) and the kernel (src/main.zig).
|
|
//!
|
|
//! Both binaries import this as the "danos" module, so the handoff layout is
|
|
//! defined in exactly one place.
|
|
|
|
const std = @import("std");
|
|
|
|
/// Calling convention for the bootloader→kernel jump. Pinned to SysV so it does
|
|
/// not depend on each binary's target default: the UEFI bootloader's C
|
|
/// convention is Microsoft x64 (first arg in RCX), the freestanding kernel's is
|
|
/// SysV (first arg in RDI). Both reference this to agree on where `*BootInfo`
|
|
/// is passed.
|
|
pub const kernel_abi: std.builtin.CallingConvention = .{ .x86_64_sysv = .{} };
|
|
|
|
/// Pixel byte order of the linear framebuffer the firmware handed us.
|
|
pub const PixelFormat = enum(u32) {
|
|
/// Byte 0 = Red, 1 = Green, 2 = Blue, 3 = reserved.
|
|
rgbx,
|
|
/// Byte 0 = Blue, 1 = Green, 2 = Red, 3 = reserved.
|
|
bgrx,
|
|
};
|
|
|
|
/// A linear framebuffer: `width`x`height` pixels, each a 32-bit value, with
|
|
/// `pitch` bytes between the start of one row and the next (which may be larger
|
|
/// than `width * 4` due to hardware padding).
|
|
pub const Framebuffer = extern struct {
|
|
base: usize, // the memory address where pixel data starts
|
|
width: u32, // visible pixels per row (e.g. 1920)
|
|
height: u32, // visible rows (e.g. 1080)
|
|
pitch: u32, // bytes from the start of one row to the start of the next
|
|
format: PixelFormat,
|
|
};
|
|
|
|
/// Page size the memory map is measured in. 4 KiB on every architecture danos
|
|
/// targets so far.
|
|
pub const page_size = 4096;
|
|
|
|
/// danos's own classification of a span of physical memory — deliberately not
|
|
/// UEFI's vocabulary. Each boot path (UEFI now, device tree later) translates its
|
|
/// native memory description into these kinds, so the kernel never learns what
|
|
/// booted it. [[arch]] keeps the same discipline for CPU code.
|
|
pub const MemoryKind = enum(u32) {
|
|
/// Free RAM the kernel may allocate.
|
|
usable,
|
|
/// Firmware, MMIO, the kernel image, our own boot buffers — never hand out.
|
|
reserved,
|
|
/// Usable once the kernel is done with boot-time structures (e.g. UEFI boot
|
|
/// services memory, which is free after ExitBootServices).
|
|
reclaimable,
|
|
/// ACPI tables: parse, then reclaim.
|
|
acpi_tables,
|
|
/// ACPI non-volatile storage: preserve across sleep, do not allocate.
|
|
acpi_nvs,
|
|
/// Not backed by RAM: memory-mapped device registers or a reserved
|
|
/// address-space window (e.g. PCIe config space). Kept distinct from
|
|
/// `reserved` so RAM accounting doesn't count device address space.
|
|
mmio,
|
|
};
|
|
|
|
/// One contiguous span of physical memory. Because danos defines this layout
|
|
/// itself (unlike the UEFI descriptor it's built from), `@sizeOf` is
|
|
/// authoritative — the kernel walks a plain `[]MemoryRegion`, with none of the
|
|
/// firmware's variable descriptor-stride to worry about.
|
|
pub const MemoryRegion = extern struct {
|
|
base: u64, // physical start address
|
|
pages: u64, // length in `page_size` units
|
|
kind: MemoryKind,
|
|
_pad: u32 = 0,
|
|
};
|
|
|
|
/// The physical memory layout handed to the kernel: a pointer to an array of
|
|
/// `len` `MemoryRegion`s, in a buffer that outlives the loader.
|
|
pub const MemoryMap = extern struct {
|
|
regions: usize, // address of a `[len]MemoryRegion`
|
|
len: usize,
|
|
};
|
|
|
|
/// One PT_LOAD segment of the kernel image, so the kernel can re-map itself with
|
|
/// correct permissions (code R+X, rodata R, data R+W+NX). `flags` are raw ELF
|
|
/// segment flags: PF_X=1, PF_W=2, PF_R=4.
|
|
pub const KernelSegment = extern struct {
|
|
virt: u64,
|
|
pages: u64,
|
|
flags: u32,
|
|
_pad: u32 = 0,
|
|
};
|
|
|
|
/// Handoff structure the bootloader fills in and passes to the kernel's
|
|
/// `_start` in RDI (the first argument under the SysV AMD64 C ABI).
|
|
pub const BootInfo = extern struct {
|
|
framebuffer: Framebuffer,
|
|
memory_map: MemoryMap,
|
|
/// The kernel's own PT_LOAD segments (it has three: text, rodata, data).
|
|
kernel_segments: [8]KernelSegment,
|
|
kernel_segment_count: u32,
|
|
};
|