Skip to content

Commit

Permalink
feat: add experimental generation detection (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
LeagueRaINi authored May 14, 2023
1 parent 4c89270 commit debe923
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 41 deletions.
1 change: 1 addition & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
25 changes: 13 additions & 12 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}

Expand Down Expand Up @@ -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"),
),
}
}
}
Expand Down
78 changes: 51 additions & 27 deletions src/parsers.rs
Original file line number Diff line number Diff line change
@@ -1,72 +1,96 @@
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<dyn Iterator<Item = (usize, Result<&'a PspEntryHeader>)> + 'a>;
type Iter<'a> =
Box<dyn Iterator<Item = (usize, Result<&'a PspEntryHeader>, Option<Generation>)> + 'a>;

fn header(location: usize, header: &PspEntryHeader) -> Iter<'_> {
Box::new(iter::once((location, Ok(header))))
fn header(location: usize, header: &PspEntryHeader, generation: Option<Generation>) -> 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<Generation>) -> 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<Generation>,
) -> 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<Generation>,
) -> 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<Generation>,
) -> 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!(
"Unknown PSP entry signature: {} ({:#x})",
std::str::from_utf8(sig).unwrap_or("<invalid>"),
u32::from_be_bytes([sig[0], sig[1], sig[2], sig[3]]),
),
generation,
),
}
}
Expand All @@ -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<_>>();
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<Generation>)> {
let mut vec = parse_directory(data, address, offset, None).collect::<Vec<_>>();
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,
Expand Down
30 changes: 28 additions & 2 deletions src/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit debe923

Please sign in to comment.