1use super::FlashError;
2use crate::{Target, architecture::riscv, core::Architecture};
3use probe_rs_target::{
4 CoreType, Endian, FlashProperties, MemoryRegion, PageInfo, RamRegion, RawFlashAlgorithm,
5 RegionMergeIterator, SectorInfo, TransferEncoding,
6};
7use std::collections::BTreeMap;
8use std::mem::size_of_val;
9
10#[derive(Debug, Default, Clone)]
17pub struct FlashAlgorithm {
18 pub name: String,
20 pub default: bool,
22 pub load_address: u64,
24 pub instructions: Vec<u32>,
26 pub pc_init: Option<u64>,
28 pub pc_uninit: Option<u64>,
30 pub pc_program_page: u64,
32 pub pc_erase_sector: u64,
34 pub pc_erase_all: Option<u64>,
36 pub pc_verify: Option<u64>,
38 pub pc_blank_check: Option<u64>,
40 pub pc_read: Option<u64>,
42 pub vendor_functions: BTreeMap<String, u64>,
44 pub static_base: u64,
47 pub stack_top: u64,
49 pub stack_size: u64,
51 pub stack_overflow_check: bool,
53 pub page_buffers: Vec<u64>,
57
58 pub rtt_control_block: Option<u64>,
62
63 pub rtt_poll_interval: u64,
65
66 pub flash_properties: FlashProperties,
68
69 pub transfer_encoding: TransferEncoding,
71}
72
73impl FlashAlgorithm {
74 pub fn sector_info(&self, address: u64) -> Option<SectorInfo> {
80 if !self.flash_properties.address_range.contains(&address) {
81 tracing::trace!("Address {:08x} not contained in this flash device", address);
82 return None;
83 }
84
85 let offset_address = address - self.flash_properties.address_range.start;
86
87 let containing_sector = self
88 .flash_properties
89 .sectors
90 .iter()
91 .rfind(|s| s.address <= offset_address)?;
92
93 let sector_index = (offset_address - containing_sector.address) / containing_sector.size;
94
95 let sector_address = self.flash_properties.address_range.start
96 + containing_sector.address
97 + sector_index * containing_sector.size;
98
99 Some(SectorInfo {
100 base_address: sector_address,
101 size: containing_sector.size,
102 })
103 }
104
105 pub fn page_info(&self, address: u64) -> Option<PageInfo> {
108 if !self.flash_properties.address_range.contains(&address) {
109 return None;
110 }
111
112 Some(PageInfo {
113 base_address: address - (address % self.flash_properties.page_size as u64),
114 size: self.flash_properties.page_size,
115 })
116 }
117
118 pub fn iter_sectors(&self) -> impl Iterator<Item = SectorInfo> + '_ {
120 let props = &self.flash_properties;
121
122 assert!(!props.sectors.is_empty());
123 assert!(props.sectors[0].address == 0);
124
125 let mut addr = props.address_range.start;
126 let mut desc_idx = 0;
127 std::iter::from_fn(move || {
128 if addr >= props.address_range.end {
129 return None;
130 }
131
132 if let Some(next_desc) = props.sectors.get(desc_idx + 1)
134 && props.address_range.start + next_desc.address <= addr
135 {
136 desc_idx += 1;
137 }
138
139 let size = props.sectors[desc_idx].size;
140 let sector = SectorInfo {
141 base_address: addr,
142 size,
143 };
144 addr += size;
145
146 Some(sector)
147 })
148 }
149
150 pub fn iter_pages(&self) -> impl Iterator<Item = PageInfo> + '_ {
152 let props = &self.flash_properties;
153
154 let mut addr = props.address_range.start;
155 std::iter::from_fn(move || {
156 if addr >= props.address_range.end {
157 return None;
158 }
159
160 let page = PageInfo {
161 base_address: addr,
162 size: props.page_size,
163 };
164 addr += props.page_size as u64;
165
166 Some(page)
167 })
168 }
169
170 pub fn is_erased(&self, data: &[u8]) -> bool {
172 for b in data {
173 if *b != self.flash_properties.erased_byte_value {
174 return false;
175 }
176 }
177 true
178 }
179
180 const FLASH_ALGO_STACK_SIZE: u32 = 512;
181
182 const RISCV_FLASH_BLOB_HEADER: [u32; 2] = [riscv::assembly::EBREAK, riscv::assembly::EBREAK];
184
185 const ARM_ASSEMBLY_BKPT_T32: u32 = 0xBE00_BE00;
187 const ARM_ASSEMBLY_BKPT_A32: u32 = 0xE1200070;
188 const ARM_ASSEMBLY_HLT: u32 = 0xBA80_BA80;
190
191 const ARM_FLASH_BLOB_HEADER_BKPT_T32_LE: [u32; 1] = [Self::ARM_ASSEMBLY_BKPT_T32];
195 const ARM_FLASH_BLOB_HEADER_BKPT_T32_BE: [u32; 1] = [Self::ARM_ASSEMBLY_BKPT_T32.swap_bytes()];
196 const ARM_FLASH_BLOB_HEADER_BKPT_A32_LE: [u32; 1] = [Self::ARM_ASSEMBLY_BKPT_A32];
197 const ARM_FLASH_BLOB_HEADER_BKPT_A32_BE: [u32; 1] = [Self::ARM_ASSEMBLY_BKPT_A32.swap_bytes()];
198 const ARM_FLASH_BLOB_HEADER_HLT_LE: [u32; 1] = [Self::ARM_ASSEMBLY_HLT];
199 const ARM_FLASH_BLOB_HEADER_HLT_BE: [u32; 1] = [Self::ARM_ASSEMBLY_HLT.swap_bytes()];
200
201 const XTENSA_FLASH_BLOB_HEADER: [u32; 0] = [];
202
203 pub fn get_max_algorithm_header_size() -> u64 {
206 let algos = [
207 Self::algorithm_header(CoreType::Armv6m, Endian::Big),
208 Self::algorithm_header(CoreType::Armv6m, Endian::Little),
209 Self::algorithm_header(CoreType::Armv7a, Endian::Big),
210 Self::algorithm_header(CoreType::Armv7a, Endian::Little),
211 Self::algorithm_header(CoreType::Armv7m, Endian::Big),
212 Self::algorithm_header(CoreType::Armv7m, Endian::Little),
213 Self::algorithm_header(CoreType::Armv7em, Endian::Big),
214 Self::algorithm_header(CoreType::Armv7em, Endian::Little),
215 Self::algorithm_header(CoreType::Armv8a, Endian::Big),
216 Self::algorithm_header(CoreType::Armv8a, Endian::Little),
217 Self::algorithm_header(CoreType::Armv8a, Endian::Big),
218 Self::algorithm_header(CoreType::Armv8a, Endian::Little),
219 Self::algorithm_header(CoreType::Armv8m, Endian::Big),
220 Self::algorithm_header(CoreType::Armv8m, Endian::Little),
221 Self::algorithm_header(CoreType::Riscv, Endian::Little),
222 Self::algorithm_header(CoreType::Riscv64, Endian::Little),
223 Self::algorithm_header(CoreType::Xtensa, Endian::Big),
224 Self::algorithm_header(CoreType::Xtensa, Endian::Little),
225 ];
226
227 algos.iter().copied().map(size_of_val).max().unwrap() as u64
228 }
229
230 fn algorithm_header(core_type: CoreType, endian: Endian) -> &'static [u32] {
231 match core_type {
232 CoreType::Armv6m | CoreType::Armv7m | CoreType::Armv7em | CoreType::Armv8m => {
233 match endian {
234 Endian::Little => &Self::ARM_FLASH_BLOB_HEADER_BKPT_T32_LE,
235 Endian::Big => &Self::ARM_FLASH_BLOB_HEADER_BKPT_T32_BE,
236 }
237 }
238 CoreType::Armv7a | CoreType::Armv7r => match endian {
239 Endian::Little => &Self::ARM_FLASH_BLOB_HEADER_BKPT_A32_LE,
240 Endian::Big => &Self::ARM_FLASH_BLOB_HEADER_BKPT_A32_BE,
241 },
242 CoreType::Armv8a => match endian {
243 Endian::Little => &Self::ARM_FLASH_BLOB_HEADER_HLT_LE,
244 Endian::Big => &Self::ARM_FLASH_BLOB_HEADER_HLT_BE,
245 },
246 CoreType::Riscv | CoreType::Riscv64 => &Self::RISCV_FLASH_BLOB_HEADER,
247 CoreType::Xtensa => &Self::XTENSA_FLASH_BLOB_HEADER,
248 }
249 }
250
251 fn required_stack_alignment(architecture: Architecture) -> u64 {
252 match architecture {
253 Architecture::Arm => 8,
254 Architecture::Riscv => 16,
255 Architecture::Xtensa => 16,
256 }
257 }
258
259 pub fn assemble_from_raw(
261 raw: &RawFlashAlgorithm,
262 ram_region: &RamRegion,
263 target: &Target,
264 ) -> Result<Self, FlashError> {
265 Self::assemble_from_raw_with_data(raw, ram_region, ram_region, target)
266 }
267
268 pub fn assemble_from_raw_with_data(
270 raw: &RawFlashAlgorithm,
271 ram_region: &RamRegion,
272 data_ram_region: &RamRegion,
273 target: &Target,
274 ) -> Result<Self, FlashError> {
275 use std::mem::size_of;
276
277 let assembled_instructions = raw.instructions.chunks_exact(size_of::<u32>());
278
279 let remainder = assembled_instructions.remainder();
280 let last_elem = if !remainder.is_empty() {
281 let word = u32::from_le_bytes(
282 remainder
283 .iter()
284 .cloned()
285 .chain([0u8, 0u8, 0u8])
287 .take(4)
288 .collect::<Vec<u8>>()
289 .try_into()
290 .unwrap(),
291 );
292 Some(word)
293 } else {
294 None
295 };
296
297 let header = Self::algorithm_header(
298 target.default_core().core_type,
299 if raw.big_endian {
300 Endian::Big
301 } else {
302 Endian::Little
303 },
304 );
305
306 let instructions: Vec<u32> = header
307 .iter()
308 .copied()
309 .chain(
310 assembled_instructions.map(|bytes| u32::from_le_bytes(bytes.try_into().unwrap())),
311 )
312 .chain(last_elem)
313 .collect();
314
315 let header_size = size_of_val(header) as u64;
316
317 let addr_load = match raw.load_address {
319 Some(address) => {
320 address
322 .checked_sub(header_size)
323 .ok_or(FlashError::InvalidFlashAlgorithmLoadAddress { address })?
324 }
325
326 None => {
327 ram_region.range.start
329 }
330 };
331
332 if addr_load < ram_region.range.start {
333 return Err(FlashError::InvalidFlashAlgorithmLoadAddress { address: addr_load });
334 }
335
336 let code_start = addr_load + header_size;
346 let code_size_bytes = (instructions.len() * size_of::<u32>()) as u64;
347
348 let stack_align = Self::required_stack_alignment(target.architecture());
349 let code_end = (code_start + code_size_bytes).next_multiple_of(stack_align);
351
352 let buffer_page_size = raw.flash_properties.page_size as u64;
353
354 let stack_size = raw.stack_size.unwrap_or(Self::FLASH_ALGO_STACK_SIZE) as u64;
355 tracing::info!("The flash algorithm will be configured with {stack_size} bytes of stack");
356
357 let data_load_addr = if let Some(data_load_addr) = raw.data_load_address {
358 data_load_addr
359 } else if ram_region == data_ram_region {
360 code_end
362 } else {
363 data_ram_region.range.start
365 };
366
367 if data_ram_region.range.end < data_load_addr {
369 return Err(FlashError::InvalidDataAddress {
370 data_load_addr,
371 data_ram: data_ram_region.range.clone(),
372 });
373 }
374 let mut ram_for_data = data_ram_region.range.end - data_load_addr;
375 if code_end + stack_size > data_load_addr && ram_region == data_ram_region {
376 if stack_size > ram_for_data {
378 return Err(FlashError::InvalidFlashAlgorithmStackSize { size: stack_size });
379 }
380 ram_for_data -= stack_size;
381 }
382
383 let double_buffering = if ram_for_data >= 2 * buffer_page_size {
385 true
388 } else if ram_for_data >= buffer_page_size {
389 false
391 } else {
392 return Err(FlashError::InvalidFlashAlgorithmStackSize { size: stack_size });
396 };
397
398 let stack_bottom =
400 if code_end + stack_size <= data_load_addr || ram_region != data_ram_region {
401 code_end } else {
407 let page_count = if double_buffering { 2 } else { 1 };
410 (data_load_addr + page_count * buffer_page_size).next_multiple_of(stack_align)
411 };
412
413 let stack_top = stack_bottom + stack_size;
415 tracing::info!("Stack top: {:#010x}", stack_top);
416
417 if stack_top > ram_region.range.end {
418 return Err(FlashError::InvalidFlashAlgorithmStackSize { size: stack_size });
419 }
420
421 let page_buffers = if double_buffering {
423 let second_buffer_start = data_load_addr + buffer_page_size;
424 vec![data_load_addr, second_buffer_start]
425 } else {
426 vec![data_load_addr]
427 };
428
429 tracing::debug!("Page buffers: {:#010x?}", page_buffers);
430
431 let name = raw.name.clone();
432
433 Ok(FlashAlgorithm {
434 name,
435 default: raw.default,
436 load_address: addr_load,
437 instructions,
438 pc_init: raw.pc_init.map(|v| code_start + v),
439 pc_uninit: raw.pc_uninit.map(|v| code_start + v),
440 pc_program_page: code_start + raw.pc_program_page,
441 pc_erase_sector: code_start + raw.pc_erase_sector,
442 pc_erase_all: raw.pc_erase_all.map(|v| code_start + v),
443 pc_verify: raw.pc_verify.map(|v| code_start + v),
444 pc_blank_check: raw.pc_blank_check.map(|v| code_start + v),
445 pc_read: raw.pc_read.map(|v| code_start + v),
446 vendor_functions: raw
447 .vendor_functions
448 .iter()
449 .map(|(name, addr)| (name.clone(), code_start + addr))
450 .collect(),
451 static_base: code_start + raw.data_section_offset,
452 stack_top,
453 stack_size,
454 page_buffers,
455 rtt_control_block: raw.rtt_location,
456 rtt_poll_interval: raw.rtt_poll_interval,
457 flash_properties: raw.flash_properties.clone(),
458 transfer_encoding: raw.transfer_encoding.unwrap_or_default(),
459 stack_overflow_check: raw.stack_overflow_check(),
460 })
461 }
462
463 pub fn assemble_from_raw_with_core(
465 algo: &RawFlashAlgorithm,
466 core_name: &str,
467 target: &Target,
468 ) -> Result<FlashAlgorithm, FlashError> {
469 let mm = &target.memory_map;
471
472 let ram_regions = mm
473 .iter()
474 .filter_map(MemoryRegion::as_ram_region)
475 .filter(|ram| ram.accessible_by(core_name))
476 .merge_consecutive();
477
478 let ram = ram_regions
479 .clone()
480 .filter(|ram| is_ram_suitable_for_algo(ram, algo.load_address))
481 .max_by_key(|region| region.range.end - region.range.start)
482 .ok_or(FlashError::NoRamDefined {
483 name: target.name.clone(),
484 })?;
485 tracing::info!("Chosen RAM to run the algo: {:x?}", ram);
486
487 let data_ram;
488 let data_ram = if let Some(data_load_address) = algo.data_load_address {
489 data_ram = ram_regions
490 .clone()
491 .find(|ram| is_ram_suitable_for_data(ram, data_load_address))
492 .ok_or(FlashError::NoRamDefined {
493 name: target.name.clone(),
494 })?;
495
496 &data_ram
497 } else {
498 &ram
500 };
501 tracing::info!("Data will be loaded to: {:x?}", data_ram);
502
503 Self::assemble_from_raw_with_data(algo, &ram, data_ram, target)
504 }
505}
506
507fn is_ram_suitable_for_algo(ram: &RamRegion, load_address: Option<u64>) -> bool {
509 if !ram.is_executable() {
510 return false;
511 }
512
513 if let Some(load_addr) = load_address {
520 ram.range.contains(&load_addr)
524 } else {
525 true
526 }
527}
528
529fn is_ram_suitable_for_data(ram: &RamRegion, load_address: u64) -> bool {
531 ram.range.contains(&load_address)
535}
536
537#[cfg(test)]
538mod test {
539 use probe_rs_target::{FlashProperties, SectorDescription, SectorInfo};
540
541 use crate::flashing::FlashAlgorithm;
542
543 #[test]
544 fn flash_sector_single_size() {
545 let config = FlashAlgorithm {
546 flash_properties: FlashProperties {
547 sectors: vec![SectorDescription {
548 size: 0x100,
549 address: 0x0,
550 }],
551 address_range: 0x1000..0x1000 + 0x1000,
552 page_size: 0x10,
553 ..Default::default()
554 },
555 ..Default::default()
556 };
557
558 let expected_first = SectorInfo {
559 base_address: 0x1000,
560 size: 0x100,
561 };
562
563 assert!(config.sector_info(0x1000 - 1).is_none());
564
565 assert_eq!(Some(expected_first), config.sector_info(0x1000));
566 assert_eq!(Some(expected_first), config.sector_info(0x10ff));
567
568 assert_eq!(Some(expected_first), config.sector_info(0x100b));
569 assert_eq!(Some(expected_first), config.sector_info(0x10ea));
570 }
571
572 #[test]
573 fn flash_sector_single_size_weird_sector_size() {
574 let config = FlashAlgorithm {
575 flash_properties: FlashProperties {
576 sectors: vec![SectorDescription {
577 size: 258,
578 address: 0x0,
579 }],
580 address_range: 0x800_0000..0x800_0000 + 258 * 10,
581 page_size: 0x10,
582 ..Default::default()
583 },
584 ..Default::default()
585 };
586
587 let expected_first = SectorInfo {
588 base_address: 0x800_0000,
589 size: 258,
590 };
591
592 assert!(config.sector_info(0x800_0000 - 1).is_none());
593
594 assert_eq!(Some(expected_first), config.sector_info(0x800_0000));
595 assert_eq!(Some(expected_first), config.sector_info(0x800_0000 + 257));
596
597 assert_eq!(Some(expected_first), config.sector_info(0x800_000b));
598 assert_eq!(Some(expected_first), config.sector_info(0x800_00e0));
599 }
600
601 #[test]
602 fn flash_sector_multiple_sizes() {
603 let config = FlashAlgorithm {
604 flash_properties: FlashProperties {
605 sectors: vec![
606 SectorDescription {
607 size: 0x4000,
608 address: 0x0,
609 },
610 SectorDescription {
611 size: 0x1_0000,
612 address: 0x1_0000,
613 },
614 SectorDescription {
615 size: 0x2_0000,
616 address: 0x2_0000,
617 },
618 ],
619 address_range: 0x800_0000..0x800_0000 + 0x10_0000,
620 page_size: 0x10,
621 ..Default::default()
622 },
623 ..Default::default()
624 };
625
626 let expected_a = SectorInfo {
627 base_address: 0x800_4000,
628 size: 0x4000,
629 };
630
631 let expected_b = SectorInfo {
632 base_address: 0x801_0000,
633 size: 0x1_0000,
634 };
635
636 let expected_c = SectorInfo {
637 base_address: 0x80A_0000,
638 size: 0x2_0000,
639 };
640
641 assert_eq!(Some(expected_a), config.sector_info(0x800_4000));
642 assert_eq!(Some(expected_b), config.sector_info(0x801_0000));
643 assert_eq!(Some(expected_c), config.sector_info(0x80A_0000));
644 }
645
646 #[test]
647 fn flash_sector_multiple_sizes_iter() {
648 let config = FlashAlgorithm {
649 flash_properties: FlashProperties {
650 sectors: vec![
651 SectorDescription {
652 size: 0x4000,
653 address: 0x0,
654 },
655 SectorDescription {
656 size: 0x1_0000,
657 address: 0x1_0000,
658 },
659 SectorDescription {
660 size: 0x2_0000,
661 address: 0x2_0000,
662 },
663 ],
664 address_range: 0x800_0000..0x800_0000 + 0x8_0000,
665 page_size: 0x10,
666 ..Default::default()
667 },
668 ..Default::default()
669 };
670
671 let got: Vec<SectorInfo> = config.iter_sectors().collect();
672
673 let expected = &[
674 SectorInfo {
675 base_address: 0x800_0000,
676 size: 0x4000,
677 },
678 SectorInfo {
679 base_address: 0x800_4000,
680 size: 0x4000,
681 },
682 SectorInfo {
683 base_address: 0x800_8000,
684 size: 0x4000,
685 },
686 SectorInfo {
687 base_address: 0x800_c000,
688 size: 0x4000,
689 },
690 SectorInfo {
691 base_address: 0x801_0000,
692 size: 0x1_0000,
693 },
694 SectorInfo {
695 base_address: 0x802_0000,
696 size: 0x2_0000,
697 },
698 SectorInfo {
699 base_address: 0x804_0000,
700 size: 0x2_0000,
701 },
702 SectorInfo {
703 base_address: 0x806_0000,
704 size: 0x2_0000,
705 },
706 ];
707 assert_eq!(&got, expected);
708 }
709}