diff --git a/tool/src/legacy.rs b/tool/src/legacy.rs new file mode 100644 index 0000000..e0d91df --- /dev/null +++ b/tool/src/legacy.rs @@ -0,0 +1,68 @@ +use crate::{ + Error, + Pmc, + SuperIo, + Timeout, +}; + +pub struct EcLegacy { + pub pmc: Pmc, +} + +impl EcLegacy { + /// Probes for a compatible EC + pub unsafe fn new(primary: bool, timeout: T) -> Result { + let mut sio = SuperIo::new(if primary { 0x2E } else { 0x4E }); + + let id = + (sio.read(0x20) as u16) << 8 | + (sio.read(0x21) as u16); + + match id { + 0x5570 | 0x8587 => (), + _ => return Err(Error::SuperIoId(id)), + } + + //TODO: is there a good way to probe? + + Ok(Self { + pmc: Pmc::new(if primary { 0x62 } else { 0x68 }, timeout), + }) + } + + pub unsafe fn project(&mut self, data: &mut [u8]) -> Result { + let mut i = 0; + self.pmc.command(0x92)?; + while i < data.len() { + data[i] = self.pmc.read()?; + if data[i] == b'$' { + break; + } + i += 1; + } + Ok(i) + } + + pub unsafe fn version(&mut self, data: &mut [u8]) -> Result { + // Prepend `1.` to version string + let mut i = 0; + if i < data.len() { + data[i] = b'1'; + i += 1; + } + if i < data.len() { + data[i] = b'.'; + i += 1; + } + + self.pmc.command(0x93)?; + while i < data.len() { + data[i] = self.pmc.read()?; + if data[i] == b'$' { + break; + } + i += 1; + } + Ok(i) + } +} diff --git a/tool/src/lib.rs b/tool/src/lib.rs index da6dcd5..043076c 100644 --- a/tool/src/lib.rs +++ b/tool/src/lib.rs @@ -9,6 +9,9 @@ mod error; pub use self::firmware::Firmware; mod firmware; +pub use self::legacy::EcLegacy; +mod legacy; + pub use self::pmc::Pmc; mod pmc; diff --git a/tool/src/main.rs b/tool/src/main.rs index 2298a7c..6ba0b8f 100644 --- a/tool/src/main.rs +++ b/tool/src/main.rs @@ -1,12 +1,17 @@ use ectool::{ Ec, Error, + Firmware, Timeout, }; use std::{ + env, + fs, io, process, + str, time::{Duration, Instant}, + thread, }; pub struct StdTimeout { @@ -33,7 +38,82 @@ impl Timeout for StdTimeout { } } -unsafe fn tool() -> Result<(), Error> { +unsafe fn iopl() { + extern { + fn iopl(level: isize) -> isize; + } + + if iopl(3) < 0 { + eprintln!("failed to get I/O permission: {}", io::Error::last_os_error()); + process::exit(1); + } +} + +unsafe fn console() -> Result<(), Error> { + iopl(); + + let mut ec = Ec::new( + true, + StdTimeout::new(Duration::new(1, 0)), + )?; + + let mut head = ec.debug(0) as usize; + loop { + let tail = ec.debug(0) as usize; + if tail == 0 || head == tail { + thread::sleep(Duration::from_millis(1)); + } else { + while head != tail { + head += 1; + if head >= 256 { head = 1; } + let c = ec.debug(head as u8); + print!("{}", c as char); + } + } + } +} + +unsafe fn flash(path: &str) -> Result<(), Error> { + //TODO: remove unwraps + let firmware_data = fs::read(path).unwrap(); + let firmware = Firmware::new(&firmware_data).unwrap(); + println!("file board: {:?}", str::from_utf8(firmware.board)); + println!("file version: {:?}", str::from_utf8(firmware.version)); + + iopl(); + + let mut ec = Ec::new( + true, + StdTimeout::new(Duration::new(1, 0)), + )?; + + { + let mut data = [0; 256]; + let size = ec.board(&mut data)?; + + let ec_board = &data[..size]; + println!("ec board: {:?}", str::from_utf8(ec_board)); + + if ec_board != firmware.board { + panic!("file board does not match ec board"); + } + } + + { + print!("ec version: "); + let mut data = [0; 256]; + let size = ec.version(&mut data)?; + + let ec_version = &data[..size]; + println!("ec version: {:?}", str::from_utf8(ec_version)); + } + + Ok(()) +} + +unsafe fn info() -> Result<(), Error> { + iopl(); + let mut ec = Ec::new( true, StdTimeout::new(Duration::new(1, 0)), @@ -62,21 +142,55 @@ unsafe fn tool() -> Result<(), Error> { Ok(()) } -fn main() { - extern { - fn iopl(level: isize) -> isize; - } - - if unsafe { iopl(3) < 0 } { - eprintln!("failed to get I/O permission: {}", io::Error::last_os_error()); - process::exit(1); - } - - match unsafe { tool() } { - Ok(()) => (), - Err(err) => { - eprintln!("failed to run tool: {:X?}", err); - process::exit(1); - } - } +fn usage() { + eprintln!(" console"); + eprintln!(" flash [file]"); + eprintln!(" info"); +} + +fn main() { + let mut args = env::args().skip(1); + + match args.next() { + Some(arg) => match arg.as_str() { + "console" => match unsafe { console() } { + Ok(()) => (), + Err(err) => { + eprintln!("failed to read console: {:X?}", err); + process::exit(1); + }, + }, + "flash" => match args.next() { + Some(path) => match unsafe { flash(&path) } { + Ok(()) => (), + Err(err) => { + eprintln!("failed to flash '{}': {:X?}", path, err); + process::exit(1); + }, + }, + None => { + eprintln!("no file provided"); + process::exit(1); + } + }, + "info" => match unsafe { info() } { + Ok(()) => (), + Err(err) => { + eprintln!("failed to read info: {:X?}", err); + process::exit(1); + }, + }, + _ => { + eprintln!("unknown subcommand '{}'", arg); + usage(); + process::exit(1); + }, + }, + None => { + eprintln!("no subcommand provided"); + usage(); + process::exit(1); + }, + } + }