diff options
| author | Mathias <[email protected]> | 2022-09-26 06:01:18 +0200 |
|---|---|---|
| committer | Mathias <[email protected]> | 2022-09-26 06:01:18 +0200 |
| commit | 7f16b1cd23f53a429bf074e76254bcf592c0b9cf (patch) | |
| tree | 33a2f697b970e92f3146e2aa95b061f51f373642 /embassy-boot/boot/src/lib.rs | |
| parent | 3c24ad2db64ff46d8b16a55248bbe7af0798a9a4 (diff) | |
Add blocking API to FirmwareUpdater, and allow for a split prepare/write api
Diffstat (limited to 'embassy-boot/boot/src/lib.rs')
| -rw-r--r-- | embassy-boot/boot/src/lib.rs | 186 |
1 files changed, 179 insertions, 7 deletions
diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs index 96878ace9..1c4d2d47f 100644 --- a/embassy-boot/boot/src/lib.rs +++ b/embassy-boot/boot/src/lib.rs | |||
| @@ -660,12 +660,6 @@ impl FirmwareUpdater { | |||
| 660 | ) -> Result<(), F::Error> { | 660 | ) -> Result<(), F::Error> { |
| 661 | assert!(data.len() >= F::ERASE_SIZE); | 661 | assert!(data.len() >= F::ERASE_SIZE); |
| 662 | 662 | ||
| 663 | trace!( | ||
| 664 | "Writing firmware at offset 0x{:x} len {}", | ||
| 665 | self.dfu.from + offset, | ||
| 666 | data.len() | ||
| 667 | ); | ||
| 668 | |||
| 669 | flash | 663 | flash |
| 670 | .erase( | 664 | .erase( |
| 671 | (self.dfu.from + offset) as u32, | 665 | (self.dfu.from + offset) as u32, |
| @@ -679,7 +673,141 @@ impl FirmwareUpdater { | |||
| 679 | self.dfu.from + offset + data.len() | 673 | self.dfu.from + offset + data.len() |
| 680 | ); | 674 | ); |
| 681 | 675 | ||
| 682 | let mut write_offset = self.dfu.from + offset; | 676 | FirmwareWriter(self) |
| 677 | .write_firmware(offset, data, flash, block_size) | ||
| 678 | .await?; | ||
| 679 | |||
| 680 | Ok(()) | ||
| 681 | } | ||
| 682 | |||
| 683 | /// Prepare for an incoming DFU update by erasing the entire DFU area and | ||
| 684 | /// returning a `FirmwareWriter`. | ||
| 685 | /// | ||
| 686 | /// Using this instead of `write_firmware` allows for an optimized API in | ||
| 687 | /// exchange for added complexity. | ||
| 688 | pub fn prepare_update<F: NorFlash>(&mut self, flash: &mut F) -> Result<FirmwareWriter, F::Error> { | ||
| 689 | flash.erase((self.dfu.from) as u32, (self.dfu.to) as u32)?; | ||
| 690 | |||
| 691 | trace!("Erased from {} to {}", self.dfu.from, self.dfu.to); | ||
| 692 | |||
| 693 | Ok(FirmwareWriter(self)) | ||
| 694 | } | ||
| 695 | |||
| 696 | // | ||
| 697 | // Blocking API | ||
| 698 | // | ||
| 699 | |||
| 700 | /// Mark to trigger firmware swap on next boot. | ||
| 701 | /// | ||
| 702 | /// # Safety | ||
| 703 | /// | ||
| 704 | /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. | ||
| 705 | pub fn mark_updated_blocking<F: NorFlash>(&mut self, flash: &mut F, aligned: &mut [u8]) -> Result<(), F::Error> { | ||
| 706 | assert_eq!(aligned.len(), F::WRITE_SIZE); | ||
| 707 | self.set_magic_blocking(aligned, SWAP_MAGIC, flash) | ||
| 708 | } | ||
| 709 | |||
| 710 | /// Mark firmware boot successful and stop rollback on reset. | ||
| 711 | /// | ||
| 712 | /// # Safety | ||
| 713 | /// | ||
| 714 | /// The `aligned` buffer must have a size of F::WRITE_SIZE, and follow the alignment rules for the flash being written to. | ||
| 715 | pub fn mark_booted_blocking<F: NorFlash>(&mut self, flash: &mut F, aligned: &mut [u8]) -> Result<(), F::Error> { | ||
| 716 | assert_eq!(aligned.len(), F::WRITE_SIZE); | ||
| 717 | self.set_magic_blocking(aligned, BOOT_MAGIC, flash) | ||
| 718 | } | ||
| 719 | |||
| 720 | fn set_magic_blocking<F: NorFlash>( | ||
| 721 | &mut self, | ||
| 722 | aligned: &mut [u8], | ||
| 723 | magic: u8, | ||
| 724 | flash: &mut F, | ||
| 725 | ) -> Result<(), F::Error> { | ||
| 726 | flash.read(self.state.from as u32, aligned)?; | ||
| 727 | |||
| 728 | if aligned.iter().any(|&b| b != magic) { | ||
| 729 | aligned.fill(0); | ||
| 730 | |||
| 731 | flash.write(self.state.from as u32, aligned)?; | ||
| 732 | flash.erase(self.state.from as u32, self.state.to as u32)?; | ||
| 733 | |||
| 734 | aligned.fill(magic); | ||
| 735 | flash.write(self.state.from as u32, aligned)?; | ||
| 736 | } | ||
| 737 | Ok(()) | ||
| 738 | } | ||
| 739 | |||
| 740 | /// Write data to a flash page. | ||
| 741 | /// | ||
| 742 | /// The buffer must follow alignment requirements of the target flash and a multiple of page size big. | ||
| 743 | /// | ||
| 744 | /// # Safety | ||
| 745 | /// | ||
| 746 | /// Failing to meet alignment and size requirements may result in a panic. | ||
| 747 | pub fn write_firmware_blocking<F: NorFlash>( | ||
| 748 | &mut self, | ||
| 749 | offset: usize, | ||
| 750 | data: &[u8], | ||
| 751 | flash: &mut F, | ||
| 752 | block_size: usize, | ||
| 753 | ) -> Result<(), F::Error> { | ||
| 754 | assert!(data.len() >= F::ERASE_SIZE); | ||
| 755 | |||
| 756 | flash.erase( | ||
| 757 | (self.dfu.from + offset) as u32, | ||
| 758 | (self.dfu.from + offset + data.len()) as u32, | ||
| 759 | )?; | ||
| 760 | |||
| 761 | trace!( | ||
| 762 | "Erased from {} to {}", | ||
| 763 | self.dfu.from + offset, | ||
| 764 | self.dfu.from + offset + data.len() | ||
| 765 | ); | ||
| 766 | |||
| 767 | FirmwareWriter(self).write_firmware_blocking(offset, data, flash, block_size)?; | ||
| 768 | |||
| 769 | Ok(()) | ||
| 770 | } | ||
| 771 | |||
| 772 | /// Prepare for an incoming DFU update by erasing the entire DFU area and | ||
| 773 | /// returning a `FirmwareWriter`. | ||
| 774 | /// | ||
| 775 | /// Using this instead of `write_firmware_blocking` allows for an optimized | ||
| 776 | /// API in exchange for added complexity. | ||
| 777 | pub fn prepare_update_blocking<F: NorFlash>(&mut self, flash: &mut F) -> Result<FirmwareWriter, F::Error> { | ||
| 778 | flash.erase((self.dfu.from) as u32, (self.dfu.to) as u32)?; | ||
| 779 | |||
| 780 | trace!("Erased from {} to {}", self.dfu.from, self.dfu.to); | ||
| 781 | |||
| 782 | Ok(FirmwareWriter(self)) | ||
| 783 | } | ||
| 784 | } | ||
| 785 | |||
| 786 | /// FirmwareWriter allows writing blocks to an already erased flash. | ||
| 787 | pub struct FirmwareWriter<'a>(&'a mut FirmwareUpdater); | ||
| 788 | |||
| 789 | impl<'a> FirmwareWriter<'a> { | ||
| 790 | /// Write data to a flash page. | ||
| 791 | /// | ||
| 792 | /// The buffer must follow alignment requirements of the target flash and a multiple of page size big. | ||
| 793 | /// | ||
| 794 | /// # Safety | ||
| 795 | /// | ||
| 796 | /// Failing to meet alignment and size requirements may result in a panic. | ||
| 797 | pub async fn write_firmware<F: AsyncNorFlash>( | ||
| 798 | &mut self, | ||
| 799 | offset: usize, | ||
| 800 | data: &[u8], | ||
| 801 | flash: &mut F, | ||
| 802 | block_size: usize, | ||
| 803 | ) -> Result<(), F::Error> { | ||
| 804 | trace!( | ||
| 805 | "Writing firmware at offset 0x{:x} len {}", | ||
| 806 | self.0.dfu.from + offset, | ||
| 807 | data.len() | ||
| 808 | ); | ||
| 809 | |||
| 810 | let mut write_offset = self.0.dfu.from + offset; | ||
| 683 | for chunk in data.chunks(block_size) { | 811 | for chunk in data.chunks(block_size) { |
| 684 | trace!("Wrote chunk at {}: {:?}", write_offset, chunk); | 812 | trace!("Wrote chunk at {}: {:?}", write_offset, chunk); |
| 685 | flash.write(write_offset as u32, chunk).await?; | 813 | flash.write(write_offset as u32, chunk).await?; |
| @@ -702,6 +830,50 @@ impl FirmwareUpdater { | |||
| 702 | 830 | ||
| 703 | Ok(()) | 831 | Ok(()) |
| 704 | } | 832 | } |
| 833 | |||
| 834 | /// Write data to a flash page. | ||
| 835 | /// | ||
| 836 | /// The buffer must follow alignment requirements of the target flash and a multiple of page size big. | ||
| 837 | /// | ||
| 838 | /// # Safety | ||
| 839 | /// | ||
| 840 | /// Failing to meet alignment and size requirements may result in a panic. | ||
| 841 | pub fn write_firmware_blocking<F: NorFlash>( | ||
| 842 | &mut self, | ||
| 843 | offset: usize, | ||
| 844 | data: &[u8], | ||
| 845 | flash: &mut F, | ||
| 846 | block_size: usize, | ||
| 847 | ) -> Result<(), F::Error> { | ||
| 848 | trace!( | ||
| 849 | "Writing firmware at offset 0x{:x} len {}", | ||
| 850 | self.0.dfu.from + offset, | ||
| 851 | data.len() | ||
| 852 | ); | ||
| 853 | |||
| 854 | let mut write_offset = self.0.dfu.from + offset; | ||
| 855 | for chunk in data.chunks(block_size) { | ||
| 856 | trace!("Wrote chunk at {}: {:?}", write_offset, chunk); | ||
| 857 | flash.write(write_offset as u32, chunk)?; | ||
| 858 | write_offset += chunk.len(); | ||
| 859 | } | ||
| 860 | /* | ||
| 861 | trace!("Wrote data, reading back for verification"); | ||
| 862 | |||
| 863 | let mut buf: [u8; 4096] = [0; 4096]; | ||
| 864 | let mut data_offset = 0; | ||
| 865 | let mut read_offset = self.dfu.from + offset; | ||
| 866 | for chunk in buf.chunks_mut(block_size) { | ||
| 867 | flash.read(read_offset as u32, chunk).await?; | ||
| 868 | trace!("Read chunk at {}: {:?}", read_offset, chunk); | ||
| 869 | assert_eq!(&data[data_offset..data_offset + block_size], chunk); | ||
| 870 | read_offset += chunk.len(); | ||
| 871 | data_offset += chunk.len(); | ||
| 872 | } | ||
| 873 | */ | ||
| 874 | |||
| 875 | Ok(()) | ||
| 876 | } | ||
| 705 | } | 877 | } |
| 706 | 878 | ||
| 707 | #[cfg(test)] | 879 | #[cfg(test)] |
