//! esp_app_desc_t, the 256-byte block the second-stage bootloader reads from image offset 0x20. //! //! Two facts about it were established by flashing deliberately broken images at this board: //! * the magic word is never validated in a default build - the descriptor is trusted purely by //! position, so an image with ordinary rodata there can boot; //! * what the loader actually reads is min/max_efuse_blk_rev_full at offsets 0xB0/0xB2, and //! `IS_FIELD_SET()` treats zero as "unset" (bootloader_common_loader.c:102-112). //! //! Everything past 0xB5 is reserved padding, so `minimal` stops there and saves 72 bytes of flash. //! `full` keeps all 256 so that `esptool image-info` can parse it. const config = @import("config"); pub const magic: u32 = 0xABCD5432; pub const Minimal = extern struct { magic_word: u32 = magic, secure_version: u32 = 0, reserv1: [2]u32 = .{ 0, 0 }, version: [32]u8, project_name: [32]u8, time: [16]u8 = @splat(0), date: [16]u8 = @splat(0), idf_ver: [32]u8 = @splat(0), app_elf_sha256: [32]u8 = @splat(0), min_efuse_blk_rev_full: u16, max_efuse_blk_rev_full: u16, mmu_page_size: u8 = 16, // log2(64 KiB); fixed on the P4, which has no configurable MMU page reserv3: [3]u8 = @splat(0), }; pub const Full = extern struct { head: Minimal, reserv2: [18]u32 = @splat(0), }; fn str(comptime n: usize, comptime s: []const u8) [n]u8 { var out: [n]u8 = @splat(0); @memcpy(out[0..s.len], s); return out; } const head: Minimal = .{ .version = str(32, "0.1"), .project_name = str(32, "zig-p4"), // The eFuse *block* revision, which has nothing to do with the silicon revision window that // -Dmin-rev sets in the image header. Deriving one from the other made `-Dmin-rev=150` emit an // image the bootloader refuses with "Image requires efuse blk rev >= v0.50". Zero means unset, // which is what `IS_FIELD_SET()` checks for (bootloader_common_loader.c:102-112). .min_efuse_blk_rev_full = 0, .max_efuse_blk_rev_full = 0, }; /// Placed first in .flash.rodata by the linker script, so it lands at image offset 0x20. /// /// `export` is load-bearing: a `comptime _ = descriptor;` reference is enough in Debug but not /// under ReleaseSmall, where the constant is folded away, the section disappears, `KEEP` has /// nothing to keep, and the image ends up with one mapped segment starting at the wrong offset. /// An exported symbol is always emitted. pub export const esp_app_desc linksection(".rodata.appdesc") = if (config.full_descriptor) Full{ .head = head } else head;