//! 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, };