Skip to content

Commit fe3fcf5

Browse files
Refactor to use boards
1 parent 85df83a commit fe3fcf5

11 files changed

Lines changed: 520 additions & 244 deletions

File tree

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ default-members = ["crates/elf2uf2-rs"]
77
[workspace.package]
88
version = "2.2.0"
99
authors = ["Jonathan Nilsson <jonathan@voysys.se>"]
10-
edition = "2021"
10+
edition = "2024"
1111
readme = "README.md"
1212
license = "0BSD"
1313
repository = "https://github.com/JoNil/elf2uf2-rs"
@@ -25,3 +25,4 @@ elf = "0.8"
2525
thiserror = "2"
2626
log = "0.4"
2727
env_logger = "0.11"
28+
nusb = "0.2"

crates/elf2uf2-core/Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,15 @@ readme = "README.md"
1111
description = "The core library behind elf2uf2-rs"
1212
documentation = "https://docs.rs/elf2uf2-core"
1313

14+
[features]
15+
default = ["clap"]
16+
1417
[dependencies]
1518
assert_into = { workspace = true }
16-
clap = { workspace = true, optional = true }
1719
static_assertions = { workspace = true }
1820
zerocopy = { workspace = true }
1921
elf = { workspace = true }
2022
thiserror = { workspace = true }
2123
log = { workspace = true }
24+
25+
clap = { workspace = true, optional = true }
Lines changed: 36 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
use std::io::{Read, Seek};
2+
3+
use elf::{ElfStream, abi::PT_LOAD, endian::EndianParse};
4+
15
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
26
pub enum AddressRangeType {
37
/// May have contents
@@ -31,85 +35,39 @@ impl Default for AddressRange {
3135
}
3236
}
3337

34-
pub const FLASH_SECTOR_ERASE_SIZE: u64 = 4096;
35-
pub const MAIN_RAM_START_RP2040: u64 = 0x20000000;
36-
pub const MAIN_RAM_END_RP2040: u64 = 0x20042000;
37-
pub const MAIN_RAM_START_RP2350: u64 = 0x20000000;
38-
pub const MAIN_RAM_END_RP2350: u64 = 0x20082000;
39-
pub const FLASH_START_RP2040: u64 = 0x10000000;
40-
pub const FLASH_END_RP2040: u64 = 0x15000000;
41-
// From RP2350 datasheet:
42-
// RP2040 required images to be stored at the beginning of flash (0x10000000). RP2350 supports storing executable images
43-
// in a partitions at arbitrary locations, to support more robust upgrade cycles via A/B versions, among other uses.
44-
// Therefore, the values below are possibly incorrect but FLASH_END_RP2040 appears to be incorrect too
45-
pub const FLASH_START_RP2350: u64 = 0x10000000;
46-
pub const FLASH_END_RP2350: u64 = 0x15000000;
47-
pub const XIP_SRAM_START_RP2040: u64 = 0x15000000;
48-
pub const XIP_SRAM_END_RP2040: u64 = 0x15004000;
49-
pub const XIP_SRAM_START_RP2350: u64 = 0x13ffc000;
50-
pub const XIP_SRAM_END_RP2350: u64 = 0x14000000;
51-
pub const MAIN_RAM_BANKED_START_RP2040: u64 = 0x21000000;
52-
pub const MAIN_RAM_BANKED_END_RP2040: u64 = 0x21040000;
53-
pub const ROM_START_RP2040: u64 = 0x00000000;
54-
pub const ROM_END_RP2040: u64 = 0x00004000;
55-
pub const ROM_START_RP2350: u64 = 0x00000000;
56-
pub const ROM_END_RP2350: u64 = 0x00008000;
38+
pub fn address_ranges_from_elf<E: EndianParse, S: Read + Seek>(
39+
file: &ElfStream<E, S>,
40+
) -> Vec<AddressRange> {
41+
let segments = file.segments();
5742

58-
pub const RP2040_ADDRESS_RANGES_FLASH: &[AddressRange] = &[
59-
AddressRange::new(
60-
FLASH_START_RP2040,
61-
FLASH_END_RP2040,
62-
AddressRangeType::Contents,
63-
),
64-
AddressRange::new(
65-
MAIN_RAM_START_RP2040,
66-
MAIN_RAM_END_RP2040,
67-
AddressRangeType::NoContents,
68-
),
69-
AddressRange::new(
70-
MAIN_RAM_BANKED_START_RP2040,
71-
MAIN_RAM_BANKED_END_RP2040,
72-
AddressRangeType::NoContents,
73-
),
74-
];
43+
let mut ranges = Vec::new();
7544

76-
pub const RP2040_ADDRESS_RANGES_RAM: &[AddressRange] = &[
77-
AddressRange::new(
78-
MAIN_RAM_START_RP2040,
79-
MAIN_RAM_END_RP2040,
80-
AddressRangeType::Contents,
81-
),
82-
AddressRange::new(
83-
XIP_SRAM_START_RP2040,
84-
XIP_SRAM_END_RP2040,
85-
AddressRangeType::Contents,
86-
),
87-
AddressRange::new(ROM_START_RP2040, ROM_END_RP2040, AddressRangeType::Ignore), // for now we ignore the bootrom if present
88-
];
45+
for seg in segments {
46+
if seg.p_type != PT_LOAD || seg.p_memsz == 0 {
47+
continue;
48+
}
8949

90-
pub const RP2350_ADDRESS_RANGES_FLASH: &[AddressRange] = &[
91-
AddressRange::new(
92-
FLASH_START_RP2350,
93-
FLASH_END_RP2350,
94-
AddressRangeType::Contents,
95-
),
96-
AddressRange::new(
97-
MAIN_RAM_START_RP2350,
98-
MAIN_RAM_END_RP2350,
99-
AddressRangeType::NoContents,
100-
),
101-
];
50+
let start = seg.p_paddr;
51+
let end = start + seg.p_memsz;
52+
53+
if seg.p_filesz > 0 {
54+
// initialized contents
55+
ranges.push(AddressRange::new(
56+
start,
57+
start + seg.p_filesz,
58+
AddressRangeType::Contents,
59+
));
60+
}
10261

103-
pub const RP2350_ADDRESS_RANGES_RAM: &[AddressRange] = &[
104-
AddressRange::new(
105-
MAIN_RAM_START_RP2350,
106-
MAIN_RAM_END_RP2350,
107-
AddressRangeType::Contents,
108-
),
109-
AddressRange::new(
110-
XIP_SRAM_START_RP2350,
111-
XIP_SRAM_END_RP2350,
112-
AddressRangeType::Contents,
113-
),
114-
AddressRange::new(ROM_START_RP2350, ROM_END_RP2350, AddressRangeType::Ignore), // for now we ignore the bootrom if present
115-
];
62+
if seg.p_memsz > seg.p_filesz {
63+
// uninitialized (BSS)
64+
ranges.push(AddressRange::new(
65+
start + seg.p_filesz,
66+
end,
67+
AddressRangeType::NoContents,
68+
));
69+
}
70+
}
71+
72+
ranges
73+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
pub use rp2040::RP2040;
2+
pub use rp2350::RP2350;
3+
4+
use crate::address_range::AddressRange;
5+
6+
pub mod rp2040;
7+
pub mod rp2350;
8+
9+
/// This is a helper struct, which allows you to iterate over every board defined
10+
pub struct BoardIter {
11+
inner: std::vec::IntoIter<Box<dyn BoardInfo>>,
12+
}
13+
14+
impl BoardIter {
15+
/// Creates a new BoardIter
16+
pub fn new() -> Self {
17+
Self {
18+
inner: vec![
19+
Box::new(RP2040::default()) as Box<dyn BoardInfo>,
20+
Box::new(RP2350::default()),
21+
]
22+
.into_iter(),
23+
}
24+
}
25+
26+
pub fn find_by_name(name: &str) -> Option<Box<dyn BoardInfo>> {
27+
for board in Self::new() {
28+
if board.board_name().eq_ignore_ascii_case(name) {
29+
return Some(board);
30+
}
31+
}
32+
None
33+
}
34+
}
35+
36+
impl Iterator for BoardIter {
37+
type Item = Box<dyn BoardInfo>;
38+
fn next(&mut self) -> Option<Self::Item> {
39+
self.inner.next()
40+
}
41+
}
42+
43+
/// This is the version of the firmware on the usb device
44+
#[allow(unused)]
45+
#[derive(Debug, Clone)]
46+
pub struct UsbVersion(pub u8, pub u8, pub u8);
47+
48+
/// This is the usb device information from the usb device. It is possible to generate this information with something like
49+
/// nusb
50+
#[allow(unused)]
51+
#[derive(Debug, Clone)]
52+
pub struct UsbDevice {
53+
pub bus_number: u8,
54+
pub address: u8,
55+
pub vendor_id: u16,
56+
pub product_id: u16,
57+
pub version: UsbVersion,
58+
}
59+
60+
#[derive(Debug, Clone)]
61+
pub struct AddressLocations<'a> {
62+
pub address_ranges_ram: Option<&'a [AddressRange]>,
63+
pub address_ranges_flash: Option<&'a [AddressRange]>,
64+
pub main_ram_start: Option<u64>,
65+
pub main_ram_end: Option<u64>,
66+
pub xip_sram_start: Option<u64>,
67+
pub xip_sram_end: Option<u64>,
68+
}
69+
70+
impl<'a> Default for AddressLocations<'a> {
71+
fn default() -> Self {
72+
Self {
73+
address_ranges_ram: None,
74+
address_ranges_flash: None,
75+
main_ram_start: None,
76+
main_ram_end: None,
77+
xip_sram_start: None,
78+
xip_sram_end: None,
79+
}
80+
}
81+
}
82+
83+
/// This trait helps by allowing for definitions of multiple different boards.
84+
pub trait BoardInfo {
85+
/// Check if the board is connected to the specified UsbDevice
86+
fn is_device_board(&self, device: &UsbDevice) -> bool;
87+
88+
/// Returns the proper family id to use for the uf2 device
89+
fn family_id(&self) -> u32;
90+
91+
/// Optional, just sent to a sensible default of 256, as long as it is less than 512 - 32 it should be okay, but boards very, and so does the bootloader firmware
92+
fn page_size(&self) -> u32 {
93+
256
94+
}
95+
96+
/// Optional, with a default erase size of 4096
97+
fn flash_sector_erase_size(&self) -> u64 {
98+
4096
99+
}
100+
101+
fn address_locations<'a>(&'a self) -> AddressLocations<'a> {
102+
AddressLocations::default()
103+
}
104+
105+
/// Get the board's name
106+
fn board_name(&self) -> String;
107+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
use crate::{
2+
address_range::{AddressRange, AddressRangeType},
3+
boards::{AddressLocations, BoardInfo, UsbDevice},
4+
};
5+
6+
#[derive(Debug, Default, Clone)]
7+
pub struct RP2040;
8+
9+
impl BoardInfo for RP2040 {
10+
fn is_device_board(&self, device: &UsbDevice) -> bool {
11+
if device.vendor_id == 0x2e8a || device.product_id == 0x0003 {
12+
return true;
13+
}
14+
return false;
15+
}
16+
17+
fn family_id(&self) -> u32 {
18+
0xe48bff56
19+
}
20+
21+
fn address_locations<'a>(&'a self) -> AddressLocations<'a> {
22+
AddressLocations {
23+
address_ranges_ram: Some(RP2040_ADDRESS_RANGES_RAM),
24+
address_ranges_flash: Some(RP2040_ADDRESS_RANGES_FLASH),
25+
main_ram_start: Some(MAIN_RAM_START_RP2040),
26+
main_ram_end: Some(MAIN_RAM_END_RP2040),
27+
xip_sram_start: Some(XIP_SRAM_START_RP2040),
28+
xip_sram_end: Some(XIP_SRAM_END_RP2040),
29+
}
30+
}
31+
32+
fn board_name(&self) -> String {
33+
"rp2040".to_string()
34+
}
35+
}
36+
37+
pub const MAIN_RAM_START_RP2040: u64 = 0x20000000;
38+
pub const MAIN_RAM_END_RP2040: u64 = 0x20042000;
39+
pub const FLASH_START_RP2040: u64 = 0x10000000;
40+
pub const FLASH_END_RP2040: u64 = 0x15000000;
41+
42+
pub const XIP_SRAM_START_RP2040: u64 = 0x15000000;
43+
pub const XIP_SRAM_END_RP2040: u64 = 0x15004000;
44+
45+
pub const MAIN_RAM_BANKED_START_RP2040: u64 = 0x21000000;
46+
pub const MAIN_RAM_BANKED_END_RP2040: u64 = 0x21040000;
47+
48+
pub const ROM_START_RP2040: u64 = 0x00000000;
49+
pub const ROM_END_RP2040: u64 = 0x00004000;
50+
51+
pub const RP2040_ADDRESS_RANGES_FLASH: &[AddressRange] = &[
52+
AddressRange::new(
53+
FLASH_START_RP2040,
54+
FLASH_END_RP2040,
55+
AddressRangeType::Contents,
56+
),
57+
AddressRange::new(
58+
MAIN_RAM_START_RP2040,
59+
MAIN_RAM_END_RP2040,
60+
AddressRangeType::NoContents,
61+
),
62+
AddressRange::new(
63+
MAIN_RAM_BANKED_START_RP2040,
64+
MAIN_RAM_BANKED_END_RP2040,
65+
AddressRangeType::NoContents,
66+
),
67+
];
68+
69+
pub const RP2040_ADDRESS_RANGES_RAM: &[AddressRange] = &[
70+
AddressRange::new(
71+
MAIN_RAM_START_RP2040,
72+
MAIN_RAM_END_RP2040,
73+
AddressRangeType::Contents,
74+
),
75+
AddressRange::new(
76+
XIP_SRAM_START_RP2040,
77+
XIP_SRAM_END_RP2040,
78+
AddressRangeType::Contents,
79+
),
80+
AddressRange::new(ROM_START_RP2040, ROM_END_RP2040, AddressRangeType::Ignore), // for now we ignore the bootrom if present
81+
];

0 commit comments

Comments
 (0)