diff --git a/Cargo.lock b/Cargo.lock index 0d3f3ea..6cbc2de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -87,9 +87,11 @@ name = "blflash" version = "0.1.0" dependencies = [ "byteorder", + "crc", "deku", "directories-next", "env_logger", + "hex", "indicatif", "log", "main_error", @@ -112,6 +114,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "build_const" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" + [[package]] name = "byteorder" version = "1.3.4" @@ -193,6 +201,15 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" +[[package]] +name = "crc" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" +dependencies = [ + "build_const", +] + [[package]] name = "darling" version = "0.10.2" @@ -384,6 +401,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" + [[package]] name = "humantime" version = "2.0.1" diff --git a/blflash/Cargo.toml b/blflash/Cargo.toml index 84d4b77..3d2295b 100644 --- a/blflash/Cargo.toml +++ b/blflash/Cargo.toml @@ -26,3 +26,5 @@ byteorder = "1.3.4" sha2 = "0.9.2" structopt = { version = "0.3.21", features = ["paw"] } paw = "1.0.0" +crc = "1.8.1" +hex = "0.4.2" diff --git a/blflash/src/chip/bl602/cfg/partition_cfg_2M.toml b/blflash/src/chip/bl602/cfg/partition_cfg_2M.toml new file mode 100644 index 0000000..29de67e --- /dev/null +++ b/blflash/src/chip/bl602/cfg/partition_cfg_2M.toml @@ -0,0 +1,94 @@ +[pt_table] +#partition table is 4K in size +address0 = 0xE000 +address1 = 0xF000 + +[[pt_entry]] +type = 0 +name = "FW" +device = 0 +address0 = 0x10000 +size0 = 0xC8000 +address1 = 0xD8000 +size1 = 0x88000 +# compressed image must set len,normal image can left it to 0 +len = 0 + +[[pt_entry]] +type = 2 +name = "mfg" +device = 0 +address0 = 0x160000 +size0 = 0x32000 +address1 = 0 +size1 = 0 +# compressed image must set len,normal image can left it to 0 +len = 0 + +[[pt_entry]] +type = 3 +name = "media" +device = 0 +address0 = 0x192000 +size0 = 0x57000 +address1 = 0 +size1 = 0 +# compressed image must set len,normal image can left it to 0 +len = 0 + +[[pt_entry]] +type = 4 +name = "PSM" +device = 0 +address0 = 0x1E9000 +size0 = 0x8000 +address1 = 0 +size1 = 0 +# compressed image must set len,normal image can left it to 0 +len = 0 + +[[pt_entry]] +type = 5 +name = "KEY" +device = 0 +address0 = 0x1F1000 +size0 = 0x2000 +address1 = 0 +size1 = 0 +# compressed image must set len,normal image can left it to 0 +len = 0 + +[[pt_entry]] +type = 6 +name = "DATA" +device = 0 +address0 = 0x1F3000 +size0 = 0x5000 +address1 = 0 +size1 = 0 +# compressed image must set len,normal image can left it to 0 +len = 0 + + +[[pt_entry]] +type = 7 +name = "factory" +device = 0 +address0 = 0x1F8000 +size0 = 0x7000 +address1 = 0 +size1 = 0 +# compressed image must set len,normal image can left it to 0 +len = 0 + +#if user want to put RF calibration data on flash, uncomment following pt entry +#[[pt_entry]] +#type = 8 +#name = "rf_para" +#device = 0 +#address0 = 0x1FF000 +#size0 = 0x1000 +#address1 = 0 +#size1 = 0 +## compressed image must set len,normal image can left it to 0 +#len = 0 diff --git a/blflash/src/chip/bl602/image/boot2image.bin b/blflash/src/chip/bl602/image/boot2image.bin new file mode 100644 index 0000000..24a3771 Binary files /dev/null and b/blflash/src/chip/bl602/image/boot2image.bin differ diff --git a/blflash/src/chip/bl602/mod.rs b/blflash/src/chip/bl602/mod.rs index a9e19f5..9b20a9a 100644 --- a/blflash/src/chip/bl602/mod.rs +++ b/blflash/src/chip/bl602/mod.rs @@ -1,16 +1,38 @@ use super::{Chip, CodeSegment, FlashSegment}; +use crate::{Error, image::PartitionCfg}; +use deku::prelude::*; -const EFLASH_LOADER: &'static [u8] = include_bytes!("image/eflash_loader_40m.bin"); +pub const DEFAULT_PARTITION_CFG: &'static [u8] = include_bytes!("cfg/partition_cfg_2M.toml"); +pub const BOOT2IMAGE: &'static [u8] = include_bytes!("image/boot2image.bin"); +pub const EFLASH_LOADER: &'static [u8] = include_bytes!("image/eflash_loader_40m.bin"); const ROM_START: u32 = 0x23000000; // 16MB const ROM_END: u32 = 0x23000000 + 0x1000000; +#[derive(Copy, Clone)] pub struct Bl602; impl Bl602 { fn addr_is_flash(&self, addr: u32) -> bool { addr >= ROM_START && addr < ROM_END } + pub fn with_boot2( + &self, + mut partition_cfg: PartitionCfg, + bin: &[u8], + ) -> Result, Error> { + partition_cfg.update()?; + let partition_cfg = partition_cfg.to_bytes()?; + + let segments = vec![ + CodeSegment::from_slice(0x0, &BOOT2IMAGE), + CodeSegment::from_slice(0xe000, &partition_cfg), + CodeSegment::from_slice(0xf000, &partition_cfg), + // CodeSegment::from_slice(0x10000, &c), + // CodeSegment::from_slice(0x1f8000, &d), + ]; + todo!() + } } impl Chip for Bl602 { diff --git a/blflash/src/chip/mod.rs b/blflash/src/chip/mod.rs index ff509dc..9e1b916 100644 --- a/blflash/src/chip/mod.rs +++ b/blflash/src/chip/mod.rs @@ -1,4 +1,4 @@ -mod bl602; +pub mod bl602; pub use bl602::Bl602; pub use crate::elf::{FirmwareImage, CodeSegment}; pub use crate::flasher::FlashSegment; diff --git a/blflash/src/error.rs b/blflash/src/error.rs index 900baf7..9bcec8c 100644 --- a/blflash/src/error.rs +++ b/blflash/src/error.rs @@ -25,6 +25,8 @@ pub enum Error { RomError(RomError), #[error("Parse error")] ParseError(#[from] deku::error::DekuError), + #[error("Parse toml error")] + TomlError(#[from] toml::de::Error), } impl From for Error { diff --git a/blflash/src/flasher.rs b/blflash/src/flasher.rs index 87bee25..8ce3fc0 100644 --- a/blflash/src/flasher.rs +++ b/blflash/src/flasher.rs @@ -37,13 +37,14 @@ pub struct Flasher { impl Flasher { pub fn connect( + chip: impl Chip + 'static, serial: impl SerialPort + 'static, speed: Option, ) -> Result { let mut flasher = Flasher { connection: Connection::new(serial), boot_info: protocol::BootInfo::default(), - chip: Box::new(Bl602), + chip: Box::new(chip), }; flasher.connection.set_baud(speed.unwrap_or(DEFAULT_BAUDRATE))?; flasher.start_connection()?; diff --git a/blflash/src/image.rs b/blflash/src/image.rs deleted file mode 100644 index e69de29..0000000 diff --git a/blflash/src/image/mod.rs b/blflash/src/image/mod.rs new file mode 100644 index 0000000..a1d95ba --- /dev/null +++ b/blflash/src/image/mod.rs @@ -0,0 +1,3 @@ +mod partition; + +pub use partition::PartitionCfg; \ No newline at end of file diff --git a/blflash/src/image/partition.rs b/blflash/src/image/partition.rs new file mode 100644 index 0000000..0a0c19c --- /dev/null +++ b/blflash/src/image/partition.rs @@ -0,0 +1,75 @@ +use serde::Deserialize; +use deku::prelude::*; +use std::iter; +use std::io::Write; + + +#[derive(Debug, Deserialize, DekuWrite, Default)] +#[deku(magic = b"\x42\x46\x50\x54\x00\x00")] +pub struct PartitionCfg { + #[serde(skip)] + #[deku(update = "self.pt_entry.len()")] + pub entry_len: u32, + #[serde(skip)] + #[deku(update = "0")] + _unused1: u16, + #[serde(skip)] + #[deku(update = "self.header_checksum()")] + pub checksum: u32, + #[deku(skip)] + pub pt_table: Table, + pub pt_entry: Vec, + #[serde(skip)] + #[deku(update = "self.checksum()")] + pub file_checksum: u32, +} + +#[derive(Debug, Deserialize, DekuWrite, Default)] +pub struct Table { + pub address0: u32, + pub address1: u32, +} + +#[derive(Debug, Deserialize, DekuWrite, Default)] +pub struct Entry { + #[deku(bytes = "3")] + pub r#type: u32, + #[deku(writer = "Entry::write_name(name, output)")] + pub name: String, + pub address0: u32, + pub address1: u32, + pub size0: u32, + pub size1: u32, + pub len: u32, + #[serde(skip)] + pub _unused1: u32, +} + +impl PartitionCfg { + fn header_checksum(&self) -> u32 { + let data = self.to_bytes().unwrap(); + crc::crc32::checksum_ieee(&data[0..12]) + } + fn checksum(&self) -> u32 { + let data = self.to_bytes().unwrap(); + crc::crc32::checksum_ieee(&data[16..16+36*self.pt_entry.len()]) + } +} + +impl Entry { + fn write_name( + name: &str, + output: &mut BitVec, + ) -> Result<(), DekuError> { + if name.len() > 8 { + return Err(DekuError::Unexpected("name too long".to_string())) + } + let bytes = name + .bytes() + .chain(iter::repeat(0)) + .take(8 + 1) // last is null? + .collect::>(); + output.write_all(&bytes).unwrap(); + Ok(()) + } +} diff --git a/blflash/src/lib.rs b/blflash/src/lib.rs index 60dec7b..449b49e 100644 --- a/blflash/src/lib.rs +++ b/blflash/src/lib.rs @@ -1,7 +1,7 @@ mod config; mod flasher; mod connection; -mod chip; +pub mod chip; mod error; mod image; pub mod elf; diff --git a/blflash/src/main.rs b/blflash/src/main.rs index 6453ba5..8d40b52 100644 --- a/blflash/src/main.rs +++ b/blflash/src/main.rs @@ -1,6 +1,6 @@ use std::fs::read; -use blflash::{Config, Flasher, Error}; +use blflash::{Config, Flasher, Error, chip::bl602::{self, Bl602}}; use main_error::MainError; use serial::BaudRate; use env_logger::Env; @@ -15,6 +15,11 @@ struct FlashOpt { /// Bin file #[structopt(parse(from_os_str))] image: PathBuf, + /// Path to partition_cfg.toml, default to be partition/partition_cfg_2M.toml + partition_cfg: Option, + /// With boot2 + #[structopt(short, long)] + without_boot2: bool, } #[derive(StructOpt)] @@ -37,34 +42,59 @@ enum Opt { fn flash(opt: FlashOpt) -> Result<(), Error> { let serial = serial::open(&opt.port)?; - let mut flasher = Flasher::connect(serial, Some(BaudRate::Baud115200))?; + let chip = Bl602; - log::info!("Bootrom version: {}", flasher.boot_info().bootrom_version); - log::trace!("Boot info: {:x?}", flasher.boot_info()); - // use blflash::elf::CodeSegment; - // let a = read("image/boot2image.bin")?; - // let b = read("image/partition.bin")?; - // let c = read("image/fwimage.bin")?; - // let d = read("image/ro_params.dtb")?; - // let segments = vec![ - // CodeSegment::from_slice(0x0, &a), - // CodeSegment::from_slice(0xe000, &b), - // CodeSegment::from_slice(0xf000, &b), - // CodeSegment::from_slice(0x10000, &c), - // CodeSegment::from_slice(0x1f8000, &d), - // ]; - // flasher.load_segments(segments.into_iter())?; - let input_bytes = read(&opt.image)?; - flasher.load_elf_to_flash(&input_bytes)?; + if !opt.without_boot2 { + let partition_cfg = opt + .partition_cfg + .map(read) + .unwrap_or_else(|| Ok(bl602::DEFAULT_PARTITION_CFG.to_vec()))?; + let partition_cfg = toml::from_slice(&partition_cfg)?; + + let bin = read(&opt.image)?; + let segments = chip.with_boot2( + partition_cfg, + &bin + )?; + let mut flasher = Flasher::connect( + chip, + serial, + Some(BaudRate::Baud115200) + )?; + + log::info!("Bootrom version: {}", flasher.boot_info().bootrom_version); + log::trace!("Boot info: {:x?}", flasher.boot_info()); + + flasher.load_segments(segments.into_iter())?; + + flasher.reset()?; + } else { + let mut flasher = Flasher::connect( + chip, + serial, + Some(BaudRate::Baud115200) + )?; + + log::info!("Bootrom version: {}", flasher.boot_info().bootrom_version); + log::trace!("Boot info: {:x?}", flasher.boot_info()); + + let input_bytes = read(&opt.image)?; + flasher.load_elf_to_flash(&input_bytes)?; + + flasher.reset()?; + } - flasher.reset()?; log::info!("Success"); Ok(()) } fn check(opt: CheckOpt) -> Result<(), Error> { let serial = serial::open(&opt.port)?; - let mut flasher = Flasher::connect(serial, Some(BaudRate::Baud115200))?; + let mut flasher = Flasher::connect( + Bl602, + serial, + Some(BaudRate::Baud115200), + )?; log::info!("Bootrom version: {}", flasher.boot_info().bootrom_version); log::trace!("Boot info: {:x?}", flasher.boot_info());