1use espflash::flasher::{FlashData, FlashSettings, FlashSize};
2use espflash::image_format::idf::IdfBootloaderFormat;
3use ihex::Record;
4use probe_rs_target::{
5 InstructionSet, MemoryRange, MemoryRegion, NvmRegion, RawFlashAlgorithm,
6 TargetDescriptionSource,
7};
8use std::io::{Read, Seek, SeekFrom};
9use std::ops::Range;
10use std::str::FromStr;
11use std::time::Duration;
12
13use super::builder::FlashBuilder;
14use super::{
15 BinOptions, DownloadOptions, ElfOptions, FileDownloadError, FlashError, Flasher, IdfOptions,
16 extract_from_elf,
17};
18use crate::Target;
19use crate::config::DebugSequence;
20use crate::flashing::progress::ProgressOperation;
21use crate::flashing::{FlashLayout, FlashProgress, Format};
22use crate::memory::MemoryInterface;
23use crate::session::Session;
24
25pub trait ImageReader: Read + Seek {}
27impl<T> ImageReader for T where T: Read + Seek {}
28
29pub trait ImageLoader {
33 fn load(
35 &self,
36 flash_loader: &mut FlashLoader,
37 session: &mut Session,
38 file: &mut dyn ImageReader,
39 ) -> Result<(), FileDownloadError>;
40}
41
42impl ImageLoader for Format {
43 fn load(
44 &self,
45 flash_loader: &mut FlashLoader,
46 session: &mut Session,
47 file: &mut dyn ImageReader,
48 ) -> Result<(), FileDownloadError> {
49 match self {
50 Format::Bin(options) => BinLoader(options.clone()).load(flash_loader, session, file),
51 Format::Elf(options) => ElfLoader(options.clone()).load(flash_loader, session, file),
52 Format::Hex => HexLoader.load(flash_loader, session, file),
53 Format::Idf(options) => IdfLoader(options.clone()).load(flash_loader, session, file),
54 Format::Uf2 => Uf2Loader.load(flash_loader, session, file),
55 }
56 }
57}
58
59struct BinLoader(BinOptions);
61
62impl ImageLoader for BinLoader {
63 fn load(
64 &self,
65 flash_loader: &mut FlashLoader,
66 _session: &mut Session,
67 file: &mut dyn ImageReader,
68 ) -> Result<(), FileDownloadError> {
69 file.seek(SeekFrom::Start(u64::from(self.0.skip)))?;
71
72 let mut buf = Vec::new();
73 file.read_to_end(&mut buf)?;
74
75 flash_loader.add_data(
76 self.0.base_address.unwrap_or_default(),
79 &buf,
80 )?;
81
82 Ok(())
83 }
84}
85
86struct ElfLoader(ElfOptions);
89
90impl ImageLoader for ElfLoader {
91 fn load(
92 &self,
93 flash_loader: &mut FlashLoader,
94 _session: &mut Session,
95 file: &mut dyn ImageReader,
96 ) -> Result<(), FileDownloadError> {
97 const VECTOR_TABLE_SECTION_NAME: &str = ".vector_table";
98 let mut elf_buffer = Vec::new();
99 file.read_to_end(&mut elf_buffer)?;
100
101 let extracted_data = extract_from_elf(&elf_buffer, &self.0)?;
102
103 if extracted_data.is_empty() {
104 tracing::warn!("No loadable segments were found in the ELF file.");
105 return Err(FileDownloadError::NoLoadableSegments);
106 }
107
108 tracing::info!("Found {} loadable sections:", extracted_data.len());
109
110 for section in &extracted_data {
111 let source = match section.section_names.len() {
112 0 => "Unknown",
113 1 => section.section_names[0].as_str(),
114 _ => "Multiple sections",
115 };
116
117 if source == VECTOR_TABLE_SECTION_NAME {
118 flash_loader.set_vector_table_addr(section.address as _);
119 }
120
121 tracing::info!(
122 " {} at {:#010X} ({} byte{})",
123 source,
124 section.address,
125 section.data.len(),
126 if section.data.len() == 1 { "" } else { "s" }
127 );
128 }
129
130 for data in extracted_data {
131 flash_loader.add_data(data.address.into(), data.data)?;
132 }
133
134 Ok(())
135 }
136}
137
138struct HexLoader;
141
142impl ImageLoader for HexLoader {
143 fn load(
144 &self,
145 flash_loader: &mut FlashLoader,
146 _session: &mut Session,
147 file: &mut dyn ImageReader,
148 ) -> Result<(), FileDownloadError> {
149 let mut base_address = 0;
150
151 let mut data = String::new();
152 file.read_to_string(&mut data)?;
153
154 for record in ihex::Reader::new(&data) {
155 match record? {
156 Record::Data { offset, value } => {
157 let offset = base_address + offset as u64;
158 flash_loader.add_data(offset, &value)?;
159 }
160 Record::ExtendedSegmentAddress(address) => {
161 base_address = (address as u64) * 16;
162 }
163 Record::ExtendedLinearAddress(address) => {
164 base_address = (address as u64) << 16;
165 }
166
167 Record::EndOfFile
168 | Record::StartSegmentAddress { .. }
169 | Record::StartLinearAddress(_) => {}
170 }
171 }
172 Ok(())
173 }
174}
175
176struct Uf2Loader;
179
180impl ImageLoader for Uf2Loader {
181 fn load(
182 &self,
183 flash_loader: &mut FlashLoader,
184 _session: &mut Session,
185 file: &mut dyn ImageReader,
186 ) -> Result<(), FileDownloadError> {
187 let mut uf2_buffer = Vec::new();
188 file.read_to_end(&mut uf2_buffer)?;
189
190 let (converted, family_to_target) = uf2_decode::convert_from_uf2(&uf2_buffer).unwrap();
191 let target_addresses = family_to_target.values();
192 let num_sections = family_to_target.len();
193
194 if let Some(target_address) = target_addresses.min() {
195 tracing::info!("Found {} loadable sections:", num_sections);
196 if num_sections > 1 {
197 tracing::warn!("More than 1 section found in UF2 file. Using first section.");
198 }
199 flash_loader.add_data(*target_address, &converted)?;
200
201 Ok(())
202 } else {
203 tracing::warn!("No loadable segments were found in the UF2 file.");
204 Err(FileDownloadError::NoLoadableSegments)
205 }
206 }
207}
208
209struct IdfLoader(IdfOptions);
215
216impl ImageLoader for IdfLoader {
217 fn load(
218 &self,
219 flash_loader: &mut FlashLoader,
220 session: &mut Session,
221 file: &mut dyn ImageReader,
222 ) -> Result<(), FileDownloadError> {
223 let target = session.target();
224 let target_name = target
225 .name
226 .split_once('-')
227 .map(|(name, _)| name)
228 .unwrap_or(target.name.as_str());
229 let chip = espflash::target::Chip::from_str(target_name)
230 .map_err(|_| FileDownloadError::IdfUnsupported(target.name.to_string()))?;
231
232 let flash_size_result = session.halted_access(|session| {
233 match session.target().debug_sequence.clone() {
235 DebugSequence::Riscv(sequence) => sequence.detect_flash_size(session),
236 DebugSequence::Xtensa(sequence) => sequence.detect_flash_size(session),
237 DebugSequence::Arm(_) => panic!("There are no ARM ESP targets."),
238 }
239 });
240
241 let flash_size = match flash_size_result.map_err(FileDownloadError::FlashSizeDetection)? {
242 Some(0x40000) => Some(FlashSize::_256Kb),
243 Some(0x80000) => Some(FlashSize::_512Kb),
244 Some(0x100000) => Some(FlashSize::_1Mb),
245 Some(0x200000) => Some(FlashSize::_2Mb),
246 Some(0x400000) => Some(FlashSize::_4Mb),
247 Some(0x800000) => Some(FlashSize::_8Mb),
248 Some(0x1000000) => Some(FlashSize::_16Mb),
249 Some(0x2000000) => Some(FlashSize::_32Mb),
250 Some(0x4000000) => Some(FlashSize::_64Mb),
251 Some(0x8000000) => Some(FlashSize::_128Mb),
252 Some(0x10000000) => Some(FlashSize::_256Mb),
253 _ => None,
254 };
255
256 let flash_data = FlashData::new(
257 {
258 let mut settings = FlashSettings::default();
259
260 settings.size = flash_size;
261
262 settings
263 },
264 0,
265 None,
266 chip,
267 chip.default_xtal_frequency(),
269 );
270
271 let mut buf = Vec::new();
272 file.read_to_end(&mut buf)?;
273 let image = IdfBootloaderFormat::new(
274 &buf,
275 &flash_data,
276 self.0.partition_table.as_deref(),
277 self.0.bootloader.as_deref(),
278 None,
279 self.0.target_app_partition.as_deref(),
280 )?;
281
282 for data in image.flash_segments() {
283 flash_loader.add_data(data.addr.into(), &data.data)?;
284 }
285
286 Ok(())
287 }
288}
289
290#[derive(Clone, Debug, Default)]
292pub enum BootInfo {
293 FromRam {
295 vector_table_addr: u64,
297 cores_to_reset: Vec<String>,
299 },
300 #[default]
302 Other,
303}
304
305pub struct FlashLoader {
312 memory_map: Vec<MemoryRegion>,
313 builder: FlashBuilder,
314
315 source: TargetDescriptionSource,
318 vector_table_addr: Option<u64>,
320}
321
322impl FlashLoader {
323 pub fn new(memory_map: Vec<MemoryRegion>, source: TargetDescriptionSource) -> Self {
325 Self {
326 memory_map,
327 builder: FlashBuilder::new(),
328 source,
329 vector_table_addr: None,
330 }
331 }
332
333 fn set_vector_table_addr(&mut self, vector_table_addr: u64) {
334 self.vector_table_addr = Some(vector_table_addr);
335 }
336
337 pub fn boot_info(&self) -> BootInfo {
339 let Some(vector_table_addr) = self.vector_table_addr else {
340 return BootInfo::Other;
341 };
342
343 match Self::get_region_for_address(&self.memory_map, vector_table_addr) {
344 Some(MemoryRegion::Ram(region)) => BootInfo::FromRam {
345 vector_table_addr,
346 cores_to_reset: region.cores.clone(),
347 },
348 _ => BootInfo::Other,
349 }
350 }
351
352 fn check_data_in_memory_map(&mut self, range: Range<u64>) -> Result<(), FlashError> {
355 let mut address = range.start;
356 while address < range.end {
357 match Self::get_region_for_address(&self.memory_map, address) {
358 Some(MemoryRegion::Nvm(region)) => address = region.range.end,
359 Some(MemoryRegion::Ram(region)) => address = region.range.end,
360 _ => {
361 return Err(FlashError::NoSuitableNvm {
362 range,
363 description_source: self.source.clone(),
364 });
365 }
366 }
367 }
368 Ok(())
369 }
370
371 pub fn add_data(&mut self, address: u64, data: &[u8]) -> Result<(), FlashError> {
375 tracing::trace!(
376 "Adding data at address {:#010x} with size {} bytes",
377 address,
378 data.len()
379 );
380
381 self.check_data_in_memory_map(address..address + data.len() as u64)?;
382 self.builder.add_data(address, data)
383 }
384
385 pub(super) fn get_region_for_address(
386 memory_map: &[MemoryRegion],
387 address: u64,
388 ) -> Option<&MemoryRegion> {
389 memory_map.iter().find(|region| region.contains(address))
390 }
391
392 pub fn has_data_for_address(&self, address: u64) -> bool {
394 self.builder.has_data_in_range(&(address..address + 1))
395 }
396
397 pub fn load_image<T: Read + Seek>(
399 &mut self,
400 session: &mut Session,
401 file: &mut T,
402 format: Format,
403 image_instruction_set: Option<InstructionSet>,
404 ) -> Result<(), FileDownloadError> {
405 if let Some(instr_set) = image_instruction_set {
406 let mut target_archs = Vec::with_capacity(session.list_cores().len());
407
408 for (core, _) in session.list_cores() {
410 match session.core(core) {
411 Ok(mut core) => {
412 if let Ok(set) = core.instruction_set()
413 && !target_archs.contains(&set)
414 {
415 target_archs.push(set);
416 }
417 }
418 Err(crate::Error::CoreDisabled(_)) => continue,
419 Err(error) => return Err(FileDownloadError::Other(error)),
420 }
421 }
422
423 if !target_archs
425 .iter()
426 .any(|target| target.is_compatible(instr_set))
427 {
428 return Err(FileDownloadError::IncompatibleImage {
429 target: target_archs,
430 image: instr_set,
431 });
432 }
433 }
434
435 format.load(self, session, file)
436 }
437
438 pub fn verify(
440 &self,
441 session: &mut Session,
442 progress: &mut FlashProgress<'_>,
443 ) -> Result<(), FlashError> {
444 let mut algos = self.prepare_plan(session, false)?;
445
446 for flasher in algos.iter_mut() {
447 let mut program_size = 0;
448 for region in flasher.regions.iter_mut() {
449 program_size += region
450 .data
451 .encoder(flasher.flash_algorithm.transfer_encoding, true)
452 .program_size();
453 }
454 progress.add_progress_bar(ProgressOperation::Verify, Some(program_size));
455 }
456
457 for mut flasher in algos {
459 tracing::debug!(
460 "Verifying ranges for algo: {}",
461 flasher.flash_algorithm.name
462 );
463
464 if !flasher.verify(session, progress, true)? {
465 return Err(FlashError::Verify);
466 }
467 }
468
469 self.verify_ram(session)?;
470
471 Ok(())
472 }
473
474 pub fn commit(
478 &self,
479 session: &mut Session,
480 mut options: DownloadOptions,
481 ) -> Result<(), FlashError> {
482 tracing::debug!("Committing FlashLoader!");
483 let mut algos = self.prepare_plan(session, options.keep_unwritten_bytes)?;
484
485 if options.dry_run {
486 tracing::info!("Skipping programming, dry run!");
487
488 options.progress.failed_filling();
489 options.progress.failed_erasing();
490 options.progress.failed_programming();
491
492 return Ok(());
493 }
494
495 self.initialize(&mut algos, session, &mut options)?;
496
497 let mut do_chip_erase = options.do_chip_erase;
498 let mut did_chip_erase = false;
499
500 for mut flasher in algos {
502 tracing::debug!("Flashing ranges for algo: {}", flasher.flash_algorithm.name);
503
504 if do_chip_erase {
505 tracing::debug!(" Doing chip erase...");
506 flasher.run_erase_all(session, &mut options.progress)?;
507 do_chip_erase = false;
508 did_chip_erase = true;
509 }
510
511 let mut do_use_double_buffering = flasher.double_buffering_supported();
512 if do_use_double_buffering && options.disable_double_buffering {
513 tracing::info!(
514 "Disabled double-buffering support for loader via passed option, though target supports it."
515 );
516 do_use_double_buffering = false;
517 }
518
519 flasher.program(
521 session,
522 &mut options.progress,
523 options.keep_unwritten_bytes,
524 do_use_double_buffering,
525 options.skip_erase || did_chip_erase,
526 options.verify,
527 )?;
528 }
529
530 tracing::debug!("Committing RAM!");
531
532 if let BootInfo::FromRam { cores_to_reset, .. } = self.boot_info() {
533 tracing::debug!(
536 " -- action: vector table in RAM, assuming RAM boot, resetting and halting"
537 );
538 for (core_to_reset_index, _) in session
539 .target()
540 .cores
541 .clone()
542 .iter()
543 .enumerate()
544 .filter(|(_, c)| cores_to_reset.contains(&c.name))
545 {
546 session
547 .core(core_to_reset_index)
548 .and_then(|mut core| core.reset_and_halt(Duration::from_millis(500)))
549 .map_err(FlashError::Core)?;
550 }
551 }
552
553 for region in self
555 .memory_map
556 .iter()
557 .filter_map(MemoryRegion::as_ram_region)
558 {
559 let ranges_in_region: Vec<_> = self.builder.data_in_range(®ion.range).collect();
560
561 if ranges_in_region.is_empty() {
562 continue;
563 }
564
565 tracing::debug!(
566 " region: {:#010X?} ({} bytes)",
567 region.range,
568 region.range.end - region.range.start
569 );
570
571 let region_core_index = session
572 .target()
573 .core_index_by_name(
574 region
575 .cores
576 .first()
577 .ok_or_else(|| FlashError::NoRamCoreAccess(region.clone()))?,
578 )
579 .unwrap();
580
581 let mut core = session.core(region_core_index).map_err(FlashError::Core)?;
583
584 if !core.core_halted().map_err(FlashError::Core)? {
588 tracing::debug!(
589 " -- action: core is not halted and RAM is being written, halting"
590 );
591 core.halt(Duration::from_millis(500))
592 .map_err(FlashError::Core)?;
593 }
594
595 for (address, data) in ranges_in_region {
596 tracing::debug!(
597 " -- writing: {:#010X}..{:#010X} ({} bytes)",
598 address,
599 address + data.len() as u64,
600 data.len()
601 );
602 core.write(address, data).map_err(FlashError::Core)?;
604 }
605 }
606
607 if options.verify {
608 self.verify_ram(session)?;
609 }
610
611 Ok(())
612 }
613
614 fn prepare_plan(
615 &self,
616 session: &mut Session,
617 restore_unwritten_bytes: bool,
618 ) -> Result<Vec<Flasher>, FlashError> {
619 tracing::debug!("Contents of builder:");
620 for (&address, data) in &self.builder.data {
621 tracing::debug!(
622 " data: {:#010X}..{:#010X} ({} bytes)",
623 address,
624 address + data.len() as u64,
625 data.len()
626 );
627 }
628
629 tracing::debug!("Flash algorithms:");
630 for algorithm in &session.target().flash_algorithms {
631 let Range { start, end } = algorithm.flash_properties.address_range;
632
633 tracing::debug!(
634 " algo {}: {:#010X}..{:#010X} ({} bytes)",
635 algorithm.name,
636 start,
637 end,
638 end - start
639 );
640 }
641
642 if self.memory_map != session.target().memory_map {
645 tracing::warn!("Memory map of flash loader does not match memory map of target!");
646 }
647
648 let mut algos = Vec::<Flasher>::new();
649
650 tracing::debug!("Regions:");
660 for region in self
661 .memory_map
662 .iter()
663 .filter_map(MemoryRegion::as_nvm_region)
664 {
665 tracing::debug!(
666 " region: {:#010X?} ({} bytes)",
667 region.range,
668 region.range.end - region.range.start
669 );
670
671 if !self.builder.has_data_in_range(®ion.range) {
676 tracing::debug!(" -- empty, ignoring!");
677 continue;
678 }
679
680 let region = region.clone();
681
682 let Some(core_name) = region.cores.first() else {
683 return Err(FlashError::NoNvmCoreAccess(region));
684 };
685
686 let target = session.target();
687 let core = target.core_index_by_name(core_name).unwrap();
688 let algo = Self::get_flash_algorithm_for_region(®ion, target, core_name)?;
689
690 tracing::debug!(" -- using algorithm: {}", algo.name);
692 if let Some(entry) = algos
693 .iter_mut()
694 .find(|entry| entry.flash_algorithm.name == algo.name && entry.core_index == core)
695 {
696 entry.add_region(region, &self.builder, restore_unwritten_bytes)?;
697 } else {
698 let mut flasher = Flasher::new(target, core, algo)?;
699 flasher.add_region(region, &self.builder, restore_unwritten_bytes)?;
700 algos.push(flasher);
701 }
702 }
703
704 Ok(algos)
705 }
706
707 fn initialize(
708 &self,
709 algos: &mut [Flasher],
710 session: &mut Session,
711 options: &mut DownloadOptions,
712 ) -> Result<(), FlashError> {
713 let mut phases = vec![];
714
715 for flasher in algos.iter() {
716 if options.do_chip_erase && !flasher.is_chip_erase_supported(session) {
719 options.do_chip_erase = false;
720 tracing::warn!(
721 "Chip erase was the selected method to erase the sectors but this chip does not support chip erases (yet)."
722 );
723 tracing::warn!("A manual sector erase will be performed.");
724 }
725 }
726
727 if options.do_chip_erase {
728 options
729 .progress
730 .add_progress_bar(ProgressOperation::Erase, None);
731 }
732
733 for flasher in algos.iter_mut() {
735 let mut phase_layout = FlashLayout::default();
736
737 let mut fill_size = 0;
738 let mut erase_size = 0;
739 let mut program_size = 0;
740
741 for region in flasher.regions.iter_mut() {
742 let layout = region.flash_layout();
743 phase_layout.merge_from(layout.clone());
744
745 erase_size += layout.sectors().iter().map(|s| s.size()).sum::<u64>();
746 fill_size += layout.fills().iter().map(|s| s.size()).sum::<u64>();
747 program_size += region
748 .data
749 .encoder(
750 flasher.flash_algorithm.transfer_encoding,
751 !options.keep_unwritten_bytes,
752 )
753 .program_size();
754 }
755
756 if options.keep_unwritten_bytes {
757 options
758 .progress
759 .add_progress_bar(ProgressOperation::Fill, Some(fill_size));
760 }
761 if !options.do_chip_erase {
762 options
763 .progress
764 .add_progress_bar(ProgressOperation::Erase, Some(erase_size));
765 }
766 options
767 .progress
768 .add_progress_bar(ProgressOperation::Program, Some(program_size));
769 if options.verify {
770 options
771 .progress
772 .add_progress_bar(ProgressOperation::Verify, Some(program_size));
773 }
774
775 phases.push(phase_layout);
776 }
777
778 options.progress.initialized(phases);
779
780 Ok(())
781 }
782
783 fn verify_ram(&self, session: &mut Session) -> Result<(), FlashError> {
784 tracing::debug!("Verifying RAM!");
785 for (&address, data) in &self.builder.data {
786 tracing::debug!(
787 " data: {:#010X}..{:#010X} ({} bytes)",
788 address,
789 address + data.len() as u64,
790 data.len()
791 );
792
793 let associated_region = session.target().memory_region_by_address(address).unwrap();
794
795 if !associated_region.is_ram() {
797 continue;
798 }
799
800 let core_name = associated_region.cores().first().unwrap();
801 let core_index = session.target().core_index_by_name(core_name).unwrap();
802 let mut core = session.core(core_index).map_err(FlashError::Core)?;
803
804 let mut written_data = vec![0; data.len()];
805 core.read(address, &mut written_data)
806 .map_err(FlashError::Core)?;
807
808 if data != &written_data {
809 return Err(FlashError::Verify);
810 }
811 }
812
813 Ok(())
814 }
815
816 pub(crate) fn get_flash_algorithm_for_region<'a>(
822 region: &NvmRegion,
823 target: &'a Target,
824 core_name: &String,
825 ) -> Result<&'a RawFlashAlgorithm, FlashError> {
826 let available = &target.flash_algorithms;
827 tracing::debug!("Available algorithms:");
828 for algorithm in available {
829 tracing::debug!(
830 "Algorithm: {} for {:?} @ 0x{:08x} - 0x{:08x} default? {}",
831 algorithm.name,
832 algorithm.cores,
833 algorithm.flash_properties.address_range.start,
834 algorithm.flash_properties.address_range.end,
835 algorithm.default
836 );
837 }
838 let algorithms = target
839 .flash_algorithms
840 .iter()
841 .filter(|&fa| {
843 fa.flash_properties
844 .address_range
845 .contains_range(®ion.range)
846 && (fa.cores.is_empty() || fa.cores.contains(core_name))
847 })
848 .collect::<Vec<_>>();
849
850 match algorithms.len() {
851 0 => Err(FlashError::NoFlashLoaderAlgorithmAttached {
852 range: region.range.clone(),
853 name: target.name.clone(),
854 }),
855 1 => Ok(algorithms[0]),
856 _ => {
857 let defaults = algorithms
859 .iter()
860 .filter(|&fa| fa.default)
861 .collect::<Vec<_>>();
862
863 match defaults.len() {
864 0 => Err(FlashError::MultipleFlashLoaderAlgorithmsNoDefault {
865 region: region.clone(),
866 }),
867 1 => Ok(defaults[0]),
868 _ => Err(FlashError::MultipleDefaultFlashLoaderAlgorithms {
869 region: region.clone(),
870 }),
871 }
872 }
873 }
874 }
875
876 pub fn data(&self) -> impl Iterator<Item = (u64, &[u8])> {
878 self.builder
879 .data
880 .iter()
881 .map(|(address, data)| (*address, data.as_slice()))
882 }
883}