diff --git a/Cargo.lock b/Cargo.lock index f5de9d1..6daddfb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -147,17 +147,6 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "365a784774bb381e8c19edb91190a90d7f2625e057b55de2bc0f6b57bc779ff2" -[[package]] -name = "ihex_ext" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96571d3f3e7bd5b9b0bb5de815243e8caf38f5bf40b52e023d61037ed2ec717d" -dependencies = [ - "ihex", - "log", - "thiserror", -] - [[package]] name = "io-lifetimes" version = "1.0.10" @@ -291,18 +280,18 @@ checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" [[package]] name = "proc-macro2" -version = "1.0.56" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.26" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" dependencies = [ "proc-macro2", ] @@ -366,16 +355,16 @@ dependencies = [ [[package]] name = "sinowealth-kb-tool" -version = "0.0.2" +version = "0.0.3" dependencies = [ "clap", "ihex", - "ihex_ext", "log", "md5", "phf", "rusb", "simple_logger", + "thiserror", ] [[package]] @@ -403,9 +392,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.13" +version = "2.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" +checksum = "15e3fc8c0c74267e2df136e5e5fb656a464158aa57624053375eb9c8c6e25ae2" dependencies = [ "proc-macro2", "quote", @@ -414,22 +403,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.25", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index fcd540b..fbf2dfd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ description = """ A utility for reading and writing flash contents on Sinowealth 8051-based devices """ repository = "https://github.com/carlossless/sinowealth-kb-tool" -version = "0.0.2" +version = "0.0.3" edition = "2021" license = "MIT" @@ -12,8 +12,8 @@ license = "MIT" clap = "4.1" rusb = "0.9" ihex = "3.0" -ihex_ext = "1.0" md5 = "0.7" +thiserror = "1.0" [dependencies.log] version = "0.4" diff --git a/src/ihex.rs b/src/ihex.rs new file mode 100644 index 0000000..69d7c53 --- /dev/null +++ b/src/ihex.rs @@ -0,0 +1,75 @@ +use ihex::*; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum UnpackingError { + #[error("Unsupported record type")] + UnsupportedRecordType(Record), + #[error("Error while parsing IHEX records")] + Parsing(#[from] ReaderError), + #[error("Address ({0}) greater than binary size ({1})")] + AddressTooHigh(usize, usize), +} + +#[derive(Debug, Error)] +pub enum ConversionError { + #[error("Error while unpacking IHEX into array")] + Unpacking(#[from] UnpackingError), + #[error("Errow while writing IHEX to string")] + Serializing(#[from] WriterError) +} + +pub fn to_ihex(byte_array: Vec) -> Result { + let mut result: Vec = vec![]; + for (i, chunk) in byte_array.chunks(16).enumerate() { + result.push(Record::Data { + offset: (i as u16) * 16, + value: chunk.to_vec(), + }); + } + result.push(Record::EndOfFile); + return create_object_file_representation(&result) + .map_err(ConversionError::from); +} + +pub fn from_ihex(ihex_string: &str, max_length: usize) -> Result, ConversionError> { + let mut reader = Reader::new(ihex_string); + return unpack_records(&mut reader, max_length) + .map_err(ConversionError::from); +} + +fn unpack_records( + records: &mut impl Iterator>, + max_length: usize, +) -> Result, UnpackingError> { + let mut result: Vec = vec![]; + for rec in records { + match rec { + Ok(rec) => match rec { + Record::Data { offset, value } => { + let end_addr = offset as usize + value.len(); + if end_addr > max_length { + return Err(UnpackingError::AddressTooHigh(end_addr, max_length)); + } + if end_addr > result.len() { + result.resize(end_addr, 0); + } + + for (n, b) in value.iter().enumerate() { + result[offset as usize + n] = *b; + } + } + Record::ExtendedSegmentAddress(_base) => { + return Err(UnpackingError::UnsupportedRecordType(rec)) + } + Record::ExtendedLinearAddress(_base) => { + return Err(UnpackingError::UnsupportedRecordType(rec)) + } + Record::EndOfFile => break, + Record::StartLinearAddress(_) | Record::StartSegmentAddress { .. } => {} + }, + Err(err) => return Err(UnpackingError::Parsing(err)), + } + } + return Ok(result); +} diff --git a/src/isp.rs b/src/isp.rs index d23fa96..119937d 100644 --- a/src/isp.rs +++ b/src/isp.rs @@ -98,18 +98,12 @@ impl ISPDevice<'static> { pub fn write_cycle(&self, firmware: &mut Vec) -> Result<(), VerificationError> { let length = firmware.len(); - assert_eq!( - self.part.flash_size, length, - "Wrong firmware size. Expected {}, but got {}", - self.part.flash_size, length - ); - self.erase(); self.write(&firmware); let written = self.read(0, self.part.flash_size); // ARCANE: the ISP will copy the LJMP instruction (if existing) from the end to the very start of memory. - // We need to make the modifications to the expected payload to account for this. + // We need to make modifications to the expected payload to account for this. if firmware[length - 5] == LJMP_OPCODE { firmware[0] = LJMP_OPCODE; } diff --git a/src/main.rs b/src/main.rs index a70537d..ff5d838 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,21 +1,20 @@ use clap::*; -use ihex::*; -use ihex_ext::*; use log::*; use simple_logger::SimpleLogger; +use std::io::Read; use std::{fs, process}; mod part; -pub use part::*; - mod isp; -pub use isp::*; - +mod hid; mod util; -pub use util::*; +mod ihex; -mod hid; -pub use hid::*; +pub use crate::part::*; +pub use crate::isp::*; +pub use crate::hid::*; +pub use crate::ihex::*; +pub use crate::util::*; fn cli() -> Command { return Command::new("sinowealth-kb-tool") @@ -87,11 +86,8 @@ fn main() { let digest = md5::compute(&result); println!("MD5: {:x}", digest); - let ihex = result.to_ihex(); - - let obj = create_object_file_representation(&ihex).unwrap(); - - fs::write(output_file, obj).expect("Unable to write file"); + let ihex = to_ihex(result).expect("Failed converting to IHEX"); + fs::write(output_file, ihex).expect("Unable to write file"); } Some(("write", sub_matches)) => { let input_file = sub_matches @@ -106,7 +102,15 @@ fn main() { let part = PARTS.get(part_name).unwrap(); - let (mut firmware, _) = load_file_vec(input_file, part.flash_size, 0).unwrap(); + let mut file = fs::File::open(input_file).unwrap(); + let mut file_buf = Vec::new(); + file.read_to_end(&mut file_buf).unwrap(); + let file_str = String::from_utf8_lossy(&file_buf[..]); + let mut firmware = from_ihex(&file_str, part.flash_size).unwrap(); + + if firmware.len() < part.flash_size { + firmware.resize(part.flash_size, 0); + } match ISPDevice::new(part).write_cycle(&mut firmware) { Err(e) => { diff --git a/src/util.rs b/src/util.rs index f9ceb60..1d3098d 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,24 +1,3 @@ -use ihex::*; - -pub trait IHexConversion { - // fn from_ihex() -> Self; - fn to_ihex(&self) -> Vec; -} - -impl IHexConversion for Vec { - fn to_ihex(&self) -> Vec { - let mut result: Vec = vec![]; - for (i, chunk) in self.chunks(16).enumerate() { - result.push(Record::Data { - offset: (i as u16) * 16, - value: chunk.to_vec(), - }); - } - result.push(Record::EndOfFile); - return result; - } -} - #[derive(Debug, Clone)] pub enum VerificationError { ByteMismatch(usize, u8, u8),