sylveos

Toy Operating System
Log | Files | Refs

bootload.rs (3250B)


      1 use std::path::Path;
      2 
      3 use crc_fast::{CrcAlgorithm::Crc32IsoHdlc, checksum};
      4 use indicatif::ProgressStyle;
      5 use tokio::{
      6     fs::File,
      7     io::{AsyncReadExt, AsyncWriteExt},
      8 };
      9 use tokio_serial::SerialStream;
     10 use tracing::{debug, instrument, trace};
     11 use tracing_indicatif::span_ext::IndicatifSpanExt;
     12 
     13 #[repr(u32)]
     14 #[derive(Debug)]
     15 pub enum Message {
     16     GetProgInfo = 0x11112222,
     17     PutProgInfo = 0x33334444,
     18 
     19     GetCode = 0x55556666,
     20     PutCode = 0x77778888,
     21 
     22     BootSuccess = 0x9999AAAA,
     23     BadCodeAddr = 0xDEADBEEF,
     24     BadCodeChecksum = 0xFEEDFACE,
     25 }
     26 
     27 #[derive(thiserror::Error, Debug)]
     28 pub enum Error {
     29     #[error("invalid boot address")]
     30     BadAddress,
     31     #[error("checksum did not match")]
     32     BadChecksum,
     33     #[error("io: {0}")]
     34     Io(#[from] std::io::Error),
     35 }
     36 
     37 #[instrument(skip_all, fields(indicatif.pb_show))]
     38 pub async fn boot(port: &mut SerialStream, bin: &Path, base_address: u32) -> Result<(), Error> {
     39     let current = tracing::Span::current();
     40 
     41     let mut code = Vec::new();
     42 
     43     File::open(bin).await?.read_to_end(&mut code).await?;
     44 
     45     let checksum = checksum(Crc32IsoHdlc, &code) as u32;
     46 
     47     debug!("boot parameters: crc32={checksum:x}, file={bin:?}, base_address=0x{base_address:X}");
     48 
     49     current.pb_set_style(&ProgressStyle::default_spinner());
     50     current.pb_set_message("waiting for GetProgInfo");
     51 
     52     loop {
     53         match port.read_u32_le().await? {
     54             v if v == (Message::GetProgInfo as u32) => break,
     55             v => {
     56                 trace!("got invalid GetProgInfo: {v:X}");
     57                 // Read 1 to offset
     58                 port.read_u8().await?;
     59                 continue;
     60             }
     61         }
     62     }
     63 
     64     port.write_u32_le(Message::PutProgInfo as u32).await?;
     65     port.write_u32_le(base_address).await?;
     66     port.write_u32_le(code.len() as u32).await?;
     67     port.write_u32_le(checksum).await?;
     68     port.flush().await?;
     69 
     70     loop {
     71         match port.read_u32_le().await? {
     72             v if v == (Message::GetCode as u32) => break,
     73             v if v == (Message::BadCodeAddr as u32) => return Err(Error::BadAddress),
     74             v => {
     75                 trace!("got invalid GetCode: {v:X}");
     76                 continue;
     77             }
     78         }
     79     }
     80 
     81     let checksum_ret = port.read_u32_le().await?;
     82 
     83     if checksum != checksum_ret {
     84         return Err(Error::BadChecksum);
     85     }
     86 
     87     port.write_u32_le(Message::PutCode as u32).await?;
     88 
     89     current.pb_set_style(
     90         &ProgressStyle::with_template(
     91             "[{elapsed}] [{wide_bar}] {binary_bytes}/{binary_total_bytes} (eta: {eta})",
     92         )
     93         .unwrap()
     94         .progress_chars("=> "),
     95     );
     96     current.pb_set_length(code.len() as u64);
     97 
     98     for b in code.iter() {
     99         port.write_u8(*b).await?;
    100         current.pb_inc(1);
    101     }
    102     port.flush().await?;
    103 
    104     current.pb_set_style(&ProgressStyle::default_spinner());
    105     current.pb_set_message("waiting for BootSuccess");
    106 
    107     loop {
    108         match port.read_u32_le().await? {
    109             v if v == (Message::BootSuccess as u32) => break,
    110             v if v == (Message::BadCodeChecksum as u32) => return Err(Error::BadAddress),
    111             v => {
    112                 debug!("got invalid BootSuccess: {v}");
    113                 continue;
    114             }
    115         }
    116     }
    117 
    118     Ok(())
    119 }