mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-25 15:16:53 +01:00
firmware verification
This commit is contained in:
parent
0b7ba63184
commit
a0a6423b92
9
build.sh
9
build.sh
@ -89,11 +89,10 @@ build_update () {
|
||||
rm -f ./sc64-firmware.bin
|
||||
fi
|
||||
GIT_INFO=""
|
||||
if [ ! -z "${GIT_BRANCH}" ]; then GIT_INFO+="branch: [$GIT_BRANCH] "; fi
|
||||
if [ ! -z "${GIT_TAG}" ]; then GIT_INFO+="tag: [$GIT_TAG] "; fi
|
||||
if [ ! -z "${GIT_SHA}" ]; then GIT_INFO+="sha: [$GIT_SHA] "; fi
|
||||
if [ ! -z "${GIT_MESSAGE}" ]; then GIT_INFO+="message: [$GIT_MESSAGE] "; fi
|
||||
GIT_INFO=$(echo "$GIT_INFO" | xargs)
|
||||
if [ ! -z "${GIT_BRANCH}" ]; then GIT_INFO+=$'\n'"branch: $GIT_BRANCH"; fi
|
||||
if [ ! -z "${GIT_TAG}" ]; then GIT_INFO+=$'\n'"tag: $GIT_TAG"; fi
|
||||
if [ ! -z "${GIT_SHA}" ]; then GIT_INFO+=$'\n'"sha: $GIT_SHA"; fi
|
||||
if [ ! -z "${GIT_MESSAGE}" ]; then GIT_INFO+=$'\n'"commit msg: $GIT_MESSAGE"; fi
|
||||
python3 update.py \
|
||||
--git "$GIT_INFO" \
|
||||
--mcu ../controller/build/app/app.bin \
|
||||
|
@ -53,6 +53,12 @@ impl From<DataType> for u8 {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DataType> for u32 {
|
||||
fn from(value: DataType) -> Self {
|
||||
u8::from(value) as u32
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler {
|
||||
pub fn handle_debug_packet(&mut self, debug_packet: sc64::DebugPacket) {
|
||||
let sc64::DebugPacket { datatype, data } = debug_packet;
|
||||
@ -97,13 +103,13 @@ impl Handler {
|
||||
println!("Invalid header length for screenshot datatype");
|
||||
return;
|
||||
}
|
||||
if u32::from_be_bytes(header[0..4].try_into().unwrap()) != DataType::Screenshot as u32 {
|
||||
if u32::from_be_bytes(header[0..4].try_into().unwrap()) != DataType::Screenshot.into() {
|
||||
println!("Invalid header datatype for screenshot datatype");
|
||||
return;
|
||||
}
|
||||
let pixel_format: u32 = u32::from_be_bytes(header[4..8].try_into().unwrap());
|
||||
let width: u32 = u32::from_be_bytes(header[8..12].try_into().unwrap());
|
||||
let height: u32 = u32::from_be_bytes(header[12..16].try_into().unwrap());
|
||||
let pixel_format = u32::from_be_bytes(header[4..8].try_into().unwrap());
|
||||
let width = u32::from_be_bytes(header[8..12].try_into().unwrap());
|
||||
let height = u32::from_be_bytes(header[12..16].try_into().unwrap());
|
||||
if pixel_format != 2 && pixel_format != 4 {
|
||||
println!("Invalid pixel format for screenshot datatype");
|
||||
return;
|
||||
@ -141,7 +147,9 @@ impl Handler {
|
||||
let filename = &self.generate_filename("screenshot", "png");
|
||||
if let Some(error) = image.save(filename).err() {
|
||||
println!("Error during image save: {error}");
|
||||
return;
|
||||
}
|
||||
println!("Wrote {width}x{height} pixels to [{filename}]");
|
||||
} else {
|
||||
println!("Got screenshot packet without header data");
|
||||
}
|
||||
|
@ -451,9 +451,9 @@ fn handle_firmware_command(
|
||||
let mut firmware = vec![0u8; firmware_length as usize];
|
||||
firmware_file.read_exact(&mut firmware)?;
|
||||
|
||||
// TODO: print firmware metadata
|
||||
|
||||
println!("{}", "Sorry nothing".yellow());
|
||||
let metadata = sc64::firmware::verify(&firmware)?;
|
||||
println!("{}", "Firmware metadata:".bold());
|
||||
println!("{}", metadata);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -463,12 +463,16 @@ fn handle_firmware_command(
|
||||
|
||||
let (mut backup_file, backup_name) = create_file(&args.firmware)?;
|
||||
|
||||
sc64.reset_state()?;
|
||||
|
||||
let firmware = log_wait(
|
||||
format!("Generating firmware backup, this might take a while [{backup_name}]"),
|
||||
|| sc64.backup_firmware(),
|
||||
)?;
|
||||
|
||||
// TODO: print firmware metadata
|
||||
let metadata = sc64::firmware::verify(&firmware)?;
|
||||
println!("{}", "Firmware metadata:".bold());
|
||||
println!("{}", metadata);
|
||||
|
||||
backup_file.write(&firmware)?;
|
||||
|
||||
@ -480,14 +484,18 @@ fn handle_firmware_command(
|
||||
|
||||
let (mut update_file, update_name, update_length) = open_file(&args.firmware)?;
|
||||
|
||||
let mut fimware = vec![0u8; update_length as usize];
|
||||
update_file.read_exact(&mut fimware)?;
|
||||
let mut firmware = vec![0u8; update_length as usize];
|
||||
update_file.read_exact(&mut firmware)?;
|
||||
|
||||
// TODO: print firmware metadata
|
||||
let metadata = sc64::firmware::verify(&firmware)?;
|
||||
println!("{}", "Firmware metadata:".bold());
|
||||
println!("{}", metadata);
|
||||
|
||||
sc64.reset_state()?;
|
||||
|
||||
log_wait(
|
||||
format!("Updating firmware, this might take a while [{update_name}]"),
|
||||
|| sc64.update_firmware(&fimware),
|
||||
|| sc64.update_firmware(&firmware),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::io::{Error, Read, Seek};
|
||||
use std::io::{Error, Read, Seek, SeekFrom};
|
||||
|
||||
pub enum SaveType {
|
||||
None,
|
||||
@ -16,7 +16,7 @@ pub fn guess_save_type<T: Read + Seek>(
|
||||
) -> Result<(SaveType, Option<String>), Error> {
|
||||
let mut ed64_header = vec![0u8; 4];
|
||||
|
||||
reader.seek(std::io::SeekFrom::Start(0x3C))?;
|
||||
reader.seek(SeekFrom::Start(0x3C))?;
|
||||
reader.read(&mut ed64_header)?;
|
||||
|
||||
if &ed64_header[0..2] == b"ED" {
|
||||
|
@ -1,5 +1,4 @@
|
||||
use super::Error;
|
||||
use crc32fast::Hasher;
|
||||
|
||||
pub const IPL3_OFFSET: u32 = 0x40;
|
||||
pub const IPL3_LENGTH: usize = 0xFC0;
|
||||
@ -66,11 +65,7 @@ pub fn guess_ipl3_seed(ipl3: &[u8]) -> Result<u8, Error> {
|
||||
return Err(Error::new("Invalid IPL3 length provided"));
|
||||
}
|
||||
|
||||
let mut hasher = Hasher::new();
|
||||
|
||||
hasher.update(ipl3);
|
||||
|
||||
let cic_type: CicType = hasher.finalize().into();
|
||||
let cic_type: CicType = crc32fast::hash(ipl3).into();
|
||||
|
||||
Ok(cic_type.into())
|
||||
}
|
||||
|
149
sw/deployer/src/sc64/firmware.rs
Normal file
149
sw/deployer/src/sc64/firmware.rs
Normal file
@ -0,0 +1,149 @@
|
||||
use super::Error;
|
||||
use std::{
|
||||
fmt::Display,
|
||||
io::{Cursor, Read, Seek, SeekFrom},
|
||||
};
|
||||
|
||||
enum ChunkId {
|
||||
UpdateInfo,
|
||||
McuData,
|
||||
FpgaData,
|
||||
BootloaderData,
|
||||
PrimerData,
|
||||
}
|
||||
|
||||
impl TryFrom<u32> for ChunkId {
|
||||
type Error = Error;
|
||||
fn try_from(value: u32) -> Result<Self, Self::Error> {
|
||||
Ok(match value {
|
||||
1 => Self::UpdateInfo,
|
||||
2 => Self::McuData,
|
||||
3 => Self::FpgaData,
|
||||
4 => Self::BootloaderData,
|
||||
5 => Self::PrimerData,
|
||||
_ => return Err(Error::new("Unknown chunk id inside firmware update file")),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ChunkId {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(match self {
|
||||
ChunkId::UpdateInfo => "Update info",
|
||||
ChunkId::McuData => "MCU data",
|
||||
ChunkId::FpgaData => "FPGA data",
|
||||
ChunkId::BootloaderData => "Bootloader data",
|
||||
ChunkId::PrimerData => "Primer data",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Firmware {
|
||||
update_info: Option<String>,
|
||||
mcu_data: Option<Vec<u8>>,
|
||||
fpga_data: Option<Vec<u8>>,
|
||||
bootloader_data: Option<Vec<u8>>,
|
||||
primer_data: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl Display for Firmware {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if let Some(update_info) = &self.update_info {
|
||||
f.write_fmt(format_args!("{}", &update_info))?;
|
||||
} else {
|
||||
f.write_str("No update info data included")?;
|
||||
}
|
||||
if let Some(data) = &self.mcu_data {
|
||||
f.write_fmt(format_args!(
|
||||
"\nMCU data present, length: 0x{:X}",
|
||||
data.len()
|
||||
))?;
|
||||
} else {
|
||||
f.write_str("\nNo MCU data included")?;
|
||||
}
|
||||
if let Some(data) = &self.fpga_data {
|
||||
f.write_fmt(format_args!(
|
||||
"\nFPGA data present, length: 0x{:X}",
|
||||
data.len()
|
||||
))?;
|
||||
} else {
|
||||
f.write_str("\nNo FPGA data included")?;
|
||||
}
|
||||
if let Some(data) = &self.bootloader_data {
|
||||
f.write_fmt(format_args!(
|
||||
"\nBootloader data present, length: 0x{:X}",
|
||||
data.len()
|
||||
))?;
|
||||
} else {
|
||||
f.write_str("\nNo bootloader data included")?;
|
||||
}
|
||||
if let Some(data) = &self.primer_data {
|
||||
f.write_fmt(format_args!(
|
||||
"\nPrimer data present, length: 0x{:X}",
|
||||
data.len()
|
||||
))?;
|
||||
} else {
|
||||
f.write_str("\nNo primer data included")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
const SC64_FIRMWARE_UPDATE_TOKEN: &[u8; 16] = b"SC64 Update v2.0";
|
||||
|
||||
pub fn verify(data: &[u8]) -> Result<Firmware, Error> {
|
||||
let mut buffer = vec![0u8; 16];
|
||||
|
||||
let mut reader = Cursor::new(data);
|
||||
|
||||
reader.read(&mut buffer)?;
|
||||
if buffer != SC64_FIRMWARE_UPDATE_TOKEN {
|
||||
return Err(Error::new("Invalid firmware update header"));
|
||||
}
|
||||
|
||||
let mut firmware = Firmware {
|
||||
update_info: None,
|
||||
mcu_data: None,
|
||||
fpga_data: None,
|
||||
bootloader_data: None,
|
||||
primer_data: None,
|
||||
};
|
||||
|
||||
loop {
|
||||
let bytes = reader.read(&mut buffer)?;
|
||||
if bytes == 16 {
|
||||
let id: ChunkId = u32::from_le_bytes(buffer[0..4].try_into().unwrap()).try_into()?;
|
||||
let aligned_length = u32::from_le_bytes(buffer[4..8].try_into().unwrap());
|
||||
let checksum = u32::from_le_bytes(buffer[8..12].try_into().unwrap());
|
||||
let data_length = u32::from_le_bytes(buffer[12..16].try_into().unwrap());
|
||||
|
||||
let mut data = vec![0u8; data_length as usize];
|
||||
reader.read(&mut data)?;
|
||||
|
||||
let align = aligned_length - 4 - 4 - data_length;
|
||||
reader.seek(SeekFrom::Current(align as i64))?;
|
||||
|
||||
if crc32fast::hash(&data) != checksum {
|
||||
return Err(Error::new(
|
||||
format!("Invalid checksum for chunk [{id}]").as_str(),
|
||||
));
|
||||
}
|
||||
|
||||
match id {
|
||||
ChunkId::UpdateInfo => {
|
||||
firmware.update_info = Some(String::from_utf8_lossy(&data).to_string())
|
||||
}
|
||||
ChunkId::McuData => firmware.mcu_data = Some(data),
|
||||
ChunkId::FpgaData => firmware.fpga_data = Some(data),
|
||||
ChunkId::BootloaderData => firmware.bootloader_data = Some(data),
|
||||
ChunkId::PrimerData => firmware.primer_data = Some(data),
|
||||
}
|
||||
} else if bytes == 0 {
|
||||
break;
|
||||
} else {
|
||||
return Err(Error::new("Unexpected end of data in firmware update"));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(firmware)
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
mod cic;
|
||||
mod error;
|
||||
pub mod firmware;
|
||||
mod link;
|
||||
mod types;
|
||||
mod utils;
|
||||
|
@ -219,13 +219,12 @@ if __name__ == "__main__":
|
||||
|
||||
hostname = platform.node()
|
||||
creation_datetime = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
|
||||
info = [
|
||||
f'build system: [{hostname}]',
|
||||
f'creation datetime: [{creation_datetime}]',
|
||||
]
|
||||
update_info = '\n'.join([
|
||||
f'build system: {hostname}',
|
||||
f'creation datetime: {creation_datetime}',
|
||||
])
|
||||
if (args.git):
|
||||
info.append(args.git)
|
||||
update_info = ' '.join(info)
|
||||
update_info += args.git
|
||||
print(update_info)
|
||||
update.add_update_info(update_info.encode())
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user