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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// Extension API for the Firmion binary image compiler.
//
// This crate defines the public API for Firmion extension authors.
//
// FirmionExtension -- the single trait all extensions implement.
//
// ExtArg -- typed argument passed to execute(). Each parameter passed
// to an extension in Firmion code maps to one ExtArg passed to the extension
// by the compiler.
//
// Argument types:
// Int(u64) -- numeric expression (u64, i64, or integer const)
// Str(&str) -- quoted string const
// Slice { start, len, data } -- Data slice from the in-flight output data.
// Firmion automatically converts sections names
// into slices.
//
// Args may appear in any order. Firmion resolves the section name to its
// location and provides the image bytes without extension authors having to
// compute offsets.
//
// Firmion registers extensions at startup via the ExtensionRegistry.
// Firmion calls size() exactly once during registration and caches
// the result. The `firmion` and `std` namespaces are reserved.
//
// Named parameters:
// An extension declares named parameters via params(), returning a slice of
// ParamDesc values. Each ParamDesc pairs a name with a ParamKind.
// ParamKind::Slice declares that a parameter accepts a sequence of bytes
// (supplied at call sites as a section name). ParamKind::Int and
// ParamKind::Str declare numeric and string parameters respectively.
// Don't clutter upstream docs.rs for an otherwise private library.
/// The kind of a declared extension parameter.
///
/// Used in [`ParamDesc`] to specify what type of argument a parameter accepts.
/// Describes one declared parameter of an extension.
///
/// An extension returns a slice of `ParamDesc` from [`FirmionExtension::params`]
/// to opt into named-argument call sites.
/// The argument type passed to an extension at execution time.
///
/// Each Firmion call-site argument produces exactly one `ExtArg`.
/// Implement this trait to create a Firmion extension.
///
/// An extension writes a fixed number of bytes into the output image.
/// Arguments arrive as typed [`ExtArg`] values corresponding 1:1 to the
/// Firmion call-site arguments. A section name argument delivers the image
/// bytes at that section directly in the [`ExtArg::Section`] variant.
///
/// # Example: numeric argument
///
/// ```rust
/// use firmion_extension::{FirmionExtension, ParamArg};
///
/// pub struct MyCrc;
///
/// impl FirmionExtension for MyCrc {
/// fn name(&self) -> &str { "my_org::crc" }
/// fn size(&self) -> usize { 4 }
/// fn execute<'a>(&self, args: &[ParamArg<'a>], out: &mut [u8]) -> Result<(), String> {
/// let val = match args.first() {
/// Some(ParamArg::Int(v)) => *v as u32,
/// _ => return Err("Expected one numeric argument".to_string()),
/// };
/// out.copy_from_slice(&val.to_be_bytes());
/// Ok(())
/// }
/// }
/// ```
///
/// # Example: section argument
///
/// ```rust
/// use firmion_extension::{FirmionExtension, ParamArg};
///
/// pub struct MyChecksum;
///
/// impl FirmionExtension for MyChecksum {
/// fn name(&self) -> &str { "my_org::checksum" }
/// fn size(&self) -> usize { 8 }
/// fn execute<'a>(&self, args: &[ParamArg<'a>], out: &mut [u8]) -> Result<(), String> {
/// let data = match args.first() {
/// Some(ParamArg::Slice { data }) => *data,
/// _ => return Err("Expected a slice argument".to_string()),
/// };
/// let sum: u64 = data.iter().map(|&b| b as u64).sum();
/// out.copy_from_slice(&sum.to_le_bytes());
/// Ok(())
/// }
/// }
/// ```