mirror of
				https://review.coreboot.org/flashrom.git
				synced 2025-11-04 07:00:39 +01: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:
		
				
					committed by
					
						
						Edward O'Callaghan
					
				
			
			
				
	
			
			
			
						parent
						
							b41bb5622c
						
					
				
				
					commit
					f6d9a2847e
				
			@@ -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" }
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										160
									
								
								util/flashrom_tester/flashrom/src/flashromlib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								util/flashrom_tester/flashrom/src/flashromlib.rs
									
									
									
									
									
										Normal 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()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user