aboutsummaryrefslogtreecommitdiff
path: root/embassy-boot/boot/src/lib.rs
diff options
context:
space:
mode:
authorMathias <[email protected]>2022-09-26 06:01:18 +0200
committerMathias <[email protected]>2022-09-26 06:01:18 +0200
commit7f16b1cd23f53a429bf074e76254bcf592c0b9cf (patch)
tree33a2f697b970e92f3146e2aa95b061f51f373642 /embassy-boot/boot/src/lib.rs
parent3c24ad2db64ff46d8b16a55248bbe7af0798a9a4 (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.rs186
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.
787pub struct FirmwareWriter<'a>(&'a mut FirmwareUpdater);
788
789impl<'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)]