aboutsummaryrefslogtreecommitdiff
path: root/embassy-boot/boot/src/partition.rs
blob: 7b56a82406e4d326b920081075f88bed0270579f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
#[cfg(feature = "nightly")]
use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash};

/// A region in flash used by the bootloader.
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Partition {
    /// The offset into the flash where the partition starts.
    pub from: u32,
    /// The offset into the flash where the partition ends.
    pub to: u32,
}

impl Partition {
    /// Create a new partition with the provided range
    pub const fn new(from: u32, to: u32) -> Self {
        Self { from, to }
    }

    /// Return the size of the partition
    pub const fn size(&self) -> u32 {
        self.to - self.from
    }

    /// Read from the partition on the provided flash
    #[cfg(feature = "nightly")]
    pub async fn read<F: AsyncReadNorFlash>(
        &self,
        flash: &mut F,
        offset: u32,
        bytes: &mut [u8],
    ) -> Result<(), F::Error> {
        let offset = self.from as u32 + offset;
        flash.read(offset, bytes).await
    }

    /// Write to the partition on the provided flash
    #[cfg(feature = "nightly")]
    pub async fn write<F: AsyncNorFlash>(&self, flash: &mut F, offset: u32, bytes: &[u8]) -> Result<(), F::Error> {
        let offset = self.from as u32 + offset;
        flash.write(offset, bytes).await?;
        trace!("Wrote from 0x{:x} len {}", offset, bytes.len());
        Ok(())
    }

    /// Erase part of the partition on the provided flash
    #[cfg(feature = "nightly")]
    pub async fn erase<F: AsyncNorFlash>(&self, flash: &mut F, from: u32, to: u32) -> Result<(), F::Error> {
        let from = self.from as u32 + from;
        let to = self.from as u32 + to;
        flash.erase(from, to).await?;
        trace!("Erased from 0x{:x} to 0x{:x}", from, to);
        Ok(())
    }

    /// Erase the entire partition
    #[cfg(feature = "nightly")]
    pub(crate) async fn wipe<F: AsyncNorFlash>(&self, flash: &mut F) -> Result<(), F::Error> {
        let from = self.from as u32;
        let to = self.to as u32;
        flash.erase(from, to).await?;
        trace!("Wiped from 0x{:x} to 0x{:x}", from, to);
        Ok(())
    }

    /// Read from the partition on the provided flash
    pub fn read_blocking<F: ReadNorFlash>(&self, flash: &mut F, offset: u32, bytes: &mut [u8]) -> Result<(), F::Error> {
        let offset = self.from as u32 + offset;
        flash.read(offset, bytes)
    }

    /// Write to the partition on the provided flash
    pub fn write_blocking<F: NorFlash>(&self, flash: &mut F, offset: u32, bytes: &[u8]) -> Result<(), F::Error> {
        let offset = self.from as u32 + offset;
        flash.write(offset, bytes)?;
        trace!("Wrote from 0x{:x} len {}", offset, bytes.len());
        Ok(())
    }

    /// Erase part of the partition on the provided flash
    pub fn erase_blocking<F: NorFlash>(&self, flash: &mut F, from: u32, to: u32) -> Result<(), F::Error> {
        let from = self.from as u32 + from;
        let to = self.from as u32 + to;
        flash.erase(from, to)?;
        trace!("Erased from 0x{:x} to 0x{:x}", from, to);
        Ok(())
    }

    /// Erase the entire partition
    pub(crate) fn wipe_blocking<F: NorFlash>(&self, flash: &mut F) -> Result<(), F::Error> {
        let from = self.from as u32;
        let to = self.to as u32;
        flash.erase(from, to)?;
        trace!("Wiped from 0x{:x} to 0x{:x}", from, to);
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use crate::mem_flash::MemFlash;
    use crate::Partition;

    #[test]
    fn can_erase() {
        let mut flash = MemFlash::<1024, 64, 4>::new(0x00);
        let partition = Partition::new(256, 512);

        partition.erase_blocking(&mut flash, 64, 192).unwrap();

        for (index, byte) in flash.mem.iter().copied().enumerate().take(256 + 64) {
            assert_eq!(0x00, byte, "Index {}", index);
        }

        for (index, byte) in flash.mem.iter().copied().enumerate().skip(256 + 64).take(128) {
            assert_eq!(0xFF, byte, "Index {}", index);
        }

        for (index, byte) in flash.mem.iter().copied().enumerate().skip(256 + 64 + 128) {
            assert_eq!(0x00, byte, "Index {}", index);
        }
    }

    #[test]
    fn can_wipe() {
        let mut flash = MemFlash::<1024, 64, 4>::new(0x00);
        let partition = Partition::new(256, 512);

        partition.wipe_blocking(&mut flash).unwrap();

        for (index, byte) in flash.mem.iter().copied().enumerate().take(256) {
            assert_eq!(0x00, byte, "Index {}", index);
        }

        for (index, byte) in flash.mem.iter().copied().enumerate().skip(256).take(256) {
            assert_eq!(0xFF, byte, "Index {}", index);
        }

        for (index, byte) in flash.mem.iter().copied().enumerate().skip(512) {
            assert_eq!(0x00, byte, "Index {}", index);
        }
    }
}