Repository navigation
Expand file tree
/
Copy pathbuild.rs
More file actions
335 lines (304 loc) · 12 KB
/
Copy pathbuild.rs
File metadata and controls
335 lines (304 loc) · 12 KB
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
use std::env;
use std::fs;
use std::path::Path;
fn main() {
let out_dir = env::var("OUT_DIR").unwrap();
let out = Path::new(&out_dir);
let is_rp2040 = env::var("CARGO_FEATURE_RP2040").is_ok();
let is_nrf52840 = env::var("CARGO_FEATURE_NRF52840").is_ok();
let is_nrf52833 = env::var("CARGO_FEATURE_NRF52833").is_ok();
let is_noswap = env::var("CARGO_FEATURE_NOSWAP").is_ok();
let is_dfu_ext = env::var("CARGO_FEATURE_DFU_EXT").is_ok();
let is_defmt = env::var("CARGO_FEATURE_DEFMT").is_ok();
if is_defmt {
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
}
// Feature list for the generated rmk-memory.x header, e.g. " with dfu_ext,defmt"
let mut enabled: Vec<&str> = Vec::new();
if is_dfu_ext {
enabled.push("dfu_ext");
}
if is_noswap {
enabled.push("noswap");
}
if is_defmt {
enabled.push("defmt");
}
let features = if enabled.is_empty() {
String::new()
} else {
format!(" with {}", enabled.join(","))
};
if is_nrf52840 && is_nrf52833 {
panic!("nrf52840 and nrf52833 are mutually exclusive");
}
const PAGE_SIZE: usize = 4 * 1024;
const STORAGE_SIZE: usize = 32 * 1024;
if is_rp2040 {
let (variant_label, variant_slug, flash_size) =
if env::var("CARGO_FEATURE_RP2040_2MB").is_ok() {
("RP2040 2 MB", "rp2040-2mb", 2 * 1024 * 1024)
} else if env::var("CARGO_FEATURE_RP2040_4MB").is_ok() {
("RP2040 4 MB", "rp2040-4mb", 4 * 1024 * 1024)
} else if env::var("CARGO_FEATURE_RP2040_8MB").is_ok() {
("RP2040 8 MB", "rp2040-8mb", 8 * 1024 * 1024)
} else if env::var("CARGO_FEATURE_RP2040_16MB").is_ok() {
("RP2040 16 MB", "rp2040-16mb", 16 * 1024 * 1024)
} else {
panic!(
"No RP2040 flash size feature enabled — enable one of rp2040-2mb, \
rp2040-4mb, rp2040-8mb or rp2040-16mb (optionally combined with \
noswap, dfu_ext, defmt)"
);
};
let variant_slug = if is_noswap {
format!("{variant_slug}-noswap")
} else if is_dfu_ext {
format!("{variant_slug}-dfu_ext")
} else {
variant_slug.to_string()
};
let remaining = flash_size - 28 * 1024 - STORAGE_SIZE;
const SWAP_PAGE_SIZE: usize = 64 * 1024;
let (active_size, dfu_size) = if is_dfu_ext {
// ACTIVE capacity must be a multiple of the swap page size
// (embassy computes PAGE_SIZE = max(ERASE_SIZE) of both flashes)
((remaining / SWAP_PAGE_SIZE) * SWAP_PAGE_SIZE, 0)
} else if is_noswap {
(remaining, 0)
} else {
(
(remaining - PAGE_SIZE) / 2,
(remaining - PAGE_SIZE) / 2 + PAGE_SIZE,
)
};
// Absolute XIP addresses
let abs_active_offset = 0x1000_7000u32;
let abs_dfu_offset = abs_active_offset + active_size as u32;
let abs_state_offset = 0x1000_6000u32;
// Flash-relative offsets (for DFU symbols)
let flash_base = 0x1000_0000u32;
let rel_state_offset = abs_state_offset - flash_base;
let rel_dfu_offset = abs_dfu_offset - flash_base;
let rel_dfu_size = dfu_size as u32;
let rel_storage_offset = abs_dfu_offset - flash_base + dfu_size as u32;
let memory_x = format!(
"\
MEMORY
{{
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
FLASH : ORIGIN = 0x10000100, LENGTH = 24K - 0x100
BOOTLOADER_STATE : ORIGIN = 0x10006000, LENGTH = 4K
ACTIVE : ORIGIN = 0x{abs_active_offset:08X}, LENGTH = {active_size}
DFU : ORIGIN = 0x{abs_dfu_offset:08X}, LENGTH = {dfu_size}
RAM : ORIGIN = 0x20000000, LENGTH = 256K
}}
__bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOT2);
__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE) - ORIGIN(BOOT2);
__bootloader_active_start = ORIGIN(ACTIVE) - ORIGIN(BOOT2);
__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE) - ORIGIN(BOOT2);
__bootloader_dfu_start = ORIGIN(DFU) - ORIGIN(BOOT2);
__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU) - ORIGIN(BOOT2);
"
);
fs::write(out.join("memory.x"), &memory_x).unwrap();
println!("cargo:rustc-link-search={}", out.display());
println!("cargo:rustc-link-arg-bins=-Tlink.x");
println!("cargo:rustc-link-arg-bins=-Tlink-rp.x");
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_RP2040_2MB");
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_RP2040_4MB");
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_RP2040_8MB");
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_RP2040_16MB");
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_NOSWAP");
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_DFU_EXT");
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_DEFMT");
let rmk_boot_x = build_rmk_boot_x(
variant_label,
abs_active_offset,
active_size as u32,
rel_state_offset,
0x1000,
if is_noswap || is_dfu_ext {
0
} else {
rel_dfu_offset
},
if is_noswap || is_dfu_ext {
0
} else {
rel_dfu_size
},
rel_storage_offset,
STORAGE_SIZE as u32,
0x1000_0000, // XIP flash base
256 * 1024,
&features,
);
let project_root = Path::new(env!("CARGO_MANIFEST_DIR"));
write_rmk_boot_x(&project_root, &variant_slug, &rmk_boot_x);
} else if is_nrf52840 || is_nrf52833 {
let (variant_label, variant_slug, flash_size, ram_size) = if is_nrf52840 {
("nRF52840", "nrf52840", 1024 * 1024, 256 * 1024)
} else {
("nRF52833", "nrf52833", 512 * 1024, 128 * 1024)
};
// 24K bootloader — same as the RP2040 layout. Defmt debug builds need
// 32K (~29K binary); pair the app with the generated rmk-memory.x when
// flashing a defmt bootloader.
let bootloader_size = if is_defmt { 32 * 1024 } else { 24 * 1024 };
let state_size = 4 * 1024;
let remaining = flash_size - bootloader_size - state_size - STORAGE_SIZE;
const SWAP_PAGE_SIZE: usize = 64 * 1024;
let (active_size, dfu_size) = if is_dfu_ext {
((remaining / SWAP_PAGE_SIZE) * SWAP_PAGE_SIZE, 0)
} else if is_noswap {
(remaining, 0)
} else {
(
(remaining - PAGE_SIZE) / 2,
(remaining - PAGE_SIZE) / 2 + PAGE_SIZE,
)
};
let abs_state_offset = bootloader_size as u32;
let abs_active_offset = (bootloader_size + state_size) as u32;
let abs_dfu_offset = abs_active_offset + active_size as u32;
let (dfu_start_sym, dfu_end_sym) = if is_noswap || is_dfu_ext {
(
format!("__bootloader_dfu_start = ORIGIN(ACTIVE);"),
format!("__bootloader_dfu_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE);"),
)
} else {
(
format!("__bootloader_dfu_start = ORIGIN(DFU);"),
format!("__bootloader_dfu_end = ORIGIN(DFU) + LENGTH(DFU);"),
)
};
let memory_x = format!(
"\
MEMORY
{{
FLASH : ORIGIN = 0x00000000, LENGTH = {bootloader_size}
BOOTLOADER_STATE : ORIGIN = 0x{abs_state_offset:08X}, LENGTH = {state_size}
ACTIVE : ORIGIN = 0x{abs_active_offset:08X}, LENGTH = {active_size}
DFU : ORIGIN = 0x{abs_dfu_offset:08X}, LENGTH = {dfu_size}
RAM : ORIGIN = 0x20000000, LENGTH = {ram_size}
}}
__bootloader_state_start = ORIGIN(BOOTLOADER_STATE);
__bootloader_state_end = ORIGIN(BOOTLOADER_STATE) + LENGTH(BOOTLOADER_STATE);
__bootloader_active_start = ORIGIN(ACTIVE);
__bootloader_active_end = ORIGIN(ACTIVE) + LENGTH(ACTIVE);
{dfu_start_sym}
{dfu_end_sym}
"
);
fs::write(out.join("memory.x"), &memory_x).unwrap();
println!("cargo:rustc-link-search={}", out.display());
println!("cargo:rustc-link-arg-bins=-Tlink.x");
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_NOSWAP");
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_DFU_EXT");
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_DEFMT");
let rmk_boot_x = build_rmk_boot_x(
variant_label,
abs_active_offset,
active_size as u32,
abs_state_offset,
state_size as u32,
if is_noswap || is_dfu_ext {
0
} else {
abs_dfu_offset
},
if is_noswap || is_dfu_ext {
0
} else {
dfu_size as u32
},
abs_dfu_offset + dfu_size as u32,
STORAGE_SIZE as u32,
0x0000_0000, // flash base
ram_size as u32,
&features,
);
let project_root = Path::new(env!("CARGO_MANIFEST_DIR"));
write_rmk_boot_x(
&project_root,
&nrf_variant_slug(variant_slug, is_noswap, is_dfu_ext),
&rmk_boot_x,
);
} else {
panic!("No platform feature enabled (rp2040 or nrf52840 or nrf52833)");
}
println!("cargo:rerun-if-changed=build.rs");
}
/// Write the RMK linker script to the project root both under the generic
/// name `rmk-memory.x` and under the variant-specific `rmk-boot-{variant}-memory.x`
/// release name.
fn write_rmk_boot_x(project_root: &Path, variant_slug: &str, content: &str) {
fs::write(project_root.join("rmk-memory.x"), content).unwrap();
fs::write(
project_root.join(format!("rmk-boot-{variant_slug}-memory.x")),
content,
)
.unwrap();
}
/// Variant slug for the nRF platform, appending the layout-modifying
/// `noswap`/`dfu_ext` feature when enabled.
fn nrf_variant_slug(platform: &str, is_noswap: bool, is_dfu_ext: bool) -> String {
if is_noswap {
format!("{platform}-noswap")
} else if is_dfu_ext {
format!("{platform}-dfu_ext")
} else {
platform.to_string()
}
}
fn build_rmk_boot_x(
variant: &str,
active_offset: u32,
active_size: u32,
state_offset: u32,
state_size: u32,
dfu_offset: u32,
dfu_size: u32,
storage_offset: u32,
storage_size: u32,
flash_base: u32,
ram_size: u32,
features: &str,
) -> String {
let rel_active_offset = active_offset - flash_base;
let state_end = state_offset + state_size;
let active_end = rel_active_offset + active_size;
let dfu_end = dfu_offset + dfu_size;
let storage_end = storage_offset + storage_size;
format!(
"\
/* rmk-memory.x for {variant}{features} — generated by rmk-boot/build.rs
*
* Provides the MEMORY layout (absolute XIP addresses) and the standard
* embassy-boot `__bootloader_*` partition symbols (flash-relative offsets)
* consumed by partitions_from_linkerscript().
*
* If your board has a different flash size, replace this file with the
* matching variant from the rmk-boot releases:
* https://github.com/rmk-rs/rmk-boot/releases
*/
MEMORY {{
FLASH : ORIGIN = 0x{active_offset:08X}, LENGTH = {active_size} /* ACTIVE region */
RAM : ORIGIN = 0x20000000, LENGTH = {ram_size} /* SRAM */
}}
/* Bootloader partition symbols — offsets relative to flash start.
* The active/state/dfu names match embassy-boot's from_linkerfile_blocking(),
* storage is an RMK extension.
*/
__bootloader_state_start = 0x{state_offset:X};
__bootloader_state_end = 0x{state_end:X};
__bootloader_active_start = 0x{rel_active_offset:X};
__bootloader_active_end = 0x{active_end:X};
__bootloader_dfu_start = 0x{dfu_offset:X};
__bootloader_dfu_end = 0x{dfu_end:X};
__bootloader_storage_start = 0x{storage_offset:X};
__bootloader_storage_end = 0x{storage_end:X};
"
)
}