xref: /aosp_15_r20/external/flashrom/util/flashrom_tester/src/utils.rs (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
1*0d6140beSAndroid Build Coastguard Worker //
2*0d6140beSAndroid Build Coastguard Worker // Copyright 2019, Google Inc.
3*0d6140beSAndroid Build Coastguard Worker // All rights reserved.
4*0d6140beSAndroid Build Coastguard Worker //
5*0d6140beSAndroid Build Coastguard Worker // Redistribution and use in source and binary forms, with or without
6*0d6140beSAndroid Build Coastguard Worker // modification, are permitted provided that the following conditions are
7*0d6140beSAndroid Build Coastguard Worker // met:
8*0d6140beSAndroid Build Coastguard Worker //
9*0d6140beSAndroid Build Coastguard Worker //    * Redistributions of source code must retain the above copyright
10*0d6140beSAndroid Build Coastguard Worker // notice, this list of conditions and the following disclaimer.
11*0d6140beSAndroid Build Coastguard Worker //    * Redistributions in binary form must reproduce the above
12*0d6140beSAndroid Build Coastguard Worker // copyright notice, this list of conditions and the following disclaimer
13*0d6140beSAndroid Build Coastguard Worker // in the documentation and/or other materials provided with the
14*0d6140beSAndroid Build Coastguard Worker // distribution.
15*0d6140beSAndroid Build Coastguard Worker //    * Neither the name of Google Inc. nor the names of its
16*0d6140beSAndroid Build Coastguard Worker // contributors may be used to endorse or promote products derived from
17*0d6140beSAndroid Build Coastguard Worker // this software without specific prior written permission.
18*0d6140beSAndroid Build Coastguard Worker //
19*0d6140beSAndroid Build Coastguard Worker // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20*0d6140beSAndroid Build Coastguard Worker // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21*0d6140beSAndroid Build Coastguard Worker // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22*0d6140beSAndroid Build Coastguard Worker // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23*0d6140beSAndroid Build Coastguard Worker // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24*0d6140beSAndroid Build Coastguard Worker // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25*0d6140beSAndroid Build Coastguard Worker // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26*0d6140beSAndroid Build Coastguard Worker // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27*0d6140beSAndroid Build Coastguard Worker // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28*0d6140beSAndroid Build Coastguard Worker // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29*0d6140beSAndroid Build Coastguard Worker // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30*0d6140beSAndroid Build Coastguard Worker //
31*0d6140beSAndroid Build Coastguard Worker // Alternatively, this software may be distributed under the terms of the
32*0d6140beSAndroid Build Coastguard Worker // GNU General Public License ("GPL") version 2 as published by the Free
33*0d6140beSAndroid Build Coastguard Worker // Software Foundation.
34*0d6140beSAndroid Build Coastguard Worker //
35*0d6140beSAndroid Build Coastguard Worker 
36*0d6140beSAndroid Build Coastguard Worker use std::io::prelude::*;
37*0d6140beSAndroid Build Coastguard Worker use std::process::Command;
38*0d6140beSAndroid Build Coastguard Worker 
39*0d6140beSAndroid Build Coastguard Worker #[derive(Debug, PartialEq, Eq, Clone, Copy)]
40*0d6140beSAndroid Build Coastguard Worker pub enum LayoutNames {
41*0d6140beSAndroid Build Coastguard Worker     TopQuad,
42*0d6140beSAndroid Build Coastguard Worker     TopHalf,
43*0d6140beSAndroid Build Coastguard Worker     BottomHalf,
44*0d6140beSAndroid Build Coastguard Worker     BottomQuad,
45*0d6140beSAndroid Build Coastguard Worker }
46*0d6140beSAndroid Build Coastguard Worker 
47*0d6140beSAndroid Build Coastguard Worker impl LayoutNames {
48*0d6140beSAndroid Build Coastguard Worker     // Return a section that does not overlap
get_non_overlapping_section(&self) -> LayoutNames49*0d6140beSAndroid Build Coastguard Worker     pub fn get_non_overlapping_section(&self) -> LayoutNames {
50*0d6140beSAndroid Build Coastguard Worker         match self {
51*0d6140beSAndroid Build Coastguard Worker             LayoutNames::TopQuad => LayoutNames::BottomQuad,
52*0d6140beSAndroid Build Coastguard Worker             LayoutNames::TopHalf => LayoutNames::BottomHalf,
53*0d6140beSAndroid Build Coastguard Worker             LayoutNames::BottomHalf => LayoutNames::TopHalf,
54*0d6140beSAndroid Build Coastguard Worker             LayoutNames::BottomQuad => LayoutNames::TopQuad,
55*0d6140beSAndroid Build Coastguard Worker         }
56*0d6140beSAndroid Build Coastguard Worker     }
57*0d6140beSAndroid Build Coastguard Worker }
58*0d6140beSAndroid Build Coastguard Worker 
59*0d6140beSAndroid Build Coastguard Worker #[derive(Debug, PartialEq, Eq, Clone, Copy)]
60*0d6140beSAndroid Build Coastguard Worker pub struct LayoutSizes {
61*0d6140beSAndroid Build Coastguard Worker     half_sz: i64,
62*0d6140beSAndroid Build Coastguard Worker     quad_sz: i64,
63*0d6140beSAndroid Build Coastguard Worker     rom_top: i64,
64*0d6140beSAndroid Build Coastguard Worker     bottom_half_top: i64,
65*0d6140beSAndroid Build Coastguard Worker     bottom_quad_top: i64,
66*0d6140beSAndroid Build Coastguard Worker     top_quad_bottom: i64,
67*0d6140beSAndroid Build Coastguard Worker }
68*0d6140beSAndroid Build Coastguard Worker 
get_layout_sizes(rom_sz: i64) -> Result<LayoutSizes, String>69*0d6140beSAndroid Build Coastguard Worker pub fn get_layout_sizes(rom_sz: i64) -> Result<LayoutSizes, String> {
70*0d6140beSAndroid Build Coastguard Worker     if rom_sz <= 0 {
71*0d6140beSAndroid Build Coastguard Worker         return Err("invalid rom size provided".into());
72*0d6140beSAndroid Build Coastguard Worker     }
73*0d6140beSAndroid Build Coastguard Worker     if rom_sz & (rom_sz - 1) != 0 {
74*0d6140beSAndroid Build Coastguard Worker         return Err("invalid rom size, not a power of 2".into());
75*0d6140beSAndroid Build Coastguard Worker     }
76*0d6140beSAndroid Build Coastguard Worker     Ok(LayoutSizes {
77*0d6140beSAndroid Build Coastguard Worker         half_sz: rom_sz / 2,
78*0d6140beSAndroid Build Coastguard Worker         quad_sz: rom_sz / 4,
79*0d6140beSAndroid Build Coastguard Worker         rom_top: rom_sz - 1,
80*0d6140beSAndroid Build Coastguard Worker         bottom_half_top: (rom_sz / 2) - 1,
81*0d6140beSAndroid Build Coastguard Worker         bottom_quad_top: (rom_sz / 4) - 1,
82*0d6140beSAndroid Build Coastguard Worker         top_quad_bottom: (rom_sz / 4) * 3,
83*0d6140beSAndroid Build Coastguard Worker     })
84*0d6140beSAndroid Build Coastguard Worker }
85*0d6140beSAndroid Build Coastguard Worker 
layout_section(ls: &LayoutSizes, ln: LayoutNames) -> (&'static str, i64, i64)86*0d6140beSAndroid Build Coastguard Worker pub fn layout_section(ls: &LayoutSizes, ln: LayoutNames) -> (&'static str, i64, i64) {
87*0d6140beSAndroid Build Coastguard Worker     match ln {
88*0d6140beSAndroid Build Coastguard Worker         LayoutNames::TopQuad => ("TOP_QUAD", ls.top_quad_bottom, ls.quad_sz),
89*0d6140beSAndroid Build Coastguard Worker         LayoutNames::TopHalf => ("TOP_HALF", ls.half_sz, ls.half_sz),
90*0d6140beSAndroid Build Coastguard Worker         LayoutNames::BottomHalf => ("BOTTOM_HALF", 0, ls.half_sz),
91*0d6140beSAndroid Build Coastguard Worker         LayoutNames::BottomQuad => ("BOTTOM_QUAD", 0, ls.quad_sz),
92*0d6140beSAndroid Build Coastguard Worker     }
93*0d6140beSAndroid Build Coastguard Worker }
94*0d6140beSAndroid Build Coastguard Worker 
construct_layout_file<F: Write>(mut target: F, ls: &LayoutSizes) -> std::io::Result<()>95*0d6140beSAndroid Build Coastguard Worker pub fn construct_layout_file<F: Write>(mut target: F, ls: &LayoutSizes) -> std::io::Result<()> {
96*0d6140beSAndroid Build Coastguard Worker     writeln!(target, "000000:{:x} BOTTOM_QUAD", ls.bottom_quad_top)?;
97*0d6140beSAndroid Build Coastguard Worker     writeln!(target, "000000:{:x} BOTTOM_HALF", ls.bottom_half_top)?;
98*0d6140beSAndroid Build Coastguard Worker     writeln!(target, "{:x}:{:x} TOP_HALF", ls.half_sz, ls.rom_top)?;
99*0d6140beSAndroid Build Coastguard Worker     writeln!(target, "{:x}:{:x} TOP_QUAD", ls.top_quad_bottom, ls.rom_top)
100*0d6140beSAndroid Build Coastguard Worker }
101*0d6140beSAndroid Build Coastguard Worker 
toggle_hw_wp(dis: bool) -> Result<(), String>102*0d6140beSAndroid Build Coastguard Worker pub fn toggle_hw_wp(dis: bool) -> Result<(), String> {
103*0d6140beSAndroid Build Coastguard Worker     // The easist way to toggle the hardware write-protect is
104*0d6140beSAndroid Build Coastguard Worker     // to {dis}connect the battery (and/or {open,close} the WP screw).
105*0d6140beSAndroid Build Coastguard Worker     let s = if dis { "dis" } else { "" };
106*0d6140beSAndroid Build Coastguard Worker     let screw_state = if dis { "open" } else { "close" };
107*0d6140beSAndroid Build Coastguard Worker     // Print a failure message, but not on the first try.
108*0d6140beSAndroid Build Coastguard Worker     let mut fail_msg = None;
109*0d6140beSAndroid Build Coastguard Worker     while dis == get_hardware_wp()? {
110*0d6140beSAndroid Build Coastguard Worker         if let Some(msg) = fail_msg {
111*0d6140beSAndroid Build Coastguard Worker             eprintln!("{msg}");
112*0d6140beSAndroid Build Coastguard Worker         }
113*0d6140beSAndroid Build Coastguard Worker         fail_msg = Some(format!("Hardware write protect is still {}!", !dis));
114*0d6140beSAndroid Build Coastguard Worker         // The following message is read by the tast test. Do not modify.
115*0d6140beSAndroid Build Coastguard Worker         info!("Prompt for hardware WP {}able", s);
116*0d6140beSAndroid Build Coastguard Worker         eprintln!(" > {}connect the battery (and/or {} the WP screw)", s, screw_state);
117*0d6140beSAndroid Build Coastguard Worker         pause();
118*0d6140beSAndroid Build Coastguard Worker     }
119*0d6140beSAndroid Build Coastguard Worker     Ok(())
120*0d6140beSAndroid Build Coastguard Worker }
121*0d6140beSAndroid Build Coastguard Worker 
ac_power_warning()122*0d6140beSAndroid Build Coastguard Worker pub fn ac_power_warning() {
123*0d6140beSAndroid Build Coastguard Worker     info!("*****************************");
124*0d6140beSAndroid Build Coastguard Worker     info!("AC power *must be* connected!");
125*0d6140beSAndroid Build Coastguard Worker     info!("*****************************");
126*0d6140beSAndroid Build Coastguard Worker     pause();
127*0d6140beSAndroid Build Coastguard Worker }
128*0d6140beSAndroid Build Coastguard Worker 
pause()129*0d6140beSAndroid Build Coastguard Worker fn pause() {
130*0d6140beSAndroid Build Coastguard Worker     // The following message is read by the tast test. Do not modify.
131*0d6140beSAndroid Build Coastguard Worker     println!("Press enter to continue...");
132*0d6140beSAndroid Build Coastguard Worker     // Rust stdout is always LineBuffered at time of writing.
133*0d6140beSAndroid Build Coastguard Worker     // But this is not guaranteed, so flush anyway.
134*0d6140beSAndroid Build Coastguard Worker     std::io::stdout().flush().unwrap();
135*0d6140beSAndroid Build Coastguard Worker     // This reads one line, there is no guarantee the line came
136*0d6140beSAndroid Build Coastguard Worker     // after the above prompt. But it is good enough.
137*0d6140beSAndroid Build Coastguard Worker     if std::io::stdin().read_line(&mut String::new()).unwrap() == 0 {
138*0d6140beSAndroid Build Coastguard Worker         panic!("stdin closed");
139*0d6140beSAndroid Build Coastguard Worker     }
140*0d6140beSAndroid Build Coastguard Worker }
141*0d6140beSAndroid Build Coastguard Worker 
get_hardware_wp() -> std::result::Result<bool, String>142*0d6140beSAndroid Build Coastguard Worker pub fn get_hardware_wp() -> std::result::Result<bool, String> {
143*0d6140beSAndroid Build Coastguard Worker     let wp_s_val = collect_crosssystem(&["wpsw_cur"])?.parse::<u32>();
144*0d6140beSAndroid Build Coastguard Worker     match wp_s_val {
145*0d6140beSAndroid Build Coastguard Worker         Ok(v) => {
146*0d6140beSAndroid Build Coastguard Worker             if v == 1 {
147*0d6140beSAndroid Build Coastguard Worker                 Ok(true)
148*0d6140beSAndroid Build Coastguard Worker             } else if v == 0 {
149*0d6140beSAndroid Build Coastguard Worker                 Ok(false)
150*0d6140beSAndroid Build Coastguard Worker             } else {
151*0d6140beSAndroid Build Coastguard Worker                 Err("Unknown write protect value".into())
152*0d6140beSAndroid Build Coastguard Worker             }
153*0d6140beSAndroid Build Coastguard Worker         }
154*0d6140beSAndroid Build Coastguard Worker         Err(_) => Err("Cannot parse write protect value".into()),
155*0d6140beSAndroid Build Coastguard Worker     }
156*0d6140beSAndroid Build Coastguard Worker }
157*0d6140beSAndroid Build Coastguard Worker 
collect_crosssystem(args: &[&str]) -> Result<String, String>158*0d6140beSAndroid Build Coastguard Worker pub fn collect_crosssystem(args: &[&str]) -> Result<String, String> {
159*0d6140beSAndroid Build Coastguard Worker     let cmd = match Command::new("crossystem").args(args).output() {
160*0d6140beSAndroid Build Coastguard Worker         Ok(x) => x,
161*0d6140beSAndroid Build Coastguard Worker         Err(e) => return Err(format!("Failed to run crossystem: {}", e)),
162*0d6140beSAndroid Build Coastguard Worker     };
163*0d6140beSAndroid Build Coastguard Worker 
164*0d6140beSAndroid Build Coastguard Worker     if !cmd.status.success() {
165*0d6140beSAndroid Build Coastguard Worker         return Err(translate_command_error(&cmd).to_string());
166*0d6140beSAndroid Build Coastguard Worker     };
167*0d6140beSAndroid Build Coastguard Worker 
168*0d6140beSAndroid Build Coastguard Worker     Ok(String::from_utf8_lossy(&cmd.stdout).into_owned())
169*0d6140beSAndroid Build Coastguard Worker }
170*0d6140beSAndroid Build Coastguard Worker 
translate_command_error(output: &std::process::Output) -> std::io::Error171*0d6140beSAndroid Build Coastguard Worker pub fn translate_command_error(output: &std::process::Output) -> std::io::Error {
172*0d6140beSAndroid Build Coastguard Worker     use std::io::{Error, ErrorKind};
173*0d6140beSAndroid Build Coastguard Worker     // There is two cases on failure;
174*0d6140beSAndroid Build Coastguard Worker     //  i. ) A bad exit code,
175*0d6140beSAndroid Build Coastguard Worker     //  ii.) A SIG killed us.
176*0d6140beSAndroid Build Coastguard Worker     match output.status.code() {
177*0d6140beSAndroid Build Coastguard Worker         Some(code) => {
178*0d6140beSAndroid Build Coastguard Worker             let e = format!(
179*0d6140beSAndroid Build Coastguard Worker                 "{}\nExited with error code: {}",
180*0d6140beSAndroid Build Coastguard Worker                 String::from_utf8_lossy(&output.stderr),
181*0d6140beSAndroid Build Coastguard Worker                 code
182*0d6140beSAndroid Build Coastguard Worker             );
183*0d6140beSAndroid Build Coastguard Worker             Error::new(ErrorKind::Other, e)
184*0d6140beSAndroid Build Coastguard Worker         }
185*0d6140beSAndroid Build Coastguard Worker         None => Error::new(
186*0d6140beSAndroid Build Coastguard Worker             ErrorKind::Other,
187*0d6140beSAndroid Build Coastguard Worker             "Process terminated by a signal".to_string(),
188*0d6140beSAndroid Build Coastguard Worker         ),
189*0d6140beSAndroid Build Coastguard Worker     }
190*0d6140beSAndroid Build Coastguard Worker }
191*0d6140beSAndroid Build Coastguard Worker 
192*0d6140beSAndroid Build Coastguard Worker #[cfg(test)]
193*0d6140beSAndroid Build Coastguard Worker mod tests {
194*0d6140beSAndroid Build Coastguard Worker     use super::*;
195*0d6140beSAndroid Build Coastguard Worker 
196*0d6140beSAndroid Build Coastguard Worker     #[test]
construct_layout_file()197*0d6140beSAndroid Build Coastguard Worker     fn construct_layout_file() {
198*0d6140beSAndroid Build Coastguard Worker         use super::{construct_layout_file, get_layout_sizes};
199*0d6140beSAndroid Build Coastguard Worker 
200*0d6140beSAndroid Build Coastguard Worker         let mut buf = Vec::new();
201*0d6140beSAndroid Build Coastguard Worker         construct_layout_file(
202*0d6140beSAndroid Build Coastguard Worker             &mut buf,
203*0d6140beSAndroid Build Coastguard Worker             &get_layout_sizes(0x10000).expect("64k is a valid chip size"),
204*0d6140beSAndroid Build Coastguard Worker         )
205*0d6140beSAndroid Build Coastguard Worker         .expect("no I/O errors expected");
206*0d6140beSAndroid Build Coastguard Worker 
207*0d6140beSAndroid Build Coastguard Worker         assert_eq!(
208*0d6140beSAndroid Build Coastguard Worker             &buf[..],
209*0d6140beSAndroid Build Coastguard Worker             &b"000000:3fff BOTTOM_QUAD\n\
210*0d6140beSAndroid Build Coastguard Worker                000000:7fff BOTTOM_HALF\n\
211*0d6140beSAndroid Build Coastguard Worker                8000:ffff TOP_HALF\n\
212*0d6140beSAndroid Build Coastguard Worker                c000:ffff TOP_QUAD\n"[..]
213*0d6140beSAndroid Build Coastguard Worker         );
214*0d6140beSAndroid Build Coastguard Worker     }
215*0d6140beSAndroid Build Coastguard Worker 
216*0d6140beSAndroid Build Coastguard Worker     #[test]
get_layout_sizes()217*0d6140beSAndroid Build Coastguard Worker     fn get_layout_sizes() {
218*0d6140beSAndroid Build Coastguard Worker         use super::get_layout_sizes;
219*0d6140beSAndroid Build Coastguard Worker 
220*0d6140beSAndroid Build Coastguard Worker         assert_eq!(
221*0d6140beSAndroid Build Coastguard Worker             get_layout_sizes(-128).err(),
222*0d6140beSAndroid Build Coastguard Worker             Some("invalid rom size provided".into())
223*0d6140beSAndroid Build Coastguard Worker         );
224*0d6140beSAndroid Build Coastguard Worker 
225*0d6140beSAndroid Build Coastguard Worker         assert_eq!(
226*0d6140beSAndroid Build Coastguard Worker             get_layout_sizes(3 << 20).err(),
227*0d6140beSAndroid Build Coastguard Worker             Some("invalid rom size, not a power of 2".into())
228*0d6140beSAndroid Build Coastguard Worker         );
229*0d6140beSAndroid Build Coastguard Worker 
230*0d6140beSAndroid Build Coastguard Worker         assert_eq!(
231*0d6140beSAndroid Build Coastguard Worker             get_layout_sizes(64 << 10).unwrap(),
232*0d6140beSAndroid Build Coastguard Worker             LayoutSizes {
233*0d6140beSAndroid Build Coastguard Worker                 half_sz: 0x8000,
234*0d6140beSAndroid Build Coastguard Worker                 quad_sz: 0x4000,
235*0d6140beSAndroid Build Coastguard Worker                 rom_top: 0xFFFF,
236*0d6140beSAndroid Build Coastguard Worker                 bottom_half_top: 0x7FFF,
237*0d6140beSAndroid Build Coastguard Worker                 bottom_quad_top: 0x3FFF,
238*0d6140beSAndroid Build Coastguard Worker                 top_quad_bottom: 0xC000,
239*0d6140beSAndroid Build Coastguard Worker             }
240*0d6140beSAndroid Build Coastguard Worker         );
241*0d6140beSAndroid Build Coastguard Worker     }
242*0d6140beSAndroid Build Coastguard Worker }
243