1use crate::flash_device::FlashDevice;
2use anyhow::{Context, Result, anyhow};
3use probe_rs_target::{FlashProperties, MemoryRange, RawFlashAlgorithm, SectorDescription};
4
5pub(crate) fn read_elf_bin_data<'a>(
10 elf: &'a goblin::elf::Elf<'_>,
11 buffer: &'a [u8],
12 address: u32,
13 size: u32,
14) -> Option<&'a [u8]> {
15 log::debug!("Trying to read {size} bytes from {address:#010x}.");
16
17 let start = address as u64;
18 let end = (address + size) as u64;
19 let range_to_read = start..end;
20
21 for ph in &elf.program_headers {
23 let segment_address = ph.p_paddr;
24 let segment_size = ph.p_memsz.min(ph.p_filesz);
25
26 log::debug!("Segment address: {segment_address:#010x}");
27 log::debug!("Segment size: {segment_size} bytes");
28
29 let segment = segment_address..segment_address + segment_size;
30 if !segment.contains_range(&range_to_read) {
32 log::debug!("Skipping segment.");
33 continue;
34 }
35
36 let start = ph.p_offset as u32 + address - segment_address as u32;
37 return Some(&buffer[start as usize..][..size as usize]);
38 }
39
40 None
41}
42
43fn extract_flash_device(elf: &goblin::elf::Elf, buffer: &[u8]) -> Result<FlashDevice> {
44 for sym in elf.syms.iter() {
46 let name = &elf.strtab[sym.st_name];
47
48 if name == "FlashDevice" {
49 let address = sym.st_value as u32;
51 return FlashDevice::new(elf, buffer, address);
52 }
53 }
54
55 Err(anyhow!("Failed to find 'FlashDevice' symbol in ELF file."))
57}
58
59pub fn extract_flash_algo(
61 existing_algo: Option<RawFlashAlgorithm>,
62 buffer: &[u8],
63 file_name: &std::path::Path,
64 default: bool,
65 fixed_load_address: bool,
66) -> Result<RawFlashAlgorithm> {
67 let mut algo = existing_algo.unwrap_or_default();
68
69 let elf = goblin::elf::Elf::parse(buffer)?;
70
71 let flash_device = extract_flash_device(&elf, buffer).context(format!(
72 "Failed to extract flash information from ELF file '{}'.",
73 file_name.display()
74 ))?;
75
76 let algorithm_binary = crate::algorithm_binary::AlgorithmBinary::new(&elf, buffer)?;
78 algo.instructions = algorithm_binary.blob();
79
80 let code_section_offset = algorithm_binary.code_section.start;
81
82 for sym in elf.syms.iter() {
85 let name = &elf.strtab[sym.st_name];
86
87 match name {
88 "Init" => algo.pc_init = Some(sym.st_value - code_section_offset as u64),
89 "UnInit" => algo.pc_uninit = Some(sym.st_value - code_section_offset as u64),
90 "EraseChip" => algo.pc_erase_all = Some(sym.st_value - code_section_offset as u64),
91 "EraseSector" => algo.pc_erase_sector = sym.st_value - code_section_offset as u64,
92 "ProgramPage" => algo.pc_program_page = sym.st_value - code_section_offset as u64,
93 "Verify" => algo.pc_verify = Some(sym.st_value - code_section_offset as u64),
94 "BlankCheck" => algo.pc_blank_check = Some(sym.st_value - code_section_offset as u64),
95 "ReadFlash" => algo.pc_read = Some(sym.st_value - code_section_offset as u64),
97 "FlashSize" => algo.pc_flash_size = Some(sym.st_value - code_section_offset as u64),
98 "_SEGGER_RTT" => {
99 algo.rtt_location = Some(sym.st_value);
100 log::debug!("Found RTT control block at address {:#010x}", sym.st_value);
101 }
102 "PAGE_BUFFER" => {
103 algo.data_load_address = Some(sym.st_value);
104 log::debug!("Found PAGE_BUFFER at address {:#010x}", sym.st_value);
105 }
106
107 _ => {}
108 }
109 }
110
111 if fixed_load_address {
112 log::debug!(
113 "Flash algorithm will be loaded at fixed address {:#010x}",
114 algorithm_binary.code_section.load_address
115 );
116
117 anyhow::ensure!(
118 algorithm_binary.is_continuous_in_ram(),
119 "If the flash algorithm is not position independent, all sections have to follow each other in RAM. \
120 Please check your linkerscript."
121 );
122
123 algo.load_address = Some(algorithm_binary.code_section.load_address as u64);
124 algo.data_section_offset = (algorithm_binary.data_section.start
125 - algorithm_binary.code_section.load_address) as u64;
126 } else {
127 algo.data_section_offset = algorithm_binary.data_section.start as u64;
128 }
129
130 algo.description.clone_from(&flash_device.name);
131 algo.name = file_name
132 .file_stem()
133 .and_then(|f| f.to_str())
134 .unwrap()
135 .to_lowercase();
136 algo.default = default;
137 algo.flash_properties = FlashProperties::from(flash_device);
138 algo.big_endian = !elf.little_endian;
139
140 Ok(algo)
141}
142
143impl From<FlashDevice> for FlashProperties {
144 fn from(device: FlashDevice) -> Self {
145 let sectors = device
146 .sectors
147 .iter()
148 .map(|si| SectorDescription {
149 address: si.address.into(),
150 size: si.size.into(),
151 })
152 .collect();
153
154 FlashProperties {
155 address_range: device.start_address as u64
156 ..(device.start_address as u64 + device.device_size as u64),
157
158 page_size: device.page_size,
159 erased_byte_value: device.erased_default_value,
160
161 program_page_timeout: device.program_page_timeout,
162 erase_sector_timeout: device.erase_sector_timeout,
163
164 sectors,
165 }
166 }
167}