diff --git a/util/flashrom_tester/flashrom/src/cmd.rs b/util/flashrom_tester/flashrom/src/cmd.rs index 37f8a72f7..f0466da85 100644 --- a/util/flashrom_tester/flashrom/src/cmd.rs +++ b/util/flashrom_tester/flashrom/src/cmd.rs @@ -33,10 +33,39 @@ // Software Foundation. // -use crate::{FlashChip, FlashromError, FlashromOpt}; +use crate::{FlashChip, FlashromError, ROMWriteSpecifics}; use std::process::Command; +#[derive(Default)] +pub struct FlashromOpt<'a> { + pub wp_opt: WPOpt, + pub io_opt: IOOpt<'a>, + + pub layout: Option<&'a str>, // -l + pub image: Option<&'a str>, // -i + + pub flash_name: bool, // --flash-name + 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(Default)] +pub struct IOOpt<'a> { + pub read: Option<&'a str>, // -r + pub write: Option<&'a str>, // -w + pub verify: Option<&'a str>, // -v + pub erase: bool, // -E +} + #[derive(PartialEq, Debug)] pub struct FlashromCmd { pub path: String, @@ -65,6 +94,13 @@ fn flashrom_extract_size(stdout: &str) -> Result { } } +impl FlashromCmd { + fn dispatch(&self, fropt: FlashromOpt) -> Result<(Vec, Vec), FlashromError> { + let params = flashrom_decode_opts(fropt); + flashrom_dispatch(self.path.as_str(), ¶ms, self.fc) + } +} + impl crate::Flashrom for FlashromCmd { fn get_size(&self) -> Result { let (stdout, _) = flashrom_dispatch(self.path.as_str(), &["--flash-size"], self.fc)?; @@ -73,9 +109,208 @@ impl crate::Flashrom for FlashromCmd { flashrom_extract_size(&sz) } - fn dispatch(&self, fropt: FlashromOpt) -> Result<(Vec, Vec), FlashromError> { - let params = flashrom_decode_opts(fropt); - flashrom_dispatch(self.path.as_str(), ¶ms, self.fc) + fn name(&self) -> Result<(String, String), FlashromError> { + let opts = FlashromOpt { + io_opt: IOOpt { + ..Default::default() + }, + + flash_name: true, + + ..Default::default() + }; + + let (stdout, stderr) = self.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())), + } + } + + fn write_file_with_layout(&self, rws: &ROMWriteSpecifics) -> Result { + let opts = FlashromOpt { + io_opt: IOOpt { + write: rws.write_file, + ..Default::default() + }, + + layout: rws.layout_file, + image: rws.name_file, + + ..Default::default() + }; + + let (stdout, stderr) = self.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) + } + + fn wp_range(&self, range: (i64, i64), wp_enable: bool) -> Result { + let opts = FlashromOpt { + wp_opt: WPOpt { + range: Some(range), + enable: wp_enable, + ..Default::default() + }, + ..Default::default() + }; + + let (stdout, stderr) = self.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) + } + + fn wp_list(&self) -> Result { + let opts = FlashromOpt { + wp_opt: WPOpt { + list: true, + ..Default::default() + }, + ..Default::default() + }; + + let (stdout, _) = self.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(), + ); + } + Ok(output.to_string()) + } + + fn wp_status(&self, en: bool) -> Result { + 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, _) = self.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)) + } + + fn wp_toggle(&self, en: bool) -> Result { + 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 = self.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) = self.dispatch(opts)?; + let output = String::from_utf8_lossy(stdout.as_slice()); + let eoutput = String::from_utf8_lossy(stderr.as_slice()); + + debug!("wp_toggle()'stdout:\n{}.", output); + debug!("wp_toggle()'stderr:\n{}.", eoutput); + + match self.wp_status(true) { + Ok(_ret) => { + info!("Successfully {}abled write-protect", status); + Ok(true) + } + Err(e) => Err(format!("Cannot {}able write-protect: {}", status, e)), + } + } + + fn read(&self, path: &str) -> Result<(), FlashromError> { + let opts = FlashromOpt { + io_opt: IOOpt { + read: Some(path), + ..Default::default() + }, + ..Default::default() + }; + + let (stdout, _) = self.dispatch(opts)?; + let output = String::from_utf8_lossy(stdout.as_slice()); + debug!("read():\n{}", output); + Ok(()) + } + + fn write(&self, path: &str) -> Result<(), FlashromError> { + let opts = FlashromOpt { + io_opt: IOOpt { + write: Some(path), + ..Default::default() + }, + ..Default::default() + }; + + let (stdout, _) = self.dispatch(opts)?; + let output = String::from_utf8_lossy(stdout.as_slice()); + debug!("write():\n{}", output); + Ok(()) + } + + fn verify(&self, path: &str) -> Result<(), FlashromError> { + let opts = FlashromOpt { + io_opt: IOOpt { + verify: Some(path), + ..Default::default() + }, + ..Default::default() + }; + + let (stdout, _) = self.dispatch(opts)?; + let output = String::from_utf8_lossy(stdout.as_slice()); + debug!("verify():\n{}", output); + Ok(()) + } + + fn erase(&self) -> Result<(), FlashromError> { + let opts = FlashromOpt { + io_opt: IOOpt { + erase: true, + ..Default::default() + }, + ..Default::default() + }; + + let (stdout, _) = self.dispatch(opts)?; + let output = String::from_utf8_lossy(stdout.as_slice()); + debug!("erase():\n{}", output); + Ok(()) + } + + fn can_control_hw_wp(&self) -> bool { + self.fc.can_control_hw_wp() } } @@ -209,10 +444,33 @@ fn hex_range_string(s: i64, l: i64) -> String { format!("{:#08X},{:#08X}", s, l).to_string() } +/// 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, + } + } + None +} + #[cfg(test)] mod tests { use super::flashrom_decode_opts; - use crate::{FlashromOpt, IOOpt, WPOpt}; + use super::{FlashromOpt, IOOpt, WPOpt}; #[test] fn decode_wp_opt() { @@ -347,4 +605,26 @@ mod tests { Err("Found no purely-numeric lines in flashrom output".into()) ); } + + #[test] + fn extract_flash_name() { + use super::extract_flash_name; + + 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")) + ); + + assert_eq!( + extract_flash_name( + "vendor name is TEST\n\ + Something failed!" + ), + None + ) + } } diff --git a/util/flashrom_tester/flashrom/src/lib.rs b/util/flashrom_tester/flashrom/src/lib.rs index 75797d391..924a71315 100644 --- a/util/flashrom_tester/flashrom/src/lib.rs +++ b/util/flashrom_tester/flashrom/src/lib.rs @@ -83,296 +83,46 @@ impl FlashChip { 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 - pub image: Option<&'a str>, // -i - - pub flash_name: bool, // --flash-name - 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(Default)] -pub struct IOOpt<'a> { - pub read: Option<&'a str>, // -r - pub write: Option<&'a str>, // -w - pub verify: Option<&'a str>, // -v - pub erase: bool, // -E -} - -pub trait Flashrom { - fn get_size(&self) -> Result; - fn dispatch(&self, fropt: FlashromOpt) -> Result<(Vec, Vec), 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, - } - } - 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 { - let opts = FlashromOpt { - io_opt: IOOpt { - write: rws.write_file, - ..Default::default() - }, +pub trait Flashrom { + /// Returns the size of the flash in bytes. + fn get_size(&self) -> Result; - layout: rws.layout_file, - image: rws.name_file, + /// Returns the vendor name and the flash name. + fn name(&self) -> Result<(String, String), FlashromError>; - ..Default::default() - }; + /// Write only a region of the flash. + fn write_file_with_layout(&self, rws: &ROMWriteSpecifics) -> Result; - 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 { - let opts = FlashromOpt { - wp_opt: WPOpt { - range: Some(range), - enable: wp_enable, - ..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()); - debug!("wp_range()'stdout:\n{}.", output); - debug!("wp_range()'stderr:\n{}.", eoutput); - Ok(true) -} - -pub fn wp_list(cmd: &cmd::FlashromCmd) -> Result { - 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(), - ); - } - Ok(output.to_string()) -} - -pub fn wp_status(cmd: &cmd::FlashromCmd, en: bool) -> Result { - 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 { - 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()); - - debug!("wp_toggle()'stdout:\n{}.", output); - debug!("wp_toggle()'stderr:\n{}.", eoutput); - - 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)), - } -} - -pub fn read(cmd: &cmd::FlashromCmd, path: &str) -> Result<(), FlashromError> { - let opts = FlashromOpt { - io_opt: IOOpt { - read: Some(path), - ..Default::default() - }, - ..Default::default() - }; - - let (stdout, _) = cmd.dispatch(opts)?; - let output = String::from_utf8_lossy(stdout.as_slice()); - debug!("read():\n{}", output); - Ok(()) -} - -pub fn write(cmd: &cmd::FlashromCmd, path: &str) -> Result<(), FlashromError> { - let opts = FlashromOpt { - io_opt: IOOpt { - write: Some(path), - ..Default::default() - }, - ..Default::default() - }; - - let (stdout, _) = cmd.dispatch(opts)?; - let output = String::from_utf8_lossy(stdout.as_slice()); - debug!("write():\n{}", output); - Ok(()) -} - -pub fn verify(cmd: &cmd::FlashromCmd, path: &str) -> Result<(), FlashromError> { - let opts = FlashromOpt { - io_opt: IOOpt { - verify: Some(path), - ..Default::default() - }, - ..Default::default() - }; - - let (stdout, _) = cmd.dispatch(opts)?; - let output = String::from_utf8_lossy(stdout.as_slice()); - debug!("verify():\n{}", output); - Ok(()) -} - -pub fn erase(cmd: &cmd::FlashromCmd) -> Result<(), FlashromError> { - let opts = FlashromOpt { - io_opt: IOOpt { - erase: true, - ..Default::default() - }, - ..Default::default() - }; - - let (stdout, _) = cmd.dispatch(opts)?; - let output = String::from_utf8_lossy(stdout.as_slice()); - debug!("erase():\n{}", output); - Ok(()) -} - -#[cfg(test)] -mod tests { - #[test] - fn extract_flash_name() { - use super::extract_flash_name; - - 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")) - ); - - assert_eq!( - extract_flash_name( - "vendor name is TEST\n\ - Something failed!" - ), - None - ) - } + /// Set write protect status for a range. + fn wp_range(&self, range: (i64, i64), wp_enable: bool) -> Result; + + /// Read the write protect regions for the flash. + fn wp_list(&self) -> Result; + + /// Return true if the flash write protect status matches `en`. + fn wp_status(&self, en: bool) -> Result; + + /// Set write protect status. + fn wp_toggle(&self, en: bool) -> Result; + + /// Read the whole flash to the file specified by `path`. + fn read(&self, path: &str) -> Result<(), FlashromError>; + + /// Write the whole flash to the file specified by `path`. + fn write(&self, path: &str) -> Result<(), FlashromError>; + + /// Verify the whole flash against the file specified by `path`. + fn verify(&self, path: &str) -> Result<(), FlashromError>; + + /// Erase the whole flash. + fn erase(&self) -> Result<(), FlashromError>; + + /// Return true if the hardware write protect of this flash can be controlled. + fn can_control_hw_wp(&self) -> bool; } diff --git a/util/flashrom_tester/src/main.rs b/util/flashrom_tester/src/main.rs index 80484d206..69bb92dbd 100644 --- a/util/flashrom_tester/src/main.rs +++ b/util/flashrom_tester/src/main.rs @@ -39,7 +39,7 @@ extern crate log; mod logger; use clap::{App, Arg}; -use flashrom::FlashChip; +use flashrom::{FlashChip, Flashrom, FlashromCmd}; use flashrom_tester::{tester, tests}; use std::path::PathBuf; use std::sync::atomic::AtomicBool; @@ -123,6 +123,11 @@ fn main() { ) .expect("ccd_target_type should admit only known types"); + let cmd: Box = Box::new(FlashromCmd { + path: flashrom_path.to_string(), + fc: ccd_type, + }); + let print_layout = matches.is_present("print-layout"); let output_format = matches .value_of("output-format") @@ -132,7 +137,7 @@ fn main() { let test_names = matches.values_of("test_name"); if let Err(e) = tests::generic( - flashrom_path, + cmd.as_ref(), ccd_type, print_layout, output_format, diff --git a/util/flashrom_tester/src/tester.rs b/util/flashrom_tester/src/tester.rs index 3150a4354..172f9958d 100644 --- a/util/flashrom_tester/src/tester.rs +++ b/util/flashrom_tester/src/tester.rs @@ -36,7 +36,7 @@ use super::rand_util; use super::types; use super::utils::{self, LayoutSizes}; -use flashrom::{FlashChip, Flashrom, FlashromCmd}; +use flashrom::{FlashChip, Flashrom}; use serde_json::json; use std::mem::MaybeUninit; use std::sync::atomic::{AtomicBool, Ordering}; @@ -52,7 +52,7 @@ pub struct TestEnv<'a> { /// /// Where possible, prefer to use methods on the TestEnv rather than delegating /// to the raw flashrom functions. - pub cmd: &'a FlashromCmd, + pub cmd: &'a dyn Flashrom, layout: LayoutSizes, pub wp: WriteProtectState<'a, 'static>, @@ -65,20 +65,20 @@ pub struct TestEnv<'a> { } impl<'a> TestEnv<'a> { - pub fn create(chip_type: FlashChip, cmd: &'a FlashromCmd) -> Result { + pub fn create(chip_type: FlashChip, cmd: &'a dyn Flashrom) -> Result { let rom_sz = cmd.get_size()?; let out = TestEnv { chip_type: chip_type, cmd: cmd, layout: utils::get_layout_sizes(rom_sz)?, - wp: WriteProtectState::from_hardware(cmd)?, + wp: WriteProtectState::from_hardware(cmd, chip_type)?, original_flash_contents: "/tmp/flashrom_tester_golden.bin".into(), random_data: "/tmp/random_content.bin".into(), }; info!("Stashing golden image for verification/recovery on completion"); - flashrom::read(&out.cmd, &out.original_flash_contents)?; - flashrom::verify(&out.cmd, &out.original_flash_contents)?; + out.cmd.read(&out.original_flash_contents)?; + out.cmd.verify(&out.original_flash_contents)?; info!("Generating random flash-sized data"); rand_util::gen_rand_testdata(&out.random_data, rom_sz as usize) @@ -123,19 +123,19 @@ impl<'a> TestEnv<'a> { /// Return true if the current Flash contents are the same as the golden image /// that was present at the start of testing. pub fn is_golden(&self) -> bool { - flashrom::verify(&self.cmd, &self.original_flash_contents).is_ok() + self.cmd.verify(&self.original_flash_contents).is_ok() } /// Do whatever is necessary to make the current Flash contents the same as they /// were at the start of testing. pub fn ensure_golden(&mut self) -> Result<(), String> { self.wp.set_hw(false)?.set_sw(false)?; - flashrom::write(&self.cmd, &self.original_flash_contents) + self.cmd.write(&self.original_flash_contents) } /// Attempt to erase the flash. pub fn erase(&self) -> Result<(), String> { - flashrom::erase(self.cmd) + self.cmd.erase() } /// Verify that the current Flash contents are the same as the file at the given @@ -143,11 +143,11 @@ impl<'a> TestEnv<'a> { /// /// Returns Err if they are not the same. pub fn verify(&self, contents_path: &str) -> Result<(), String> { - flashrom::verify(self.cmd, contents_path) + self.cmd.verify(contents_path) } } -impl Drop for TestEnv<'_> { +impl<'a> Drop for TestEnv<'a> { fn drop(&mut self) { info!("Verifying flash remains unmodified"); if !self.is_golden() { @@ -177,7 +177,8 @@ pub struct WriteProtectState<'a, 'p> { initial: InitialState<'p>, // Tuples are (hardware, software) current: (bool, bool), - cmd: &'a FlashromCmd, + cmd: &'a dyn Flashrom, + fc: FlashChip, } enum InitialState<'p> { @@ -199,7 +200,7 @@ impl<'a> WriteProtectState<'a, 'static> { /// /// Panics if there is already a live state derived from hardware. In such a situation the /// new state must be derived from the live one, or the live one must be dropped first. - pub fn from_hardware(cmd: &'a FlashromCmd) -> Result { + pub fn from_hardware(cmd: &'a dyn Flashrom, fc: FlashChip) -> Result { let mut lock = Self::get_liveness_lock() .lock() .expect("Somebody panicked during WriteProtectState init from hardware"); @@ -217,12 +218,13 @@ impl<'a> WriteProtectState<'a, 'static> { initial: InitialState::Hardware(hw, sw), current: (hw, sw), cmd, + fc, }) } /// Get the actual hardware write protect state. - fn get_hw(cmd: &FlashromCmd) -> Result { - if cmd.fc.can_control_hw_wp() { + fn get_hw(cmd: &dyn Flashrom) -> Result { + if cmd.can_control_hw_wp() { super::utils::get_hardware_wp() } else { Ok(false) @@ -230,8 +232,8 @@ impl<'a> WriteProtectState<'a, 'static> { } /// Get the actual software write protect state. - fn get_sw(cmd: &FlashromCmd) -> Result { - flashrom::wp_status(cmd, true) + fn get_sw(cmd: &dyn Flashrom) -> Result { + cmd.wp_status(true) } } @@ -241,14 +243,14 @@ impl<'a, 'p> WriteProtectState<'a, 'p> { /// /// If false, calls to set_hw() will do nothing. pub fn can_control_hw_wp(&self) -> bool { - self.cmd.fc.can_control_hw_wp() + self.cmd.can_control_hw_wp() } /// Set the software write protect. pub fn set_sw(&mut self, enable: bool) -> Result<&mut Self, String> { info!("request={}, current={}", enable, self.current.1); if self.current.1 != enable { - flashrom::wp_toggle(self.cmd, /* en= */ enable)?; + self.cmd.wp_toggle(/* en= */ enable)?; self.current.1 = enable; } Ok(self) @@ -263,7 +265,7 @@ impl<'a, 'p> WriteProtectState<'a, 'p> { } else if enable { info!( "Ignoring attempt to enable hardware WP with {:?} programmer", - self.cmd.fc + self.fc ); } } @@ -277,7 +279,7 @@ impl<'a, 'p> WriteProtectState<'a, 'p> { /// ```no_run /// # fn main() -> Result<(), String> { /// # let cmd: flashrom::FlashromCmd = unimplemented!(); - /// let wp = flashrom_tester::tester::WriteProtectState::from_hardware(&cmd)?; + /// let wp = flashrom_tester::tester::WriteProtectState::from_hardware(&cmd, flashrom::FlashChip::SERVO)?; /// { /// let mut wp = wp.push(); /// wp.set_sw(false)?; @@ -297,6 +299,7 @@ impl<'a, 'p> WriteProtectState<'a, 'p> { initial: InitialState::Previous(self), current: self.current, cmd: self.cmd, + fc: self.fc, } } @@ -376,7 +379,7 @@ impl<'a, 'p> WriteProtectState<'a, 'p> { ) })?; } - flashrom::wp_toggle(self.cmd, /* en= */ sw).map_err(|e| { + self.cmd.wp_toggle(/* en= */ sw).map_err(|e| { format!( "Failed to {}able software write protect: {}", enable_str(sw), @@ -386,7 +389,7 @@ impl<'a, 'p> WriteProtectState<'a, 'p> { } assert!( - self.cmd.fc.can_control_hw_wp() || (!self.current.0 && !hw), + self.cmd.can_control_hw_wp() || (!self.current.0 && !hw), "HW WP must be disabled if it cannot be controlled" ); if hw != self.current.0 { @@ -479,7 +482,7 @@ fn decode_test_result(res: TestResult, con: TestConclusion) -> (TestConclusion, pub fn run_all_tests( chip: FlashChip, - cmd: &FlashromCmd, + cmd: &dyn Flashrom, ts: TS, terminate_flag: Option<&AtomicBool>, ) -> Vec<(String, (TestConclusion, Option))> diff --git a/util/flashrom_tester/src/tests.rs b/util/flashrom_tester/src/tests.rs index 86c0da5bd..208e98cb4 100644 --- a/util/flashrom_tester/src/tests.rs +++ b/util/flashrom_tester/src/tests.rs @@ -36,7 +36,7 @@ use super::cros_sysinfo; use super::tester::{self, OutputFormat, TestCase, TestEnv, TestResult}; use super::utils::{self, LayoutNames}; -use flashrom::{FlashChip, Flashrom, FlashromCmd}; +use flashrom::{FlashChip, Flashrom}; use std::collections::{HashMap, HashSet}; use std::fs::File; use std::io::{BufRead, Write}; @@ -78,16 +78,13 @@ fn filter_tests<'n, 't: 'n, T: TestCase>( /// tests are run. Provided names that don't match any known test will be logged /// as a warning. pub fn generic<'a, TN: Iterator>( - path: &str, + cmd: &dyn Flashrom, fc: FlashChip, print_layout: bool, output_format: OutputFormat, test_names: Option, terminate_flag: Option<&AtomicBool>, ) -> Result<(), Box> { - let p = path.to_string(); - let cmd = FlashromCmd { path: p, fc }; - utils::ac_power_warning(); info!("Calculate ROM partition sizes & Create the layout file."); @@ -142,18 +139,20 @@ pub fn generic<'a, TN: Iterator>( }; let tests = filter_tests(tests, &mut filter_names); + let chip_name = cmd + .name() + .map(|x| format!("vendor=\"{}\" name=\"{}\"", x.0, x.1)) + .unwrap_or("".into()); + // ------------------------. // Run all the tests and collate the findings: - let results = tester::run_all_tests(fc, &cmd, tests, terminate_flag); + let results = tester::run_all_tests(fc, cmd, tests, terminate_flag); // Any leftover filtered names were specified to be run but don't exist for leftover in filter_names.iter().flatten() { warn!("No test matches filter name \"{}\"", leftover); } - let chip_name = flashrom::name(&cmd) - .map(|x| format!("vendor=\"{}\" name=\"{}\"", x.0, x.1)) - .unwrap_or("".into()); let os_rel = sys_info::os_release().unwrap_or("".to_string()); let system_info = cros_sysinfo::system_info().unwrap_or("".to_string()); let bios_info = cros_sysinfo::bios_info().unwrap_or("".to_string()); @@ -170,7 +169,7 @@ pub fn generic<'a, TN: Iterator>( fn get_device_name_test(env: &mut TestEnv) -> TestResult { // Success means we got something back, which is good enough. - flashrom::name(env.cmd)?; + env.cmd.name()?; Ok(()) } @@ -178,7 +177,7 @@ fn wp_toggle_test(env: &mut TestEnv) -> TestResult { // NOTE: This is not strictly a 'test' as it is allowed to fail on some platforms. // However, we will warn when it does fail. // List the write-protected regions of flash. - match flashrom::wp_list(env.cmd) { + match env.cmd.wp_list() { Ok(list_str) => info!("\n{}", list_str), Err(e) => warn!("{}", e), }; @@ -289,7 +288,7 @@ fn partial_lock_test(section: LayoutNames) -> impl Fn(&mut TestEnv) -> TestResul // Disable software WP so we can do range protection, but hardware WP // must remain enabled for (most) range protection to do anything. env.wp.set_hw(false)?.set_sw(false)?; - flashrom::wp_range(env.cmd, (start, len), true)?; + env.cmd.wp_range((start, len), true)?; env.wp.set_hw(true)?; let rws = flashrom::ROMWriteSpecifics { @@ -297,7 +296,7 @@ fn partial_lock_test(section: LayoutNames) -> impl Fn(&mut TestEnv) -> TestResul write_file: Some(env.random_data_file()), name_file: Some(name), }; - if flashrom::write_file_with_layout(env.cmd, &rws).is_ok() { + if env.cmd.write_file_with_layout(&rws).is_ok() { return Err( "Section should be locked, should not have been overwritable with random data" .into(),