rp_binary_info/
types.rs

1//! Types for the Binary Info system
2
3/// This is the 'Binary Info' header block that `picotool` looks for in your UF2
4/// file/ELF file/Pico in Bootloader Mode to give you useful metadata about your
5/// program.
6///
7/// It should be placed in the first 4096 bytes of flash, so use your `memory.x`
8/// to insert a section between `.text` and `.vector_table` and put a static
9/// value of this type in that section.
10#[repr(C)]
11pub struct Header {
12    /// Must be equal to Picotool::MARKER_START
13    marker_start: u32,
14    /// The first in our table of pointers to Entries
15    entries_start: *const EntryAddr,
16    /// The last in our table of pointers to Entries
17    entries_end: *const EntryAddr,
18    /// The first entry in a null-terminated RAM/Flash mapping table
19    mapping_table: *const MappingTableEntry,
20    /// Must be equal to Picotool::MARKER_END
21    marker_end: u32,
22}
23
24impl Header {
25    /// This is the `BINARY_INFO_MARKER_START` magic value from `picotool`
26    const MARKER_START: u32 = 0x7188ebf2;
27    /// This is the `BINARY_INFO_MARKER_END` magic value from `picotool`
28    const MARKER_END: u32 = 0xe71aa390;
29
30    /// Create a new `picotool` compatible header.
31    ///
32    /// * `entries_start` - the first [`EntryAddr`] in the table
33    /// * `entries_end` - the last [`EntryAddr`] in the table
34    /// * `mapping_table` - the RAM/Flash address mapping table
35    pub const fn new(
36        entries_start: *const EntryAddr,
37        entries_end: *const EntryAddr,
38        mapping_table: &'static [MappingTableEntry],
39    ) -> Self {
40        let mapping_table = mapping_table.as_ptr();
41        Self {
42            marker_start: Self::MARKER_START,
43            entries_start,
44            entries_end,
45            mapping_table,
46            marker_end: Self::MARKER_END,
47        }
48    }
49}
50
51// We need this as rustc complains that is is unsafe to share `*const u32`
52// pointers between threads. We only allow these to be created with static
53// data, so this is OK.
54unsafe impl Sync for Header {}
55
56/// This is a reference to an entry. It's like a `&dyn` ref to some type `T:
57/// Entry`, except that the run-time type information is encoded into the
58/// Entry itself in very specific way.
59#[repr(transparent)]
60pub struct EntryAddr(*const u32);
61
62// We need this as rustc complains that is is unsafe to share `*const u32`
63// pointers between threads. We only allow these to be created with static
64// data, so this is OK.
65unsafe impl Sync for EntryAddr {}
66
67/// Allows us to tell picotool where values are in the UF2 given their run-time
68/// address.
69///
70/// The most obvious example is RAM variables, which must be found in the
71/// `.data` section of the UF2.
72#[repr(C)]
73pub struct MappingTableEntry {
74    /// The start address in RAM (or wherever the address picotool finds will
75    /// point)
76    pub source_addr_start: *const u32,
77    /// The start address in flash (or whever the data actually lives in the
78    /// ELF)
79    pub dest_addr_start: *const u32,
80    /// The end address in flash
81    pub dest_addr_end: *const u32,
82}
83
84impl MappingTableEntry {
85    /// Generate a null entry to mark the end of the list
86    pub const fn null() -> MappingTableEntry {
87        MappingTableEntry {
88            source_addr_start: core::ptr::null(),
89            dest_addr_start: core::ptr::null(),
90            dest_addr_end: core::ptr::null(),
91        }
92    }
93}
94
95// We need this as rustc complains that is is unsafe to share `*const u32`
96// pointers between threads. We only allow these to be created with static
97// data, so this is OK.
98unsafe impl Sync for MappingTableEntry {}
99
100/// This is the set of data types that `picotool` supports.
101#[repr(u16)]
102pub enum DataType {
103    /// Raw data
104    Raw = 1,
105    /// Data with a size
106    SizedData = 2,
107    /// A list of binary data
108    BinaryInfoListZeroTerminated = 3,
109    /// A BSON encoded blob
110    Bson = 4,
111    /// An Integer with an ID
112    IdAndInt = 5,
113    /// A string with an Id
114    IdAndString = 6,
115    /// A block device
116    BlockDevice = 7,
117    /// GPIO pins, with their function
118    PinsWithFunction = 8,
119    /// GPIO pins, with their name
120    PinsWithName = 9,
121    /// GPIO pins, with multiple names?
122    PinsWithNames = 10,
123}
124
125/// All Entries start with this common header
126#[repr(C)]
127struct EntryCommon {
128    data_type: DataType,
129    tag: u16,
130}
131
132/// An entry which contains both an ID (e.g. `ID_RP_PROGRAM_NAME`) and a pointer
133/// to a null-terminated string.
134#[repr(C)]
135pub struct StringEntry {
136    header: EntryCommon,
137    id: u32,
138    value: *const core::ffi::c_char,
139}
140
141impl StringEntry {
142    /// Create a new `StringEntry`
143    pub const fn new(tag: u16, id: u32, value: &'static core::ffi::CStr) -> StringEntry {
144        StringEntry {
145            header: EntryCommon {
146                data_type: DataType::IdAndString,
147                tag,
148            },
149            id,
150            value: value.as_ptr(),
151        }
152    }
153
154    /// Get this entry's address
155    pub const fn addr(&self) -> EntryAddr {
156        EntryAddr(self as *const Self as *const u32)
157    }
158}
159
160// We need this as rustc complains that is is unsafe to share `*const
161// core::ffi::c_char` pointers between threads. We only allow these to be
162// created with static string slices, so it's OK.
163unsafe impl Sync for StringEntry {}
164
165/// An entry which contains both an ID (e.g. `ID_RP_BINARY_END`) and an integer.
166#[repr(C)]
167pub struct IntegerEntry {
168    header: EntryCommon,
169    id: u32,
170    value: u32,
171}
172
173impl IntegerEntry {
174    /// Create a new `StringEntry`
175    pub const fn new(tag: u16, id: u32, value: u32) -> IntegerEntry {
176        IntegerEntry {
177            header: EntryCommon {
178                data_type: DataType::IdAndInt,
179                tag,
180            },
181            id,
182            value,
183        }
184    }
185
186    /// Get this entry's address
187    pub const fn addr(&self) -> EntryAddr {
188        EntryAddr(self as *const Self as *const u32)
189    }
190}
191
192// End of file