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