blflash/
flasher.rs

1use crate::chip::Chip;
2use crate::Error;
3use crate::{connection::Connection, elf::RomSegment};
4use indicatif::{HumanBytes, ProgressBar, ProgressStyle};
5use serial::{BaudRate, SerialPort};
6use sha2::{Digest, Sha256};
7use std::{
8    io::{Cursor, Read, Write},
9    time::{Duration, Instant},
10};
11use std::{ops::Range, thread::sleep};
12
13fn get_bar(len: u64) -> ProgressBar {
14    let bar = ProgressBar::new(len);
15    bar.set_style(
16        ProgressStyle::default_bar()
17            .template("  {wide_bar} {bytes}/{total_bytes} {bytes_per_sec} {eta}  ")
18            .progress_chars("#>-"),
19    );
20    bar
21}
22
23pub struct Flasher {
24    connection: Connection,
25    boot_info: protocol::BootInfo,
26    chip: Box<dyn Chip>,
27    flash_speed: BaudRate,
28}
29
30impl Flasher {
31    pub fn connect(
32        chip: impl Chip + 'static,
33        serial: impl SerialPort + 'static,
34        initial_speed: BaudRate,
35        flash_speed: BaudRate,
36    ) -> Result<Self, Error> {
37        let mut flasher = Flasher {
38            connection: Connection::new(serial),
39            boot_info: protocol::BootInfo::default(),
40            chip: Box::new(chip),
41            flash_speed,
42        };
43        flasher.connection.set_baud(initial_speed)?;
44        flasher.start_connection()?;
45        flasher.connection.set_timeout(Duration::from_secs(10))?;
46        flasher.boot_info = flasher.boot_rom().get_boot_info()?;
47
48        Ok(flasher)
49    }
50
51    pub fn into_inner(self) -> Connection {
52        self.connection
53    }
54
55    pub fn boot_info(&self) -> &protocol::BootInfo {
56        &self.boot_info
57    }
58
59    pub fn load_segments<'a>(
60        &'a mut self,
61        force: bool,
62        segments: impl Iterator<Item = RomSegment<'a>>,
63    ) -> Result<(), Error> {
64        self.load_eflash_loader()?;
65
66        for segment in segments {
67            let local_hash = Sha256::digest(&segment.data[0..segment.size() as usize]);
68
69            // skip segment if the contents are matched
70            if !force {
71                let sha256 = self
72                    .eflash_loader()
73                    .sha256_read(segment.addr, segment.size())?;
74                if sha256 == &local_hash[..] {
75                    log::info!(
76                        "Skip segment addr: {:x} size: {} sha256 matches",
77                        segment.addr,
78                        segment.size()
79                    );
80                    continue;
81                }
82            }
83
84            log::info!(
85                "Erase flash addr: {:x} size: {}",
86                segment.addr,
87                segment.size()
88            );
89            self.eflash_loader()
90                .flash_erase(segment.addr, segment.addr + segment.size())?;
91
92            let mut reader = Cursor::new(&segment.data);
93            let mut cur = segment.addr;
94
95            let start = Instant::now();
96            log::info!("Program flash... {:x}", local_hash);
97            let pb = get_bar(segment.size() as u64);
98            loop {
99                let size = self.eflash_loader().flash_program(cur, &mut reader)?;
100                // log::trace!("program {:x} {:x}", cur, size);
101                cur += size;
102                pb.inc(size as u64);
103                if size == 0 {
104                    break;
105                }
106            }
107            pb.finish_and_clear();
108            let elapsed = start.elapsed();
109            log::info!(
110                "Program done {:?} {}/s",
111                elapsed,
112                HumanBytes((segment.size() as f64 / elapsed.as_millis() as f64 * 1000.0) as u64)
113            );
114
115            let sha256 = self
116                .eflash_loader()
117                .sha256_read(segment.addr, segment.size())?;
118            if sha256 != &local_hash[..] {
119                log::warn!(
120                    "sha256 not match: {} != {}",
121                    hex::encode(sha256),
122                    hex::encode(local_hash)
123                );
124            }
125        }
126        Ok(())
127    }
128
129    pub fn check_segments<'a>(
130        &'a mut self,
131        segments: impl Iterator<Item = RomSegment<'a>>,
132    ) -> Result<(), Error> {
133        self.load_eflash_loader()?;
134
135        for segment in segments {
136            let local_hash = Sha256::digest(&segment.data[0..segment.size() as usize]);
137
138            let sha256 = self
139                .eflash_loader()
140                .sha256_read(segment.addr, segment.size())?;
141            if sha256 != &local_hash[..] {
142                log::warn!(
143                    "{:x} sha256 not match: {} != {}",
144                    segment.addr,
145                    hex::encode(sha256),
146                    hex::encode(local_hash)
147                );
148            } else {
149                log::info!("{:x} sha256 match", segment.addr);
150            }
151        }
152        Ok(())
153    }
154
155    pub fn dump_flash(&mut self, range: Range<u32>, mut writer: impl Write) -> Result<(), Error> {
156        self.load_eflash_loader()?;
157
158        const BLOCK_SIZE: usize = 4096;
159        let mut cur = range.start;
160        let pb = get_bar(range.len() as u64);
161        while cur < range.end {
162            let data = self
163                .eflash_loader()
164                .flash_read(cur, (range.end - cur).min(BLOCK_SIZE as u32))?;
165            writer.write_all(&data)?;
166            cur += data.len() as u32;
167            pb.inc(data.len() as u64);
168        }
169        pb.finish_and_clear();
170
171        Ok(())
172    }
173
174    pub fn load_eflash_loader(&mut self) -> Result<(), Error> {
175        let input = self.chip.get_eflash_loader().to_vec();
176        let len = input.len();
177        let mut reader = Cursor::new(input);
178        self.boot_rom().load_boot_header(&mut reader)?;
179        self.boot_rom().load_segment_header(&mut reader)?;
180
181        let start = Instant::now();
182        log::info!("Sending eflash_loader...");
183        let pb = get_bar(len as u64);
184        loop {
185            let size = self.boot_rom().load_segment_data(&mut reader)?;
186            pb.inc(size as u64);
187            if size == 0 {
188                break;
189            }
190        }
191        pb.finish_and_clear();
192        let elapsed = start.elapsed();
193        log::info!(
194            "Finished {:?} {}/s",
195            elapsed,
196            HumanBytes((len as f64 / elapsed.as_millis() as f64 * 1000.0) as u64)
197        );
198
199        self.boot_rom().check_image()?;
200        self.boot_rom().run_image()?;
201        sleep(Duration::from_millis(500));
202        self.connection.set_baud(self.flash_speed)?;
203        self.handshake()?;
204
205        log::info!("Entered eflash_loader");
206
207        Ok(())
208    }
209
210    pub fn reset(&mut self) -> Result<(), Error> {
211        Ok(self.connection.reset()?)
212    }
213
214    fn boot_rom(&mut self) -> BootRom {
215        BootRom(&mut self.connection)
216    }
217
218    fn eflash_loader(&mut self) -> EflashLoader {
219        EflashLoader(&mut self.connection)
220    }
221
222    fn handshake(&mut self) -> Result<(), Error> {
223        self.connection
224            .with_timeout(Duration::from_millis(200), |connection| {
225                let len = connection.calc_duration_length(Duration::from_millis(5));
226                log::trace!("5ms send count {}", len);
227                let data: Vec<u8> = std::iter::repeat(0x55u8).take(len).collect();
228                let start = Instant::now();
229                connection.write_all(&data)?;
230                connection.flush()?;
231                log::trace!("handshake sent elapsed {:?}", start.elapsed());
232                sleep(Duration::from_millis(200));
233
234                for _ in 0..5 {
235                    if connection.read_response(0).is_ok() {
236                        return Ok(());
237                    }
238                }
239
240                Err(Error::Timeout)
241            })
242    }
243
244    fn start_connection(&mut self) -> Result<(), Error> {
245        log::info!("Start connection...");
246        self.connection.reset_to_flash()?;
247        for i in 1..=10 {
248            self.connection.flush()?;
249            if self.handshake().is_ok() {
250                log::info!("Connection Succeed");
251                return Ok(());
252            } else {
253                log::debug!("Retry {}", i);
254            }
255        }
256        Err(Error::ConnectionFailed)
257    }
258}
259
260pub struct BootRom<'a>(&'a mut Connection);
261
262impl<'a> BootRom<'a> {
263    pub fn run_image(&mut self) -> Result<(), Error> {
264        self.0.command(protocol::RunImage {})?;
265        Ok(())
266    }
267
268    pub fn check_image(&mut self) -> Result<(), Error> {
269        self.0.command(protocol::CheckImage {})?;
270        Ok(())
271    }
272
273    pub fn load_boot_header(&mut self, reader: &mut impl Read) -> Result<(), Error> {
274        let mut boot_header = vec![0u8; protocol::LOAD_BOOT_HEADER_LEN];
275        reader.read_exact(&mut boot_header)?;
276        self.0.command(protocol::LoadBootHeader { boot_header })?;
277        Ok(())
278    }
279
280    pub fn load_segment_header(&mut self, reader: &mut impl Read) -> Result<(), Error> {
281        let mut segment_header = vec![0u8; protocol::LOAD_SEGMENT_HEADER_LEN];
282        reader.read_exact(&mut segment_header)?;
283
284        let resp = self.0.command(protocol::LoadSegmentHeaderReq {
285            segment_header: segment_header.clone(),
286        })?;
287
288        if resp.data != segment_header {
289            log::warn!(
290                "Segment header not match req:{:x?} != resp:{:x?}",
291                segment_header,
292                resp.data
293            )
294        }
295
296        Ok(())
297    }
298
299    pub fn load_segment_data(&mut self, reader: &mut impl Read) -> Result<u32, Error> {
300        let mut segment_data = vec![0u8; 4000];
301        let size = reader.read(&mut segment_data)?;
302        if size == 0 {
303            return Ok(0);
304        }
305        segment_data.truncate(size);
306
307        self.0.command(protocol::LoadSegmentData { segment_data })?;
308
309        Ok(size as u32)
310    }
311
312    pub fn get_boot_info(&mut self) -> Result<protocol::BootInfo, Error> {
313        self.0.command(protocol::BootInfoReq {})
314    }
315}
316
317pub struct EflashLoader<'a>(&'a mut Connection);
318
319impl<'a> EflashLoader<'a> {
320    pub fn sha256_read(&mut self, addr: u32, len: u32) -> Result<[u8; 32], Error> {
321        Ok(self.0.command(protocol::Sha256Read { addr, len })?.digest)
322    }
323
324    pub fn flash_read(&mut self, addr: u32, size: u32) -> Result<Vec<u8>, Error> {
325        Ok(self.0.command(protocol::FlashRead { addr, size })?.data)
326    }
327
328    pub fn flash_program(&mut self, addr: u32, reader: &mut impl Read) -> Result<u32, Error> {
329        let mut data = vec![0u8; 4000];
330        let size = reader.read(&mut data)?;
331        if size == 0 {
332            return Ok(0);
333        }
334        data.truncate(size);
335
336        self.0.command(protocol::FlashProgram { addr, data })?;
337
338        Ok(size as u32)
339    }
340
341    pub fn flash_erase(&mut self, start: u32, end: u32) -> Result<(), Error> {
342        self.0.command(protocol::FlashErase { start, end })?;
343
344        Ok(())
345    }
346}
347
348mod protocol {
349    use crate::connection::{Command, Response};
350    use deku::prelude::*;
351
352    pub const LOAD_BOOT_HEADER_LEN: usize = 176;
353    pub const LOAD_SEGMENT_HEADER_LEN: usize = 16;
354
355    #[derive(Debug, DekuWrite, Default)]
356    pub struct CheckImage {}
357    impl_command!(0x19, CheckImage);
358
359    #[derive(Debug, DekuWrite, Default)]
360    pub struct RunImage {}
361    impl_command!(0x1a, RunImage);
362
363    #[derive(Debug, DekuWrite, Default)]
364    pub struct BootInfoReq {}
365    #[derive(Debug, DekuRead, Default)]
366    pub struct BootInfo {
367        pub len: u16,
368        pub bootrom_version: u32,
369        pub otp_info: [u8; 16],
370    }
371    impl_command!(0x10, BootInfoReq, BootInfo);
372
373    #[derive(Debug, DekuWrite, Default)]
374    pub struct LoadBootHeader {
375        // length must be 176
376        pub boot_header: Vec<u8>,
377    }
378    impl_command!(0x11, LoadBootHeader);
379
380    #[derive(Debug, DekuWrite, Default)]
381    pub struct LoadSegmentHeaderReq {
382        // length must be 16
383        pub segment_header: Vec<u8>,
384    }
385    #[derive(Debug, DekuRead)]
386    pub struct LoadSegmentHeader {
387        pub len: u16,
388        #[deku(count = "len")]
389        pub data: Vec<u8>,
390    }
391    impl_command!(0x17, LoadSegmentHeaderReq, LoadSegmentHeader);
392
393    #[derive(Debug, DekuWrite, Default)]
394    pub struct LoadSegmentData {
395        pub segment_data: Vec<u8>,
396    }
397    impl_command!(0x18, LoadSegmentData);
398
399    #[derive(Debug, DekuWrite, Default)]
400    pub struct FlashErase {
401        pub start: u32,
402        pub end: u32,
403    }
404    impl_command!(0x30, FlashErase);
405
406    #[derive(Debug, DekuWrite, Default)]
407    pub struct FlashProgram {
408        pub addr: u32,
409        pub data: Vec<u8>,
410    }
411    impl_command!(0x31, FlashProgram);
412
413    #[derive(Debug, DekuWrite, Default)]
414    pub struct FlashRead {
415        pub addr: u32,
416        pub size: u32,
417    }
418    #[derive(Debug, DekuRead)]
419    pub struct FlashReadResp {
420        pub len: u16,
421        #[deku(count = "len")]
422        pub data: Vec<u8>,
423    }
424    impl_command!(0x32, FlashRead, FlashReadResp);
425
426    #[derive(Debug, DekuWrite, Default)]
427    pub struct Sha256Read {
428        pub addr: u32,
429        pub len: u32,
430    }
431
432    #[derive(Debug, DekuRead)]
433    #[deku(magic = b"\x20\x00")]
434    pub struct Sha256ReadResp {
435        pub digest: [u8; 32],
436    }
437    impl_command!(0x3d, Sha256Read, Sha256ReadResp);
438}