xref: /aosp_15_r20/external/flashrom/bindings/rust/libflashrom/src/lib.rs (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
1*0d6140beSAndroid Build Coastguard Worker /*
2*0d6140beSAndroid Build Coastguard Worker  * This file is part of the flashrom project.
3*0d6140beSAndroid Build Coastguard Worker  *
4*0d6140beSAndroid Build Coastguard Worker  * Copyright (C) 2022 The Chromium OS Authors
5*0d6140beSAndroid Build Coastguard Worker  *
6*0d6140beSAndroid Build Coastguard Worker  * This program is free software; you can redistribute it and/or modify
7*0d6140beSAndroid Build Coastguard Worker  * it under the terms of the GNU General Public License as published by
8*0d6140beSAndroid Build Coastguard Worker  * the Free Software Foundation; either version 2 of the License, or
9*0d6140beSAndroid Build Coastguard Worker  * (at your option) any later version.
10*0d6140beSAndroid Build Coastguard Worker  *
11*0d6140beSAndroid Build Coastguard Worker  * This program is distributed in the hope that it will be useful,
12*0d6140beSAndroid Build Coastguard Worker  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*0d6140beSAndroid Build Coastguard Worker  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*0d6140beSAndroid Build Coastguard Worker  * GNU General Public License for more details.
15*0d6140beSAndroid Build Coastguard Worker  */
16*0d6140beSAndroid Build Coastguard Worker 
17*0d6140beSAndroid Build Coastguard Worker //! # libflashrom
18*0d6140beSAndroid Build Coastguard Worker //!
19*0d6140beSAndroid Build Coastguard Worker //! The `libflashrom` library is a rust FFI binding to the flashrom library.
20*0d6140beSAndroid Build Coastguard Worker //! libflashrom can be used to read write and modify some settings of flash chips.
21*0d6140beSAndroid Build Coastguard Worker //! The library closely follows the libflashrom C API, but exports a `safe` interface
22*0d6140beSAndroid Build Coastguard Worker //! including automatic resource management and forced error checking.
23*0d6140beSAndroid Build Coastguard Worker //!
24*0d6140beSAndroid Build Coastguard Worker //! libflashrom does not support threading, all usage of this library must occur on one thread.
25*0d6140beSAndroid Build Coastguard Worker //!
26*0d6140beSAndroid Build Coastguard Worker //! Most of the library functionality is defined on the [`Chip`] type.
27*0d6140beSAndroid Build Coastguard Worker //!
28*0d6140beSAndroid Build Coastguard Worker //! Example:
29*0d6140beSAndroid Build Coastguard Worker //!
30*0d6140beSAndroid Build Coastguard Worker //! ```
31*0d6140beSAndroid Build Coastguard Worker //! use libflashrom::*;
32*0d6140beSAndroid Build Coastguard Worker //! let mut chip = Chip::new(
33*0d6140beSAndroid Build Coastguard Worker //!     Programmer::new("dummy", Some("emulate=W25Q128FV")).unwrap(),
34*0d6140beSAndroid Build Coastguard Worker //!     Some("W25Q128.V")
35*0d6140beSAndroid Build Coastguard Worker //! ).unwrap();
36*0d6140beSAndroid Build Coastguard Worker //! let mut buf = chip.image_read(None).unwrap();
37*0d6140beSAndroid Build Coastguard Worker //! buf[0] = 0xFE;
38*0d6140beSAndroid Build Coastguard Worker //! chip.image_write(&mut buf, None).unwrap();
39*0d6140beSAndroid Build Coastguard Worker //! ```
40*0d6140beSAndroid Build Coastguard Worker 
41*0d6140beSAndroid Build Coastguard Worker use once_cell::sync::Lazy;
42*0d6140beSAndroid Build Coastguard Worker use regex::Regex;
43*0d6140beSAndroid Build Coastguard Worker use std::error;
44*0d6140beSAndroid Build Coastguard Worker use std::ffi::c_void;
45*0d6140beSAndroid Build Coastguard Worker use std::ffi::CStr;
46*0d6140beSAndroid Build Coastguard Worker use std::ffi::CString;
47*0d6140beSAndroid Build Coastguard Worker use std::fmt;
48*0d6140beSAndroid Build Coastguard Worker use std::io::Write;
49*0d6140beSAndroid Build Coastguard Worker use std::ptr::null;
50*0d6140beSAndroid Build Coastguard Worker use std::ptr::null_mut;
51*0d6140beSAndroid Build Coastguard Worker use std::ptr::NonNull;
52*0d6140beSAndroid Build Coastguard Worker use std::sync::Mutex;
53*0d6140beSAndroid Build Coastguard Worker use std::sync::Once;
54*0d6140beSAndroid Build Coastguard Worker 
55*0d6140beSAndroid Build Coastguard Worker pub use libflashrom_sys::{
56*0d6140beSAndroid Build Coastguard Worker     flashrom_log_level, FLASHROM_MSG_DEBUG, FLASHROM_MSG_DEBUG2, FLASHROM_MSG_ERROR,
57*0d6140beSAndroid Build Coastguard Worker     FLASHROM_MSG_INFO, FLASHROM_MSG_SPEW, FLASHROM_MSG_WARN,
58*0d6140beSAndroid Build Coastguard Worker };
59*0d6140beSAndroid Build Coastguard Worker 
60*0d6140beSAndroid Build Coastguard Worker pub use libflashrom_sys::flashrom_wp_mode;
61*0d6140beSAndroid Build Coastguard Worker 
62*0d6140beSAndroid Build Coastguard Worker // libflashrom uses (start, len) or inclusive [start, end] for ranges.
63*0d6140beSAndroid Build Coastguard Worker // This type exists to rust RangeBounds types to a convenient internal format.
64*0d6140beSAndroid Build Coastguard Worker #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
65*0d6140beSAndroid Build Coastguard Worker struct RangeInternal {
66*0d6140beSAndroid Build Coastguard Worker     start: usize,
67*0d6140beSAndroid Build Coastguard Worker     len: usize,
68*0d6140beSAndroid Build Coastguard Worker }
69*0d6140beSAndroid Build Coastguard Worker 
70*0d6140beSAndroid Build Coastguard Worker /// The type returned for write protect and layout queries
71*0d6140beSAndroid Build Coastguard Worker pub type Range = std::ops::Range<usize>;
72*0d6140beSAndroid Build Coastguard Worker 
73*0d6140beSAndroid Build Coastguard Worker impl<T> From<T> for RangeInternal
74*0d6140beSAndroid Build Coastguard Worker where
75*0d6140beSAndroid Build Coastguard Worker     T: std::ops::RangeBounds<usize>,
76*0d6140beSAndroid Build Coastguard Worker {
from(range: T) -> Self77*0d6140beSAndroid Build Coastguard Worker     fn from(range: T) -> Self {
78*0d6140beSAndroid Build Coastguard Worker         let start = match range.start_bound() {
79*0d6140beSAndroid Build Coastguard Worker             std::ops::Bound::Included(start) => *start,
80*0d6140beSAndroid Build Coastguard Worker             std::ops::Bound::Excluded(start) => *start + 1,
81*0d6140beSAndroid Build Coastguard Worker             std::ops::Bound::Unbounded => 0,
82*0d6140beSAndroid Build Coastguard Worker         };
83*0d6140beSAndroid Build Coastguard Worker         RangeInternal {
84*0d6140beSAndroid Build Coastguard Worker             start,
85*0d6140beSAndroid Build Coastguard Worker             len: match range.end_bound() {
86*0d6140beSAndroid Build Coastguard Worker                 std::ops::Bound::Included(end) => *end - start + 1,
87*0d6140beSAndroid Build Coastguard Worker                 std::ops::Bound::Excluded(end) => *end - start,
88*0d6140beSAndroid Build Coastguard Worker                 std::ops::Bound::Unbounded => usize::MAX - start,
89*0d6140beSAndroid Build Coastguard Worker             },
90*0d6140beSAndroid Build Coastguard Worker         }
91*0d6140beSAndroid Build Coastguard Worker     }
92*0d6140beSAndroid Build Coastguard Worker }
93*0d6140beSAndroid Build Coastguard Worker 
94*0d6140beSAndroid Build Coastguard Worker impl RangeInternal {
95*0d6140beSAndroid Build Coastguard Worker     // inclusive end for libflashrom
end(&self) -> usize96*0d6140beSAndroid Build Coastguard Worker     fn end(&self) -> usize {
97*0d6140beSAndroid Build Coastguard Worker         self.start + self.len - 1
98*0d6140beSAndroid Build Coastguard Worker     }
99*0d6140beSAndroid Build Coastguard Worker }
100*0d6140beSAndroid Build Coastguard Worker 
101*0d6140beSAndroid Build Coastguard Worker // log_c is set to be the callback at [`Programmer`] init. It deals with va_list and calls log_rust.
102*0d6140beSAndroid Build Coastguard Worker // log_rust calls a user defined function, or by default log_eprint.
103*0d6140beSAndroid Build Coastguard Worker // log_eprint just writes to stderr.
104*0d6140beSAndroid Build Coastguard Worker extern "C" {
set_log_callback()105*0d6140beSAndroid Build Coastguard Worker     fn set_log_callback();
106*0d6140beSAndroid Build Coastguard Worker     // Modifying and reading current_level is not thread safe, but neither is
107*0d6140beSAndroid Build Coastguard Worker     // the libflashrom implementation, so we shouldnt be using threads anyway.
108*0d6140beSAndroid Build Coastguard Worker     static mut current_level: libflashrom_sys::flashrom_log_level;
109*0d6140beSAndroid Build Coastguard Worker }
110*0d6140beSAndroid Build Coastguard Worker 
111*0d6140beSAndroid Build Coastguard Worker /// Callers can use this function to log to the [`Logger`] they have set via [`set_log_level`]
112*0d6140beSAndroid Build Coastguard Worker ///
113*0d6140beSAndroid Build Coastguard Worker /// However from rust it is likely easier to call the [`Logger`] directly.
114*0d6140beSAndroid Build Coastguard Worker #[no_mangle]
log_rust( level: libflashrom_sys::flashrom_log_level, format: &std::os::raw::c_char, )115*0d6140beSAndroid Build Coastguard Worker pub extern "C" fn log_rust(
116*0d6140beSAndroid Build Coastguard Worker     level: libflashrom_sys::flashrom_log_level,
117*0d6140beSAndroid Build Coastguard Worker     format: &std::os::raw::c_char,
118*0d6140beSAndroid Build Coastguard Worker ) {
119*0d6140beSAndroid Build Coastguard Worker     // Because this function is called from C, it must not panic.
120*0d6140beSAndroid Build Coastguard Worker     // SAFETY: log_c always provides a non null ptr to a null terminated string
121*0d6140beSAndroid Build Coastguard Worker     // msg does not outlive format.
122*0d6140beSAndroid Build Coastguard Worker     let msg = unsafe { CStr::from_ptr(format) }.to_string_lossy();
123*0d6140beSAndroid Build Coastguard Worker     // Locking can fail if a thread panics while holding the lock.
124*0d6140beSAndroid Build Coastguard Worker     match LOG_FN.lock() {
125*0d6140beSAndroid Build Coastguard Worker         Ok(g) => (*g)(level, msg.as_ref()),
126*0d6140beSAndroid Build Coastguard Worker         Err(_) => eprintln!("ERROR: libflashrom log failure to lock function"),
127*0d6140beSAndroid Build Coastguard Worker     };
128*0d6140beSAndroid Build Coastguard Worker }
129*0d6140beSAndroid Build Coastguard Worker 
log_eprint(_level: libflashrom_sys::flashrom_log_level, msg: &str)130*0d6140beSAndroid Build Coastguard Worker fn log_eprint(_level: libflashrom_sys::flashrom_log_level, msg: &str) {
131*0d6140beSAndroid Build Coastguard Worker     // Because this function is called from C, it must not panic.
132*0d6140beSAndroid Build Coastguard Worker     // Ignore the error.
133*0d6140beSAndroid Build Coastguard Worker     let _ = std::io::stderr().write_all(msg.as_bytes());
134*0d6140beSAndroid Build Coastguard Worker }
135*0d6140beSAndroid Build Coastguard Worker 
136*0d6140beSAndroid Build Coastguard Worker // Can't directly atexit(flashrom_shutdown) because it is unsafe
shutdown_wrapper()137*0d6140beSAndroid Build Coastguard Worker extern "C" fn shutdown_wrapper() {
138*0d6140beSAndroid Build Coastguard Worker     unsafe {
139*0d6140beSAndroid Build Coastguard Worker         libflashrom_sys::flashrom_shutdown();
140*0d6140beSAndroid Build Coastguard Worker     }
141*0d6140beSAndroid Build Coastguard Worker }
142*0d6140beSAndroid Build Coastguard Worker 
143*0d6140beSAndroid Build Coastguard Worker /// A callback to log flashrom messages. This must not panic.
144*0d6140beSAndroid Build Coastguard Worker pub type Logger = fn(libflashrom_sys::flashrom_log_level, &str);
145*0d6140beSAndroid Build Coastguard Worker 
146*0d6140beSAndroid Build Coastguard Worker static LOG_FN: Lazy<Mutex<Logger>> = Lazy::new(|| Mutex::new(log_eprint));
147*0d6140beSAndroid Build Coastguard Worker 
148*0d6140beSAndroid Build Coastguard Worker /// Set the maximum log message level that will be passed to [`Logger`]
149*0d6140beSAndroid Build Coastguard Worker ///
150*0d6140beSAndroid Build Coastguard Worker /// log_rust and therefore the provided [`Logger`] will only be called for messages
151*0d6140beSAndroid Build Coastguard Worker /// greater or equal to the provided priority.
152*0d6140beSAndroid Build Coastguard Worker ///
153*0d6140beSAndroid Build Coastguard Worker /// ```
154*0d6140beSAndroid Build Coastguard Worker /// use libflashrom::set_log_level;
155*0d6140beSAndroid Build Coastguard Worker /// use libflashrom::FLASHROM_MSG_SPEW;
156*0d6140beSAndroid Build Coastguard Worker /// // Disable logging.
157*0d6140beSAndroid Build Coastguard Worker /// set_log_level(None);
158*0d6140beSAndroid Build Coastguard Worker /// // Log all messages  at priority FLASHROM_MSG_SPEW and above.
159*0d6140beSAndroid Build Coastguard Worker /// set_log_level(Some(FLASHROM_MSG_SPEW));
160*0d6140beSAndroid Build Coastguard Worker /// ```
set_log_level(level: Option<libflashrom_sys::flashrom_log_level>)161*0d6140beSAndroid Build Coastguard Worker pub fn set_log_level(level: Option<libflashrom_sys::flashrom_log_level>) {
162*0d6140beSAndroid Build Coastguard Worker     // SAFETY: current_level is only read by log_c, in this thread.
163*0d6140beSAndroid Build Coastguard Worker     match level {
164*0d6140beSAndroid Build Coastguard Worker         Some(level) => unsafe { current_level = level + 1 },
165*0d6140beSAndroid Build Coastguard Worker         None => unsafe { current_level = 0 },
166*0d6140beSAndroid Build Coastguard Worker     };
167*0d6140beSAndroid Build Coastguard Worker }
168*0d6140beSAndroid Build Coastguard Worker 
169*0d6140beSAndroid Build Coastguard Worker /// Set a [`Logger`] logging callback function
170*0d6140beSAndroid Build Coastguard Worker ///
171*0d6140beSAndroid Build Coastguard Worker /// Provided function must not panic, as it is called from C.
set_log_function(logger: Logger)172*0d6140beSAndroid Build Coastguard Worker pub fn set_log_function(logger: Logger) {
173*0d6140beSAndroid Build Coastguard Worker     *LOG_FN.lock().unwrap() = logger;
174*0d6140beSAndroid Build Coastguard Worker }
175*0d6140beSAndroid Build Coastguard Worker 
176*0d6140beSAndroid Build Coastguard Worker /// A type holding the error code returned by libflashrom and the function that returned the error.
177*0d6140beSAndroid Build Coastguard Worker ///
178*0d6140beSAndroid Build Coastguard Worker /// The error codes returned from each function differ in meaning, see libflashrom.h
179*0d6140beSAndroid Build Coastguard Worker #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
180*0d6140beSAndroid Build Coastguard Worker pub struct ErrorCode {
181*0d6140beSAndroid Build Coastguard Worker     function: &'static str,
182*0d6140beSAndroid Build Coastguard Worker     code: i32,
183*0d6140beSAndroid Build Coastguard Worker }
184*0d6140beSAndroid Build Coastguard Worker 
185*0d6140beSAndroid Build Coastguard Worker impl fmt::Display for ErrorCode {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result186*0d6140beSAndroid Build Coastguard Worker     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
187*0d6140beSAndroid Build Coastguard Worker         write!(f, "libflashrom: {} returned {}", self.function, self.code)
188*0d6140beSAndroid Build Coastguard Worker     }
189*0d6140beSAndroid Build Coastguard Worker }
190*0d6140beSAndroid Build Coastguard Worker 
191*0d6140beSAndroid Build Coastguard Worker impl error::Error for ErrorCode {}
192*0d6140beSAndroid Build Coastguard Worker 
193*0d6140beSAndroid Build Coastguard Worker impl From<ErrorCode> for String {
from(e: ErrorCode) -> Self194*0d6140beSAndroid Build Coastguard Worker     fn from(e: ErrorCode) -> Self {
195*0d6140beSAndroid Build Coastguard Worker         format!("{}", e)
196*0d6140beSAndroid Build Coastguard Worker     }
197*0d6140beSAndroid Build Coastguard Worker }
198*0d6140beSAndroid Build Coastguard Worker 
199*0d6140beSAndroid Build Coastguard Worker /// Errors from initialising libflashrom or a [`Programmer`]
200*0d6140beSAndroid Build Coastguard Worker #[derive(Clone, Debug, Eq, PartialEq)]
201*0d6140beSAndroid Build Coastguard Worker pub enum InitError {
202*0d6140beSAndroid Build Coastguard Worker     DuplicateInit,
203*0d6140beSAndroid Build Coastguard Worker     FlashromInit(ErrorCode),
204*0d6140beSAndroid Build Coastguard Worker     InvalidName(std::ffi::NulError),
205*0d6140beSAndroid Build Coastguard Worker     ProgrammerInit(ErrorCode),
206*0d6140beSAndroid Build Coastguard Worker }
207*0d6140beSAndroid Build Coastguard Worker 
208*0d6140beSAndroid Build Coastguard Worker impl fmt::Display for InitError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result209*0d6140beSAndroid Build Coastguard Worker     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
210*0d6140beSAndroid Build Coastguard Worker         write!(f, "{:?}", self)
211*0d6140beSAndroid Build Coastguard Worker     }
212*0d6140beSAndroid Build Coastguard Worker }
213*0d6140beSAndroid Build Coastguard Worker 
214*0d6140beSAndroid Build Coastguard Worker impl error::Error for InitError {}
215*0d6140beSAndroid Build Coastguard Worker 
216*0d6140beSAndroid Build Coastguard Worker impl From<InitError> for String {
from(e: InitError) -> Self217*0d6140beSAndroid Build Coastguard Worker     fn from(e: InitError) -> Self {
218*0d6140beSAndroid Build Coastguard Worker         format!("{:?}", e)
219*0d6140beSAndroid Build Coastguard Worker     }
220*0d6140beSAndroid Build Coastguard Worker }
221*0d6140beSAndroid Build Coastguard Worker 
222*0d6140beSAndroid Build Coastguard Worker impl From<std::ffi::NulError> for InitError {
from(err: std::ffi::NulError) -> InitError223*0d6140beSAndroid Build Coastguard Worker     fn from(err: std::ffi::NulError) -> InitError {
224*0d6140beSAndroid Build Coastguard Worker         InitError::InvalidName(err)
225*0d6140beSAndroid Build Coastguard Worker     }
226*0d6140beSAndroid Build Coastguard Worker }
227*0d6140beSAndroid Build Coastguard Worker 
228*0d6140beSAndroid Build Coastguard Worker /// Errors from probing a [`Chip`]
229*0d6140beSAndroid Build Coastguard Worker #[derive(Clone, Debug, Eq, PartialEq)]
230*0d6140beSAndroid Build Coastguard Worker pub enum ChipInitError {
231*0d6140beSAndroid Build Coastguard Worker     InvalidName(std::ffi::NulError),
232*0d6140beSAndroid Build Coastguard Worker     NoChipError,
233*0d6140beSAndroid Build Coastguard Worker     MultipleChipsError,
234*0d6140beSAndroid Build Coastguard Worker     ProbeError,
235*0d6140beSAndroid Build Coastguard Worker }
236*0d6140beSAndroid Build Coastguard Worker 
237*0d6140beSAndroid Build Coastguard Worker impl fmt::Display for ChipInitError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result238*0d6140beSAndroid Build Coastguard Worker     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
239*0d6140beSAndroid Build Coastguard Worker         write!(f, "{:?}", self)
240*0d6140beSAndroid Build Coastguard Worker     }
241*0d6140beSAndroid Build Coastguard Worker }
242*0d6140beSAndroid Build Coastguard Worker 
243*0d6140beSAndroid Build Coastguard Worker impl error::Error for ChipInitError {}
244*0d6140beSAndroid Build Coastguard Worker 
245*0d6140beSAndroid Build Coastguard Worker impl From<ChipInitError> for String {
from(e: ChipInitError) -> Self246*0d6140beSAndroid Build Coastguard Worker     fn from(e: ChipInitError) -> Self {
247*0d6140beSAndroid Build Coastguard Worker         format!("{:?}", e)
248*0d6140beSAndroid Build Coastguard Worker     }
249*0d6140beSAndroid Build Coastguard Worker }
250*0d6140beSAndroid Build Coastguard Worker 
251*0d6140beSAndroid Build Coastguard Worker impl From<std::ffi::NulError> for ChipInitError {
from(err: std::ffi::NulError) -> ChipInitError252*0d6140beSAndroid Build Coastguard Worker     fn from(err: std::ffi::NulError) -> ChipInitError {
253*0d6140beSAndroid Build Coastguard Worker         ChipInitError::InvalidName(err)
254*0d6140beSAndroid Build Coastguard Worker     }
255*0d6140beSAndroid Build Coastguard Worker }
256*0d6140beSAndroid Build Coastguard Worker 
257*0d6140beSAndroid Build Coastguard Worker #[derive(Clone, Debug, Eq, PartialEq)]
258*0d6140beSAndroid Build Coastguard Worker pub enum RegionError {
259*0d6140beSAndroid Build Coastguard Worker     ErrorCode(ErrorCode),
260*0d6140beSAndroid Build Coastguard Worker     InvalidName(std::ffi::NulError),
261*0d6140beSAndroid Build Coastguard Worker }
262*0d6140beSAndroid Build Coastguard Worker 
263*0d6140beSAndroid Build Coastguard Worker impl fmt::Display for RegionError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result264*0d6140beSAndroid Build Coastguard Worker     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
265*0d6140beSAndroid Build Coastguard Worker         write!(f, "{:?}", self)
266*0d6140beSAndroid Build Coastguard Worker     }
267*0d6140beSAndroid Build Coastguard Worker }
268*0d6140beSAndroid Build Coastguard Worker 
269*0d6140beSAndroid Build Coastguard Worker impl error::Error for RegionError {}
270*0d6140beSAndroid Build Coastguard Worker 
271*0d6140beSAndroid Build Coastguard Worker impl From<RegionError> for String {
from(e: RegionError) -> Self272*0d6140beSAndroid Build Coastguard Worker     fn from(e: RegionError) -> Self {
273*0d6140beSAndroid Build Coastguard Worker         format!("{:?}", e)
274*0d6140beSAndroid Build Coastguard Worker     }
275*0d6140beSAndroid Build Coastguard Worker }
276*0d6140beSAndroid Build Coastguard Worker 
277*0d6140beSAndroid Build Coastguard Worker impl From<std::ffi::NulError> for RegionError {
from(err: std::ffi::NulError) -> RegionError278*0d6140beSAndroid Build Coastguard Worker     fn from(err: std::ffi::NulError) -> RegionError {
279*0d6140beSAndroid Build Coastguard Worker         RegionError::InvalidName(err)
280*0d6140beSAndroid Build Coastguard Worker     }
281*0d6140beSAndroid Build Coastguard Worker }
282*0d6140beSAndroid Build Coastguard Worker 
283*0d6140beSAndroid Build Coastguard Worker #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
284*0d6140beSAndroid Build Coastguard Worker pub struct ParseLayoutError(String);
285*0d6140beSAndroid Build Coastguard Worker 
286*0d6140beSAndroid Build Coastguard Worker impl fmt::Display for ParseLayoutError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result287*0d6140beSAndroid Build Coastguard Worker     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
288*0d6140beSAndroid Build Coastguard Worker         write!(f, "{:?}", self)
289*0d6140beSAndroid Build Coastguard Worker     }
290*0d6140beSAndroid Build Coastguard Worker }
291*0d6140beSAndroid Build Coastguard Worker 
292*0d6140beSAndroid Build Coastguard Worker impl error::Error for ParseLayoutError {}
293*0d6140beSAndroid Build Coastguard Worker 
294*0d6140beSAndroid Build Coastguard Worker impl From<ParseLayoutError> for String {
from(e: ParseLayoutError) -> Self295*0d6140beSAndroid Build Coastguard Worker     fn from(e: ParseLayoutError) -> Self {
296*0d6140beSAndroid Build Coastguard Worker         format!("{:?}", e)
297*0d6140beSAndroid Build Coastguard Worker     }
298*0d6140beSAndroid Build Coastguard Worker }
299*0d6140beSAndroid Build Coastguard Worker 
300*0d6140beSAndroid Build Coastguard Worker /// A translation of the flashrom_wp_result type
301*0d6140beSAndroid Build Coastguard Worker ///
302*0d6140beSAndroid Build Coastguard Worker /// WpOK is omitted, as it is not an error.
303*0d6140beSAndroid Build Coastguard Worker /// WpErrUnknown is used for an unknown error type.
304*0d6140beSAndroid Build Coastguard Worker /// Keep this list in sync with libflashrom.h
305*0d6140beSAndroid Build Coastguard Worker #[derive(Clone, Debug, Eq, Hash, PartialEq)]
306*0d6140beSAndroid Build Coastguard Worker pub enum WPError {
307*0d6140beSAndroid Build Coastguard Worker     WpErrChipUnsupported,
308*0d6140beSAndroid Build Coastguard Worker     WpErrOther,
309*0d6140beSAndroid Build Coastguard Worker     WpErrReadFailed,
310*0d6140beSAndroid Build Coastguard Worker     WpErrWriteFailed,
311*0d6140beSAndroid Build Coastguard Worker     WpErrVerifyFailed,
312*0d6140beSAndroid Build Coastguard Worker     WpErrRangeUnsupported,
313*0d6140beSAndroid Build Coastguard Worker     WpErrModeUnsupported,
314*0d6140beSAndroid Build Coastguard Worker     WpErrRangeListUnavailable,
315*0d6140beSAndroid Build Coastguard Worker     WpErrUnsupportedState,
316*0d6140beSAndroid Build Coastguard Worker     WpErrUnknown(libflashrom_sys::flashrom_wp_result),
317*0d6140beSAndroid Build Coastguard Worker }
318*0d6140beSAndroid Build Coastguard Worker 
319*0d6140beSAndroid Build Coastguard Worker impl From<libflashrom_sys::flashrom_wp_result> for WPError {
from(e: libflashrom_sys::flashrom_wp_result) -> Self320*0d6140beSAndroid Build Coastguard Worker     fn from(e: libflashrom_sys::flashrom_wp_result) -> Self {
321*0d6140beSAndroid Build Coastguard Worker         assert!(e != libflashrom_sys::flashrom_wp_result::FLASHROM_WP_OK);
322*0d6140beSAndroid Build Coastguard Worker         match e {
323*0d6140beSAndroid Build Coastguard Worker             libflashrom_sys::flashrom_wp_result::FLASHROM_WP_ERR_CHIP_UNSUPPORTED => {
324*0d6140beSAndroid Build Coastguard Worker                 WPError::WpErrChipUnsupported
325*0d6140beSAndroid Build Coastguard Worker             }
326*0d6140beSAndroid Build Coastguard Worker             libflashrom_sys::flashrom_wp_result::FLASHROM_WP_ERR_OTHER => WPError::WpErrOther,
327*0d6140beSAndroid Build Coastguard Worker             libflashrom_sys::flashrom_wp_result::FLASHROM_WP_ERR_READ_FAILED => {
328*0d6140beSAndroid Build Coastguard Worker                 WPError::WpErrReadFailed
329*0d6140beSAndroid Build Coastguard Worker             }
330*0d6140beSAndroid Build Coastguard Worker             libflashrom_sys::flashrom_wp_result::FLASHROM_WP_ERR_WRITE_FAILED => {
331*0d6140beSAndroid Build Coastguard Worker                 WPError::WpErrWriteFailed
332*0d6140beSAndroid Build Coastguard Worker             }
333*0d6140beSAndroid Build Coastguard Worker             libflashrom_sys::flashrom_wp_result::FLASHROM_WP_ERR_VERIFY_FAILED => {
334*0d6140beSAndroid Build Coastguard Worker                 WPError::WpErrVerifyFailed
335*0d6140beSAndroid Build Coastguard Worker             }
336*0d6140beSAndroid Build Coastguard Worker             libflashrom_sys::flashrom_wp_result::FLASHROM_WP_ERR_RANGE_UNSUPPORTED => {
337*0d6140beSAndroid Build Coastguard Worker                 WPError::WpErrRangeUnsupported
338*0d6140beSAndroid Build Coastguard Worker             }
339*0d6140beSAndroid Build Coastguard Worker             libflashrom_sys::flashrom_wp_result::FLASHROM_WP_ERR_MODE_UNSUPPORTED => {
340*0d6140beSAndroid Build Coastguard Worker                 WPError::WpErrModeUnsupported
341*0d6140beSAndroid Build Coastguard Worker             }
342*0d6140beSAndroid Build Coastguard Worker             libflashrom_sys::flashrom_wp_result::FLASHROM_WP_ERR_RANGE_LIST_UNAVAILABLE => {
343*0d6140beSAndroid Build Coastguard Worker                 WPError::WpErrRangeListUnavailable
344*0d6140beSAndroid Build Coastguard Worker             }
345*0d6140beSAndroid Build Coastguard Worker             libflashrom_sys::flashrom_wp_result::FLASHROM_WP_ERR_UNSUPPORTED_STATE => {
346*0d6140beSAndroid Build Coastguard Worker                 WPError::WpErrUnsupportedState
347*0d6140beSAndroid Build Coastguard Worker             }
348*0d6140beSAndroid Build Coastguard Worker             _ => WPError::WpErrUnknown(e), // this could also be a panic
349*0d6140beSAndroid Build Coastguard Worker         }
350*0d6140beSAndroid Build Coastguard Worker     }
351*0d6140beSAndroid Build Coastguard Worker }
352*0d6140beSAndroid Build Coastguard Worker 
353*0d6140beSAndroid Build Coastguard Worker impl fmt::Display for WPError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result354*0d6140beSAndroid Build Coastguard Worker     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
355*0d6140beSAndroid Build Coastguard Worker         write!(f, "{:?}", self)
356*0d6140beSAndroid Build Coastguard Worker     }
357*0d6140beSAndroid Build Coastguard Worker }
358*0d6140beSAndroid Build Coastguard Worker 
359*0d6140beSAndroid Build Coastguard Worker impl error::Error for WPError {}
360*0d6140beSAndroid Build Coastguard Worker 
361*0d6140beSAndroid Build Coastguard Worker impl From<WPError> for String {
from(e: WPError) -> Self362*0d6140beSAndroid Build Coastguard Worker     fn from(e: WPError) -> Self {
363*0d6140beSAndroid Build Coastguard Worker         format!("{:?}", e)
364*0d6140beSAndroid Build Coastguard Worker     }
365*0d6140beSAndroid Build Coastguard Worker }
366*0d6140beSAndroid Build Coastguard Worker 
367*0d6140beSAndroid Build Coastguard Worker /// Return a rust sanitised string derived from flashrom_version_info.
flashrom_version_info() -> Option<String>368*0d6140beSAndroid Build Coastguard Worker pub fn flashrom_version_info() -> Option<String> {
369*0d6140beSAndroid Build Coastguard Worker     let p = unsafe { libflashrom_sys::flashrom_version_info() };
370*0d6140beSAndroid Build Coastguard Worker     if p.is_null() {
371*0d6140beSAndroid Build Coastguard Worker         None
372*0d6140beSAndroid Build Coastguard Worker     } else {
373*0d6140beSAndroid Build Coastguard Worker         // SAFETY: flashrom_version_info returns a global `const char flashrom_version[]`
374*0d6140beSAndroid Build Coastguard Worker         // derived from `-DFLASHROM_VERSION`, this is not guaranteed to be
375*0d6140beSAndroid Build Coastguard Worker         // null terminated, but is in a normal build.
376*0d6140beSAndroid Build Coastguard Worker         Some(unsafe { CStr::from_ptr(p) }.to_string_lossy().into_owned())
377*0d6140beSAndroid Build Coastguard Worker     }
378*0d6140beSAndroid Build Coastguard Worker }
379*0d6140beSAndroid Build Coastguard Worker 
380*0d6140beSAndroid Build Coastguard Worker /// Structure for an initialised flashrom_programmer
381*0d6140beSAndroid Build Coastguard Worker // flashrom_programmer_init returns a pointer accepted by flashrom_flash_probe
382*0d6140beSAndroid Build Coastguard Worker // but this is not implemented at time of writing. When implemented the pointer
383*0d6140beSAndroid Build Coastguard Worker // can be stored here.
384*0d6140beSAndroid Build Coastguard Worker #[derive(Debug)]
385*0d6140beSAndroid Build Coastguard Worker pub struct Programmer {}
386*0d6140beSAndroid Build Coastguard Worker 
387*0d6140beSAndroid Build Coastguard Worker /// Structure for an initialised flashrom chip, or flashrom_flashctx
388*0d6140beSAndroid Build Coastguard Worker // As returned by flashrom_flash_probe
389*0d6140beSAndroid Build Coastguard Worker // The layout is owned here as the chip only stores a pointer when a layout is set.
390*0d6140beSAndroid Build Coastguard Worker #[derive(Debug)]
391*0d6140beSAndroid Build Coastguard Worker pub struct Chip {
392*0d6140beSAndroid Build Coastguard Worker     ctx: NonNull<libflashrom_sys::flashrom_flashctx>,
393*0d6140beSAndroid Build Coastguard Worker     _programmer: Programmer,
394*0d6140beSAndroid Build Coastguard Worker     layout: Option<Layout>,
395*0d6140beSAndroid Build Coastguard Worker }
396*0d6140beSAndroid Build Coastguard Worker 
397*0d6140beSAndroid Build Coastguard Worker impl Programmer {
398*0d6140beSAndroid Build Coastguard Worker     /// Initialise libflashrom and a programmer
399*0d6140beSAndroid Build Coastguard Worker     ///
400*0d6140beSAndroid Build Coastguard Worker     /// See libflashrom.h flashrom_programmer_init for argument documentation.
401*0d6140beSAndroid Build Coastguard Worker     ///
402*0d6140beSAndroid Build Coastguard Worker     /// Panics:
403*0d6140beSAndroid Build Coastguard Worker     ///
404*0d6140beSAndroid Build Coastguard Worker     /// If this libflashrom implementation returns a programmer pointer.
new( programmer_name: &str, programmer_options: Option<&str>, ) -> Result<Programmer, InitError>405*0d6140beSAndroid Build Coastguard Worker     pub fn new(
406*0d6140beSAndroid Build Coastguard Worker         programmer_name: &str,
407*0d6140beSAndroid Build Coastguard Worker         programmer_options: Option<&str>,
408*0d6140beSAndroid Build Coastguard Worker     ) -> Result<Programmer, InitError> {
409*0d6140beSAndroid Build Coastguard Worker         static ONCE: Once = Once::new();
410*0d6140beSAndroid Build Coastguard Worker         if ONCE.is_completed() {
411*0d6140beSAndroid Build Coastguard Worker             // Flashrom does not currently support concurrent programmers
412*0d6140beSAndroid Build Coastguard Worker             // Flashrom also does not currently support initialising a second programmer after a first has been initialised.
413*0d6140beSAndroid Build Coastguard Worker             // This is used to warn the user if they try to initialise a second programmer.
414*0d6140beSAndroid Build Coastguard Worker             return Err(InitError::DuplicateInit);
415*0d6140beSAndroid Build Coastguard Worker         }
416*0d6140beSAndroid Build Coastguard Worker         ONCE.call_once(|| {});
417*0d6140beSAndroid Build Coastguard Worker 
418*0d6140beSAndroid Build Coastguard Worker         static INIT_RES: Lazy<Result<(), InitError>> = Lazy::new(|| {
419*0d6140beSAndroid Build Coastguard Worker             unsafe { set_log_callback() };
420*0d6140beSAndroid Build Coastguard Worker             // always perform_selfcheck
421*0d6140beSAndroid Build Coastguard Worker             let res = unsafe { libflashrom_sys::flashrom_init(1) };
422*0d6140beSAndroid Build Coastguard Worker             if res == 0 {
423*0d6140beSAndroid Build Coastguard Worker                 let res = unsafe { libc::atexit(shutdown_wrapper) };
424*0d6140beSAndroid Build Coastguard Worker                 if res == 0 {
425*0d6140beSAndroid Build Coastguard Worker                     Ok(())
426*0d6140beSAndroid Build Coastguard Worker                 } else {
427*0d6140beSAndroid Build Coastguard Worker                     unsafe { libflashrom_sys::flashrom_shutdown() };
428*0d6140beSAndroid Build Coastguard Worker                     Err(InitError::FlashromInit(ErrorCode {
429*0d6140beSAndroid Build Coastguard Worker                         function: "atexit",
430*0d6140beSAndroid Build Coastguard Worker                         code: res,
431*0d6140beSAndroid Build Coastguard Worker                     }))
432*0d6140beSAndroid Build Coastguard Worker                 }
433*0d6140beSAndroid Build Coastguard Worker             } else {
434*0d6140beSAndroid Build Coastguard Worker                 Err(InitError::FlashromInit(ErrorCode {
435*0d6140beSAndroid Build Coastguard Worker                     function: "flashrom_init",
436*0d6140beSAndroid Build Coastguard Worker                     code: res,
437*0d6140beSAndroid Build Coastguard Worker                 }))
438*0d6140beSAndroid Build Coastguard Worker             }
439*0d6140beSAndroid Build Coastguard Worker         });
440*0d6140beSAndroid Build Coastguard Worker         (*INIT_RES).clone()?;
441*0d6140beSAndroid Build Coastguard Worker 
442*0d6140beSAndroid Build Coastguard Worker         let mut programmer: *mut libflashrom_sys::flashrom_programmer = null_mut();
443*0d6140beSAndroid Build Coastguard Worker         let programmer_name = CString::new(programmer_name)?;
444*0d6140beSAndroid Build Coastguard Worker         let programmer_options = match programmer_options {
445*0d6140beSAndroid Build Coastguard Worker             Some(programmer_options) => Some(CString::new(programmer_options)?),
446*0d6140beSAndroid Build Coastguard Worker             None => None,
447*0d6140beSAndroid Build Coastguard Worker         };
448*0d6140beSAndroid Build Coastguard Worker         let res = unsafe {
449*0d6140beSAndroid Build Coastguard Worker             libflashrom_sys::flashrom_programmer_init(
450*0d6140beSAndroid Build Coastguard Worker                 &mut programmer,
451*0d6140beSAndroid Build Coastguard Worker                 programmer_name.as_ptr(),
452*0d6140beSAndroid Build Coastguard Worker                 programmer_options.as_ref().map_or(null(), |x| x.as_ptr()),
453*0d6140beSAndroid Build Coastguard Worker             )
454*0d6140beSAndroid Build Coastguard Worker         };
455*0d6140beSAndroid Build Coastguard Worker         if res != 0 {
456*0d6140beSAndroid Build Coastguard Worker             Err(InitError::ProgrammerInit(ErrorCode {
457*0d6140beSAndroid Build Coastguard Worker                 function: "flashrom_programmer_init",
458*0d6140beSAndroid Build Coastguard Worker                 code: res,
459*0d6140beSAndroid Build Coastguard Worker             }))
460*0d6140beSAndroid Build Coastguard Worker         } else if !programmer.is_null() {
461*0d6140beSAndroid Build Coastguard Worker             panic!("flashrom_programmer_init returning a programmer pointer is not supported")
462*0d6140beSAndroid Build Coastguard Worker         } else {
463*0d6140beSAndroid Build Coastguard Worker             Ok(Programmer {})
464*0d6140beSAndroid Build Coastguard Worker         }
465*0d6140beSAndroid Build Coastguard Worker     }
466*0d6140beSAndroid Build Coastguard Worker }
467*0d6140beSAndroid Build Coastguard Worker 
468*0d6140beSAndroid Build Coastguard Worker impl Drop for Programmer {
drop(&mut self)469*0d6140beSAndroid Build Coastguard Worker     fn drop(&mut self) {
470*0d6140beSAndroid Build Coastguard Worker         unsafe {
471*0d6140beSAndroid Build Coastguard Worker             libflashrom_sys::flashrom_programmer_shutdown(null_mut());
472*0d6140beSAndroid Build Coastguard Worker         }
473*0d6140beSAndroid Build Coastguard Worker     }
474*0d6140beSAndroid Build Coastguard Worker }
475*0d6140beSAndroid Build Coastguard Worker 
476*0d6140beSAndroid Build Coastguard Worker /// A translation of the flashrom_flag type
477*0d6140beSAndroid Build Coastguard Worker ///
478*0d6140beSAndroid Build Coastguard Worker /// Keep this list in sync with libflashrom.h
479*0d6140beSAndroid Build Coastguard Worker #[derive(Clone, Debug, Eq, Hash, PartialEq)]
480*0d6140beSAndroid Build Coastguard Worker pub enum FlashromFlag {
481*0d6140beSAndroid Build Coastguard Worker     FlashromFlagForce,
482*0d6140beSAndroid Build Coastguard Worker     FlashromFlagForceBoardmismatch,
483*0d6140beSAndroid Build Coastguard Worker     FlashromFlagVerifyAfterWrite,
484*0d6140beSAndroid Build Coastguard Worker     FlashromFlagVerifyWholeChip,
485*0d6140beSAndroid Build Coastguard Worker     FlashromFlagSkipUnreadableRegions,
486*0d6140beSAndroid Build Coastguard Worker     FlashromFlagSkipUnwritableRegions,
487*0d6140beSAndroid Build Coastguard Worker }
488*0d6140beSAndroid Build Coastguard Worker 
489*0d6140beSAndroid Build Coastguard Worker impl From<FlashromFlag> for libflashrom_sys::flashrom_flag {
from(e: FlashromFlag) -> Self490*0d6140beSAndroid Build Coastguard Worker     fn from(e: FlashromFlag) -> Self {
491*0d6140beSAndroid Build Coastguard Worker         match e {
492*0d6140beSAndroid Build Coastguard Worker             FlashromFlag::FlashromFlagForce => libflashrom_sys::flashrom_flag::FLASHROM_FLAG_FORCE,
493*0d6140beSAndroid Build Coastguard Worker             FlashromFlag::FlashromFlagForceBoardmismatch => {
494*0d6140beSAndroid Build Coastguard Worker                 libflashrom_sys::flashrom_flag::FLASHROM_FLAG_FORCE_BOARDMISMATCH
495*0d6140beSAndroid Build Coastguard Worker             }
496*0d6140beSAndroid Build Coastguard Worker             FlashromFlag::FlashromFlagVerifyAfterWrite => {
497*0d6140beSAndroid Build Coastguard Worker                 libflashrom_sys::flashrom_flag::FLASHROM_FLAG_VERIFY_AFTER_WRITE
498*0d6140beSAndroid Build Coastguard Worker             }
499*0d6140beSAndroid Build Coastguard Worker             FlashromFlag::FlashromFlagVerifyWholeChip => {
500*0d6140beSAndroid Build Coastguard Worker                 libflashrom_sys::flashrom_flag::FLASHROM_FLAG_VERIFY_WHOLE_CHIP
501*0d6140beSAndroid Build Coastguard Worker             }
502*0d6140beSAndroid Build Coastguard Worker             FlashromFlag::FlashromFlagSkipUnreadableRegions => {
503*0d6140beSAndroid Build Coastguard Worker                 libflashrom_sys::flashrom_flag::FLASHROM_FLAG_SKIP_UNREADABLE_REGIONS
504*0d6140beSAndroid Build Coastguard Worker             }
505*0d6140beSAndroid Build Coastguard Worker             FlashromFlag::FlashromFlagSkipUnwritableRegions => {
506*0d6140beSAndroid Build Coastguard Worker                 libflashrom_sys::flashrom_flag::FLASHROM_FLAG_SKIP_UNWRITABLE_REGIONS
507*0d6140beSAndroid Build Coastguard Worker             }
508*0d6140beSAndroid Build Coastguard Worker             e => panic!("Unexpected FlashromFlag: {:?}", e),
509*0d6140beSAndroid Build Coastguard Worker         }
510*0d6140beSAndroid Build Coastguard Worker     }
511*0d6140beSAndroid Build Coastguard Worker }
512*0d6140beSAndroid Build Coastguard Worker 
513*0d6140beSAndroid Build Coastguard Worker /// Various flags of the flashrom context
514*0d6140beSAndroid Build Coastguard Worker ///
515*0d6140beSAndroid Build Coastguard Worker /// Keep the struct in sync with the flags in flash.h
516*0d6140beSAndroid Build Coastguard Worker #[derive(Debug)]
517*0d6140beSAndroid Build Coastguard Worker pub struct FlashromFlags {
518*0d6140beSAndroid Build Coastguard Worker     pub force: bool,
519*0d6140beSAndroid Build Coastguard Worker     pub force_boardmismatch: bool,
520*0d6140beSAndroid Build Coastguard Worker     pub verify_after_write: bool,
521*0d6140beSAndroid Build Coastguard Worker     pub verify_whole_chip: bool,
522*0d6140beSAndroid Build Coastguard Worker     pub skip_unreadable_regions: bool,
523*0d6140beSAndroid Build Coastguard Worker     pub skip_unwritable_regions: bool,
524*0d6140beSAndroid Build Coastguard Worker }
525*0d6140beSAndroid Build Coastguard Worker 
526*0d6140beSAndroid Build Coastguard Worker /// Keep the default values in sync with cli_classic.c
527*0d6140beSAndroid Build Coastguard Worker impl Default for FlashromFlags {
default() -> Self528*0d6140beSAndroid Build Coastguard Worker     fn default() -> Self {
529*0d6140beSAndroid Build Coastguard Worker         Self {
530*0d6140beSAndroid Build Coastguard Worker             force: false,
531*0d6140beSAndroid Build Coastguard Worker             force_boardmismatch: false,
532*0d6140beSAndroid Build Coastguard Worker             verify_after_write: true,
533*0d6140beSAndroid Build Coastguard Worker             verify_whole_chip: true,
534*0d6140beSAndroid Build Coastguard Worker             // These flags are introduced to address issues related to CSME locking parts. Setting
535*0d6140beSAndroid Build Coastguard Worker             // them to true as default values
536*0d6140beSAndroid Build Coastguard Worker             skip_unreadable_regions: true,
537*0d6140beSAndroid Build Coastguard Worker             skip_unwritable_regions: true,
538*0d6140beSAndroid Build Coastguard Worker         }
539*0d6140beSAndroid Build Coastguard Worker     }
540*0d6140beSAndroid Build Coastguard Worker }
541*0d6140beSAndroid Build Coastguard Worker 
542*0d6140beSAndroid Build Coastguard Worker impl fmt::Display for FlashromFlags {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result543*0d6140beSAndroid Build Coastguard Worker     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
544*0d6140beSAndroid Build Coastguard Worker         write!(
545*0d6140beSAndroid Build Coastguard Worker             f,
546*0d6140beSAndroid Build Coastguard Worker             "FlashromFlags {{ force: {}, force_boardmismatch: {}, verify_after_write: {}, verify_whole_chip: {}, skip_unreadable_regions: {}, skip_unwritable_regions: {} }}",
547*0d6140beSAndroid Build Coastguard Worker             self.force,
548*0d6140beSAndroid Build Coastguard Worker             self.force_boardmismatch,
549*0d6140beSAndroid Build Coastguard Worker             self.verify_after_write,
550*0d6140beSAndroid Build Coastguard Worker             self.verify_whole_chip,
551*0d6140beSAndroid Build Coastguard Worker             self.skip_unreadable_regions,
552*0d6140beSAndroid Build Coastguard Worker             self.skip_unwritable_regions,
553*0d6140beSAndroid Build Coastguard Worker         )
554*0d6140beSAndroid Build Coastguard Worker     }
555*0d6140beSAndroid Build Coastguard Worker }
556*0d6140beSAndroid Build Coastguard Worker 
557*0d6140beSAndroid Build Coastguard Worker impl Chip {
558*0d6140beSAndroid Build Coastguard Worker     /// Probe for a chip
559*0d6140beSAndroid Build Coastguard Worker     ///
560*0d6140beSAndroid Build Coastguard Worker     /// See libflashrom.h flashrom_flash_probe for argument documentation.
new(programmer: Programmer, chip_name: Option<&str>) -> Result<Chip, ChipInitError>561*0d6140beSAndroid Build Coastguard Worker     pub fn new(programmer: Programmer, chip_name: Option<&str>) -> Result<Chip, ChipInitError> {
562*0d6140beSAndroid Build Coastguard Worker         let mut flash_ctx: *mut libflashrom_sys::flashrom_flashctx = null_mut();
563*0d6140beSAndroid Build Coastguard Worker         let chip_name = match chip_name {
564*0d6140beSAndroid Build Coastguard Worker             Some(chip_name) => Some(CString::new(chip_name)?),
565*0d6140beSAndroid Build Coastguard Worker             None => None,
566*0d6140beSAndroid Build Coastguard Worker         };
567*0d6140beSAndroid Build Coastguard Worker         match unsafe {
568*0d6140beSAndroid Build Coastguard Worker             libflashrom_sys::flashrom_flash_probe(
569*0d6140beSAndroid Build Coastguard Worker                 &mut flash_ctx,
570*0d6140beSAndroid Build Coastguard Worker                 null(),
571*0d6140beSAndroid Build Coastguard Worker                 chip_name.as_ref().map_or(null(), |x| x.as_ptr()),
572*0d6140beSAndroid Build Coastguard Worker             )
573*0d6140beSAndroid Build Coastguard Worker         } {
574*0d6140beSAndroid Build Coastguard Worker             0 => Ok(Chip {
575*0d6140beSAndroid Build Coastguard Worker                 ctx: NonNull::new(flash_ctx).expect("flashrom_flash_probe returned null"),
576*0d6140beSAndroid Build Coastguard Worker                 _programmer: programmer,
577*0d6140beSAndroid Build Coastguard Worker                 layout: None,
578*0d6140beSAndroid Build Coastguard Worker             }),
579*0d6140beSAndroid Build Coastguard Worker             3 => Err(ChipInitError::MultipleChipsError),
580*0d6140beSAndroid Build Coastguard Worker             2 => Err(ChipInitError::NoChipError),
581*0d6140beSAndroid Build Coastguard Worker             _ => Err(ChipInitError::ProbeError),
582*0d6140beSAndroid Build Coastguard Worker         }
583*0d6140beSAndroid Build Coastguard Worker     }
584*0d6140beSAndroid Build Coastguard Worker 
get_size(&self) -> usize585*0d6140beSAndroid Build Coastguard Worker     pub fn get_size(&self) -> usize {
586*0d6140beSAndroid Build Coastguard Worker         unsafe { libflashrom_sys::flashrom_flash_getsize(self.ctx.as_ref()) }
587*0d6140beSAndroid Build Coastguard Worker     }
588*0d6140beSAndroid Build Coastguard Worker 
589*0d6140beSAndroid Build Coastguard Worker     /// Read the write protect config of this [`Chip`]
get_wp(&mut self) -> std::result::Result<WriteProtectCfg, WPError>590*0d6140beSAndroid Build Coastguard Worker     pub fn get_wp(&mut self) -> std::result::Result<WriteProtectCfg, WPError> {
591*0d6140beSAndroid Build Coastguard Worker         let mut cfg = WriteProtectCfg::new()?;
592*0d6140beSAndroid Build Coastguard Worker         let res =
593*0d6140beSAndroid Build Coastguard Worker             unsafe { libflashrom_sys::flashrom_wp_read_cfg(cfg.wp.as_mut(), self.ctx.as_mut()) };
594*0d6140beSAndroid Build Coastguard Worker         if res != libflashrom_sys::flashrom_wp_result::FLASHROM_WP_OK {
595*0d6140beSAndroid Build Coastguard Worker             return Err(res.into());
596*0d6140beSAndroid Build Coastguard Worker         }
597*0d6140beSAndroid Build Coastguard Worker         Ok(cfg)
598*0d6140beSAndroid Build Coastguard Worker     }
599*0d6140beSAndroid Build Coastguard Worker 
600*0d6140beSAndroid Build Coastguard Worker     /// Set the write protect config of this [`Chip`]
set_wp(&mut self, wp: &WriteProtectCfg) -> std::result::Result<(), WPError>601*0d6140beSAndroid Build Coastguard Worker     pub fn set_wp(&mut self, wp: &WriteProtectCfg) -> std::result::Result<(), WPError> {
602*0d6140beSAndroid Build Coastguard Worker         let res =
603*0d6140beSAndroid Build Coastguard Worker             unsafe { libflashrom_sys::flashrom_wp_write_cfg(self.ctx.as_mut(), wp.wp.as_ref()) };
604*0d6140beSAndroid Build Coastguard Worker         if res != libflashrom_sys::flashrom_wp_result::FLASHROM_WP_OK {
605*0d6140beSAndroid Build Coastguard Worker             return Err(res.into());
606*0d6140beSAndroid Build Coastguard Worker         }
607*0d6140beSAndroid Build Coastguard Worker         Ok(())
608*0d6140beSAndroid Build Coastguard Worker     }
609*0d6140beSAndroid Build Coastguard Worker 
610*0d6140beSAndroid Build Coastguard Worker     /// Read the write protect ranges of this [`Chip`]
611*0d6140beSAndroid Build Coastguard Worker     ///
612*0d6140beSAndroid Build Coastguard Worker     /// # Panics
613*0d6140beSAndroid Build Coastguard Worker     ///
614*0d6140beSAndroid Build Coastguard Worker     /// Panics if flashrom_wp_get_available_ranges returns FLASHROM_WP_OK and a NULL pointer.
get_wp_ranges(&mut self) -> std::result::Result<Vec<Range>, WPError>615*0d6140beSAndroid Build Coastguard Worker     pub fn get_wp_ranges(&mut self) -> std::result::Result<Vec<Range>, WPError> {
616*0d6140beSAndroid Build Coastguard Worker         let mut ranges: *mut libflashrom_sys::flashrom_wp_ranges = null_mut();
617*0d6140beSAndroid Build Coastguard Worker         let res = unsafe {
618*0d6140beSAndroid Build Coastguard Worker             libflashrom_sys::flashrom_wp_get_available_ranges(&mut ranges, self.ctx.as_mut())
619*0d6140beSAndroid Build Coastguard Worker         };
620*0d6140beSAndroid Build Coastguard Worker         if res != libflashrom_sys::flashrom_wp_result::FLASHROM_WP_OK {
621*0d6140beSAndroid Build Coastguard Worker             return Err(res.into());
622*0d6140beSAndroid Build Coastguard Worker         }
623*0d6140beSAndroid Build Coastguard Worker         let ranges = WriteProtectRanges {
624*0d6140beSAndroid Build Coastguard Worker             ranges: NonNull::new(ranges).expect("flashrom_wp_get_available_ranges returned null"),
625*0d6140beSAndroid Build Coastguard Worker         };
626*0d6140beSAndroid Build Coastguard Worker 
627*0d6140beSAndroid Build Coastguard Worker         let count =
628*0d6140beSAndroid Build Coastguard Worker             unsafe { libflashrom_sys::flashrom_wp_ranges_get_count(ranges.ranges.as_ref()) };
629*0d6140beSAndroid Build Coastguard Worker         let mut ret = Vec::with_capacity(count);
630*0d6140beSAndroid Build Coastguard Worker         for index in 0..count {
631*0d6140beSAndroid Build Coastguard Worker             let mut start = 0;
632*0d6140beSAndroid Build Coastguard Worker             let mut len = 0;
633*0d6140beSAndroid Build Coastguard Worker             let res = unsafe {
634*0d6140beSAndroid Build Coastguard Worker                 libflashrom_sys::flashrom_wp_ranges_get_range(
635*0d6140beSAndroid Build Coastguard Worker                     &mut start,
636*0d6140beSAndroid Build Coastguard Worker                     &mut len,
637*0d6140beSAndroid Build Coastguard Worker                     ranges.ranges.as_ref(),
638*0d6140beSAndroid Build Coastguard Worker                     // TODO: fix after https://review.coreboot.org/c/flashrom/+/64996
639*0d6140beSAndroid Build Coastguard Worker                     index
640*0d6140beSAndroid Build Coastguard Worker                         .try_into()
641*0d6140beSAndroid Build Coastguard Worker                         .expect("flashrom_wp_ranges_get_count does not fit in a u32"),
642*0d6140beSAndroid Build Coastguard Worker                 )
643*0d6140beSAndroid Build Coastguard Worker             };
644*0d6140beSAndroid Build Coastguard Worker             if res != libflashrom_sys::flashrom_wp_result::FLASHROM_WP_OK {
645*0d6140beSAndroid Build Coastguard Worker                 return Err(res.into());
646*0d6140beSAndroid Build Coastguard Worker             }
647*0d6140beSAndroid Build Coastguard Worker             ret.push(start..(start + len))
648*0d6140beSAndroid Build Coastguard Worker         }
649*0d6140beSAndroid Build Coastguard Worker         Ok(ret)
650*0d6140beSAndroid Build Coastguard Worker     }
651*0d6140beSAndroid Build Coastguard Worker 
652*0d6140beSAndroid Build Coastguard Worker     /// Returns the layout read from the fmap of this [`Chip`]
653*0d6140beSAndroid Build Coastguard Worker     ///
654*0d6140beSAndroid Build Coastguard Worker     /// # Panics
655*0d6140beSAndroid Build Coastguard Worker     ///
656*0d6140beSAndroid Build Coastguard Worker     /// Panics if flashrom_layout_read_fmap_from_rom returns FLASHROM_WP_OK and a NULL pointer.
layout_read_fmap_from_rom(&mut self) -> std::result::Result<Layout, ErrorCode>657*0d6140beSAndroid Build Coastguard Worker     pub fn layout_read_fmap_from_rom(&mut self) -> std::result::Result<Layout, ErrorCode> {
658*0d6140beSAndroid Build Coastguard Worker         let mut layout: *mut libflashrom_sys::flashrom_layout = null_mut();
659*0d6140beSAndroid Build Coastguard Worker         let err = unsafe {
660*0d6140beSAndroid Build Coastguard Worker             libflashrom_sys::flashrom_layout_read_fmap_from_rom(
661*0d6140beSAndroid Build Coastguard Worker                 &mut layout,
662*0d6140beSAndroid Build Coastguard Worker                 self.ctx.as_mut(),
663*0d6140beSAndroid Build Coastguard Worker                 0,
664*0d6140beSAndroid Build Coastguard Worker                 self.get_size(),
665*0d6140beSAndroid Build Coastguard Worker             )
666*0d6140beSAndroid Build Coastguard Worker         };
667*0d6140beSAndroid Build Coastguard Worker         if err != 0 {
668*0d6140beSAndroid Build Coastguard Worker             return Err(ErrorCode {
669*0d6140beSAndroid Build Coastguard Worker                 function: "flashrom_layout_read_fmap_from_rom",
670*0d6140beSAndroid Build Coastguard Worker                 code: err,
671*0d6140beSAndroid Build Coastguard Worker             });
672*0d6140beSAndroid Build Coastguard Worker         }
673*0d6140beSAndroid Build Coastguard Worker         Ok(Layout {
674*0d6140beSAndroid Build Coastguard Worker             layout: NonNull::new(layout).expect("flashrom_layout_read_fmap_from_rom returned null"),
675*0d6140beSAndroid Build Coastguard Worker         })
676*0d6140beSAndroid Build Coastguard Worker     }
677*0d6140beSAndroid Build Coastguard Worker 
678*0d6140beSAndroid Build Coastguard Worker     /// Sets the layout of this [`Chip`]
679*0d6140beSAndroid Build Coastguard Worker     ///
680*0d6140beSAndroid Build Coastguard Worker     /// [`Chip`] takes ownership of Layout to ensure it is not released before the [`Chip`].
set_layout(&mut self, layout: Layout)681*0d6140beSAndroid Build Coastguard Worker     fn set_layout(&mut self, layout: Layout) {
682*0d6140beSAndroid Build Coastguard Worker         unsafe { libflashrom_sys::flashrom_layout_set(self.ctx.as_mut(), layout.layout.as_ref()) };
683*0d6140beSAndroid Build Coastguard Worker         self.layout = Some(layout)
684*0d6140beSAndroid Build Coastguard Worker     }
685*0d6140beSAndroid Build Coastguard Worker 
unset_layout(&mut self) -> Option<Layout>686*0d6140beSAndroid Build Coastguard Worker     fn unset_layout(&mut self) -> Option<Layout> {
687*0d6140beSAndroid Build Coastguard Worker         unsafe { libflashrom_sys::flashrom_layout_set(self.ctx.as_mut(), null()) };
688*0d6140beSAndroid Build Coastguard Worker         self.layout.take()
689*0d6140beSAndroid Build Coastguard Worker     }
690*0d6140beSAndroid Build Coastguard Worker 
691*0d6140beSAndroid Build Coastguard Worker     /// Read the whole [`Chip`], or a portion specified in a Layout
image_read( &mut self, layout: Option<Layout>, ) -> std::result::Result<Vec<u8>, ErrorCode>692*0d6140beSAndroid Build Coastguard Worker     pub fn image_read(
693*0d6140beSAndroid Build Coastguard Worker         &mut self,
694*0d6140beSAndroid Build Coastguard Worker         layout: Option<Layout>,
695*0d6140beSAndroid Build Coastguard Worker     ) -> std::result::Result<Vec<u8>, ErrorCode> {
696*0d6140beSAndroid Build Coastguard Worker         if let Some(layout) = layout {
697*0d6140beSAndroid Build Coastguard Worker             self.set_layout(layout);
698*0d6140beSAndroid Build Coastguard Worker         }
699*0d6140beSAndroid Build Coastguard Worker         let len = self.get_size();
700*0d6140beSAndroid Build Coastguard Worker         let mut buf = vec![0; len];
701*0d6140beSAndroid Build Coastguard Worker         let res = unsafe {
702*0d6140beSAndroid Build Coastguard Worker             libflashrom_sys::flashrom_image_read(
703*0d6140beSAndroid Build Coastguard Worker                 self.ctx.as_mut(),
704*0d6140beSAndroid Build Coastguard Worker                 buf.as_mut_ptr() as *mut c_void,
705*0d6140beSAndroid Build Coastguard Worker                 len,
706*0d6140beSAndroid Build Coastguard Worker             )
707*0d6140beSAndroid Build Coastguard Worker         };
708*0d6140beSAndroid Build Coastguard Worker         self.unset_layout();
709*0d6140beSAndroid Build Coastguard Worker 
710*0d6140beSAndroid Build Coastguard Worker         if res == 0 {
711*0d6140beSAndroid Build Coastguard Worker             Ok(buf)
712*0d6140beSAndroid Build Coastguard Worker         } else {
713*0d6140beSAndroid Build Coastguard Worker             Err(ErrorCode {
714*0d6140beSAndroid Build Coastguard Worker                 function: "flashrom_image_read",
715*0d6140beSAndroid Build Coastguard Worker                 code: res,
716*0d6140beSAndroid Build Coastguard Worker             })
717*0d6140beSAndroid Build Coastguard Worker         }
718*0d6140beSAndroid Build Coastguard Worker     }
719*0d6140beSAndroid Build Coastguard Worker 
720*0d6140beSAndroid Build Coastguard Worker     /// Write the whole [`Chip`], or a portion specified in a Layout
image_write( &mut self, buf: &mut [u8], layout: Option<Layout>, ) -> std::result::Result<(), ErrorCode>721*0d6140beSAndroid Build Coastguard Worker     pub fn image_write(
722*0d6140beSAndroid Build Coastguard Worker         &mut self,
723*0d6140beSAndroid Build Coastguard Worker         buf: &mut [u8],
724*0d6140beSAndroid Build Coastguard Worker         layout: Option<Layout>,
725*0d6140beSAndroid Build Coastguard Worker     ) -> std::result::Result<(), ErrorCode> {
726*0d6140beSAndroid Build Coastguard Worker         if let Some(layout) = layout {
727*0d6140beSAndroid Build Coastguard Worker             self.set_layout(layout);
728*0d6140beSAndroid Build Coastguard Worker         }
729*0d6140beSAndroid Build Coastguard Worker         let res = unsafe {
730*0d6140beSAndroid Build Coastguard Worker             libflashrom_sys::flashrom_image_write(
731*0d6140beSAndroid Build Coastguard Worker                 self.ctx.as_mut(),
732*0d6140beSAndroid Build Coastguard Worker                 buf.as_mut_ptr() as *mut c_void,
733*0d6140beSAndroid Build Coastguard Worker                 buf.len(),
734*0d6140beSAndroid Build Coastguard Worker                 null(),
735*0d6140beSAndroid Build Coastguard Worker             )
736*0d6140beSAndroid Build Coastguard Worker         };
737*0d6140beSAndroid Build Coastguard Worker         self.unset_layout();
738*0d6140beSAndroid Build Coastguard Worker 
739*0d6140beSAndroid Build Coastguard Worker         if res == 0 {
740*0d6140beSAndroid Build Coastguard Worker             Ok(())
741*0d6140beSAndroid Build Coastguard Worker         } else {
742*0d6140beSAndroid Build Coastguard Worker             Err(ErrorCode {
743*0d6140beSAndroid Build Coastguard Worker                 function: "flashrom_image_write",
744*0d6140beSAndroid Build Coastguard Worker                 code: res,
745*0d6140beSAndroid Build Coastguard Worker             })
746*0d6140beSAndroid Build Coastguard Worker         }
747*0d6140beSAndroid Build Coastguard Worker     }
748*0d6140beSAndroid Build Coastguard Worker 
749*0d6140beSAndroid Build Coastguard Worker     /// Verify the whole [`Chip`], or a portion specified in a Layout
image_verify( &mut self, buf: &[u8], layout: Option<Layout>, ) -> std::result::Result<(), ErrorCode>750*0d6140beSAndroid Build Coastguard Worker     pub fn image_verify(
751*0d6140beSAndroid Build Coastguard Worker         &mut self,
752*0d6140beSAndroid Build Coastguard Worker         buf: &[u8],
753*0d6140beSAndroid Build Coastguard Worker         layout: Option<Layout>,
754*0d6140beSAndroid Build Coastguard Worker     ) -> std::result::Result<(), ErrorCode> {
755*0d6140beSAndroid Build Coastguard Worker         if let Some(layout) = layout {
756*0d6140beSAndroid Build Coastguard Worker             self.set_layout(layout);
757*0d6140beSAndroid Build Coastguard Worker         }
758*0d6140beSAndroid Build Coastguard Worker         let res = unsafe {
759*0d6140beSAndroid Build Coastguard Worker             libflashrom_sys::flashrom_image_verify(
760*0d6140beSAndroid Build Coastguard Worker                 self.ctx.as_mut(),
761*0d6140beSAndroid Build Coastguard Worker                 buf.as_ptr() as *const c_void,
762*0d6140beSAndroid Build Coastguard Worker                 buf.len(),
763*0d6140beSAndroid Build Coastguard Worker             )
764*0d6140beSAndroid Build Coastguard Worker         };
765*0d6140beSAndroid Build Coastguard Worker         self.unset_layout();
766*0d6140beSAndroid Build Coastguard Worker 
767*0d6140beSAndroid Build Coastguard Worker         if res == 0 {
768*0d6140beSAndroid Build Coastguard Worker             Ok(())
769*0d6140beSAndroid Build Coastguard Worker         } else {
770*0d6140beSAndroid Build Coastguard Worker             Err(ErrorCode {
771*0d6140beSAndroid Build Coastguard Worker                 function: "flashrom_image_verify",
772*0d6140beSAndroid Build Coastguard Worker                 code: res,
773*0d6140beSAndroid Build Coastguard Worker             })
774*0d6140beSAndroid Build Coastguard Worker         }
775*0d6140beSAndroid Build Coastguard Worker     }
776*0d6140beSAndroid Build Coastguard Worker 
777*0d6140beSAndroid Build Coastguard Worker     /// Erase the whole [`Chip`]
erase(&mut self) -> std::result::Result<(), ErrorCode>778*0d6140beSAndroid Build Coastguard Worker     pub fn erase(&mut self) -> std::result::Result<(), ErrorCode> {
779*0d6140beSAndroid Build Coastguard Worker         let res = unsafe { libflashrom_sys::flashrom_flash_erase(self.ctx.as_mut()) };
780*0d6140beSAndroid Build Coastguard Worker         if res == 0 {
781*0d6140beSAndroid Build Coastguard Worker             Ok(())
782*0d6140beSAndroid Build Coastguard Worker         } else {
783*0d6140beSAndroid Build Coastguard Worker             Err(ErrorCode {
784*0d6140beSAndroid Build Coastguard Worker                 function: "flashrom_flash_erase",
785*0d6140beSAndroid Build Coastguard Worker                 code: res,
786*0d6140beSAndroid Build Coastguard Worker             })
787*0d6140beSAndroid Build Coastguard Worker         }
788*0d6140beSAndroid Build Coastguard Worker     }
789*0d6140beSAndroid Build Coastguard Worker 
790*0d6140beSAndroid Build Coastguard Worker     /// Set a flag in the given flash context
flag_set(&mut self, flag: FlashromFlag, value: bool) -> ()791*0d6140beSAndroid Build Coastguard Worker     pub fn flag_set(&mut self, flag: FlashromFlag, value: bool) -> () {
792*0d6140beSAndroid Build Coastguard Worker         unsafe { libflashrom_sys::flashrom_flag_set(self.ctx.as_mut(), flag.into(), value) }
793*0d6140beSAndroid Build Coastguard Worker     }
794*0d6140beSAndroid Build Coastguard Worker }
795*0d6140beSAndroid Build Coastguard Worker 
796*0d6140beSAndroid Build Coastguard Worker impl Drop for Chip {
drop(&mut self)797*0d6140beSAndroid Build Coastguard Worker     fn drop(&mut self) {
798*0d6140beSAndroid Build Coastguard Worker         unsafe {
799*0d6140beSAndroid Build Coastguard Worker             libflashrom_sys::flashrom_flash_release(self.ctx.as_mut());
800*0d6140beSAndroid Build Coastguard Worker         }
801*0d6140beSAndroid Build Coastguard Worker     }
802*0d6140beSAndroid Build Coastguard Worker }
803*0d6140beSAndroid Build Coastguard Worker 
804*0d6140beSAndroid Build Coastguard Worker /// Structure for an initialised flashrom_wp_cfg
805*0d6140beSAndroid Build Coastguard Worker #[derive(Debug)]
806*0d6140beSAndroid Build Coastguard Worker pub struct WriteProtectCfg {
807*0d6140beSAndroid Build Coastguard Worker     wp: NonNull<libflashrom_sys::flashrom_wp_cfg>,
808*0d6140beSAndroid Build Coastguard Worker }
809*0d6140beSAndroid Build Coastguard Worker 
810*0d6140beSAndroid Build Coastguard Worker impl WriteProtectCfg {
811*0d6140beSAndroid Build Coastguard Worker     /// Create an empty [`WriteProtectCfg`]
812*0d6140beSAndroid Build Coastguard Worker     ///
813*0d6140beSAndroid Build Coastguard Worker     /// # Panics
814*0d6140beSAndroid Build Coastguard Worker     ///
815*0d6140beSAndroid Build Coastguard Worker     /// Panics if flashrom_wp_cfg_new returns FLASHROM_WP_OK and a NULL pointer.
new() -> std::result::Result<WriteProtectCfg, WPError>816*0d6140beSAndroid Build Coastguard Worker     pub fn new() -> std::result::Result<WriteProtectCfg, WPError> {
817*0d6140beSAndroid Build Coastguard Worker         let mut cfg: *mut libflashrom_sys::flashrom_wp_cfg = null_mut();
818*0d6140beSAndroid Build Coastguard Worker         let res = unsafe { libflashrom_sys::flashrom_wp_cfg_new(&mut cfg) };
819*0d6140beSAndroid Build Coastguard Worker         if res != libflashrom_sys::flashrom_wp_result::FLASHROM_WP_OK {
820*0d6140beSAndroid Build Coastguard Worker             return Err(res.into());
821*0d6140beSAndroid Build Coastguard Worker         }
822*0d6140beSAndroid Build Coastguard Worker         Ok(WriteProtectCfg {
823*0d6140beSAndroid Build Coastguard Worker             wp: NonNull::new(cfg).expect("flashrom_wp_cfg_new returned null"),
824*0d6140beSAndroid Build Coastguard Worker         })
825*0d6140beSAndroid Build Coastguard Worker     }
826*0d6140beSAndroid Build Coastguard Worker 
get_mode(&self) -> libflashrom_sys::flashrom_wp_mode827*0d6140beSAndroid Build Coastguard Worker     pub fn get_mode(&self) -> libflashrom_sys::flashrom_wp_mode {
828*0d6140beSAndroid Build Coastguard Worker         unsafe { libflashrom_sys::flashrom_wp_get_mode(self.wp.as_ref()) }
829*0d6140beSAndroid Build Coastguard Worker     }
830*0d6140beSAndroid Build Coastguard Worker 
set_mode(&mut self, mode: libflashrom_sys::flashrom_wp_mode)831*0d6140beSAndroid Build Coastguard Worker     pub fn set_mode(&mut self, mode: libflashrom_sys::flashrom_wp_mode) {
832*0d6140beSAndroid Build Coastguard Worker         unsafe { libflashrom_sys::flashrom_wp_set_mode(self.wp.as_mut(), mode) }
833*0d6140beSAndroid Build Coastguard Worker     }
834*0d6140beSAndroid Build Coastguard Worker 
get_range(&self) -> Range835*0d6140beSAndroid Build Coastguard Worker     pub fn get_range(&self) -> Range {
836*0d6140beSAndroid Build Coastguard Worker         let mut start = 0;
837*0d6140beSAndroid Build Coastguard Worker         let mut len = 0;
838*0d6140beSAndroid Build Coastguard Worker         unsafe { libflashrom_sys::flashrom_wp_get_range(&mut start, &mut len, self.wp.as_ref()) };
839*0d6140beSAndroid Build Coastguard Worker         start..(start + len)
840*0d6140beSAndroid Build Coastguard Worker     }
841*0d6140beSAndroid Build Coastguard Worker 
set_range<T>(&mut self, range: T) where T: std::ops::RangeBounds<usize>,842*0d6140beSAndroid Build Coastguard Worker     pub fn set_range<T>(&mut self, range: T)
843*0d6140beSAndroid Build Coastguard Worker     where
844*0d6140beSAndroid Build Coastguard Worker         T: std::ops::RangeBounds<usize>,
845*0d6140beSAndroid Build Coastguard Worker     {
846*0d6140beSAndroid Build Coastguard Worker         let range: RangeInternal = range.into();
847*0d6140beSAndroid Build Coastguard Worker         unsafe { libflashrom_sys::flashrom_wp_set_range(self.wp.as_mut(), range.start, range.len) }
848*0d6140beSAndroid Build Coastguard Worker     }
849*0d6140beSAndroid Build Coastguard Worker }
850*0d6140beSAndroid Build Coastguard Worker 
851*0d6140beSAndroid Build Coastguard Worker impl Drop for WriteProtectCfg {
drop(&mut self)852*0d6140beSAndroid Build Coastguard Worker     fn drop(&mut self) {
853*0d6140beSAndroid Build Coastguard Worker         unsafe {
854*0d6140beSAndroid Build Coastguard Worker             libflashrom_sys::flashrom_wp_cfg_release(self.wp.as_mut());
855*0d6140beSAndroid Build Coastguard Worker         }
856*0d6140beSAndroid Build Coastguard Worker     }
857*0d6140beSAndroid Build Coastguard Worker }
858*0d6140beSAndroid Build Coastguard Worker 
859*0d6140beSAndroid Build Coastguard Worker impl fmt::Display for WriteProtectCfg {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result860*0d6140beSAndroid Build Coastguard Worker     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
861*0d6140beSAndroid Build Coastguard Worker         write!(f, "range:{:?} mode:{:?}", self.get_range(), self.get_mode())
862*0d6140beSAndroid Build Coastguard Worker     }
863*0d6140beSAndroid Build Coastguard Worker }
864*0d6140beSAndroid Build Coastguard Worker 
865*0d6140beSAndroid Build Coastguard Worker #[derive(Debug)]
866*0d6140beSAndroid Build Coastguard Worker struct WriteProtectRanges {
867*0d6140beSAndroid Build Coastguard Worker     ranges: NonNull<libflashrom_sys::flashrom_wp_ranges>,
868*0d6140beSAndroid Build Coastguard Worker }
869*0d6140beSAndroid Build Coastguard Worker 
870*0d6140beSAndroid Build Coastguard Worker impl WriteProtectRanges {}
871*0d6140beSAndroid Build Coastguard Worker 
872*0d6140beSAndroid Build Coastguard Worker impl Drop for WriteProtectRanges {
drop(&mut self)873*0d6140beSAndroid Build Coastguard Worker     fn drop(&mut self) {
874*0d6140beSAndroid Build Coastguard Worker         unsafe {
875*0d6140beSAndroid Build Coastguard Worker             libflashrom_sys::flashrom_wp_ranges_release(self.ranges.as_mut());
876*0d6140beSAndroid Build Coastguard Worker         }
877*0d6140beSAndroid Build Coastguard Worker     }
878*0d6140beSAndroid Build Coastguard Worker }
879*0d6140beSAndroid Build Coastguard Worker 
880*0d6140beSAndroid Build Coastguard Worker /// Structure for an initialised flashrom_layout
881*0d6140beSAndroid Build Coastguard Worker #[derive(Debug)]
882*0d6140beSAndroid Build Coastguard Worker pub struct Layout {
883*0d6140beSAndroid Build Coastguard Worker     layout: NonNull<libflashrom_sys::flashrom_layout>,
884*0d6140beSAndroid Build Coastguard Worker }
885*0d6140beSAndroid Build Coastguard Worker 
886*0d6140beSAndroid Build Coastguard Worker impl Layout {
887*0d6140beSAndroid Build Coastguard Worker     /// Create an empty [`Layout`]
888*0d6140beSAndroid Build Coastguard Worker     ///
889*0d6140beSAndroid Build Coastguard Worker     /// # Panics
890*0d6140beSAndroid Build Coastguard Worker     ///
891*0d6140beSAndroid Build Coastguard Worker     /// Panics if flashrom_layout_new returns 0 and a NULL pointer.
new() -> std::result::Result<Layout, ErrorCode>892*0d6140beSAndroid Build Coastguard Worker     pub fn new() -> std::result::Result<Layout, ErrorCode> {
893*0d6140beSAndroid Build Coastguard Worker         let mut layout: *mut libflashrom_sys::flashrom_layout = null_mut();
894*0d6140beSAndroid Build Coastguard Worker         let err = unsafe { libflashrom_sys::flashrom_layout_new(&mut layout) };
895*0d6140beSAndroid Build Coastguard Worker         if err != 0 {
896*0d6140beSAndroid Build Coastguard Worker             Err(ErrorCode {
897*0d6140beSAndroid Build Coastguard Worker                 function: "flashrom_layout_new",
898*0d6140beSAndroid Build Coastguard Worker                 code: err,
899*0d6140beSAndroid Build Coastguard Worker             })
900*0d6140beSAndroid Build Coastguard Worker         } else {
901*0d6140beSAndroid Build Coastguard Worker             Ok(Layout {
902*0d6140beSAndroid Build Coastguard Worker                 layout: NonNull::new(layout).expect("flashrom_layout_new returned null"),
903*0d6140beSAndroid Build Coastguard Worker             })
904*0d6140beSAndroid Build Coastguard Worker         }
905*0d6140beSAndroid Build Coastguard Worker     }
906*0d6140beSAndroid Build Coastguard Worker 
907*0d6140beSAndroid Build Coastguard Worker     /// Add a region to the [`Layout`]
908*0d6140beSAndroid Build Coastguard Worker     ///
909*0d6140beSAndroid Build Coastguard Worker     /// Not the region will not be 'included', include_region must be called to include the region.
910*0d6140beSAndroid Build Coastguard Worker     ///
911*0d6140beSAndroid Build Coastguard Worker     /// # Errors
912*0d6140beSAndroid Build Coastguard Worker     ///
913*0d6140beSAndroid Build Coastguard Worker     /// This function will return an error if the region is not a valid CString,
914*0d6140beSAndroid Build Coastguard Worker     /// or if libflashrom returns an error.
add_region<T>(&mut self, region: &str, range: T) -> std::result::Result<(), RegionError> where T: std::ops::RangeBounds<usize>,915*0d6140beSAndroid Build Coastguard Worker     pub fn add_region<T>(&mut self, region: &str, range: T) -> std::result::Result<(), RegionError>
916*0d6140beSAndroid Build Coastguard Worker     where
917*0d6140beSAndroid Build Coastguard Worker         T: std::ops::RangeBounds<usize>,
918*0d6140beSAndroid Build Coastguard Worker     {
919*0d6140beSAndroid Build Coastguard Worker         let range: RangeInternal = range.into();
920*0d6140beSAndroid Build Coastguard Worker         let err = {
921*0d6140beSAndroid Build Coastguard Worker             let region = CString::new(region)?;
922*0d6140beSAndroid Build Coastguard Worker             unsafe {
923*0d6140beSAndroid Build Coastguard Worker                 libflashrom_sys::flashrom_layout_add_region(
924*0d6140beSAndroid Build Coastguard Worker                     self.layout.as_mut(),
925*0d6140beSAndroid Build Coastguard Worker                     range.start,
926*0d6140beSAndroid Build Coastguard Worker                     range.end(),
927*0d6140beSAndroid Build Coastguard Worker                     region.as_ptr(),
928*0d6140beSAndroid Build Coastguard Worker                 )
929*0d6140beSAndroid Build Coastguard Worker             }
930*0d6140beSAndroid Build Coastguard Worker         };
931*0d6140beSAndroid Build Coastguard Worker 
932*0d6140beSAndroid Build Coastguard Worker         if err != 0 {
933*0d6140beSAndroid Build Coastguard Worker             Err(RegionError::ErrorCode(ErrorCode {
934*0d6140beSAndroid Build Coastguard Worker                 function: "flashrom_layout_add_region",
935*0d6140beSAndroid Build Coastguard Worker                 code: err,
936*0d6140beSAndroid Build Coastguard Worker             }))
937*0d6140beSAndroid Build Coastguard Worker         } else {
938*0d6140beSAndroid Build Coastguard Worker             Ok(())
939*0d6140beSAndroid Build Coastguard Worker         }
940*0d6140beSAndroid Build Coastguard Worker     }
941*0d6140beSAndroid Build Coastguard Worker 
942*0d6140beSAndroid Build Coastguard Worker     /// Include a region
943*0d6140beSAndroid Build Coastguard Worker     ///
944*0d6140beSAndroid Build Coastguard Worker     /// # Errors
945*0d6140beSAndroid Build Coastguard Worker     ///
946*0d6140beSAndroid Build Coastguard Worker     /// This function will return an error if the region is not a valid CString,
947*0d6140beSAndroid Build Coastguard Worker     /// or if libflashrom returns an error.
include_region(&mut self, region: &str) -> std::result::Result<(), RegionError>948*0d6140beSAndroid Build Coastguard Worker     pub fn include_region(&mut self, region: &str) -> std::result::Result<(), RegionError> {
949*0d6140beSAndroid Build Coastguard Worker         let err = {
950*0d6140beSAndroid Build Coastguard Worker             let region = CString::new(region)?;
951*0d6140beSAndroid Build Coastguard Worker             unsafe {
952*0d6140beSAndroid Build Coastguard Worker                 libflashrom_sys::flashrom_layout_include_region(
953*0d6140beSAndroid Build Coastguard Worker                     self.layout.as_mut(),
954*0d6140beSAndroid Build Coastguard Worker                     region.as_ptr(),
955*0d6140beSAndroid Build Coastguard Worker                 )
956*0d6140beSAndroid Build Coastguard Worker             }
957*0d6140beSAndroid Build Coastguard Worker         };
958*0d6140beSAndroid Build Coastguard Worker         if err != 0 {
959*0d6140beSAndroid Build Coastguard Worker             Err(RegionError::ErrorCode(ErrorCode {
960*0d6140beSAndroid Build Coastguard Worker                 function: "flashrom_layout_include_region",
961*0d6140beSAndroid Build Coastguard Worker                 code: err,
962*0d6140beSAndroid Build Coastguard Worker             }))
963*0d6140beSAndroid Build Coastguard Worker         } else {
964*0d6140beSAndroid Build Coastguard Worker             Ok(())
965*0d6140beSAndroid Build Coastguard Worker         }
966*0d6140beSAndroid Build Coastguard Worker     }
967*0d6140beSAndroid Build Coastguard Worker 
968*0d6140beSAndroid Build Coastguard Worker     /// Exclude a region
969*0d6140beSAndroid Build Coastguard Worker     ///
970*0d6140beSAndroid Build Coastguard Worker     /// # Errors
971*0d6140beSAndroid Build Coastguard Worker     ///
972*0d6140beSAndroid Build Coastguard Worker     /// This function will return an error if the region is not a valid CString,
973*0d6140beSAndroid Build Coastguard Worker     /// or if libflashrom returns an error.
exclude_region(&mut self, region: &str) -> std::result::Result<(), RegionError>974*0d6140beSAndroid Build Coastguard Worker     pub fn exclude_region(&mut self, region: &str) -> std::result::Result<(), RegionError> {
975*0d6140beSAndroid Build Coastguard Worker         let err = {
976*0d6140beSAndroid Build Coastguard Worker             let region = CString::new(region)?;
977*0d6140beSAndroid Build Coastguard Worker             unsafe {
978*0d6140beSAndroid Build Coastguard Worker                 libflashrom_sys::flashrom_layout_exclude_region(
979*0d6140beSAndroid Build Coastguard Worker                     self.layout.as_mut(),
980*0d6140beSAndroid Build Coastguard Worker                     region.as_ptr(),
981*0d6140beSAndroid Build Coastguard Worker                 )
982*0d6140beSAndroid Build Coastguard Worker             }
983*0d6140beSAndroid Build Coastguard Worker         };
984*0d6140beSAndroid Build Coastguard Worker         if err != 0 {
985*0d6140beSAndroid Build Coastguard Worker             Err(RegionError::ErrorCode(ErrorCode {
986*0d6140beSAndroid Build Coastguard Worker                 function: "flashrom_layout_exclude_region",
987*0d6140beSAndroid Build Coastguard Worker                 code: err,
988*0d6140beSAndroid Build Coastguard Worker             }))
989*0d6140beSAndroid Build Coastguard Worker         } else {
990*0d6140beSAndroid Build Coastguard Worker             Ok(())
991*0d6140beSAndroid Build Coastguard Worker         }
992*0d6140beSAndroid Build Coastguard Worker     }
993*0d6140beSAndroid Build Coastguard Worker 
994*0d6140beSAndroid Build Coastguard Worker     /// Get the [`Range`] for the given region
995*0d6140beSAndroid Build Coastguard Worker     ///
996*0d6140beSAndroid Build Coastguard Worker     /// # Errors
997*0d6140beSAndroid Build Coastguard Worker     ///
998*0d6140beSAndroid Build Coastguard Worker     /// This function will return an error if the region is not a valid CString,
999*0d6140beSAndroid Build Coastguard Worker     /// or if libflashrom returns an error.
get_region_range(&mut self, region: &str) -> std::result::Result<Range, RegionError>1000*0d6140beSAndroid Build Coastguard Worker     pub fn get_region_range(&mut self, region: &str) -> std::result::Result<Range, RegionError> {
1001*0d6140beSAndroid Build Coastguard Worker         let mut start: std::os::raw::c_uint = 0;
1002*0d6140beSAndroid Build Coastguard Worker         let mut len: std::os::raw::c_uint = 0;
1003*0d6140beSAndroid Build Coastguard Worker         let err = {
1004*0d6140beSAndroid Build Coastguard Worker             let region = CString::new(region)?;
1005*0d6140beSAndroid Build Coastguard Worker             unsafe {
1006*0d6140beSAndroid Build Coastguard Worker                 libflashrom_sys::flashrom_layout_get_region_range(
1007*0d6140beSAndroid Build Coastguard Worker                     self.layout.as_mut(),
1008*0d6140beSAndroid Build Coastguard Worker                     region.as_ptr(),
1009*0d6140beSAndroid Build Coastguard Worker                     &mut start,
1010*0d6140beSAndroid Build Coastguard Worker                     &mut len,
1011*0d6140beSAndroid Build Coastguard Worker                 )
1012*0d6140beSAndroid Build Coastguard Worker             }
1013*0d6140beSAndroid Build Coastguard Worker         };
1014*0d6140beSAndroid Build Coastguard Worker         if err != 0 {
1015*0d6140beSAndroid Build Coastguard Worker             Err(RegionError::ErrorCode(ErrorCode {
1016*0d6140beSAndroid Build Coastguard Worker                 function: "flashrom_layout_get_region_range",
1017*0d6140beSAndroid Build Coastguard Worker                 code: err,
1018*0d6140beSAndroid Build Coastguard Worker             }))
1019*0d6140beSAndroid Build Coastguard Worker         } else {
1020*0d6140beSAndroid Build Coastguard Worker             // should be safe to assume sizeof(size_t) >= sizeof(unsigned int)
1021*0d6140beSAndroid Build Coastguard Worker             // TODO: fix after https://review.coreboot.org/c/flashrom/+/65944
1022*0d6140beSAndroid Build Coastguard Worker             Ok(start.try_into().unwrap()..(start + len).try_into().unwrap())
1023*0d6140beSAndroid Build Coastguard Worker         }
1024*0d6140beSAndroid Build Coastguard Worker     }
1025*0d6140beSAndroid Build Coastguard Worker }
1026*0d6140beSAndroid Build Coastguard Worker 
1027*0d6140beSAndroid Build Coastguard Worker // TODO this will be replaced with an API implementation: https://review.coreboot.org/c/flashrom/+/65999
1028*0d6140beSAndroid Build Coastguard Worker impl std::str::FromStr for Layout {
1029*0d6140beSAndroid Build Coastguard Worker     type Err = Box<dyn error::Error>;
1030*0d6140beSAndroid Build Coastguard Worker 
1031*0d6140beSAndroid Build Coastguard Worker     /// This will attempt to parse the [`Layout`] file format into a [`Layout`]
1032*0d6140beSAndroid Build Coastguard Worker     ///
1033*0d6140beSAndroid Build Coastguard Worker     /// The format is documented in the flashrom man page.
from_str(s: &str) -> std::result::Result<Self, Self::Err>1034*0d6140beSAndroid Build Coastguard Worker     fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
1035*0d6140beSAndroid Build Coastguard Worker         let mut ret = Layout::new()?;
1036*0d6140beSAndroid Build Coastguard Worker 
1037*0d6140beSAndroid Build Coastguard Worker         // format is hex:hex name
1038*0d6140beSAndroid Build Coastguard Worker         // flashrom layout.c seems to allow any characters in the name string
1039*0d6140beSAndroid Build Coastguard Worker         // I am restricting here to non whitespace
1040*0d6140beSAndroid Build Coastguard Worker         let re = Regex::new(r"^([0-9A-Za-z]+):([0-9A-Za-z]+)\s+(\S+)$").unwrap();
1041*0d6140beSAndroid Build Coastguard Worker 
1042*0d6140beSAndroid Build Coastguard Worker         // we dont use captures_iter else we would ignore incorrect lines
1043*0d6140beSAndroid Build Coastguard Worker         for line in s.lines() {
1044*0d6140beSAndroid Build Coastguard Worker             let (start, end, name) = match re.captures(line) {
1045*0d6140beSAndroid Build Coastguard Worker                 Some(caps) => (
1046*0d6140beSAndroid Build Coastguard Worker                     caps.get(1).unwrap(),
1047*0d6140beSAndroid Build Coastguard Worker                     caps.get(2).unwrap(),
1048*0d6140beSAndroid Build Coastguard Worker                     caps.get(3).unwrap(),
1049*0d6140beSAndroid Build Coastguard Worker                 ),
1050*0d6140beSAndroid Build Coastguard Worker                 None => Err(ParseLayoutError(format!("failed to parse: {:?}", line)))?,
1051*0d6140beSAndroid Build Coastguard Worker             };
1052*0d6140beSAndroid Build Coastguard Worker             let start = usize::from_str_radix(start.as_str(), 16)?;
1053*0d6140beSAndroid Build Coastguard Worker             let end = usize::from_str_radix(end.as_str(), 16)?;
1054*0d6140beSAndroid Build Coastguard Worker             ret.add_region(name.as_str(), start..=end)?;
1055*0d6140beSAndroid Build Coastguard Worker         }
1056*0d6140beSAndroid Build Coastguard Worker 
1057*0d6140beSAndroid Build Coastguard Worker         Ok(ret)
1058*0d6140beSAndroid Build Coastguard Worker     }
1059*0d6140beSAndroid Build Coastguard Worker }
1060*0d6140beSAndroid Build Coastguard Worker 
1061*0d6140beSAndroid Build Coastguard Worker impl Drop for Layout {
drop(&mut self)1062*0d6140beSAndroid Build Coastguard Worker     fn drop(&mut self) {
1063*0d6140beSAndroid Build Coastguard Worker         unsafe {
1064*0d6140beSAndroid Build Coastguard Worker             libflashrom_sys::flashrom_layout_release(self.layout.as_mut());
1065*0d6140beSAndroid Build Coastguard Worker         }
1066*0d6140beSAndroid Build Coastguard Worker     }
1067*0d6140beSAndroid Build Coastguard Worker }
1068*0d6140beSAndroid Build Coastguard Worker 
1069*0d6140beSAndroid Build Coastguard Worker #[cfg(test)]
1070*0d6140beSAndroid Build Coastguard Worker mod tests {
1071*0d6140beSAndroid Build Coastguard Worker     use gag::BufferRedirect;
1072*0d6140beSAndroid Build Coastguard Worker     use std::io::Read;
1073*0d6140beSAndroid Build Coastguard Worker 
1074*0d6140beSAndroid Build Coastguard Worker     use super::flashrom_version_info;
1075*0d6140beSAndroid Build Coastguard Worker     use super::set_log_level;
1076*0d6140beSAndroid Build Coastguard Worker     use super::Chip;
1077*0d6140beSAndroid Build Coastguard Worker     use super::ChipInitError;
1078*0d6140beSAndroid Build Coastguard Worker     use super::InitError;
1079*0d6140beSAndroid Build Coastguard Worker     use crate::set_log_function;
1080*0d6140beSAndroid Build Coastguard Worker     use crate::Layout;
1081*0d6140beSAndroid Build Coastguard Worker     use crate::Programmer;
1082*0d6140beSAndroid Build Coastguard Worker     use crate::WriteProtectCfg;
1083*0d6140beSAndroid Build Coastguard Worker 
1084*0d6140beSAndroid Build Coastguard Worker     // flashrom contains global state, which prevents correct initialisation of
1085*0d6140beSAndroid Build Coastguard Worker     // a second programmer or probing of a second chip. Run all unit tests in
1086*0d6140beSAndroid Build Coastguard Worker     // forked subprocesses to avoid this issue.
1087*0d6140beSAndroid Build Coastguard Worker     use rusty_fork::rusty_fork_test;
1088*0d6140beSAndroid Build Coastguard Worker     rusty_fork_test! {
1089*0d6140beSAndroid Build Coastguard Worker 
1090*0d6140beSAndroid Build Coastguard Worker         #[test]
1091*0d6140beSAndroid Build Coastguard Worker         fn version() {
1092*0d6140beSAndroid Build Coastguard Worker             // There is no version requirement yet, but for example:
1093*0d6140beSAndroid Build Coastguard Worker             // assert!(flashrom_version_info().contains("v1.2"))
1094*0d6140beSAndroid Build Coastguard Worker             assert!(!flashrom_version_info().unwrap().is_empty())
1095*0d6140beSAndroid Build Coastguard Worker         }
1096*0d6140beSAndroid Build Coastguard Worker 
1097*0d6140beSAndroid Build Coastguard Worker         #[test]
1098*0d6140beSAndroid Build Coastguard Worker         fn only_one_programmer() {
1099*0d6140beSAndroid Build Coastguard Worker             {
1100*0d6140beSAndroid Build Coastguard Worker                 let _1 = Programmer::new("dummy", Some("emulate=W25Q128FV")).unwrap();
1101*0d6140beSAndroid Build Coastguard Worker                 // Only one programmer can be initialised at a time.
1102*0d6140beSAndroid Build Coastguard Worker                 assert_eq!(Programmer::new("dummy", Some("emulate=W25Q128FV")).unwrap_err(), InitError::DuplicateInit)
1103*0d6140beSAndroid Build Coastguard Worker             }
1104*0d6140beSAndroid Build Coastguard Worker             // Only one programmer can ever be initialised
1105*0d6140beSAndroid Build Coastguard Worker             assert_eq!(Programmer::new("dummy", Some("emulate=W25Q128FV")).unwrap_err(), InitError::DuplicateInit)
1106*0d6140beSAndroid Build Coastguard Worker         }
1107*0d6140beSAndroid Build Coastguard Worker 
1108*0d6140beSAndroid Build Coastguard Worker         #[test]
1109*0d6140beSAndroid Build Coastguard Worker         fn programmer_bad_cstring_name() {
1110*0d6140beSAndroid Build Coastguard Worker             assert!(matches!(Programmer::new("dummy\0", None).unwrap_err(), InitError::InvalidName(_)))
1111*0d6140beSAndroid Build Coastguard Worker         }
1112*0d6140beSAndroid Build Coastguard Worker 
1113*0d6140beSAndroid Build Coastguard Worker         #[test]
1114*0d6140beSAndroid Build Coastguard Worker         fn chip_none() {
1115*0d6140beSAndroid Build Coastguard Worker             // Not specifying a chip will select one if there is one.
1116*0d6140beSAndroid Build Coastguard Worker             Chip::new(Programmer::new("dummy", Some("emulate=W25Q128FV")).unwrap(), None).unwrap();
1117*0d6140beSAndroid Build Coastguard Worker         }
1118*0d6140beSAndroid Build Coastguard Worker 
1119*0d6140beSAndroid Build Coastguard Worker         #[test]
1120*0d6140beSAndroid Build Coastguard Worker         fn chip_some() {
1121*0d6140beSAndroid Build Coastguard Worker             // Specifying a valid chip.
1122*0d6140beSAndroid Build Coastguard Worker             Chip::new(Programmer::new("dummy", Some("emulate=W25Q128FV")).unwrap(), Some("W25Q128.V")).unwrap();
1123*0d6140beSAndroid Build Coastguard Worker         }
1124*0d6140beSAndroid Build Coastguard Worker 
1125*0d6140beSAndroid Build Coastguard Worker         #[test]
1126*0d6140beSAndroid Build Coastguard Worker         fn chip_nochip() {
1127*0d6140beSAndroid Build Coastguard Worker             // Choosing a non existent chip fails.
1128*0d6140beSAndroid Build Coastguard Worker             assert_eq!(
1129*0d6140beSAndroid Build Coastguard Worker                 Chip::new(Programmer::new("dummy", None).unwrap(), Some("W25Q128.V")).unwrap_err(),
1130*0d6140beSAndroid Build Coastguard Worker                 ChipInitError::NoChipError
1131*0d6140beSAndroid Build Coastguard Worker             );
1132*0d6140beSAndroid Build Coastguard Worker         }
1133*0d6140beSAndroid Build Coastguard Worker 
1134*0d6140beSAndroid Build Coastguard Worker         #[test]
1135*0d6140beSAndroid Build Coastguard Worker         fn logging_stderr() {
1136*0d6140beSAndroid Build Coastguard Worker             let mut buf = BufferRedirect::stderr().unwrap();
1137*0d6140beSAndroid Build Coastguard Worker             let mut fc = Chip::new(Programmer::new("dummy", Some("emulate=W25Q128FV")).unwrap(), Some("W25Q128.V")).unwrap();
1138*0d6140beSAndroid Build Coastguard Worker 
1139*0d6140beSAndroid Build Coastguard Worker             set_log_level(Some(libflashrom_sys::FLASHROM_MSG_INFO));
1140*0d6140beSAndroid Build Coastguard Worker             fc.image_read(None).unwrap();
1141*0d6140beSAndroid Build Coastguard Worker             let mut stderr = String::new();
1142*0d6140beSAndroid Build Coastguard Worker             if buf.read_to_string(&mut stderr).unwrap() == 0 {
1143*0d6140beSAndroid Build Coastguard Worker                 panic!("stderr empty when it should have some messages");
1144*0d6140beSAndroid Build Coastguard Worker             }
1145*0d6140beSAndroid Build Coastguard Worker 
1146*0d6140beSAndroid Build Coastguard Worker             set_log_level(None);
1147*0d6140beSAndroid Build Coastguard Worker             fc.image_read(None).unwrap();
1148*0d6140beSAndroid Build Coastguard Worker             if buf.read_to_string(&mut stderr).unwrap() != 0 {
1149*0d6140beSAndroid Build Coastguard Worker                 panic!("stderr not empty when it should be silent");
1150*0d6140beSAndroid Build Coastguard Worker             }
1151*0d6140beSAndroid Build Coastguard Worker         }
1152*0d6140beSAndroid Build Coastguard Worker 
1153*0d6140beSAndroid Build Coastguard Worker         #[test]
1154*0d6140beSAndroid Build Coastguard Worker         fn logging_custom() {
1155*0d6140beSAndroid Build Coastguard Worker             // Check that a custom logging callback works
1156*0d6140beSAndroid Build Coastguard Worker             static mut BUF: String = String::new();
1157*0d6140beSAndroid Build Coastguard Worker             fn logger(
1158*0d6140beSAndroid Build Coastguard Worker                 _: libflashrom_sys::flashrom_log_level,
1159*0d6140beSAndroid Build Coastguard Worker                 format: &str,
1160*0d6140beSAndroid Build Coastguard Worker             ) {
1161*0d6140beSAndroid Build Coastguard Worker                 unsafe {BUF.push_str(format)}
1162*0d6140beSAndroid Build Coastguard Worker             }
1163*0d6140beSAndroid Build Coastguard Worker             set_log_function(logger);
1164*0d6140beSAndroid Build Coastguard Worker             set_log_level(Some(libflashrom_sys::FLASHROM_MSG_SPEW));
1165*0d6140beSAndroid Build Coastguard Worker             Chip::new(Programmer::new("dummy", Some("emulate=W25Q128FV")).unwrap(), Some("W25Q128.V")).unwrap();
1166*0d6140beSAndroid Build Coastguard Worker             assert_ne!(unsafe{BUF.len()}, 0);
1167*0d6140beSAndroid Build Coastguard Worker         }
1168*0d6140beSAndroid Build Coastguard Worker 
1169*0d6140beSAndroid Build Coastguard Worker         #[test]
1170*0d6140beSAndroid Build Coastguard Worker         fn flashchip() {
1171*0d6140beSAndroid Build Coastguard Worker             // basic tests of the flashchip methods
1172*0d6140beSAndroid Build Coastguard Worker             let mut fc = Chip::new(Programmer::new("dummy", Some("emulate=W25Q128FV")).unwrap(), Some("W25Q128.V")).unwrap();
1173*0d6140beSAndroid Build Coastguard Worker             fc.get_size();
1174*0d6140beSAndroid Build Coastguard Worker 
1175*0d6140beSAndroid Build Coastguard Worker             let mut wp = fc.get_wp().unwrap();
1176*0d6140beSAndroid Build Coastguard Worker             wp.set_mode(libflashrom_sys::flashrom_wp_mode::FLASHROM_WP_MODE_DISABLED);
1177*0d6140beSAndroid Build Coastguard Worker             fc.set_wp(&wp).unwrap();
1178*0d6140beSAndroid Build Coastguard Worker             fc.get_wp_ranges().unwrap();
1179*0d6140beSAndroid Build Coastguard Worker 
1180*0d6140beSAndroid Build Coastguard Worker             fn test_layout() -> Layout {
1181*0d6140beSAndroid Build Coastguard Worker                 let mut layout = Layout::new().unwrap();
1182*0d6140beSAndroid Build Coastguard Worker                 layout.add_region("xyz", 100..200).unwrap();
1183*0d6140beSAndroid Build Coastguard Worker                 layout.include_region("xyz").unwrap();
1184*0d6140beSAndroid Build Coastguard Worker                 layout.add_region("abc", 100..200).unwrap();
1185*0d6140beSAndroid Build Coastguard Worker                 layout
1186*0d6140beSAndroid Build Coastguard Worker             }
1187*0d6140beSAndroid Build Coastguard Worker 
1188*0d6140beSAndroid Build Coastguard Worker             fc.image_read(None).unwrap();
1189*0d6140beSAndroid Build Coastguard Worker             fc.image_read(Some(test_layout())).unwrap();
1190*0d6140beSAndroid Build Coastguard Worker 
1191*0d6140beSAndroid Build Coastguard Worker             let mut buf = vec![0; fc.get_size()];
1192*0d6140beSAndroid Build Coastguard Worker             fc.image_write(&mut buf, None).unwrap();
1193*0d6140beSAndroid Build Coastguard Worker             fc.image_write(&mut buf, Some(test_layout())).unwrap();
1194*0d6140beSAndroid Build Coastguard Worker 
1195*0d6140beSAndroid Build Coastguard Worker             fc.image_verify(&buf, None).unwrap();
1196*0d6140beSAndroid Build Coastguard Worker             fc.image_verify(&buf, Some(test_layout())).unwrap();
1197*0d6140beSAndroid Build Coastguard Worker 
1198*0d6140beSAndroid Build Coastguard Worker             fc.erase().unwrap();
1199*0d6140beSAndroid Build Coastguard Worker         }
1200*0d6140beSAndroid Build Coastguard Worker 
1201*0d6140beSAndroid Build Coastguard Worker         #[test]
1202*0d6140beSAndroid Build Coastguard Worker         fn write_protect() {
1203*0d6140beSAndroid Build Coastguard Worker             let mut wp = WriteProtectCfg::new().unwrap();
1204*0d6140beSAndroid Build Coastguard Worker             wp.set_mode(libflashrom_sys::flashrom_wp_mode::FLASHROM_WP_MODE_DISABLED);
1205*0d6140beSAndroid Build Coastguard Worker             wp.set_range(100..200);
1206*0d6140beSAndroid Build Coastguard Worker             assert_eq!(wp.get_mode(), libflashrom_sys::flashrom_wp_mode::FLASHROM_WP_MODE_DISABLED);
1207*0d6140beSAndroid Build Coastguard Worker             assert_eq!(wp.get_range(), 100..200);
1208*0d6140beSAndroid Build Coastguard Worker         }
1209*0d6140beSAndroid Build Coastguard Worker     }
1210*0d6140beSAndroid Build Coastguard Worker }
1211