Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 16 additions & 20 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,51 +53,47 @@ struct Cli {
/// Command to run
#[command(subcommand)]
cmd: Command,
#[clap(long, short, action)]
skip_hello: bool,
}

fn main() {
// Default to log level "info". Otherwise, you get no "regular" logs.
let env = env_logger::Env::default().default_filter_or("info");
env_logger::Builder::from_env(env).init();

let Cli { cmd, skip_hello } = Cli::parse();
let Cli { cmd } = Cli::parse();

match cmd {
Command::Info => {
let (i, e_in_addr, e_out_addr) = protocol::connect();
if !skip_hello {
protocol::hello(&i, e_in_addr);
}
let version = protocol::hello(&i, e_in_addr);

protocol::switch_mode(&i, e_in_addr, e_out_addr, protocol::Mode::Command);
protocol::info(&i, e_in_addr, e_out_addr)
protocol::switch_mode(&i, version, e_in_addr, e_out_addr, protocol::Mode::Command);
protocol::info(&i, version, e_in_addr, e_out_addr)
}
Command::End => {
let (i, e_in_addr, e_out_addr) = protocol::connect();
if !skip_hello {
protocol::hello(&i, e_in_addr);
}
let version = protocol::hello(&i, e_in_addr);

protocol::end(&i, e_in_addr, e_out_addr);
protocol::end(&i, version, e_in_addr, e_out_addr);
}
Command::Reset => {
let (i, e_in_addr, e_out_addr) = protocol::connect();
if !skip_hello {
protocol::hello(&i, e_in_addr);
}
let version = protocol::hello(&i, e_in_addr);

protocol::reset(&i, e_in_addr, e_out_addr);
}
Command::Read { address, file_name } => {
let (i, e_in_addr, e_out_addr) = protocol::connect();
if !skip_hello {
protocol::hello(&i, e_in_addr);
}
let version = protocol::hello(&i, e_in_addr);

protocol::switch_mode(&i, e_in_addr, e_out_addr, protocol::Mode::MemoryDebug);
protocol::read_mem(&i, e_in_addr, e_out_addr, address);
protocol::switch_mode(
&i,
version,
e_in_addr,
e_out_addr,
protocol::Mode::MemoryDebug,
);
protocol::read_mem(&i, version, e_in_addr, e_out_addr, address);
}
Command::Parse { file_name } => {
match mbn::from_elf(file_name.clone()) {
Expand Down
69 changes: 36 additions & 33 deletions src/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,15 +326,15 @@ pub fn hello(i: &Interface, e_in_addr: u8) -> u32 {
req.mode
}

pub fn switch_mode(i: &Interface, e_in_addr: u8, e_out_addr: u8, mode: Mode) {
pub fn switch_mode(i: &Interface, version: u32, e_in_addr: u8, e_out_addr: u8, mode: Mode) {
// As unusual as it is, we get a _request_ first, so we _send a response_.
// See hello() in which we take the request.
let res = HelloResponse {
header: PacketHeader {
message_type: SAHARA_HELLO_RESPONSE,
length: HELLO_RESPONSE_SIZE,
},
version: 2,
version,
compatible: 1,
status: 0,
mode: mode as u32,
Expand Down Expand Up @@ -403,40 +403,43 @@ fn exec(
Ok(())
}

pub fn info(i: &Interface, e_in_addr: u8, e_out_addr: u8) {
exec(i, e_in_addr, e_out_addr, Command::GetHardwareId).unwrap();
let b = &usb_read(i, e_in_addr);
let (d, _) = HardwareId::read_from_prefix(b).unwrap();
let HardwareId { model, oem, id } = d;
let name = hwids::hwid_to_name(id);
println!("Hardware ID: {id:08x} ({name})");
// TODO: map OEM + model to string names
println!("OEM: {model:04x}");
println!("Model: {oem:04x}");

pub fn info(i: &Interface, version: u32, e_in_addr: u8, e_out_addr: u8) {
exec(i, e_in_addr, e_out_addr, Command::GetSerialNum).unwrap();
let b = &usb_read(i, e_in_addr);
let (d, _) = SerialNo::read_from_prefix(b).unwrap();
// TODO: Which bytes do we really need?
let serial = d.serial;
println!("Serial number: {serial:02x?}");

exec(i, e_in_addr, e_out_addr, Command::GetOemPkHash).unwrap();
let b = &usb_read(i, e_in_addr);
// There is a condition in https://github.com/bkerler/edl that searches for
// a second occurrence of the first 4 bytes again in the other bytes, then
// takes [4+p..], where p is the position where it is found again. Wtf?
// AFAICT, there is just 3x the same hash.
let (d, _) = OemPkHash::read_from_prefix(b).unwrap();
let OemPkHash {
hash1,
hash2,
hash3,
} = d;
println!("OEM PK hashes:");
println!(" {hash1:02x?}");
println!(" {hash2:02x?}");
println!(" {hash3:02x?}");
// HWID and OEM public key hash are only for v2 and older
if version < 3 {
exec(i, e_in_addr, e_out_addr, Command::GetHardwareId).unwrap();
let b = &usb_read(i, e_in_addr);
let (d, _) = HardwareId::read_from_prefix(b).unwrap();
let HardwareId { model, oem, id } = d;
let name = hwids::hwid_to_name(id);
println!("Hardware ID: {id:08x} ({name})");
// TODO: map OEM + model to string names
println!("OEM: {model:04x}");
println!("Model: {oem:04x}");

exec(i, e_in_addr, e_out_addr, Command::GetOemPkHash).unwrap();
let b = &usb_read(i, e_in_addr);
// There is a condition in https://github.com/bkerler/edl that searches for
// a second occurrence of the first 4 bytes again in the other bytes, then
// takes [4+p..], where p is the position where it is found again. Wtf?
// AFAICT, there is just 3x the same hash.
let (d, _) = OemPkHash::read_from_prefix(b).unwrap();
let OemPkHash {
hash1,
hash2,
hash3,
} = d;
println!("OEM PK hashes:");
println!(" {hash1:02x?}");
println!(" {hash2:02x?}");
println!(" {hash3:02x?}");
}

if false {
match exec(i, e_in_addr, e_out_addr, Command::GetSblVersion) {
Expand Down Expand Up @@ -464,8 +467,8 @@ pub fn run(i: &Interface, e_in_addr: u8, e_out_addr: u8) {
//
}

pub fn read_mem(i: &Interface, e_in_addr: u8, e_out_addr: u8, address: u32) {
switch_mode(i, e_in_addr, e_out_addr, Mode::MemoryDebug);
pub fn read_mem(i: &Interface, version: u32, e_in_addr: u8, e_out_addr: u8, address: u32) {
switch_mode(i, version, e_in_addr, e_out_addr, Mode::MemoryDebug);

let size = 0x10;

Expand Down Expand Up @@ -520,8 +523,8 @@ pub fn reset(i: &Interface, e_in_addr: u8, e_out_addr: u8) {
}
}

pub fn end(i: &Interface, e_in_addr: u8, e_out_addr: u8) {
switch_mode(i, e_in_addr, e_out_addr, Mode::ImageTxPending);
pub fn end(i: &Interface, version: u32, e_in_addr: u8, e_out_addr: u8) {
switch_mode(i, version, e_in_addr, e_out_addr, Mode::ImageTxPending);

let packet = DoneRequest {
header: PacketHeader {
Expand Down