1
0
mirror of https://review.coreboot.org/flashrom.git synced 2025-04-27 07:02:34 +02:00

flashrom_tester: Rewrite IOOpts to support more operations

flashrom cli supports include regions for all of read write and verify,
as well as omitting the read/write/verify file if an include region with
file is specified. Use an enum to allow only one operation at a time.
Unify the read and write region implementations.

BUG=b:235916336
BRANCH=None
TEST=None

Change-Id: I1cb46bb1b26949fd9c19949c43708a8b652e00da
Signed-off-by: Evan Benn <evanbenn@chromium.org>
Reviewed-on: https://review.coreboot.org/c/flashrom/+/71973
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Peter Marheine <pmarheine@chromium.org>
Reviewed-by: Edward O'Callaghan <quasisec@chromium.org>
This commit is contained in:
Evan Benn 2023-01-16 16:12:44 +11:00 committed by Edward O'Callaghan
parent 69bbe7986c
commit 72e62750c8
4 changed files with 133 additions and 134 deletions

View File

@ -33,7 +33,7 @@
// Software Foundation. // Software Foundation.
// //
use crate::{FlashChip, FlashromError, ROMWriteSpecifics}; use crate::{FlashChip, FlashromError};
use std::{ use std::{
ffi::{OsStr, OsString}, ffi::{OsStr, OsString},
@ -44,10 +44,7 @@ use std::{
#[derive(Default)] #[derive(Default)]
pub struct FlashromOpt<'a> { pub struct FlashromOpt<'a> {
pub wp_opt: WPOpt, pub wp_opt: WPOpt,
pub io_opt: IOOpt<'a>, pub io_opt: Option<IOOpt<'a>>,
pub layout: Option<&'a Path>, // -l <file>
pub image: Option<&'a str>, // -i <name>
pub flash_name: bool, // --flash-name pub flash_name: bool, // --flash-name
pub verbose: bool, // -V pub verbose: bool, // -V
@ -62,13 +59,28 @@ pub struct WPOpt {
pub disable: bool, // --wp-disable pub disable: bool, // --wp-disable
} }
#[derive(Default)] pub enum OperationArgs<'a> {
pub struct IOOpt<'a> { /// The file is the whole chip.
pub read: Option<&'a Path>, // -r <file> EntireChip(&'a Path),
pub write: Option<&'a Path>, // -w <file> /// File is the size of the full chip, limited to a single named region.
pub verify: Option<&'a Path>, // -v <file> ///
pub erase: bool, // -E /// The required path is the file to use, and the optional path is a layout file
pub region: Option<(&'a str, &'a Path)>, // --image /// specifying how to locate regions (if unspecified, flashrom will attempt
/// to discover the layout itself).
FullFileRegion(&'a str, &'a Path, Option<&'a Path>),
/// File is the size of the single named region only.
///
/// The required path is the file to use, and the optional path is a layout file
/// specifying how to locate regions (if unspecified, flashrom will attempt
/// to discover the layout itself).
RegionFileRegion(&'a str, &'a Path, Option<&'a Path>), // The file contains only the region
}
pub enum IOOpt<'a> {
Read(OperationArgs<'a>), // -r <file>
Write(OperationArgs<'a>), // -w <file>
Verify(OperationArgs<'a>), // -v <file>
Erase, // -E
} }
#[derive(PartialEq, Eq, Debug)] #[derive(PartialEq, Eq, Debug)]
@ -116,12 +128,7 @@ impl crate::Flashrom for FlashromCmd {
fn name(&self) -> Result<(String, String), FlashromError> { fn name(&self) -> Result<(String, String), FlashromError> {
let opts = FlashromOpt { let opts = FlashromOpt {
io_opt: IOOpt {
..Default::default()
},
flash_name: true, flash_name: true,
..Default::default() ..Default::default()
}; };
@ -132,16 +139,18 @@ impl crate::Flashrom for FlashromCmd {
} }
} }
fn write_file_with_layout(&self, rws: &ROMWriteSpecifics) -> Result<bool, FlashromError> { fn write_from_file_region(
&self,
path: &Path,
region: &str,
layout: &Path,
) -> Result<bool, FlashromError> {
let opts = FlashromOpt { let opts = FlashromOpt {
io_opt: IOOpt { io_opt: Some(IOOpt::Write(OperationArgs::FullFileRegion(
write: rws.write_file, region,
..Default::default() path,
}, Some(layout),
))),
layout: rws.layout_file,
image: rws.name_file,
..Default::default() ..Default::default()
}; };
@ -220,10 +229,7 @@ impl crate::Flashrom for FlashromCmd {
fn read_into_file(&self, path: &Path) -> Result<(), FlashromError> { fn read_into_file(&self, path: &Path) -> Result<(), FlashromError> {
let opts = FlashromOpt { let opts = FlashromOpt {
io_opt: IOOpt { io_opt: Some(IOOpt::Read(OperationArgs::EntireChip(path))),
read: Some(path),
..Default::default()
},
..Default::default() ..Default::default()
}; };
@ -233,10 +239,9 @@ impl crate::Flashrom for FlashromCmd {
fn read_region_into_file(&self, path: &Path, region: &str) -> Result<(), FlashromError> { fn read_region_into_file(&self, path: &Path, region: &str) -> Result<(), FlashromError> {
let opts = FlashromOpt { let opts = FlashromOpt {
io_opt: IOOpt { io_opt: Some(IOOpt::Read(OperationArgs::RegionFileRegion(
region: Some((region, path)), region, path, None,
..Default::default() ))),
},
..Default::default() ..Default::default()
}; };
@ -246,10 +251,7 @@ impl crate::Flashrom for FlashromCmd {
fn write_from_file(&self, path: &Path) -> Result<(), FlashromError> { fn write_from_file(&self, path: &Path) -> Result<(), FlashromError> {
let opts = FlashromOpt { let opts = FlashromOpt {
io_opt: IOOpt { io_opt: Some(IOOpt::Write(OperationArgs::EntireChip(path))),
write: Some(path),
..Default::default()
},
..Default::default() ..Default::default()
}; };
@ -259,10 +261,7 @@ impl crate::Flashrom for FlashromCmd {
fn verify_from_file(&self, path: &Path) -> Result<(), FlashromError> { fn verify_from_file(&self, path: &Path) -> Result<(), FlashromError> {
let opts = FlashromOpt { let opts = FlashromOpt {
io_opt: IOOpt { io_opt: Some(IOOpt::Verify(OperationArgs::EntireChip(path))),
verify: Some(path),
..Default::default()
},
..Default::default() ..Default::default()
}; };
@ -272,10 +271,7 @@ impl crate::Flashrom for FlashromCmd {
fn erase(&self) -> Result<(), FlashromError> { fn erase(&self) -> Result<(), FlashromError> {
let opts = FlashromOpt { let opts = FlashromOpt {
io_opt: IOOpt { io_opt: Some(IOOpt::Erase),
erase: true,
..Default::default()
},
..Default::default() ..Default::default()
}; };
@ -312,37 +308,49 @@ fn flashrom_decode_opts(opts: FlashromOpt) -> Vec<OsString> {
} }
// io_opt // io_opt
if let Some((region, path)) = opts.io_opt.region { fn add_operation_args(opts: OperationArgs, params: &mut Vec<OsString>) {
params.push("--image".into()); let (file, region, layout) = match opts {
let mut p = OsString::new(); OperationArgs::EntireChip(file) => (Some(file), None, None),
p.push(region); OperationArgs::FullFileRegion(region, file, layout) => {
p.push(":"); (Some(file), Some(region.to_string()), layout)
p.push(path); }
params.push(p); OperationArgs::RegionFileRegion(region, file, layout) => (
params.push("-r".into()); None,
} else if opts.io_opt.read.is_some() { Some(format!("{region}:{}", file.to_string_lossy())),
params.push("-r".into()); layout,
params.push(opts.io_opt.read.unwrap().into()); ),
} else if opts.io_opt.write.is_some() { };
params.push("-w".into()); if let Some(file) = file {
params.push(opts.io_opt.write.unwrap().into()); params.push(file.into())
} else if opts.io_opt.verify.is_some() { }
params.push("-v".into()); if let Some(region) = region {
params.push(opts.io_opt.verify.unwrap().into()); params.push("--include".into());
} else if opts.io_opt.erase { params.push(region.into())
params.push("-E".into()); }
if let Some(layout) = layout {
params.push("--layout".into());
params.push(layout.into())
}
}
if let Some(io) = opts.io_opt {
match io {
IOOpt::Read(args) => {
params.push("-r".into());
add_operation_args(args, &mut params);
}
IOOpt::Write(args) => {
params.push("-w".into());
add_operation_args(args, &mut params);
}
IOOpt::Verify(args) => {
params.push("-v".into());
add_operation_args(args, &mut params);
}
IOOpt::Erase => params.push("-E".into()),
}
} }
// misc_opt // misc_opt
if opts.layout.is_some() {
params.push("-l".into());
params.push(opts.layout.unwrap().into());
}
if opts.image.is_some() {
params.push("-i".into());
params.push(opts.image.unwrap().into());
}
if opts.flash_name { if opts.flash_name {
params.push("--flash-name".into()); params.push("--flash-name".into());
} }
@ -474,7 +482,7 @@ mod tests {
fn test_io_opt(opts: IOOpt, expected: &[&str]) { fn test_io_opt(opts: IOOpt, expected: &[&str]) {
assert_eq!( assert_eq!(
flashrom_decode_opts(FlashromOpt { flashrom_decode_opts(FlashromOpt {
io_opt: opts, io_opt: Some(opts),
..Default::default() ..Default::default()
}), }),
expected expected
@ -482,53 +490,40 @@ mod tests {
} }
test_io_opt( test_io_opt(
IOOpt { IOOpt::Read(crate::cmd::OperationArgs::EntireChip(Path::new("foo.bin"))),
read: Some(Path::new("foo.bin")),
..Default::default()
},
&["-r", "foo.bin"], &["-r", "foo.bin"],
); );
test_io_opt( test_io_opt(
IOOpt { IOOpt::Write(crate::cmd::OperationArgs::EntireChip(Path::new("bar.bin"))),
write: Some(Path::new("bar.bin")),
..Default::default()
},
&["-w", "bar.bin"], &["-w", "bar.bin"],
); );
test_io_opt( test_io_opt(
IOOpt { IOOpt::Verify(crate::cmd::OperationArgs::EntireChip(Path::new("baz.bin"))),
verify: Some(Path::new("/tmp/baz.bin")), &["-v", "baz.bin"],
..Default::default()
},
&["-v", "/tmp/baz.bin"],
); );
test_io_opt(IOOpt::Erase, &["-E"]);
test_io_opt( test_io_opt(
IOOpt { IOOpt::Read(crate::cmd::OperationArgs::FullFileRegion(
erase: true, "RO",
..Default::default() Path::new("foo.bin"),
}, Some(Path::new("baz.bin")),
&["-E"], )),
&["-r", "foo.bin", "--include", "RO", "--layout", "baz.bin"],
); );
test_io_opt(
IOOpt::Read(crate::cmd::OperationArgs::RegionFileRegion(
"foo",
Path::new("bar.bin"),
None,
)),
&["-r", "--include", "foo:bar.bin"],
)
} }
#[test] #[test]
fn decode_misc() { fn decode_misc() {
//use Default::default; //use Default::default;
assert_eq!(
flashrom_decode_opts(FlashromOpt {
layout: Some(Path::new("TestLayout")),
..Default::default()
}),
&["-l", "TestLayout"]
);
assert_eq!(
flashrom_decode_opts(FlashromOpt {
image: Some("TestImage"),
..Default::default()
}),
&["-i", "TestImage"]
);
assert_eq!( assert_eq!(
flashrom_decode_opts(FlashromOpt { flashrom_decode_opts(FlashromOpt {

View File

@ -36,7 +36,7 @@ use libflashrom::{Chip, Programmer};
use std::{cell::RefCell, convert::TryFrom, fs, path::Path}; use std::{cell::RefCell, convert::TryFrom, fs, path::Path};
use crate::{FlashChip, FlashromError, ROMWriteSpecifics}; use crate::{FlashChip, FlashromError};
#[derive(Debug)] #[derive(Debug)]
pub struct FlashromLib { pub struct FlashromLib {
@ -127,14 +127,19 @@ impl crate::Flashrom for FlashromLib {
Ok(()) Ok(())
} }
fn write_file_with_layout(&self, rws: &ROMWriteSpecifics) -> Result<bool, FlashromError> { fn write_from_file_region(
let buf = fs::read(rws.layout_file.unwrap()).map_err(|error| error.to_string())?; &self,
path: &Path,
region: &str,
layout: &Path,
) -> Result<bool, FlashromError> {
let buf = fs::read(layout).map_err(|error| error.to_string())?;
let buf = String::from_utf8(buf).unwrap(); let buf = String::from_utf8(buf).unwrap();
let mut layout: libflashrom::Layout = buf let mut layout: libflashrom::Layout = buf
.parse() .parse()
.map_err(|e: Box<dyn std::error::Error>| e.to_string())?; .map_err(|e: Box<dyn std::error::Error>| e.to_string())?;
layout.include_region(rws.name_file.unwrap())?; layout.include_region(region)?;
let mut buf = fs::read(rws.write_file.unwrap()).map_err(|error| error.to_string())?; let mut buf = fs::read(path).map_err(|error| error.to_string())?;
self.flashrom self.flashrom
.borrow_mut() .borrow_mut()
.image_write(&mut buf, Some(layout))?; .image_write(&mut buf, Some(layout))?;

View File

@ -107,12 +107,6 @@ where
} }
} }
pub struct ROMWriteSpecifics<'a> {
pub layout_file: Option<&'a Path>,
pub write_file: Option<&'a Path>,
pub name_file: Option<&'a str>,
}
pub trait Flashrom { pub trait Flashrom {
/// Returns the size of the flash in bytes. /// Returns the size of the flash in bytes.
fn get_size(&self) -> Result<i64, FlashromError>; fn get_size(&self) -> Result<i64, FlashromError>;
@ -120,9 +114,6 @@ pub trait Flashrom {
/// Returns the vendor name and the flash name. /// Returns the vendor name and the flash name.
fn name(&self) -> Result<(String, String), FlashromError>; fn name(&self) -> Result<(String, String), FlashromError>;
/// Write only a region of the flash.
fn write_file_with_layout(&self, rws: &ROMWriteSpecifics) -> Result<bool, FlashromError>;
/// Set write protect status and range. /// Set write protect status and range.
fn wp_range(&self, range: (i64, i64), wp_enable: bool) -> Result<bool, FlashromError>; fn wp_range(&self, range: (i64, i64), wp_enable: bool) -> Result<bool, FlashromError>;
@ -148,6 +139,16 @@ pub trait Flashrom {
/// Write the whole flash to the file specified by `path`. /// Write the whole flash to the file specified by `path`.
fn write_from_file(&self, path: &Path) -> Result<(), FlashromError>; fn write_from_file(&self, path: &Path) -> Result<(), FlashromError>;
/// 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>;
/// Verify the whole flash against the file specified by `path`. /// Verify the whole flash against the file specified by `path`.
fn verify_from_file(&self, path: &Path) -> Result<(), FlashromError>; fn verify_from_file(&self, path: &Path) -> Result<(), FlashromError>;

View File

@ -283,12 +283,11 @@ fn partial_lock_test(section: LayoutNames) -> impl Fn(&mut TestEnv) -> TestResul
env.wp.set_hw(true)?; env.wp.set_hw(true)?;
// Check that we cannot write to the protected region. // Check that we cannot write to the protected region.
let rws = flashrom::ROMWriteSpecifics { if env
layout_file: Some(&env.layout_file), .cmd
write_file: Some(env.random_data_file()), .write_from_file_region(env.random_data_file(), wp_section_name, &env.layout_file)
name_file: Some(wp_section_name), .is_ok()
}; {
if env.cmd.write_file_with_layout(&rws).is_ok() {
return Err( return Err(
"Section should be locked, should not have been overwritable with random data" "Section should be locked, should not have been overwritable with random data"
.into(), .into(),
@ -301,12 +300,11 @@ fn partial_lock_test(section: LayoutNames) -> impl Fn(&mut TestEnv) -> TestResul
// Check that we can write to the non protected region. // Check that we can write to the non protected region.
let (non_wp_section_name, _, _) = let (non_wp_section_name, _, _) =
utils::layout_section(env.layout(), section.get_non_overlapping_section()); utils::layout_section(env.layout(), section.get_non_overlapping_section());
let rws = flashrom::ROMWriteSpecifics { env.cmd.write_from_file_region(
layout_file: Some(&env.layout_file), env.random_data_file(),
write_file: Some(env.random_data_file()), non_wp_section_name,
name_file: Some(non_wp_section_name), &env.layout_file,
}; )?;
env.cmd.write_file_with_layout(&rws)?;
Ok(()) Ok(())
} }