1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
//! 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;
|