11use crate :: {
2- address_range:: { MAIN_RAM_END , XIP_SRAM_END , XIP_SRAM_START } ,
2+ address_range:: {
3+ FLASH_SECTOR_ERASE_SIZE , MAIN_RAM_END_RP2040 , MAIN_RAM_END_RP2350 , MAIN_RAM_START_RP2040 ,
4+ MAIN_RAM_START_RP2350 , RP2040_ADDRESS_RANGES_FLASH , RP2040_ADDRESS_RANGES_RAM ,
5+ RP2350_ADDRESS_RANGES_FLASH , RP2350_ADDRESS_RANGES_RAM , XIP_SRAM_END_RP2040 ,
6+ XIP_SRAM_END_RP2350 , XIP_SRAM_START_RP2040 , XIP_SRAM_START_RP2350 ,
7+ } ,
38 elf:: { is_ram_binary, AddressRangesFromElfError , PageMap } ,
49 reporter:: ProgressBarReporter ,
510} ;
611use :: elf:: { endian:: AnyEndian , ElfStream , ParseError } ;
7- use address_range:: {
8- FLASH_SECTOR_ERASE_SIZE , MAIN_RAM_START , RP2040_ADDRESS_RANGES_FLASH , RP2040_ADDRESS_RANGES_RAM ,
9- } ;
1012use assert_into:: AssertInto ;
11- use clap:: Parser ;
13+ use clap:: { Parser , ValueEnum } ;
1214use elf:: { realize_page, AddressRangesExt , PAGE_SIZE } ;
1315use env_logger:: Env ;
1416use log:: { debug, info, Level , LevelFilter } ;
15- use static_assertions:: const_assert;
1617use std:: {
1718 collections:: HashSet ,
1819 error:: Error ,
@@ -23,8 +24,8 @@ use std::{
2324use sysinfo:: Disks ;
2425use thiserror:: Error ;
2526use uf2:: {
26- Uf2BlockData , Uf2BlockFooter , Uf2BlockHeader , RP2040_FAMILY_ID , UF2_FLAG_FAMILY_ID_PRESENT ,
27- UF2_MAGIC_END , UF2_MAGIC_START0 , UF2_MAGIC_START1 ,
27+ Uf2BlockData , Uf2BlockFooter , Uf2BlockHeader , UF2_FLAG_FAMILY_ID_PRESENT , UF2_MAGIC_END ,
28+ UF2_MAGIC_START0 , UF2_MAGIC_START1 ,
2829} ;
2930use zerocopy:: IntoBytes ;
3031
@@ -44,6 +45,10 @@ struct Opts {
4445 #[ clap( short, long) ]
4546 deploy : bool ,
4647
48+ /// Select family short name for UF2
49+ #[ clap( value_enum, short, long, default_value_t = Family :: default ( ) ) ]
50+ family : Family ,
51+
4752 /// Connect to serial after deploy
4853 #[ cfg( feature = "serial" ) ]
4954 #[ clap( short, long) ]
@@ -61,6 +66,36 @@ struct Opts {
6166 output : Option < String > ,
6267}
6368
69+ // See https://github.com/microsoft/uf2/blob/master/utils/uf2families.json for list
70+ #[ derive( Debug , ValueEnum , Clone , Copy ) ]
71+ #[ repr( u32 ) ]
72+ #[ allow( non_camel_case_types) ]
73+ pub enum Family {
74+ /// Raspberry Pi RP2040
75+ RP2040 = 0xe48bff56 ,
76+
77+ /// Raspberry Pi Microcontrollers: Absolute (unpartitioned) download
78+ RP2XXX_ABSOLUTE = 0xe48bff57 ,
79+
80+ /// Raspberry Pi Microcontrollers: Data partition download
81+ RP2XXX_DATA = 0xe48bff58 ,
82+
83+ /// Raspberry Pi RP2350, Secure Arm image
84+ RP2350_ARM_S = 0xe48bff59 ,
85+
86+ /// Raspberry Pi RP2350, RISC-V image
87+ RP2350_RISCV = 0xe48bff5a ,
88+
89+ /// Raspberry Pi RP2350, Non-secure Arm image
90+ RP2350_ARM_NS = 0xe48bff5b ,
91+ }
92+
93+ impl Default for Family {
94+ fn default ( ) -> Self {
95+ Self :: RP2040
96+ }
97+ }
98+
6499#[ derive( Error , Debug ) ]
65100pub enum Elf2Uf2Error {
66101 #[ error( "Failed to get address ranges from elf" ) ]
@@ -81,19 +116,52 @@ pub enum Elf2Uf2Error {
81116 EntryPointNotMapped ,
82117}
83118
84- fn build_page_map ( elf : & ElfStream < AnyEndian , impl Read + Seek > ) -> Result < PageMap , Elf2Uf2Error > {
85- let ram_style = is_ram_binary ( elf) . ok_or ( Elf2Uf2Error :: EntryPointNotMapped ) ?;
119+ fn build_page_map (
120+ elf : & ElfStream < AnyEndian , impl Read + Seek > ,
121+ family : Family ,
122+ ) -> Result < PageMap , Elf2Uf2Error > {
123+ let ram_style = is_ram_binary ( elf, family) . ok_or ( Elf2Uf2Error :: EntryPointNotMapped ) ?;
86124
87125 if ram_style {
88126 debug ! ( "Detected RAM binary" ) ;
89127 } else {
90128 debug ! ( "Detected FLASH binary" ) ;
91129 }
92130
131+ let (
132+ address_ranges_ram,
133+ address_ranges_flash,
134+ main_ram_start,
135+ main_ram_end,
136+ xip_sram_start,
137+ xip_sram_end,
138+ ) = match family {
139+ Family :: RP2040 => (
140+ RP2040_ADDRESS_RANGES_RAM ,
141+ RP2040_ADDRESS_RANGES_FLASH ,
142+ MAIN_RAM_START_RP2040 ,
143+ MAIN_RAM_END_RP2040 ,
144+ XIP_SRAM_START_RP2040 ,
145+ XIP_SRAM_END_RP2040 ,
146+ ) ,
147+ Family :: RP2XXX_ABSOLUTE
148+ | Family :: RP2XXX_DATA
149+ | Family :: RP2350_ARM_S
150+ | Family :: RP2350_RISCV
151+ | Family :: RP2350_ARM_NS => (
152+ RP2350_ADDRESS_RANGES_RAM ,
153+ RP2350_ADDRESS_RANGES_FLASH ,
154+ MAIN_RAM_START_RP2350 ,
155+ MAIN_RAM_END_RP2350 ,
156+ XIP_SRAM_START_RP2350 ,
157+ XIP_SRAM_END_RP2350 ,
158+ ) ,
159+ } ;
160+
93161 let valid_ranges = if ram_style {
94- RP2040_ADDRESS_RANGES_RAM
162+ address_ranges_ram
95163 } else {
96- RP2040_ADDRESS_RANGES_FLASH
164+ address_ranges_flash
97165 } ;
98166
99167 let mut pages = valid_ranges
@@ -110,9 +178,9 @@ fn build_page_map(elf: &ElfStream<AnyEndian, impl Read + Seek>) -> Result<PageMa
110178
111179 #[ allow( clippy:: manual_range_contains) ]
112180 pages. keys ( ) . copied ( ) . for_each ( |addr| {
113- if addr >= MAIN_RAM_START && addr <= MAIN_RAM_END {
181+ if addr >= main_ram_start && addr <= main_ram_end {
114182 expected_ep_main_ram = expected_ep_main_ram. min ( addr) | 0x1 ;
115- } else if addr >= XIP_SRAM_START && addr < XIP_SRAM_END {
183+ } else if addr >= xip_sram_start && addr < xip_sram_end {
116184 expected_ep_xip_sram = expected_ep_xip_sram. min ( addr) | 0x1 ;
117185 }
118186 } ) ;
@@ -132,7 +200,7 @@ fn build_page_map(elf: &ElfStream<AnyEndian, impl Read + Seek>) -> Result<PageMa
132200 elf. ehdr . e_entry as u32 ,
133201 ) ) ;
134202 }
135- const_assert ! ( 0 == ( MAIN_RAM_START & ( PAGE_SIZE - 1 ) ) ) ;
203+ assert ! ( 0 == ( main_ram_start & ( PAGE_SIZE - 1 ) ) ) ;
136204
137205 // TODO: check vector table start up
138206 // currently don't require this as entry point is now at the start, we don't know where reset vector is
@@ -167,6 +235,7 @@ fn write_output(
167235 elf_file : & mut ElfStream < AnyEndian , impl Read + Seek > ,
168236 pages : & PageMap ,
169237 mut output : impl Write ,
238+ family : Family ,
170239) -> Result < ( ) , Elf2Uf2Error > {
171240 let mut block_header = Uf2BlockHeader {
172241 magic_start0 : UF2_MAGIC_START0 ,
@@ -176,7 +245,7 @@ fn write_output(
176245 payload_size : PAGE_SIZE . assert_into ( ) ,
177246 block_no : 0 ,
178247 num_blocks : pages. len ( ) . assert_into ( ) ,
179- file_size : RP2040_FAMILY_ID ,
248+ file_size : family as u32 ,
180249 } ;
181250
182251 let mut block_data: Uf2BlockData = [ 0 ; 476 ] ;
@@ -220,10 +289,14 @@ fn open_elf<T: Read + Seek>(input: T) -> Result<ElfStream<AnyEndian, T>, Elf2Uf2
220289}
221290
222291#[ cfg_attr( not( test) , expect( unused) ) ]
223- fn elf2uf2 ( input : impl Read + Seek , output : impl Write ) -> Result < ( ) , Elf2Uf2Error > {
292+ fn elf2uf2 (
293+ input : impl Read + Seek ,
294+ output : impl Write ,
295+ family : Family ,
296+ ) -> Result < ( ) , Elf2Uf2Error > {
224297 let mut elf = open_elf ( input) ?;
225- let pages = build_page_map ( & elf) ?;
226- write_output ( & mut elf, & pages, output)
298+ let pages = build_page_map ( & elf, family ) ?;
299+ write_output ( & mut elf, & pages, output, family )
227300}
228301
229302fn main ( ) -> Result < ( ) , Box < dyn Error > > {
@@ -280,19 +353,25 @@ fn main() -> Result<(), Box<dyn Error>> {
280353 ( File :: create ( & output_path) ?, output_path)
281354 } ;
282355
356+ let family = options. family ;
357+
358+ if options. verbose {
359+ info ! ( "Using UF2 Family {:?}" , family) ;
360+ }
361+
283362 let writer = BufWriter :: new ( output) ;
284363 let mut elf = open_elf ( input) ?;
285364 let should_print_progress = log:: max_level ( ) >= LevelFilter :: Info ;
286- let pages = build_page_map ( & elf) ?;
365+ let pages = build_page_map ( & elf, family ) ?;
287366
288367 let result = if should_print_progress {
289368 let len = pages. len ( ) as u64 * 512 ;
290369 let mut reporter = ProgressBarReporter :: new ( len, writer) ;
291- let result = write_output ( & mut elf, & pages, & mut reporter) ;
370+ let result = write_output ( & mut elf, & pages, & mut reporter, family ) ;
292371 reporter. finish ( ) ;
293372 result
294373 } else {
295- write_output ( & mut elf, & pages, writer)
374+ write_output ( & mut elf, & pages, writer, family )
296375 } ;
297376
298377 if let Err ( err) = result {
@@ -399,7 +478,7 @@ mod tests {
399478 pub fn hello_usb ( ) {
400479 let bytes_in = io:: Cursor :: new ( & include_bytes ! ( "../hello_usb.elf" ) [ ..] ) ;
401480 let mut bytes_out = Vec :: new ( ) ;
402- elf2uf2 ( bytes_in, & mut bytes_out) . unwrap ( ) ;
481+ elf2uf2 ( bytes_in, & mut bytes_out, Family :: RP2040 ) . unwrap ( ) ;
403482
404483 assert_eq ! ( bytes_out, include_bytes!( "../hello_usb.uf2" ) ) ;
405484 }
@@ -408,7 +487,7 @@ mod tests {
408487 pub fn hello_serial ( ) {
409488 let bytes_in = io:: Cursor :: new ( & include_bytes ! ( "../hello_serial.elf" ) [ ..] ) ;
410489 let mut bytes_out = Vec :: new ( ) ;
411- elf2uf2 ( bytes_in, & mut bytes_out) . unwrap ( ) ;
490+ elf2uf2 ( bytes_in, & mut bytes_out, Family :: RP2040 ) . unwrap ( ) ;
412491
413492 assert_eq ! ( bytes_out, include_bytes!( "../hello_serial.uf2" ) ) ;
414493 }
0 commit comments