1use itertools::Itertools as _;
2use parking_lot::RwLock;
3use probe_rs_target::{
4 InstructionSet, MemoryRange, MemoryRegion, NvmRegion, RawFlashAlgorithm,
5 TargetDescriptionSource,
6};
7use std::io::{Read, Seek};
8use std::ops::Range;
9use std::sync::LazyLock;
10use std::time::Duration;
11use yaml_serde::Value;
12
13use super::builder::FlashBuilder;
14use super::{DownloadOptions, FileDownloadError, FlashError, Flasher};
15use crate::Target;
16use crate::flashing::progress::ProgressOperation;
17use crate::flashing::{FlashLayout, FlashProgress};
18use crate::memory::MemoryInterface;
19use crate::session::Session;
20
21pub trait ImageFormat: Sync {
25 fn formats(&self) -> &[&str];
27
28 fn create_loader(&self, options: Option<Value>) -> Box<dyn ImageLoader>;
30}
31
32pub trait ImageReader: Read + Seek {}
34
35pub trait ImageLoader {
39 fn load(
41 &self,
42 flash_loader: &mut FlashLoader,
43 session: &mut Session,
44 file: &mut dyn ImageReader,
45 ) -> Result<(), FileDownloadError>;
46}
47
48pub fn into_format_error<E>(format: &str, error: E) -> FileDownloadError
50where
51 E: std::error::Error + Send + Sync + 'static,
52{
53 FileDownloadError::ImageFormatSpecific {
54 format: format.to_string(),
55 source: Box::new(error),
56 }
57}
58
59impl<T> ImageReader for T where T: Read + Seek {}
60
61static LOADERS: LazyLock<RwLock<Vec<&'static dyn ImageFormat>>> = LazyLock::new(|| {
63 #[allow(unused_mut)]
64 let mut image_formats: Vec<&'static dyn ImageFormat> = vec![];
65
66 #[cfg(feature = "builtin-formats")]
67 {
68 image_formats.extend_from_slice(&[
69 &ElfLoaderFactory,
70 &BinLoaderFactory,
71 &HexLoaderFactory,
72 &Uf2LoaderFactory,
73 ]);
74 }
75
76 RwLock::new(image_formats)
77});
78
79pub fn image_format(format: &str) -> Option<&'static dyn ImageFormat> {
86 LOADERS
87 .read()
88 .iter()
89 .find(|factory| factory.formats().contains(&format))
90 .copied()
91}
92
93pub(crate) fn register_image_format(factory: &'static dyn ImageFormat) {
99 LOADERS.write().push(factory);
100}
101
102#[cfg(feature = "builtin-formats")]
103mod builtin {
104 use ihex::Record;
105 use probe_rs_target::MemoryRange;
106 use std::io::SeekFrom;
107 use yaml_serde::Value;
108
109 use object::{
110 Endianness, Object, ObjectSection, elf::FileHeader32, elf::FileHeader64, elf::PT_LOAD,
111 read::elf::ElfFile, read::elf::FileHeader, read::elf::ProgramHeader,
112 };
113
114 use crate::flashing::loader::{FlashLoader, ImageFormat, ImageLoader, ImageReader};
115 use crate::flashing::{BinOptions, ElfOptions, FileDownloadError};
116 use crate::session::Session;
117
118 pub(super) struct ElfLoaderFactory;
119 pub(super) struct BinLoaderFactory;
120 pub(super) struct HexLoaderFactory;
121 pub(super) struct Uf2LoaderFactory;
122
123 impl ImageFormat for ElfLoaderFactory {
124 fn formats(&self) -> &[&str] {
125 &["elf"]
126 }
127
128 fn create_loader(&self, options: Option<Value>) -> Box<dyn ImageLoader> {
129 let options = options
130 .and_then(|value| yaml_serde::from_value(value).ok())
131 .unwrap_or_default();
132 Box::new(ElfLoader(options))
133 }
134 }
135 impl ImageFormat for BinLoaderFactory {
136 fn formats(&self) -> &[&str] {
137 &["bin", "binary"]
138 }
139
140 fn create_loader(&self, options: Option<Value>) -> Box<dyn ImageLoader> {
141 let options = options
142 .and_then(|value| yaml_serde::from_value(value).ok())
143 .unwrap_or_default();
144 Box::new(BinLoader(options))
145 }
146 }
147 impl ImageFormat for HexLoaderFactory {
148 fn formats(&self) -> &[&str] {
149 &["hex", "ihex", "intelhex"]
150 }
151
152 fn create_loader(&self, _options: Option<Value>) -> Box<dyn ImageLoader> {
153 Box::new(HexLoader)
154 }
155 }
156 impl ImageFormat for Uf2LoaderFactory {
157 fn formats(&self) -> &[&str] {
158 &["uf2"]
159 }
160
161 fn create_loader(&self, _options: Option<Value>) -> Box<dyn ImageLoader> {
162 Box::new(Uf2Loader)
163 }
164 }
165
166 impl ImageLoader for Box<dyn ImageLoader> {
167 fn load(
168 &self,
169 flash_loader: &mut FlashLoader,
170 session: &mut Session,
171 file: &mut dyn ImageReader,
172 ) -> Result<(), FileDownloadError> {
173 self.as_ref().load(flash_loader, session, file)
174 }
175 }
176
177 pub struct BinLoader(pub BinOptions);
179
180 impl ImageLoader for BinLoader {
181 fn load(
182 &self,
183 flash_loader: &mut FlashLoader,
184 _session: &mut Session,
185 file: &mut dyn ImageReader,
186 ) -> Result<(), FileDownloadError> {
187 file.seek(SeekFrom::Start(u64::from(self.0.skip)))?;
189
190 let mut buf = Vec::new();
191 file.read_to_end(&mut buf)?;
192
193 flash_loader.add_data(
194 self.0.base_address.unwrap_or_default(),
197 &buf,
198 )?;
199
200 Ok(())
201 }
202 }
203
204 pub struct ElfLoader(pub ElfOptions);
207
208 impl ImageLoader for ElfLoader {
209 fn load(
210 &self,
211 flash_loader: &mut FlashLoader,
212 _session: &mut Session,
213 file: &mut dyn ImageReader,
214 ) -> Result<(), FileDownloadError> {
215 const VECTOR_TABLE_SECTION_NAME: &str = ".vector_table";
216 let mut elf_buffer = Vec::new();
217 file.read_to_end(&mut elf_buffer)?;
218
219 let extracted_data = extract_from_elf(&elf_buffer, &self.0)?;
220
221 if extracted_data.is_empty() {
222 tracing::warn!("No loadable segments were found in the ELF file.");
223 return Err(FileDownloadError::NoLoadableSegments);
224 }
225
226 tracing::info!("Found {} loadable sections:", extracted_data.len());
227
228 for section in &extracted_data {
229 let sources = §ion.section_names;
230 for name in §ion.section_names {
231 if name == VECTOR_TABLE_SECTION_NAME {
232 flash_loader.set_vector_table_addr(section.address as _);
233 }
234 }
235
236 tracing::info!(
237 " {:?} at {:#010X} ({} byte{})",
238 sources,
239 section.address,
240 section.data.len(),
241 if section.data.len() == 1 { "" } else { "s" }
242 );
243 }
244
245 for data in extracted_data {
246 flash_loader.add_data(data.address.into(), data.data)?;
247 }
248
249 Ok(())
250 }
251 }
252
253 pub(super) fn extract_from_elf<'a>(
254 elf_data: &'a [u8],
255 options: &ElfOptions,
256 ) -> Result<Vec<ExtractedFlashData<'a>>, FileDownloadError> {
257 let file_kind = object::FileKind::parse(elf_data)?;
258
259 match file_kind {
260 object::FileKind::Elf32 => {
261 let elf_header = FileHeader32::<Endianness>::parse(elf_data)?;
262 let binary =
263 object::read::elf::ElfFile::<FileHeader32<Endianness>>::parse(elf_data)?;
264 extract_from_elf_inner(elf_header, binary, elf_data, options)
265 }
266 object::FileKind::Elf64 => {
267 let elf_header = FileHeader64::<Endianness>::parse(elf_data)?;
268 let binary =
269 object::read::elf::ElfFile::<FileHeader64<Endianness>>::parse(elf_data)?;
270 extract_from_elf_inner(elf_header, binary, elf_data, options)
271 }
272 _ => Err(FileDownloadError::Object("Unsupported file type")),
273 }
274 }
275
276 fn extract_from_elf_inner<'data, T: FileHeader>(
277 elf_header: &T,
278 binary: ElfFile<'_, T>,
279 elf_data: &'data [u8],
280 options: &ElfOptions,
281 ) -> Result<Vec<ExtractedFlashData<'data>>, FileDownloadError> {
282 let endian = elf_header.endian()?;
283
284 let mut extracted_data = Vec::new();
285 for segment in elf_header.program_headers(elf_header.endian()?, elf_data)? {
286 let p_paddr: u64 = segment.p_paddr(endian).into();
288
289 let p_vaddr: u64 = segment.p_vaddr(endian).into();
290
291 let flags = segment.p_flags(endian);
292
293 let segment_data = segment.data(endian, elf_data).map_err(|_| {
294 FileDownloadError::Object("Failed to access data for an ELF segment.")
295 })?;
296
297 let mut elf_section = Vec::new();
298
299 if !segment_data.is_empty() && segment.p_type(endian) == PT_LOAD {
300 tracing::info!(
301 "Found loadable segment, physical address: {:#010x}, virtual address: {:#010x}, flags: {:#x}",
302 p_paddr,
303 p_vaddr,
304 flags
305 );
306
307 let (segment_offset, segment_filesize) = segment.file_range(endian);
308
309 let sector = segment_offset..segment_offset + segment_filesize;
310
311 for section in binary.sections() {
312 let (section_offset, section_filesize) = match section.file_range() {
313 Some(range) => range,
314 None => continue,
315 };
316
317 if sector.contains_range(&(section_offset..section_offset + section_filesize)) {
318 let name = section.name()?;
319 if options.skip_sections.iter().any(|skip| skip == name) {
320 tracing::info!("Skipping section: {:?}", name);
321 continue;
322 }
323 tracing::info!("Matching section: {:?}", name);
324
325 #[cfg(feature = "hexdump")]
326 for line in hexdump::hexdump_iter(section.data()?) {
327 tracing::trace!("{}", line);
328 }
329
330 for (offset, relocation) in section.relocations() {
331 tracing::info!(
332 "Relocation: offset={}, relocation={:?}",
333 offset,
334 relocation
335 );
336 }
337
338 elf_section.push(name.to_owned());
339 }
340 }
341
342 if elf_section.is_empty() {
343 tracing::info!("Not adding segment, no matching sections found.");
344 } else {
345 let section_data =
346 &elf_data[segment_offset as usize..][..segment_filesize as usize];
347
348 extracted_data.push(ExtractedFlashData {
349 section_names: elf_section,
350 address: p_paddr as u32,
351 data: section_data,
352 });
353 }
354 }
355 }
356
357 Ok(extracted_data)
358 }
359
360 pub(super) struct ExtractedFlashData<'data> {
362 pub(super) section_names: Vec<String>,
363 pub(super) address: u32,
364 pub(super) data: &'data [u8],
365 }
366
367 impl std::fmt::Debug for ExtractedFlashData<'_> {
368 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
369 let mut helper = f.debug_struct("ExtractedFlashData");
370
371 helper
372 .field("name", &self.section_names)
373 .field("address", &self.address);
374
375 if self.data.len() > 10 {
376 helper
377 .field("data", &format!("[..] ({} bytes)", self.data.len()))
378 .finish()
379 } else {
380 helper.field("data", &self.data).finish()
381 }
382 }
383 }
384
385 pub struct HexLoader;
388
389 impl ImageLoader for HexLoader {
390 fn load(
391 &self,
392 flash_loader: &mut FlashLoader,
393 _session: &mut Session,
394 file: &mut dyn ImageReader,
395 ) -> Result<(), FileDownloadError> {
396 let mut base_address = 0;
397
398 let mut data = String::new();
399 file.read_to_string(&mut data)?;
400
401 for record in ihex::Reader::new(&data) {
402 match record? {
403 Record::Data { offset, value } => {
404 let offset = base_address + offset as u64;
405 flash_loader.add_data(offset, &value)?;
406 }
407 Record::ExtendedSegmentAddress(address) => {
408 base_address = (address as u64) * 16;
409 }
410 Record::ExtendedLinearAddress(address) => {
411 base_address = (address as u64) << 16;
412 }
413
414 Record::EndOfFile
415 | Record::StartSegmentAddress { .. }
416 | Record::StartLinearAddress(_) => {}
417 }
418 }
419 Ok(())
420 }
421 }
422
423 pub struct Uf2Loader;
426
427 impl ImageLoader for Uf2Loader {
428 fn load(
429 &self,
430 flash_loader: &mut FlashLoader,
431 _session: &mut Session,
432 file: &mut dyn ImageReader,
433 ) -> Result<(), FileDownloadError> {
434 let mut uf2_buffer = Vec::new();
435 file.read_to_end(&mut uf2_buffer)?;
436
437 let (converted, family_to_target) = uf2_decode::convert_from_uf2(&uf2_buffer).unwrap();
438 let target_addresses = family_to_target.values();
439 let num_sections = family_to_target.len();
440
441 if let Some(target_address) = target_addresses.min() {
442 tracing::info!("Found {} loadable sections:", num_sections);
443 if num_sections > 1 {
444 tracing::warn!("More than 1 section found in UF2 file. Using first section.");
445 }
446 flash_loader.add_data(*target_address, &converted)?;
447
448 Ok(())
449 } else {
450 tracing::warn!("No loadable segments were found in the UF2 file.");
451 Err(FileDownloadError::NoLoadableSegments)
452 }
453 }
454 }
455}
456
457#[cfg(feature = "builtin-formats")]
458pub use builtin::*;
459
460#[derive(Clone, Debug, Default)]
462pub enum BootInfo {
463 FromRam {
465 vector_table_addr: u64,
467 cores_to_reset: Vec<String>,
469 },
470 #[default]
472 Other,
473}
474
475pub struct FlashLoader {
482 memory_map: Vec<MemoryRegion>,
483 builder: FlashBuilder,
484
485 source: TargetDescriptionSource,
488 vector_table_addr: Option<u64>,
490
491 read_flasher_rtt: bool,
492}
493
494impl FlashLoader {
495 pub fn new(memory_map: Vec<MemoryRegion>, source: TargetDescriptionSource) -> Self {
497 Self {
498 memory_map,
499 builder: FlashBuilder::new(),
500 source,
501 vector_table_addr: None,
502 read_flasher_rtt: false,
503 }
504 }
505
506 pub fn flash_builder(&self) -> &FlashBuilder {
509 &self.builder
510 }
511
512 pub fn read_rtt_output(&mut self, read: bool) {
514 self.read_flasher_rtt = read;
515 }
516
517 pub fn vector_table_addr(&self) -> Option<u64> {
519 self.vector_table_addr
520 }
521
522 pub fn set_vector_table_addr(&mut self, vector_table_addr: u64) {
524 self.vector_table_addr = Some(vector_table_addr);
525 }
526
527 pub fn boot_info(&self) -> BootInfo {
529 let Some(vector_table_addr) = self.vector_table_addr else {
530 return BootInfo::Other;
531 };
532
533 match Self::get_region_for_address(&self.memory_map, vector_table_addr) {
534 Some(MemoryRegion::Ram(region)) => BootInfo::FromRam {
535 vector_table_addr,
536 cores_to_reset: region.cores.clone(),
537 },
538 _ => BootInfo::Other,
539 }
540 }
541
542 fn check_data_in_memory_map(&mut self, range: Range<u64>) -> Result<(), FlashError> {
545 let mut address = range.start;
546 while address < range.end {
547 match Self::get_region_for_address(&self.memory_map, address) {
548 Some(MemoryRegion::Nvm(region)) => address = region.range.end,
549 Some(MemoryRegion::Ram(region)) => address = region.range.end,
550 _ => {
551 return Err(FlashError::NoSuitableNvm {
552 range,
553 description_source: self.source.clone(),
554 });
555 }
556 }
557 }
558 Ok(())
559 }
560
561 pub fn add_data(&mut self, address: u64, data: &[u8]) -> Result<(), FlashError> {
565 tracing::trace!(
566 "Adding data at address {:#010x} with size {} bytes",
567 address,
568 data.len()
569 );
570
571 self.check_data_in_memory_map(address..address + data.len() as u64)?;
572 self.builder.add_data(address, data)
573 }
574
575 pub(super) fn get_region_for_address(
576 memory_map: &[MemoryRegion],
577 address: u64,
578 ) -> Option<&MemoryRegion> {
579 memory_map.iter().find(|region| region.contains(address))
580 }
581
582 pub fn has_data_for_address(&self, address: u64) -> bool {
584 self.builder.has_data_in_range(&(address..address + 1))
585 }
586
587 pub fn load_image<T: Read + Seek>(
589 &mut self,
590 session: &mut Session,
591 file: &mut T,
592 format: impl ImageLoader,
593 image_instruction_set: Option<InstructionSet>,
594 ) -> Result<(), FileDownloadError> {
595 if let Some(instr_set) = image_instruction_set {
596 let mut target_archs = Vec::with_capacity(session.list_cores().len());
597
598 for (core, _) in session.list_cores() {
600 match session.core(core) {
601 Ok(mut core) => {
602 if let Ok(set) = core.instruction_set()
603 && !target_archs.contains(&set)
604 {
605 target_archs.push(set);
606 }
607 }
608 Err(crate::Error::CoreDisabled(_)) => continue,
609 Err(error) => return Err(FileDownloadError::Other(error)),
610 }
611 }
612
613 if !target_archs
615 .iter()
616 .any(|target| target.is_compatible(instr_set))
617 {
618 return Err(FileDownloadError::IncompatibleImage {
619 target: target_archs,
620 image: instr_set,
621 });
622 }
623 }
624
625 format.load(self, session, file)
626 }
627
628 pub fn verify(
630 &self,
631 session: &mut Session,
632 progress: &mut FlashProgress<'_>,
633 ) -> Result<(), FlashError> {
634 let mut algos = self.prepare_plan(session, false, &[])?;
635
636 for flasher in algos.iter_mut() {
637 let mut program_size = 0;
638 for region in flasher.regions.iter_mut() {
639 program_size += region
640 .data
641 .encoder(flasher.flash_algorithm.transfer_encoding, true)
642 .program_size();
643 }
644 progress.add_progress_bar(ProgressOperation::Verify, Some(program_size));
645 }
646
647 for mut flasher in algos {
649 tracing::debug!(
650 "Verifying ranges for algo: {}",
651 flasher.flash_algorithm.name
652 );
653
654 if !flasher.verify(session, progress, true)? {
655 return Err(FlashError::Verify);
656 }
657 }
658
659 self.verify_ram(session)?;
660
661 Ok(())
662 }
663
664 pub fn commit(
668 &self,
669 session: &mut Session,
670 mut options: DownloadOptions,
671 ) -> Result<(), FlashError> {
672 tracing::debug!("Committing FlashLoader!");
673 let mut algos = self.prepare_plan(
674 session,
675 options.keep_unwritten_bytes,
676 &options.preferred_algos,
677 )?;
678
679 if options.dry_run {
680 tracing::info!("Skipping programming, dry run!");
681
682 options.progress.failed_filling();
683 options.progress.failed_erasing();
684 options.progress.failed_programming();
685
686 return Ok(());
687 }
688
689 self.initialize(&mut algos, session, &mut options)?;
690
691 let mut do_chip_erase = options.do_chip_erase;
692 let mut did_chip_erase = false;
693
694 for mut flasher in algos {
696 tracing::debug!("Flashing ranges for algo: {}", flasher.flash_algorithm.name);
697
698 if do_chip_erase {
699 tracing::debug!(" Doing chip erase...");
700 flasher.run_erase_all(session, &mut options.progress)?;
701 do_chip_erase = false;
702 did_chip_erase = true;
703 }
704
705 let mut do_use_double_buffering = flasher.double_buffering_supported();
706 if do_use_double_buffering && options.disable_double_buffering {
707 tracing::info!(
708 "Disabled double-buffering support for loader via passed option, though target supports it."
709 );
710 do_use_double_buffering = false;
711 }
712
713 flasher.program(
715 session,
716 &mut options.progress,
717 options.keep_unwritten_bytes,
718 do_use_double_buffering,
719 options.skip_erase || did_chip_erase,
720 options.verify,
721 )?;
722 }
723
724 tracing::debug!("Committing RAM!");
725
726 if let BootInfo::FromRam { cores_to_reset, .. } = self.boot_info() {
727 tracing::debug!(
730 " -- action: vector table in RAM, assuming RAM boot, resetting and halting"
731 );
732 for (core_to_reset_index, _) in session
733 .target()
734 .cores
735 .clone()
736 .iter()
737 .enumerate()
738 .filter(|(_, c)| cores_to_reset.contains(&c.name))
739 {
740 session
741 .core(core_to_reset_index)
742 .and_then(|mut core| core.reset_and_halt(Duration::from_millis(500)))
743 .map_err(FlashError::Core)?;
744 }
745 }
746
747 for region in self
749 .memory_map
750 .iter()
751 .filter_map(MemoryRegion::as_ram_region)
752 {
753 let ranges_in_region: Vec<_> = self.builder.data_in_range(®ion.range).collect();
754
755 if ranges_in_region.is_empty() {
756 continue;
757 }
758
759 tracing::debug!(
760 " region: {:#010X?} ({} bytes)",
761 region.range,
762 region.range.end - region.range.start
763 );
764
765 let region_core_index = session
766 .target()
767 .core_index_by_name(
768 region
769 .cores
770 .first()
771 .ok_or_else(|| FlashError::NoRamCoreAccess(region.clone()))?,
772 )
773 .unwrap();
774
775 let mut core = session.core(region_core_index).map_err(FlashError::Core)?;
777
778 if !core.core_halted().map_err(FlashError::Core)? {
782 tracing::debug!(
783 " -- action: core is not halted and RAM is being written, halting"
784 );
785 core.halt(Duration::from_millis(500))
786 .map_err(FlashError::Core)?;
787 }
788
789 for (address, data) in ranges_in_region {
790 tracing::debug!(
791 " -- writing: {:#010X}..{:#010X} ({} bytes)",
792 address,
793 address + data.len() as u64,
794 data.len()
795 );
796 core.write(address, data).map_err(FlashError::Core)?;
798 }
799 }
800
801 if options.verify {
802 self.verify_ram(session)?;
803 }
804
805 Ok(())
806 }
807
808 fn prepare_plan(
809 &self,
810 session: &mut Session,
811 restore_unwritten_bytes: bool,
812 opt_preferred_algos: &[String],
813 ) -> Result<Vec<Flasher>, FlashError> {
814 tracing::debug!("Contents of builder:");
815 for (&address, data) in &self.builder.data {
816 tracing::debug!(
817 " data: {:#010X}..{:#010X} ({} bytes)",
818 address,
819 address + data.len() as u64,
820 data.len()
821 );
822 }
823
824 tracing::debug!("Flash algorithms:");
825 for algorithm in &session.target().flash_algorithms {
826 let Range { start, end } = algorithm.flash_properties.address_range;
827
828 tracing::debug!(
829 " algo {}: {:#010X}..{:#010X} ({} bytes)",
830 algorithm.name,
831 start,
832 end,
833 end - start
834 );
835 }
836
837 if self.memory_map != session.target().memory_map {
840 tracing::warn!("Memory map of flash loader does not match memory map of target!");
841 }
842
843 let mut algos = Vec::<Flasher>::new();
844
845 tracing::debug!("Regions:");
855 for region in self
856 .memory_map
857 .iter()
858 .filter_map(MemoryRegion::as_nvm_region)
859 {
860 tracing::debug!(
861 " region: {:#010X?} ({} bytes)",
862 region.range,
863 region.range.end - region.range.start
864 );
865
866 if !self.builder.has_data_in_range(®ion.range) {
871 tracing::debug!(" -- empty, ignoring!");
872 continue;
873 }
874
875 let region = region.clone();
876
877 let Some(core_name) = region.cores.first() else {
878 return Err(FlashError::NoNvmCoreAccess(region));
879 };
880
881 let target = session.target();
882 let core = target.core_index_by_name(core_name).unwrap();
883 let algo = Self::get_flash_algorithm_for_region(
884 ®ion,
885 target,
886 core_name,
887 opt_preferred_algos,
888 )?;
889
890 tracing::debug!(" -- using algorithm: {}", algo.name);
892 if let Some(entry) = algos
893 .iter_mut()
894 .find(|entry| entry.flash_algorithm.name == algo.name && entry.core_index == core)
895 {
896 entry.add_region(region, &self.builder, restore_unwritten_bytes)?;
897 } else {
898 let mut flasher = Flasher::new(target, core, algo)?;
899 flasher.add_region(region, &self.builder, restore_unwritten_bytes)?;
900
901 flasher.read_rtt_output(self.read_flasher_rtt);
902
903 algos.push(flasher);
904 }
905 }
906
907 Ok(algos)
908 }
909
910 fn initialize(
911 &self,
912 algos: &mut [Flasher],
913 session: &mut Session,
914 options: &mut DownloadOptions,
915 ) -> Result<(), FlashError> {
916 let mut phases = vec![];
917
918 for flasher in algos.iter() {
919 if options.do_chip_erase && !flasher.is_chip_erase_supported(session) {
922 options.do_chip_erase = false;
923 tracing::warn!(
924 "Chip erase was the selected method to erase the sectors but this chip does not support chip erases (yet)."
925 );
926 tracing::warn!("A manual sector erase will be performed.");
927 }
928 }
929
930 if options.do_chip_erase {
931 options
932 .progress
933 .add_progress_bar(ProgressOperation::Erase, None);
934 }
935
936 for flasher in algos.iter_mut() {
938 let mut phase_layout = FlashLayout::default();
939
940 let mut fill_size = 0;
941 let mut erase_size = 0;
942 let mut program_size = 0;
943
944 for region in flasher.regions.iter_mut() {
945 let layout = region.flash_layout();
946 phase_layout.merge_from(layout.clone());
947
948 erase_size += layout.sectors().iter().map(|s| s.size()).sum::<u64>();
949 fill_size += layout.fills().iter().map(|s| s.size()).sum::<u64>();
950 program_size += region
951 .data
952 .encoder(
953 flasher.flash_algorithm.transfer_encoding,
954 !options.keep_unwritten_bytes,
955 )
956 .program_size();
957 }
958
959 if options.keep_unwritten_bytes {
960 options
961 .progress
962 .add_progress_bar(ProgressOperation::Fill, Some(fill_size));
963 }
964 if !options.do_chip_erase {
965 options
966 .progress
967 .add_progress_bar(ProgressOperation::Erase, Some(erase_size));
968 }
969 options
970 .progress
971 .add_progress_bar(ProgressOperation::Program, Some(program_size));
972 if options.verify {
973 options
974 .progress
975 .add_progress_bar(ProgressOperation::Verify, Some(program_size));
976 }
977
978 phases.push(phase_layout);
979 }
980
981 options.progress.initialized(phases);
982
983 Ok(())
984 }
985
986 fn verify_ram(&self, session: &mut Session) -> Result<(), FlashError> {
987 tracing::debug!("Verifying RAM!");
988 for (&address, data) in &self.builder.data {
989 tracing::debug!(
990 " data: {:#010X}..{:#010X} ({} bytes)",
991 address,
992 address + data.len() as u64,
993 data.len()
994 );
995
996 let associated_region = session.target().memory_region_by_address(address).unwrap();
997
998 if !associated_region.is_ram() {
1000 continue;
1001 }
1002
1003 let core_name = associated_region.cores().first().unwrap();
1004 let core_index = session.target().core_index_by_name(core_name).unwrap();
1005 let mut core = session.core(core_index).map_err(FlashError::Core)?;
1006
1007 let mut written_data = vec![0; data.len()];
1008 core.read(address, &mut written_data)
1009 .map_err(FlashError::Core)?;
1010
1011 if data != &written_data {
1012 return Err(FlashError::Verify);
1013 }
1014 }
1015
1016 Ok(())
1017 }
1018
1019 pub(crate) fn get_flash_algorithm_for_region<'a>(
1025 region: &NvmRegion,
1026 target: &'a Target,
1027 core_name: &String,
1028 preferred_algos: &[String],
1029 ) -> Result<&'a RawFlashAlgorithm, FlashError> {
1030 let available = &target.flash_algorithms;
1031 tracing::debug!("Available algorithms:");
1032 for algorithm in available {
1033 tracing::debug!(
1034 "Algorithm: {} for {:?} @ 0x{:08x} - 0x{:08x} default? {}",
1035 algorithm.name,
1036 algorithm.cores,
1037 algorithm.flash_properties.address_range.start,
1038 algorithm.flash_properties.address_range.end,
1039 algorithm.default
1040 );
1041 }
1042 let algorithms = target
1043 .flash_algorithms
1044 .iter()
1045 .filter(|&fa| {
1047 fa.flash_properties
1048 .address_range
1049 .contains_range(®ion.range)
1050 && (fa.cores.is_empty() || fa.cores.contains(core_name))
1051 })
1052 .collect::<Vec<_>>();
1053
1054 match algorithms.len() {
1055 0 => Err(FlashError::NoFlashLoaderAlgorithmAttached {
1056 range: region.range.clone(),
1057 name: target.name.clone(),
1058 }),
1059 1 => Ok(algorithms[0]),
1060 _ => {
1061 let defaults = algorithms
1063 .iter()
1064 .filter(|&fa| fa.default)
1065 .collect::<Vec<_>>();
1066
1067 if !preferred_algos.is_empty() {
1068 tracing::debug!("selecting preferred algorithm from: {:?}", preferred_algos);
1069 let mut preferred_and_valid_algos = Vec::new();
1070 for algo in algorithms.iter() {
1073 if preferred_algos.iter().contains(&algo.name) {
1074 preferred_and_valid_algos.push(algo);
1075 }
1076 }
1077 if preferred_and_valid_algos.len() > 1 {
1078 return Err(FlashError::MultiplePreferredAlgos {
1079 region: region.clone(),
1080 });
1081 }
1082 if preferred_and_valid_algos.len() == 1 {
1084 return Ok(preferred_and_valid_algos[0]);
1085 }
1086 }
1087
1088 match defaults.len() {
1089 0 => Err(FlashError::MultipleFlashLoaderAlgorithmsNoDefault {
1090 region: region.clone(),
1091 }),
1092 1 => Ok(defaults[0]),
1093 _ => Err(FlashError::MultipleDefaultFlashLoaderAlgorithms {
1094 region: region.clone(),
1095 }),
1096 }
1097 }
1098 }
1099 }
1100
1101 pub fn data(&self) -> impl Iterator<Item = (u64, &[u8])> {
1103 self.builder
1104 .data
1105 .iter()
1106 .map(|(address, data)| (*address, data.as_slice()))
1107 }
1108}