Skip to content

Commit ff162e9

Browse files
committed
Initial import of parser with minor adjustments
Parsing code taken from https://github.com/fiedka/me_fs_rs. Commit used: `f4bf011179bdff37b8a9a2aec94c7ab28cadb9e0` Partially rework printing and integrate with the current CLI. This adds knowledge from https://github.com/corna/me_cleaner to print additional metadata on the ME image, i.e, its version and variant. Signed-off-by: Daniel Maslowski <[email protected]>
1 parent db434f7 commit ff162e9

File tree

14 files changed

+1294
-4
lines changed

14 files changed

+1294
-4
lines changed

Cargo.lock

Lines changed: 76 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,22 @@ name = "intel_fw"
33
version = "0.1.0"
44
edition = "2024"
55

6+
[lib]
7+
name = "intel_fw"
8+
path = "src/lib.rs"
9+
10+
[[bin]]
11+
name = "intel_fw"
12+
path = "src/main.rs"
13+
614
[dependencies]
715
clap = { version = "4.5.48", features = ["derive"] }
816
env_logger = "0.11.8"
917
log = "0.4.28"
18+
md5 = "0.8.0"
19+
phf = { version = "0.13.1", default-features = false, features = ["macros"] }
20+
phf_macros = "0.13.1"
21+
serde = { version = "1.0.228", features = ["derive"] }
22+
serde_bytes = "0.11.19"
1023
zerocopy = "0.8.27"
1124
zerocopy-derive = "0.8.27"

src/clean.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
enum Module {
2+
ROMP,
3+
BUP,
4+
RBE,
5+
Kernel,
6+
Syslib,
7+
}

src/dir.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub mod gen2;
2+
pub mod gen3;
3+
pub mod man;

src/dir/gen2.rs

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
use crate::dir::man::{self, Manifest};
2+
use core::fmt::{self, Display};
3+
use serde::{Deserialize, Serialize};
4+
use std::str::from_utf8;
5+
use zerocopy::{FromBytes, Ref};
6+
use zerocopy_derive::{FromBytes, Immutable, IntoBytes};
7+
8+
const ENTRY_MAGIC: &[u8] = b"$MME";
9+
const SIG_LUT: u32 = u32::from_le_bytes(*b"LLUT");
10+
const SIG_LZMA: u32 = u32::from_le_bytes([0x36, 0x00, 0x40, 0x00]);
11+
12+
// https://github.com/skochinsky/me-tools me_unpack.py MeModuleHeader2
13+
#[derive(Immutable, IntoBytes, FromBytes, Serialize, Deserialize, Clone, Copy, Debug)]
14+
#[repr(C)]
15+
pub struct Entry {
16+
pub magic: [u8; 4],
17+
pub name: [u8; 0x10],
18+
pub hash: [u8; 0x20],
19+
pub mod_base: u32, // e.g. 0x0200_9000
20+
pub offset: u32, // e.g. 0x0001_5b4a
21+
pub code_size: u32, // e.g. 0x0004_2000
22+
pub size: u32, // e.g. 0x0001_d13b
23+
pub memory_size: u32, // e.g. 0x0004_b425
24+
pub pre_uma_size: u32, // e.g. 0x0004_b425 (often same as memory_size)
25+
pub entry_point: u32, // e.g. 0x2009_1000
26+
pub flags: u32, // e.g. 0x0010_d42a
27+
pub _54: u32, // e.g. 0x0000_0008
28+
pub _58: u32, // so far all 0
29+
pub _5c: u32, // so far all 0
30+
}
31+
32+
#[derive(Clone, Copy, Debug)]
33+
pub enum Compression {
34+
Uncompressed,
35+
Huffman,
36+
Lzma,
37+
Unknown,
38+
}
39+
40+
#[derive(Clone, Copy, Debug)]
41+
pub struct BinaryMap {
42+
pub rapi: u32, // 3 bits, really
43+
pub kapi: u32, // 2 bits, really
44+
pub code_start: usize,
45+
pub code_end: usize,
46+
pub data_end: usize,
47+
}
48+
49+
impl Entry {
50+
pub fn compression_type(&self) -> Compression {
51+
let comp_flag = (self.flags >> 4) & 0b111;
52+
match comp_flag {
53+
0 => Compression::Uncompressed,
54+
1 => Compression::Huffman,
55+
2 => Compression::Lzma,
56+
_ => Compression::Unknown,
57+
}
58+
}
59+
60+
pub fn bin_map(&self) -> BinaryMap {
61+
let b = self.mod_base;
62+
let f = self.flags;
63+
let rapi = (f >> 17) & 0b111;
64+
let kapi = (f >> 20) & 0b11;
65+
let code_start = (b + (rapi + kapi) * 0x1000) as usize;
66+
let code_end = (b + self.code_size) as usize;
67+
let data_end = (b + self.memory_size) as usize;
68+
BinaryMap {
69+
rapi,
70+
kapi,
71+
code_start,
72+
code_end,
73+
data_end,
74+
}
75+
}
76+
}
77+
78+
impl Display for BinaryMap {
79+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80+
let r = self.rapi;
81+
let k = self.kapi;
82+
let s = self.code_start;
83+
let e = self.code_end;
84+
let de = self.data_end;
85+
write!(
86+
f,
87+
"RAPI {r:03b} KAPI {k:02b} code {s:08x}:{e:08x}, data end {de:08x}"
88+
)
89+
}
90+
}
91+
92+
impl Display for Entry {
93+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94+
let n = match from_utf8(&self.name) {
95+
Ok(n) => n.trim_end_matches('\0').to_string(),
96+
Err(_) => format!("{:02x?}", self.name),
97+
};
98+
let o = self.offset;
99+
let s = self.size;
100+
let e = self.entry_point;
101+
write!(f, "{n:16} {s:08x} @ {o:08x}, entry point {e:08x}")
102+
}
103+
}
104+
105+
#[derive(IntoBytes, FromBytes, Serialize, Deserialize, Clone, Copy, Debug)]
106+
#[repr(C, packed)]
107+
pub struct Header {
108+
name: [u8; 4],
109+
_pad: [u8; 8],
110+
}
111+
112+
#[derive(Serialize, Deserialize, Clone, Debug)]
113+
#[repr(C)]
114+
pub struct Directory {
115+
pub manifest: Manifest,
116+
pub header: Header,
117+
pub entries: Vec<Entry>,
118+
pub offset: usize,
119+
pub name: String,
120+
}
121+
122+
impl Display for Directory {
123+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124+
let n = &self.name;
125+
let o = self.offset;
126+
let m = self.manifest;
127+
write!(f, "{n} @ {o:08x}, {m}")
128+
}
129+
}
130+
131+
const HEADER_SIZE: usize = core::mem::size_of::<Header>();
132+
133+
impl Directory {
134+
pub fn new(data: &[u8], offset: usize) -> Result<Self, String> {
135+
let Ok(manifest) = Manifest::new(data) else {
136+
return Err("cannot parse Gen 2 directory manifest".to_string());
137+
};
138+
let count = manifest.header.entries as usize;
139+
let d = &data[man::MANIFEST_SIZE..];
140+
let Ok((header, _)) = Header::read_from_prefix(d) else {
141+
return Err("cannot parse ME FW Gen 2 directory header".to_string());
142+
};
143+
let pos = man::MANIFEST_SIZE + HEADER_SIZE;
144+
let slice = &data[pos..];
145+
let Ok((r, _)) = Ref::<_, [Entry]>::from_prefix_with_elems(slice, count) else {
146+
return Err(format!(
147+
"cannot parse ME FW Gen 2 directory entries @ {:08x}",
148+
pos
149+
));
150+
};
151+
let entries = r.to_vec();
152+
let name = match from_utf8(&header.name) {
153+
Ok(n) => n.trim_end_matches('\0').to_string(),
154+
Err(_) => format!("{:02x?}", header.name),
155+
};
156+
Ok(Self {
157+
manifest,
158+
header,
159+
entries,
160+
offset,
161+
name,
162+
})
163+
}
164+
}

0 commit comments

Comments
 (0)