diff options
Diffstat (limited to 'util/flashrom_tester/flashrom/src/lib.rs')
-rw-r--r-- | util/flashrom_tester/flashrom/src/lib.rs | 372 |
1 files changed, 78 insertions, 294 deletions
diff --git a/util/flashrom_tester/flashrom/src/lib.rs b/util/flashrom_tester/flashrom/src/lib.rs index 734e3ff4a..41393e841 100644 --- a/util/flashrom_tester/flashrom/src/lib.rs +++ b/util/flashrom_tester/flashrom/src/lib.rs @@ -37,36 +37,41 @@ extern crate log; mod cmd; +mod flashromlib; -pub use cmd::{dut_ctrl_toggle_wp, FlashromCmd}; +use std::{error, fmt, path::Path}; -#[derive(Copy, Clone, PartialEq, Debug)] +pub use cmd::FlashromCmd; +pub use flashromlib::FlashromLib; + +pub use libflashrom::{ + flashrom_log_level, FLASHROM_MSG_DEBUG, FLASHROM_MSG_DEBUG2, FLASHROM_MSG_ERROR, + FLASHROM_MSG_INFO, FLASHROM_MSG_SPEW, FLASHROM_MSG_WARN, +}; + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum FlashChip { - EC, HOST, - SERVO, - DEDIPROG, } impl FlashChip { pub fn from(s: &str) -> Result<FlashChip, &str> { - let r = match s { - "ec" => Ok(FlashChip::EC), + match s { "host" => Ok(FlashChip::HOST), - "servo" => Ok(FlashChip::SERVO), - "dediprog" => Ok(FlashChip::DEDIPROG), _ => Err("cannot convert str to enum"), - }; - return r; + } } pub fn to(fc: FlashChip) -> &'static str { - let r = match fc { - FlashChip::EC => "ec", + match fc { FlashChip::HOST => "host", - FlashChip::SERVO => "ft2231_spi:type=servo-v2", - FlashChip::DEDIPROG => "dediprog", - }; - return r; + } + } + + /// Return the programmer string and optional programmer options + pub fn to_split(fc: FlashChip) -> (&'static str, Option<&'static str>) { + let programmer = FlashChip::to(fc); + let mut bits = programmer.splitn(2, ':'); + (bits.next().unwrap(), bits.next()) } /// Return whether the hardware write protect signal can be controlled. @@ -75,307 +80,86 @@ impl FlashChip { /// disabled. pub fn can_control_hw_wp(&self) -> bool { match self { - FlashChip::HOST | FlashChip::EC => true, - FlashChip::SERVO | FlashChip::DEDIPROG => false, + FlashChip::HOST => true, } } } -pub type FlashromError = String; - -#[derive(Default)] -pub struct FlashromOpt<'a> { - pub wp_opt: WPOpt, - pub io_opt: IOOpt<'a>, - - pub layout: Option<&'a str>, // -l <file> - pub image: Option<&'a str>, // -i <name> - - pub flash_name: bool, // --flash-name - pub ignore_fmap: bool, // --ignore-fmap - pub verbose: bool, // -V -} - -#[derive(Default)] -pub struct WPOpt { - pub range: Option<(i64, i64)>, // --wp-range x0 x1 - pub status: bool, // --wp-status - pub list: bool, // --wp-list - pub enable: bool, // --wp-enable - pub disable: bool, // --wp-disable +#[derive(Debug, PartialEq, Eq)] +pub struct FlashromError { + msg: String, } -#[derive(Default)] -pub struct IOOpt<'a> { - pub read: Option<&'a str>, // -r <file> - pub write: Option<&'a str>, // -w <file> - pub verify: Option<&'a str>, // -v <file> - pub erase: bool, // -E -} - -pub trait Flashrom { - fn get_size(&self) -> Result<i64, FlashromError>; - fn dispatch(&self, fropt: FlashromOpt) -> Result<(Vec<u8>, Vec<u8>), FlashromError>; -} - -pub fn name(cmd: &cmd::FlashromCmd) -> Result<(String, String), FlashromError> { - let opts = FlashromOpt { - io_opt: IOOpt { - ..Default::default() - }, - - flash_name: true, - - ..Default::default() - }; - - let (stdout, stderr) = cmd.dispatch(opts)?; - let output = String::from_utf8_lossy(stdout.as_slice()); - let eoutput = String::from_utf8_lossy(stderr.as_slice()); - debug!("name()'stdout: {:#?}.", output); - debug!("name()'stderr: {:#?}.", eoutput); - - match extract_flash_name(&output) { - None => Err("Didn't find chip vendor/name in flashrom output".into()), - Some((vendor, name)) => Ok((vendor.into(), name.into())), - } -} - -/// Get a flash vendor and name from the first matching line of flashrom output. -/// -/// The target line looks like 'vendor="foo" name="bar"', as output by flashrom --flash-name. -/// This is usually the last line of output. -fn extract_flash_name(stdout: &str) -> Option<(&str, &str)> { - for line in stdout.lines() { - if !line.starts_with("vendor=\"") { - continue; - } - - let tail = line.trim_start_matches("vendor=\""); - let mut split = tail.splitn(2, "\" name=\""); - let vendor = split.next(); - let name = split.next().map(|s| s.trim_end_matches('"')); - - match (vendor, name) { - (Some(v), Some(n)) => return Some((v, n)), - _ => continue, - } +impl fmt::Display for FlashromError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.msg) } - None -} - -pub struct ROMWriteSpecifics<'a> { - pub layout_file: Option<&'a str>, - pub write_file: Option<&'a str>, - pub name_file: Option<&'a str>, -} - -pub fn write_file_with_layout( - cmd: &cmd::FlashromCmd, - rws: &ROMWriteSpecifics, -) -> Result<bool, FlashromError> { - let opts = FlashromOpt { - io_opt: IOOpt { - write: rws.write_file, - ..Default::default() - }, - - layout: rws.layout_file, - image: rws.name_file, - - ignore_fmap: true, - - ..Default::default() - }; - - let (stdout, stderr) = cmd.dispatch(opts)?; - let output = String::from_utf8_lossy(stdout.as_slice()); - let eoutput = String::from_utf8_lossy(stderr.as_slice()); - debug!("write_file_with_layout()'stdout:\n{}.", output); - debug!("write_file_with_layout()'stderr:\n{}.", eoutput); - Ok(true) } -pub fn wp_range( - cmd: &cmd::FlashromCmd, - range: (i64, i64), - wp_enable: bool, -) -> Result<bool, FlashromError> { - let opts = FlashromOpt { - wp_opt: WPOpt { - range: Some(range), - enable: wp_enable, - ..Default::default() - }, - ..Default::default() - }; +impl error::Error for FlashromError {} - let (stdout, stderr) = cmd.dispatch(opts)?; - let output = String::from_utf8_lossy(stdout.as_slice()); - let eoutput = String::from_utf8_lossy(stderr.as_slice()); - debug!("wp_range()'stdout:\n{}.", output); - debug!("wp_range()'stderr:\n{}.", eoutput); - Ok(true) -} - -pub fn wp_list(cmd: &cmd::FlashromCmd) -> Result<String, FlashromError> { - let opts = FlashromOpt { - wp_opt: WPOpt { - list: true, - ..Default::default() - }, - ..Default::default() - }; - - let (stdout, _) = cmd.dispatch(opts)?; - let output = String::from_utf8_lossy(stdout.as_slice()); - if output.len() == 0 { - return Err( - "wp_list isn't supported on platforms using the Linux kernel SPI driver wp_list".into(), - ); +impl<T> From<T> for FlashromError +where + T: Into<String>, +{ + fn from(msg: T) -> Self { + FlashromError { msg: msg.into() } } - Ok(output.to_string()) } -pub fn wp_status(cmd: &cmd::FlashromCmd, en: bool) -> Result<bool, FlashromError> { - let status = if en { "en" } else { "dis" }; - info!("See if chip write protect is {}abled", status); - - let opts = FlashromOpt { - wp_opt: WPOpt { - status: true, - ..Default::default() - }, - ..Default::default() - }; - - let (stdout, _) = cmd.dispatch(opts)?; - let output = String::from_utf8_lossy(stdout.as_slice()); - - debug!("wp_status():\n{}", output); - - let s = std::format!("write protect is {}abled", status); - Ok(output.contains(&s)) -} - -pub fn wp_toggle(cmd: &cmd::FlashromCmd, en: bool) -> Result<bool, FlashromError> { - let status = if en { "en" } else { "dis" }; - - // For MTD, --wp-range and --wp-enable must be used simultaneously. - let range = if en { - let rom_sz: i64 = cmd.get_size()?; - Some((0, rom_sz)) // (start, len) - } else { - None - }; - - let opts = FlashromOpt { - wp_opt: WPOpt { - range: range, - enable: en, - disable: !en, - ..Default::default() - }, - ..Default::default() - }; - - let (stdout, stderr) = cmd.dispatch(opts)?; - let output = String::from_utf8_lossy(stdout.as_slice()); - let eoutput = String::from_utf8_lossy(stderr.as_slice()); +pub trait Flashrom { + /// Returns the size of the flash in bytes. + fn get_size(&self) -> Result<i64, FlashromError>; - debug!("wp_toggle()'stdout:\n{}.", output); - debug!("wp_toggle()'stderr:\n{}.", eoutput); + /// Returns the vendor name and the flash name. + fn name(&self) -> Result<(String, String), FlashromError>; - match wp_status(&cmd, true) { - Ok(_ret) => { - info!("Successfully {}abled write-protect", status); - Ok(true) - } - Err(e) => Err(format!("Cannot {}able write-protect: {}", status, e)), - } -} + /// Set write protect status and range. + fn wp_range(&self, range: (i64, i64), wp_enable: bool) -> Result<bool, FlashromError>; -pub fn read(cmd: &cmd::FlashromCmd, path: &str) -> Result<(), FlashromError> { - let opts = FlashromOpt { - io_opt: IOOpt { - read: Some(path), - ..Default::default() - }, - ..Default::default() - }; + /// Read the write protect regions for the flash. + fn wp_list(&self) -> Result<String, FlashromError>; - let (stdout, _) = cmd.dispatch(opts)?; - let output = String::from_utf8_lossy(stdout.as_slice()); - debug!("read():\n{}", output); - Ok(()) -} + /// Return true if the flash write protect status matches `en`. + fn wp_status(&self, en: bool) -> Result<bool, FlashromError>; -pub fn write(cmd: &cmd::FlashromCmd, path: &str) -> Result<(), FlashromError> { - let opts = FlashromOpt { - io_opt: IOOpt { - write: Some(path), - ..Default::default() - }, - ..Default::default() - }; + /// Set write protect status. + /// If en=true sets wp_range to the whole chip (0,getsize()). + /// If en=false sets wp_range to (0,0). + /// This is due to the MTD driver, which requires wp enable to use a range + /// length != 0 and wp disable to have the range 0,0. + fn wp_toggle(&self, en: bool) -> Result<bool, FlashromError>; - let (stdout, _) = cmd.dispatch(opts)?; - let output = String::from_utf8_lossy(stdout.as_slice()); - debug!("write():\n{}", output); - Ok(()) -} + /// Read the whole flash to the file specified by `path`. + fn read_into_file(&self, path: &Path) -> Result<(), FlashromError>; -pub fn verify(cmd: &cmd::FlashromCmd, path: &str) -> Result<(), FlashromError> { - let opts = FlashromOpt { - io_opt: IOOpt { - verify: Some(path), - ..Default::default() - }, - ..Default::default() - }; + /// Read only a region of the flash into the file specified by `path`. Note + /// the first byte written to the file is the first byte from the region. + fn read_region_into_file(&self, path: &Path, region: &str) -> Result<(), FlashromError>; - let (stdout, _) = cmd.dispatch(opts)?; - let output = String::from_utf8_lossy(stdout.as_slice()); - debug!("verify():\n{}", output); - Ok(()) -} + /// Write the whole flash to the file specified by `path`. + fn write_from_file(&self, path: &Path) -> Result<(), FlashromError>; -pub fn erase(cmd: &cmd::FlashromCmd) -> Result<(), FlashromError> { - let opts = FlashromOpt { - io_opt: IOOpt { - erase: true, - ..Default::default() - }, - ..Default::default() - }; + /// Write only a region of the flash. + /// `path` is a file of the size of the whole flash. + /// The `region` name corresponds to a region name in the `layout` file, not the flash. + fn write_from_file_region( + &self, + path: &Path, + region: &str, + layout: &Path, + ) -> Result<bool, FlashromError>; - let (stdout, _) = cmd.dispatch(opts)?; - let output = String::from_utf8_lossy(stdout.as_slice()); - debug!("erase():\n{}", output); - Ok(()) -} + /// Verify the whole flash against the file specified by `path`. + fn verify_from_file(&self, path: &Path) -> Result<(), FlashromError>; -#[cfg(test)] -mod tests { - #[test] - fn extract_flash_name() { - use super::extract_flash_name; + /// Verify only the region against the file specified by `path`. + /// Note the first byte in the file is matched against the first byte of the region. + fn verify_region_from_file(&self, path: &Path, region: &str) -> Result<(), FlashromError>; - assert_eq!( - extract_flash_name( - "coreboot table found at 0x7cc13000\n\ - Found chipset \"Intel Braswell\". Enabling flash write... OK.\n\ - vendor=\"Winbond\" name=\"W25Q64DW\"\n" - ), - Some(("Winbond", "W25Q64DW")) - ); + /// Erase the whole flash. + fn erase(&self) -> Result<(), FlashromError>; - assert_eq!( - extract_flash_name( - "vendor name is TEST\n\ - Something failed!" - ), - None - ) - } + /// Return true if the hardware write protect of this flash can be controlled. + fn can_control_hw_wp(&self) -> bool; } |