1 // Copyright 2022, Google Inc. 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above 11 // copyright notice, this list of conditions and the following disclaimer 12 // in the documentation and/or other materials provided with the 13 // distribution. 14 // * Neither the name of Google Inc. nor the names of its 15 // contributors may be used to endorse or promote products derived from 16 // this software without specific prior written permission. 17 // 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 // 30 // Alternatively, this software may be distributed under the terms of the 31 // GNU General Public License ("GPL") version 2 as published by the Free 32 // Software Foundation. 33 // 34 35 use libflashrom::{Chip, FlashromFlag, FlashromFlags, Programmer}; 36 37 use std::{cell::RefCell, convert::TryFrom, fs, path::Path}; 38 39 use crate::{FlashChip, FlashromError}; 40 41 #[derive(Debug)] 42 pub struct FlashromLib { 43 // RefCell required here to keep Flashrom trait immutable. 44 // Cant make Flashrom methods mut because WriteProtectState 45 // and TestEnv both keep a reference. 46 pub flashrom: RefCell<Chip>, 47 pub fc: FlashChip, 48 } 49 50 impl FlashromLib { new(fc: FlashChip, log_level: libflashrom::flashrom_log_level) -> FlashromLib51 pub fn new(fc: FlashChip, log_level: libflashrom::flashrom_log_level) -> FlashromLib { 52 libflashrom::set_log_level(Some(log_level)); 53 let (programmer, options) = FlashChip::to_split(fc); 54 let flashrom = Chip::new(Programmer::new(programmer, options).unwrap(), None).unwrap(); 55 FlashromLib { 56 flashrom: RefCell::new(flashrom), 57 fc, 58 } 59 } 60 } 61 62 impl crate::Flashrom for FlashromLib { get_size(&self) -> Result<i64, FlashromError>63 fn get_size(&self) -> Result<i64, FlashromError> { 64 Ok(self.flashrom.borrow().get_size() as i64) 65 } 66 name(&self) -> Result<(String, String), FlashromError>67 fn name(&self) -> Result<(String, String), FlashromError> { 68 Ok(("not".to_string(), "implemented".to_string())) 69 } 70 wp_range(&self, range: (i64, i64), wp_enable: bool) -> Result<bool, FlashromError>71 fn wp_range(&self, range: (i64, i64), wp_enable: bool) -> Result<bool, FlashromError> { 72 let mut cfg = libflashrom::WriteProtectCfg::new()?; 73 let start = usize::try_from(range.0).unwrap(); 74 let len = usize::try_from(range.1).unwrap(); 75 cfg.set_range::<std::ops::Range<usize>>(start..(start + len)); 76 cfg.set_mode(if wp_enable { 77 libflashrom::flashrom_wp_mode::FLASHROM_WP_MODE_HARDWARE 78 } else { 79 libflashrom::flashrom_wp_mode::FLASHROM_WP_MODE_DISABLED 80 }); 81 self.flashrom.borrow_mut().set_wp(&cfg)?; 82 Ok(true) 83 } 84 wp_list(&self) -> Result<String, FlashromError>85 fn wp_list(&self) -> Result<String, FlashromError> { 86 let ranges = self.flashrom.borrow_mut().get_wp_ranges()?; 87 Ok(format!("{:?}", ranges)) 88 } 89 wp_status(&self, en: bool) -> Result<bool, FlashromError>90 fn wp_status(&self, en: bool) -> Result<bool, FlashromError> { 91 let ret = self 92 .flashrom 93 .borrow_mut() 94 .get_wp() 95 .map_err(|e| format!("{:?}", e))? 96 .get_mode(); 97 if en { 98 Ok(ret != libflashrom::flashrom_wp_mode::FLASHROM_WP_MODE_DISABLED) 99 } else { 100 Ok(ret == libflashrom::flashrom_wp_mode::FLASHROM_WP_MODE_DISABLED) 101 } 102 } 103 wp_toggle(&self, en: bool) -> Result<bool, FlashromError>104 fn wp_toggle(&self, en: bool) -> Result<bool, FlashromError> { 105 let range = if en { (0, self.get_size()?) } else { (0, 0) }; 106 self.wp_range(range, en) 107 } 108 read_into_file(&self, path: &Path) -> Result<(), FlashromError>109 fn read_into_file(&self, path: &Path) -> Result<(), FlashromError> { 110 let buf = self.flashrom.borrow_mut().image_read(None)?; 111 fs::write(path, buf).map_err(|error| error.to_string())?; 112 Ok(()) 113 } 114 read_region_into_file(&self, path: &Path, region: &str) -> Result<(), FlashromError>115 fn read_region_into_file(&self, path: &Path, region: &str) -> Result<(), FlashromError> { 116 let mut layout = self.flashrom.borrow_mut().layout_read_fmap_from_rom()?; 117 layout.include_region(region)?; 118 let range = layout.get_region_range(region)?; 119 let buf = self.flashrom.borrow_mut().image_read(None)?; 120 fs::write(path, &buf[range]).map_err(|error| error.to_string())?; 121 Ok(()) 122 } 123 write_from_file(&self, path: &Path) -> Result<(), FlashromError>124 fn write_from_file(&self, path: &Path) -> Result<(), FlashromError> { 125 let mut buf = fs::read(path).map_err(|error| error.to_string())?; 126 self.flashrom.borrow_mut().image_write(&mut buf, None)?; 127 Ok(()) 128 } 129 write_from_file_region( &self, path: &Path, region: &str, layout: &Path, ) -> Result<bool, FlashromError>130 fn write_from_file_region( 131 &self, 132 path: &Path, 133 region: &str, 134 layout: &Path, 135 ) -> Result<bool, FlashromError> { 136 let buf = fs::read(layout).map_err(|error| error.to_string())?; 137 let buf = String::from_utf8(buf).unwrap(); 138 let mut layout: libflashrom::Layout = buf 139 .parse() 140 .map_err(|e: Box<dyn std::error::Error>| e.to_string())?; 141 layout.include_region(region)?; 142 let mut buf = fs::read(path).map_err(|error| error.to_string())?; 143 self.flashrom 144 .borrow_mut() 145 .image_write(&mut buf, Some(layout))?; 146 Ok(true) 147 } 148 verify_from_file(&self, path: &Path) -> Result<(), FlashromError>149 fn verify_from_file(&self, path: &Path) -> Result<(), FlashromError> { 150 let buf = fs::read(path).map_err(|error| error.to_string())?; 151 self.flashrom.borrow_mut().image_verify(&buf, None)?; 152 Ok(()) 153 } 154 verify_region_from_file(&self, path: &Path, region: &str) -> Result<(), FlashromError>155 fn verify_region_from_file(&self, path: &Path, region: &str) -> Result<(), FlashromError> { 156 let mut layout = self.flashrom.borrow_mut().layout_read_fmap_from_rom()?; 157 layout.include_region(region)?; 158 let range = layout.get_region_range(region)?; 159 let region_data = fs::read(path).map_err(|error| error.to_string())?; 160 if region_data.len() != range.len() { 161 return Err(format!( 162 "verify region range ({}) does not match provided file size ({})", 163 range.len(), 164 region_data.len() 165 ) 166 .into()); 167 } 168 let mut buf = vec![0; self.get_size()? as usize]; 169 buf[range].copy_from_slice(®ion_data); 170 self.flashrom 171 .borrow_mut() 172 .image_verify(&buf, Some(layout))?; 173 Ok(()) 174 } 175 erase(&self) -> Result<(), FlashromError>176 fn erase(&self) -> Result<(), FlashromError> { 177 self.flashrom.borrow_mut().erase()?; 178 Ok(()) 179 } 180 can_control_hw_wp(&self) -> bool181 fn can_control_hw_wp(&self) -> bool { 182 self.fc.can_control_hw_wp() 183 } 184 set_flags(&self, flags: &FlashromFlags) -> ()185 fn set_flags(&self, flags: &FlashromFlags) -> () { 186 self.flashrom 187 .borrow_mut() 188 .flag_set(FlashromFlag::FlashromFlagForce, flags.force); 189 self.flashrom 190 .borrow_mut() 191 .flag_set(FlashromFlag::FlashromFlagForceBoardmismatch, flags.force_boardmismatch); 192 self.flashrom 193 .borrow_mut() 194 .flag_set(FlashromFlag::FlashromFlagVerifyAfterWrite, flags.verify_after_write); 195 self.flashrom 196 .borrow_mut() 197 .flag_set(FlashromFlag::FlashromFlagVerifyWholeChip, flags.verify_whole_chip); 198 self.flashrom 199 .borrow_mut() 200 .flag_set(FlashromFlag::FlashromFlagSkipUnreadableRegions, flags.skip_unreadable_regions); 201 self.flashrom 202 .borrow_mut() 203 .flag_set(FlashromFlag::FlashromFlagSkipUnwritableRegions, flags.skip_unwritable_regions); 204 } 205 } 206