summaryrefslogtreecommitdiffstats
path: root/util/flashrom_tester/flashrom/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'util/flashrom_tester/flashrom/src/lib.rs')
-rw-r--r--util/flashrom_tester/flashrom/src/lib.rs372
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;
}