1
0
mirror of https://review.coreboot.org/flashrom.git synced 2025-04-28 15:33:42 +02:00

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>
This commit is contained in:
Evan Benn 2022-06-01 12:45:01 +10:00 committed by Edward O'Callaghan
parent b41bb5622c
commit f6d9a2847e
4 changed files with 210 additions and 10 deletions

View File

@ -6,4 +6,5 @@ authors = ["Edward O'Callaghan <quasisec@chromium.org>",
edition = "2018" edition = "2018"
[dependencies] [dependencies]
log = "0.4" log = "0.4"
libflashrom = { path = "../../../bindings/rust/libflashrom" }

View File

@ -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()
}
}

View File

@ -37,10 +37,17 @@
extern crate log; extern crate log;
mod cmd; mod cmd;
mod flashromlib;
use std::{error, fmt}; use std::{error, fmt};
pub use cmd::{dut_ctrl_toggle_wp, FlashromCmd}; 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)] #[derive(Copy, Clone, PartialEq, Debug)]
pub enum FlashChip { pub enum FlashChip {
@ -71,6 +78,13 @@ impl FlashChip {
return r; 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. /// Return whether the hardware write protect signal can be controlled.
/// ///
/// Servo and dediprog adapters are assumed to always have hardware write protect /// Servo and dediprog adapters are assumed to always have hardware write protect

View File

@ -39,7 +39,7 @@ extern crate log;
mod logger; mod logger;
use clap::{App, Arg}; use clap::{App, Arg};
use flashrom::{FlashChip, Flashrom, FlashromCmd}; use flashrom::{FlashChip, Flashrom, FlashromCmd, FlashromLib};
use flashrom_tester::{tester, tests}; use flashrom_tester::{tester, tests};
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicBool;
@ -65,7 +65,21 @@ fn main() {
built_info::BUILT_TIME_UTC, built_info::BUILT_TIME_UTC,
built_info::RUSTC_VERSION, 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(
Arg::with_name("ccd_target_type") Arg::with_name("ccd_target_type")
.required(true) .required(true)
@ -117,9 +131,6 @@ fn main() {
let crossystem = let crossystem =
flashrom_tester::utils::collect_crosssystem(&[]).expect("could not run 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( let ccd_type = FlashChip::from(
matches matches
.value_of("ccd_target_type") .value_of("ccd_target_type")
@ -127,10 +138,24 @@ fn main() {
) )
.expect("ccd_target_type should admit only known types"); .expect("ccd_target_type should admit only known types");
let cmd: Box<dyn Flashrom> = Box::new(FlashromCmd { let cmd: Box<dyn Flashrom> = if matches.is_present("libflashrom") {
path: flashrom_path.to_string(), Box::new(FlashromLib::new(
fc: ccd_type, 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 print_layout = matches.is_present("print-layout");
let output_format = matches let output_format = matches