diff options
author | Evan Benn <evanbenn@chromium.org> | 2022-06-01 12:45:01 +1000 |
---|---|---|
committer | Edward O'Callaghan <quasisec@chromium.org> | 2022-08-26 05:07:09 +0000 |
commit | f6d9a2847e6b66a8f1415e04dc2bd13cc1d7e555 (patch) | |
tree | 857f5cd26ecdd05007114228d95284031fca4bd4 /util | |
parent | b41bb5622c08edb33cd83aa05973513db3869af0 (diff) | |
download | flashrom-f6d9a2847e6b66a8f1415e04dc2bd13cc1d7e555.tar.gz flashrom-f6d9a2847e6b66a8f1415e04dc2bd13cc1d7e555.tar.bz2 flashrom-f6d9a2847e6b66a8f1415e04dc2bd13cc1d7e555.zip |
flashrom_tester: Add an implementation using libflashrom
flashrom_tester 'flashrom' crate was implemented using the flashrom
commandline. Add a second implementation using the libflashrom interface
via the libflashrom and libflashrom-sys rust bindings.
BUG=b:230545739
BRANCH=None
TEST=cargo test
TEST=on grunt (AMD)
TEST=/usr/bin/flashrom_tester --libflashrom host
TEST=/usr/bin/flashrom_tester --flashrom_binary /usr/sbin/flashrom host
Change-Id: Ic4db6c829d7e8dc707a10c10e1ca0d9b8abccdec
Signed-off-by: Evan Benn <evanbenn@chromium.org>
Reviewed-on: https://review.coreboot.org/c/flashrom/+/65282
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Edward O'Callaghan <quasisec@chromium.org>
Diffstat (limited to 'util')
-rw-r--r-- | util/flashrom_tester/flashrom/Cargo.toml | 3 | ||||
-rw-r--r-- | util/flashrom_tester/flashrom/src/flashromlib.rs | 160 | ||||
-rw-r--r-- | util/flashrom_tester/flashrom/src/lib.rs | 14 | ||||
-rw-r--r-- | util/flashrom_tester/src/main.rs | 43 |
4 files changed, 210 insertions, 10 deletions
diff --git a/util/flashrom_tester/flashrom/Cargo.toml b/util/flashrom_tester/flashrom/Cargo.toml index 27216cbde..a2447d04f 100644 --- a/util/flashrom_tester/flashrom/Cargo.toml +++ b/util/flashrom_tester/flashrom/Cargo.toml @@ -6,4 +6,5 @@ authors = ["Edward O'Callaghan <quasisec@chromium.org>", edition = "2018" [dependencies] -log = "0.4"
\ No newline at end of file +log = "0.4" +libflashrom = { path = "../../../bindings/rust/libflashrom" } diff --git a/util/flashrom_tester/flashrom/src/flashromlib.rs b/util/flashrom_tester/flashrom/src/flashromlib.rs new file mode 100644 index 000000000..d20dbb228 --- /dev/null +++ b/util/flashrom_tester/flashrom/src/flashromlib.rs @@ -0,0 +1,160 @@ +// Copyright 2022, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Alternatively, this software may be distributed under the terms of the +// GNU General Public License ("GPL") version 2 as published by the Free +// Software Foundation. +// + +use libflashrom::{Chip, Programmer}; + +use std::{cell::RefCell, convert::TryFrom, fs}; + +use crate::{FlashChip, FlashromError, ROMWriteSpecifics}; + +#[derive(Debug)] +pub struct FlashromLib { + // RefCell required here to keep Flashrom trait immutable. + // Cant make Flashrom methods mut because WriteProtectState + // and TestEnv both keep a reference. + pub flashrom: RefCell<Chip>, + pub fc: FlashChip, +} + +impl FlashromLib { + pub fn new(fc: FlashChip, log_level: libflashrom::flashrom_log_level) -> FlashromLib { + libflashrom::set_log_level(Some(log_level)); + let (programmer, options) = FlashChip::to_split(fc); + let flashrom = Chip::new(Programmer::new(programmer, options).unwrap(), None).unwrap(); + FlashromLib { + flashrom: RefCell::new(flashrom), + fc, + } + } +} + +impl crate::Flashrom for FlashromLib { + fn get_size(&self) -> Result<i64, FlashromError> { + Ok(self.flashrom.borrow().get_size() as i64) + } + + fn name(&self) -> Result<(String, String), FlashromError> { + Ok(("not".to_string(), "implemented".to_string())) + } + + fn wp_range(&self, range: (i64, i64), wp_enable: bool) -> Result<bool, FlashromError> { + let mut cfg = libflashrom::WriteProtectCfg::new()?; + let start = usize::try_from(range.0).unwrap(); + let len = usize::try_from(range.1).unwrap(); + cfg.set_range::<std::ops::Range<usize>>(start..(start + len)); + cfg.set_mode(if wp_enable { + libflashrom::flashrom_wp_mode::FLASHROM_WP_MODE_HARDWARE + } else { + libflashrom::flashrom_wp_mode::FLASHROM_WP_MODE_DISABLED + }); + self.flashrom.borrow_mut().set_wp(&cfg)?; + Ok(true) + } + + fn wp_list(&self) -> Result<String, FlashromError> { + let ranges = self.flashrom.borrow_mut().get_wp_ranges()?; + Ok(format!("{:?}", ranges)) + } + + fn wp_status(&self, en: bool) -> Result<bool, FlashromError> { + let ret = self + .flashrom + .borrow_mut() + .get_wp() + .map_err(|e| format!("{:?}", e))? + .get_mode(); + if en { + Ok(ret != libflashrom::flashrom_wp_mode::FLASHROM_WP_MODE_DISABLED) + } else { + Ok(ret == libflashrom::flashrom_wp_mode::FLASHROM_WP_MODE_DISABLED) + } + } + + fn wp_toggle(&self, en: bool) -> Result<bool, FlashromError> { + // TODO why does the cmd impl not do this? + // for cmd, range is only set for enable + // and disable is not sent for the wp_range command + self.wp_range((0, self.get_size()?), en) + } + + fn read_into_file(&self, path: &str) -> Result<(), FlashromError> { + let buf = self.flashrom.borrow_mut().image_read(None)?; + fs::write(path, buf).map_err(|error| error.to_string())?; + Ok(()) + } + + fn read_region_into_file(&self, path: &str, region: &str) -> Result<(), FlashromError> { + let mut layout = self.flashrom.borrow_mut().layout_read_fmap_from_rom()?; + layout.include_region(region)?; + let range = layout.get_region_range(region)?; + let buf = self.flashrom.borrow_mut().image_read(None)?; + fs::write(path, &buf[range]).map_err(|error| error.to_string())?; + Ok(()) + } + + fn write_from_file(&self, path: &str) -> Result<(), FlashromError> { + let mut buf = fs::read(path).map_err(|error| error.to_string())?; + self.flashrom.borrow_mut().image_write(&mut buf, None)?; + Ok(()) + } + + fn write_file_with_layout(&self, rws: &ROMWriteSpecifics) -> Result<bool, FlashromError> { + let buf = fs::read(rws.layout_file.unwrap()).map_err(|error| error.to_string())?; + let buf = String::from_utf8(buf).unwrap(); + let mut layout: libflashrom::Layout = buf + .parse() + .map_err(|e: Box<dyn std::error::Error>| e.to_string())?; + layout.include_region(rws.name_file.unwrap())?; + let mut buf = fs::read(rws.write_file.unwrap()).map_err(|error| error.to_string())?; + self.flashrom + .borrow_mut() + .image_write(&mut buf, Some(layout))?; + Ok(true) + } + + fn verify_from_file(&self, path: &str) -> Result<(), FlashromError> { + let buf = fs::read(path).map_err(|error| error.to_string())?; + self.flashrom.borrow_mut().image_verify(&buf, None)?; + Ok(()) + } + + fn erase(&self) -> Result<(), FlashromError> { + self.flashrom.borrow_mut().erase()?; + Ok(()) + } + + fn can_control_hw_wp(&self) -> bool { + self.fc.can_control_hw_wp() + } +} diff --git a/util/flashrom_tester/flashrom/src/lib.rs b/util/flashrom_tester/flashrom/src/lib.rs index 5f168b529..7326391e1 100644 --- a/util/flashrom_tester/flashrom/src/lib.rs +++ b/util/flashrom_tester/flashrom/src/lib.rs @@ -37,10 +37,17 @@ extern crate log; mod cmd; +mod flashromlib; use std::{error, fmt}; pub use cmd::{dut_ctrl_toggle_wp, 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, Debug)] pub enum FlashChip { @@ -71,6 +78,13 @@ impl FlashChip { 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. /// /// Servo and dediprog adapters are assumed to always have hardware write protect diff --git a/util/flashrom_tester/src/main.rs b/util/flashrom_tester/src/main.rs index dd09f9a30..129d1a9b7 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, Flashrom, FlashromCmd}; +use flashrom::{FlashChip, Flashrom, FlashromCmd, FlashromLib}; use flashrom_tester::{tester, tests}; use std::path::PathBuf; use std::sync::atomic::AtomicBool; @@ -65,7 +65,21 @@ fn main() { built_info::BUILT_TIME_UTC, built_info::RUSTC_VERSION, )) - .arg(Arg::with_name("flashrom_binary").required(true)) + .arg( + Arg::with_name("libflashrom") + .long("libflashrom") + .takes_value(false) + .help("Test the flashrom library instead of a binary"), + ) + .arg( + Arg::with_name("flashrom_binary") + .long("flashrom_binary") + .short("b") + .takes_value(true) + .required_unless("libflashrom") + .conflicts_with("libflashrom") + .help("Path to flashrom binary to test"), + ) .arg( Arg::with_name("ccd_target_type") .required(true) @@ -117,9 +131,6 @@ fn main() { let crossystem = flashrom_tester::utils::collect_crosssystem(&[]).expect("could not run crossystem"); - let flashrom_path = matches - .value_of("flashrom_binary") - .expect("flashrom_binary should be required"); let ccd_type = FlashChip::from( matches .value_of("ccd_target_type") @@ -127,10 +138,24 @@ fn main() { ) .expect("ccd_target_type should admit only known types"); - let cmd: Box<dyn Flashrom> = Box::new(FlashromCmd { - path: flashrom_path.to_string(), - fc: ccd_type, - }); + let cmd: Box<dyn Flashrom> = if matches.is_present("libflashrom") { + Box::new(FlashromLib::new( + ccd_type, + if matches.is_present("log_debug") { + flashrom::FLASHROM_MSG_DEBUG + } else { + flashrom::FLASHROM_MSG_WARN + }, + )) + } else { + Box::new(FlashromCmd { + path: matches + .value_of("flashrom_binary") + .expect("flashrom_binary is required") + .to_string(), + fc: ccd_type, + }) + }; let print_layout = matches.is_present("print-layout"); let output_format = matches |