From debe92329df01d431f40a5f38f6cade4528660ab Mon Sep 17 00:00:00 2001 From: RaINi_ Date: Sun, 14 May 2023 23:56:11 +0200 Subject: [PATCH] feat: add experimental generation detection (#5) --- src/macros.rs | 1 + src/main.rs | 25 ++++++++-------- src/parsers.rs | 78 +++++++++++++++++++++++++++++++++----------------- src/structs.rs | 30 +++++++++++++++++-- 4 files changed, 93 insertions(+), 41 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index 9a088aa..198d65a 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -2,6 +2,7 @@ macro_rules! make_dir { ($visibility:vis $name:ident, $header_type:ty, $entry_type:ty) => { #[allow(dead_code)] + #[derive(Debug)] $visibility struct $name<'a> { $visibility address: usize, $visibility header: &'a $header_type, diff --git a/src/main.rs b/src/main.rs index 1404c85..3d518ae 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,7 +19,7 @@ use crate::utils::{find_pattern, try_find_agesa}; #[derive(Parser, Debug)] #[clap(about, author, version)] struct Opt { - #[cfg_attr(debug_assertions, structopt(default_value = "./resources/E7B93AMS.1E0"))] + #[cfg_attr(debug_assertions, structopt(default_value = "C:\\Users\\RaZoR\\Desktop\\[VOL]"))] path: PathBuf, } @@ -63,19 +63,20 @@ fn main() -> Result<()> { log::info!(""); log::info!("[{:08X}] FirmwareEntryTable", addr); - for (location, entry) in parse_directories(&data, fet.psp as usize, addr - 0x20000) { + for (location, entry, generation) in + parse_directories(&data, fet.psp as usize, addr - 0x20000) + { match entry { Err(error) => log::error!("Location {:08X}, {:?}", location, error), - Ok(entry) => { - log::info!( - " Location {:08X}, Size {:08X} ({:>3} KB) // {} {}", - location, - entry.packed_size, - entry.packed_size / 1024, - entry.get_version(), - entry.try_get_processor_arch().unwrap_or("Unknown"), - ); - }, + Ok(entry) => log::info!( + " Location {:08X}, Size {:08X} ({:>3} KB) // {:?} {} {}", + location, + entry.packed_size, + entry.packed_size / 1024, + generation, + entry.get_version(), + entry.try_get_processor_arch().unwrap_or("Unknown"), + ), } } } diff --git a/src/parsers.rs b/src/parsers.rs index 4df67ea..a79274b 100644 --- a/src/parsers.rs +++ b/src/parsers.rs @@ -1,65 +1,88 @@ use anyhow::{anyhow, Error, Result}; use std::iter; -use crate::structs::{ComboDirectory, PspDirectory, PspDirectoryEntry, PspEntryHeader}; +use crate::structs::{ComboDirectory, Generation, PspDirectory, PspDirectoryEntry, PspEntryHeader}; use crate::utils::resolve_location; -type Iter<'a> = Box)> + 'a>; +type Iter<'a> = + Box, Option)> + 'a>; -fn header(location: usize, header: &PspEntryHeader) -> Iter<'_> { - Box::new(iter::once((location, Ok(header)))) +fn header(location: usize, header: &PspEntryHeader, generation: Option) -> Iter<'_> { + Box::new(iter::once((location, Ok(header), generation))) } -fn error<'a>(location: usize, error: Error) -> Iter<'a> { - Box::new(iter::once((location, Err(error)))) +fn error<'a>(location: usize, error: Error, generation: Option) -> Iter<'a> { + Box::new(iter::once((location, Err(error), generation))) } fn parse_combo_directory(data: &[u8], address: usize, offset: usize) -> Iter<'_> { let directory = match ComboDirectory::new(address, data) { - Err(err) => return error(address, err), + Err(err) => return error(address, err, None), Ok(directory) => directory, }; - let entries = directory.entries.into_iter(); - Box::new(entries.flat_map(move |e| parse_directory(data, e.location as usize, offset))) + Box::new(entries.flat_map(move |e| { + parse_directory(data, e.location as usize, offset, Some(e.try_get_gen())) + })) } -fn parse_psp_entry<'a>(data: &'a [u8], entry: &PspDirectoryEntry, offset: usize) -> Iter<'a> { +fn parse_psp_entry<'a>( + data: &'a [u8], + entry: &PspDirectoryEntry, + offset: usize, + generation: Option, +) -> Iter<'a> { match entry.kind { - 0x40 | 0x70 => parse_directory(data, entry.location as usize, offset), + 0x40 | 0x70 => parse_directory(data, entry.location as usize, offset, generation), 0x08 | 0x12 => { let location = resolve_location(entry.location as usize, offset); let data = match data.get(location..) { - None => return error(location, anyhow!("Could not fetch PSP entry header")), + None => { + return error(location, anyhow!("Could not fetch PSP entry header"), generation) + }, Some(data) => data, }; let entry_header = match PspEntryHeader::new(data) { - Err(err) => return error(location, err), + Err(err) => return error(location, err, generation), Ok(entry_header) => entry_header, }; - header(location, entry_header) + header(location, entry_header, generation) }, _ => Box::new(iter::empty()), } } -fn parse_psp_directory(data: &[u8], address: usize, offset: usize) -> Iter<'_> { +fn parse_psp_directory( + data: &[u8], + address: usize, + offset: usize, + generation: Option, +) -> Iter<'_> { let directory = match PspDirectory::new(address, data) { Ok(directory) => directory, - Err(err) => return error(address, err), + Err(err) => return error(address, err, generation), }; - - Box::new(directory.entries.into_iter().flat_map(move |e| parse_psp_entry(data, e, offset))) + Box::new( + directory + .entries + .into_iter() + .flat_map(move |e| parse_psp_entry(data, e, offset, generation)), + ) } -fn parse_directory(data: &[u8], address: usize, offset: usize) -> Iter<'_> { +pub fn parse_directory( + data: &[u8], + address: usize, + offset: usize, + generation: Option, +) -> Iter<'_> { let address = resolve_location(address, offset); match &data[address..][..4] { - b"2PSP" => parse_combo_directory(data, address, offset), - b"$PSP" | b"$PL2" => parse_psp_directory(data, address, offset), + b"2PSP" | b"2BHD" => parse_combo_directory(data, address, offset), + b"$PSP" | b"$PL2" => parse_psp_directory(data, address, offset, generation), sig => error( address, anyhow!( @@ -67,6 +90,7 @@ fn parse_directory(data: &[u8], address: usize, offset: usize) -> Iter<'_> { std::str::from_utf8(sig).unwrap_or(""), u32::from_be_bytes([sig[0], sig[1], sig[2], sig[3]]), ), + generation, ), } } @@ -75,17 +99,17 @@ pub fn parse_directories( data: &[u8], address: usize, offset: usize, -) -> Vec<(usize, Result<&PspEntryHeader>)> { - let mut vec = parse_directory(data, address, offset).collect::>(); - vec.sort_by_key(|&(location, _)| location); - vec.dedup_by_key(|&mut (location, _)| location); - vec.sort_by(|(_, res1), (_, res2)| match (res1, res2) { +) -> Vec<(usize, Result<&PspEntryHeader>, Option)> { + let mut vec = parse_directory(data, address, offset, None).collect::>(); + vec.sort_by_key(|&(location, _, _)| location); + vec.dedup_by_key(|&mut (location, _, _)| location); + vec.sort_by(|(_, res1, _), (_, res2, _)| match (res1, res2) { (Ok(h1), Ok(h2)) => h1.packed_size.cmp(&h2.packed_size), (Ok(_), Err(_)) => std::cmp::Ordering::Less, (Err(_), Ok(_)) => std::cmp::Ordering::Greater, (Err(_), Err(_)) => std::cmp::Ordering::Equal, }); - vec.sort_by(|(_, res1), (_, res2)| match (res1, res2) { + vec.sort_by(|(_, res1, _), (_, res2, _)| match (res1, res2) { (Ok(h1), Ok(h2)) => h1.get_version().cmp(&h2.get_version()), (Ok(_), Err(_)) => std::cmp::Ordering::Less, (Err(_), Ok(_)) => std::cmp::Ordering::Greater, diff --git a/src/structs.rs b/src/structs.rs index e23a768..1a8cba6 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -8,6 +8,20 @@ use static_assertions::assert_eq_size; use crate::make_dir; +#[derive(Debug, Copy, Clone)] +pub enum Generation { + Zen1, + Zen2, + Zen3, + Unknown(u32), +} + +impl fmt::Display for Generation { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + write!(f, "{self:X?}") + } +} + #[derive(Debug, Copy, Clone, Eq, PartialEq, Pod, Zeroable)] #[repr(C)] pub struct Version { @@ -103,6 +117,18 @@ pub struct ComboDirectoryEntry { pub location: u64, } +impl ComboDirectoryEntry { + // Credits: https://github.com/PSPReverse/PSPTool + pub fn try_get_gen(&self) -> Generation { + match self.id.to_be_bytes() { + [0xBC, 0x0A, 0x00, ..] | [0xBC, 0x09, 0x00, ..] => Generation::Zen1, + [0xBC, 0x0A, 0x01, ..] | [0xBC, 0x0B, 0x05, ..] => Generation::Zen2, + [0xBC, 0x0C, 0x01, ..] | [0xBC, 0x0C, 0x00, ..] => Generation::Zen3, + _ => Generation::Unknown(self.id), + } + } +} + #[derive(Debug, Copy, Clone, Pod, Zeroable)] #[repr(C)] pub struct PspEntryHeader { @@ -142,13 +168,13 @@ impl PspEntryHeader { pub fn try_get_processor_arch(&self) -> Option<&'static str> { let Version { major, minor, .. } = self.get_version(); match [major, minor] { - [0x00, 0x38] => Some("Vermeer"), // Ryzen 5XXX + [0x00, 0x37] => Some("Vermeer"), // Ryzen 5XXX [0x00, 0x2E] => Some("Matisse"), // Ryzen 3XXX [0x00, 0x2B] => Some("Pinnacle Ridge"), // Ryzen 2XXX [0x00, 0x19] => Some("Summit Ridge"), // Ryzen 1XXX [0x00, 0x40] => Some("Cezanne"), // Ryzen 5XXX (APU) - [0x00, 0x37] => Some("Renoir"), // Ryzen 4XXX (APU) + [0x00, 0x38] => Some("Renoir"), // Ryzen 4XXX (APU) [0x04, 0x1E] => Some("Picasso"), // Ryzen 3XXX (APU) [0x00, 0x25] => Some("Raven Ridge 2"), // Ryzen 2XXX (APU - Refresh) [0x00, 0x1E] => Some("Raven Ridge"), // Ryzen 2XXX (APU)