xref: /aosp_15_r20/external/crosvm/devices/src/fw_cfg.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2023 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker //! fw_cfg device implementing QEMU's Firmware Configuration interface
6*bb4ee6a4SAndroid Build Coastguard Worker //! <https://www.qemu.org/docs/master/specs/fw_cfg.html>
7*bb4ee6a4SAndroid Build Coastguard Worker 
8*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::HashSet;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::fs;
10*bb4ee6a4SAndroid Build Coastguard Worker use std::iter::repeat;
11*bb4ee6a4SAndroid Build Coastguard Worker use std::path::PathBuf;
12*bb4ee6a4SAndroid Build Coastguard Worker 
13*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(windows)]
14*bb4ee6a4SAndroid Build Coastguard Worker use base::error;
15*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserialize;
16*bb4ee6a4SAndroid Build Coastguard Worker use serde::Serialize;
17*bb4ee6a4SAndroid Build Coastguard Worker use serde_keyvalue::FromKeyValues;
18*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error as ThisError;
19*bb4ee6a4SAndroid Build Coastguard Worker 
20*bb4ee6a4SAndroid Build Coastguard Worker use crate::BusAccessInfo;
21*bb4ee6a4SAndroid Build Coastguard Worker use crate::BusDevice;
22*bb4ee6a4SAndroid Build Coastguard Worker use crate::DeviceId;
23*bb4ee6a4SAndroid Build Coastguard Worker use crate::Suspendable;
24*bb4ee6a4SAndroid Build Coastguard Worker 
25*bb4ee6a4SAndroid Build Coastguard Worker pub const FW_CFG_BASE_PORT: u64 = 0x510;
26*bb4ee6a4SAndroid Build Coastguard Worker pub const FW_CFG_WIDTH: u64 = 0x4;
27*bb4ee6a4SAndroid Build Coastguard Worker // For the 16-bit selector, the 2nd highest-order bit represents whether the data port will be read
28*bb4ee6a4SAndroid Build Coastguard Worker // or written to. Because this has been deprecrated by Qemu, this bit is useless. The highest order
29*bb4ee6a4SAndroid Build Coastguard Worker // bit represents whether the selected configuration item is arch-specific. Therefore, only the
30*bb4ee6a4SAndroid Build Coastguard Worker // lower 14 bits are used for indexing and we mask the two highest bits off with
31*bb4ee6a4SAndroid Build Coastguard Worker // FW_CFG_SELECTOR_SELECT_MASK. 16384 = 2^14.
32*bb4ee6a4SAndroid Build Coastguard Worker pub const FW_CFG_MAX_FILE_SLOTS: usize = 16384 - FW_CFG_FILE_FIRST;
33*bb4ee6a4SAndroid Build Coastguard Worker const FW_CFG_FILE_FIRST: usize = 0x0020;
34*bb4ee6a4SAndroid Build Coastguard Worker const FW_CFG_SELECTOR_PORT_OFFSET: u64 = 0x0;
35*bb4ee6a4SAndroid Build Coastguard Worker const FW_CFG_DATA_PORT_OFFSET: u64 = 0x1;
36*bb4ee6a4SAndroid Build Coastguard Worker const FW_CFG_SELECTOR_RW_MASK: u16 = 0x2000;
37*bb4ee6a4SAndroid Build Coastguard Worker const FW_CFG_SELECTOR_ARCH_MASK: u16 = 0x4000;
38*bb4ee6a4SAndroid Build Coastguard Worker const FW_CFG_SELECTOR_SELECT_MASK: u16 = 0xbfff;
39*bb4ee6a4SAndroid Build Coastguard Worker const FW_CFG_SIGNATURE: [u8; 4] = [b'Q', b'E', b'M', b'U'];
40*bb4ee6a4SAndroid Build Coastguard Worker const FW_CFG_REVISION: [u8; 4] = [0, 0, 0, 1];
41*bb4ee6a4SAndroid Build Coastguard Worker const FW_CFG_SIGNATURE_SELECTOR: u16 = 0x0000;
42*bb4ee6a4SAndroid Build Coastguard Worker const FW_CFG_REVISION_SELECTOR: u16 = 0x0001;
43*bb4ee6a4SAndroid Build Coastguard Worker const FW_CFG_FILE_DIR_SELECTOR: u16 = 0x0019;
44*bb4ee6a4SAndroid Build Coastguard Worker // Code that uses fw_cfg expects to read a char[56] for filenames
45*bb4ee6a4SAndroid Build Coastguard Worker const FW_CFG_FILENAME_SIZE: usize = 56;
46*bb4ee6a4SAndroid Build Coastguard Worker 
47*bb4ee6a4SAndroid Build Coastguard Worker #[derive(ThisError, Debug)]
48*bb4ee6a4SAndroid Build Coastguard Worker pub enum Error {
49*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Ran out of file slots")]
50*bb4ee6a4SAndroid Build Coastguard Worker     InsufficientFileSlots,
51*bb4ee6a4SAndroid Build Coastguard Worker 
52*bb4ee6a4SAndroid Build Coastguard Worker     #[error("File already exists")]
53*bb4ee6a4SAndroid Build Coastguard Worker     FileAlreadyExists,
54*bb4ee6a4SAndroid Build Coastguard Worker 
55*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Data blob's size too large: overflowed u32")]
56*bb4ee6a4SAndroid Build Coastguard Worker     SizeOverflow,
57*bb4ee6a4SAndroid Build Coastguard Worker 
58*bb4ee6a4SAndroid Build Coastguard Worker     #[error("too many entries: oveflows u16 selector")]
59*bb4ee6a4SAndroid Build Coastguard Worker     IndexOverflow,
60*bb4ee6a4SAndroid Build Coastguard Worker 
61*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Filename must be less than 55 characters long")]
62*bb4ee6a4SAndroid Build Coastguard Worker     FileNameTooLong,
63*bb4ee6a4SAndroid Build Coastguard Worker 
64*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Unable to open file {0} for fw_cfg: {1}")]
65*bb4ee6a4SAndroid Build Coastguard Worker     FileOpen(PathBuf, std::io::Error),
66*bb4ee6a4SAndroid Build Coastguard Worker 
67*bb4ee6a4SAndroid Build Coastguard Worker     #[error("fw_cfg parameters must have exactly one of string or path")]
68*bb4ee6a4SAndroid Build Coastguard Worker     StringOrPathRequired,
69*bb4ee6a4SAndroid Build Coastguard Worker }
70*bb4ee6a4SAndroid Build Coastguard Worker 
71*bb4ee6a4SAndroid Build Coastguard Worker pub type Result<T> = std::result::Result<T, Error>;
72*bb4ee6a4SAndroid Build Coastguard Worker 
73*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Debug, Deserialize, Serialize, FromKeyValues, PartialEq, Eq)]
74*bb4ee6a4SAndroid Build Coastguard Worker #[serde(deny_unknown_fields, rename_all = "kebab-case")]
75*bb4ee6a4SAndroid Build Coastguard Worker pub struct FwCfgParameters {
76*bb4ee6a4SAndroid Build Coastguard Worker     pub name: String,
77*bb4ee6a4SAndroid Build Coastguard Worker     pub string: Option<String>,
78*bb4ee6a4SAndroid Build Coastguard Worker     pub path: Option<PathBuf>,
79*bb4ee6a4SAndroid Build Coastguard Worker }
80*bb4ee6a4SAndroid Build Coastguard Worker 
81*bb4ee6a4SAndroid Build Coastguard Worker #[derive(PartialEq)]
82*bb4ee6a4SAndroid Build Coastguard Worker pub enum FwCfgItemType {
83*bb4ee6a4SAndroid Build Coastguard Worker     GenericItem,
84*bb4ee6a4SAndroid Build Coastguard Worker     ArchSpecificItem,
85*bb4ee6a4SAndroid Build Coastguard Worker     FileDir,
86*bb4ee6a4SAndroid Build Coastguard Worker     Signature,
87*bb4ee6a4SAndroid Build Coastguard Worker     RevisionVector,
88*bb4ee6a4SAndroid Build Coastguard Worker }
89*bb4ee6a4SAndroid Build Coastguard Worker 
90*bb4ee6a4SAndroid Build Coastguard Worker impl FwCfgItemType {
value(&self) -> usize91*bb4ee6a4SAndroid Build Coastguard Worker     fn value(&self) -> usize {
92*bb4ee6a4SAndroid Build Coastguard Worker         match self {
93*bb4ee6a4SAndroid Build Coastguard Worker             FwCfgItemType::ArchSpecificItem => 1,
94*bb4ee6a4SAndroid Build Coastguard Worker             _ => 0,
95*bb4ee6a4SAndroid Build Coastguard Worker         }
96*bb4ee6a4SAndroid Build Coastguard Worker     }
97*bb4ee6a4SAndroid Build Coastguard Worker }
98*bb4ee6a4SAndroid Build Coastguard Worker 
99*bb4ee6a4SAndroid Build Coastguard Worker // Contains metadata about the entries stored in fw_cfg.
100*bb4ee6a4SAndroid Build Coastguard Worker // FwCfgFile is exposed to the the guest
101*bb4ee6a4SAndroid Build Coastguard Worker // so that the guest may search for the entry
102*bb4ee6a4SAndroid Build Coastguard Worker // with the desired filename and obtain its 16-bit-wide select
103*bb4ee6a4SAndroid Build Coastguard Worker // key to write to the control register
104*bb4ee6a4SAndroid Build Coastguard Worker struct FwCfgFile {
105*bb4ee6a4SAndroid Build Coastguard Worker     pub size: u32,
106*bb4ee6a4SAndroid Build Coastguard Worker     pub select: u16,
107*bb4ee6a4SAndroid Build Coastguard Worker     pub name: String,
108*bb4ee6a4SAndroid Build Coastguard Worker }
109*bb4ee6a4SAndroid Build Coastguard Worker 
110*bb4ee6a4SAndroid Build Coastguard Worker // Contains the actual data. The data is represented as an
111*bb4ee6a4SAndroid Build Coastguard Worker // array of u8 to conviently pass
112*bb4ee6a4SAndroid Build Coastguard Worker // a data item byte-by-byte when read() is called
113*bb4ee6a4SAndroid Build Coastguard Worker // on that item
114*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone)]
115*bb4ee6a4SAndroid Build Coastguard Worker struct FwCfgEntry {
116*bb4ee6a4SAndroid Build Coastguard Worker     pub allow_write: bool,
117*bb4ee6a4SAndroid Build Coastguard Worker     pub data: Vec<u8>,
118*bb4ee6a4SAndroid Build Coastguard Worker }
119*bb4ee6a4SAndroid Build Coastguard Worker 
120*bb4ee6a4SAndroid Build Coastguard Worker // Device exposed to the rest of crosvm. Contains state information in addition to arrays of
121*bb4ee6a4SAndroid Build Coastguard Worker // FwCfgEntry and FwCfgFile. cur_entry keeps the index of the currently selected entry. cur_offset
122*bb4ee6a4SAndroid Build Coastguard Worker // keeps the byte offset within cur_entry. Storing cur_offset is neccessary because the data IO port
123*bb4ee6a4SAndroid Build Coastguard Worker // is only 8 bits wide, so a call to read() will only retrieve one 8 bit chunk of data at a time.
124*bb4ee6a4SAndroid Build Coastguard Worker // cur_offset allows for a data item larger than 8 bits to be read through multiple calls to read(),
125*bb4ee6a4SAndroid Build Coastguard Worker // maintaining the position of the current read and incrementing across calls to read().
126*bb4ee6a4SAndroid Build Coastguard Worker pub struct FwCfgDevice {
127*bb4ee6a4SAndroid Build Coastguard Worker     file_slots: usize,
128*bb4ee6a4SAndroid Build Coastguard Worker     // entries[0] holds generic fw_cfg items in addition to special items (file dir, signature, and
129*bb4ee6a4SAndroid Build Coastguard Worker     // revision vector). entries[1] holds arch-specific items.
130*bb4ee6a4SAndroid Build Coastguard Worker     entries: [Vec<FwCfgEntry>; 2],
131*bb4ee6a4SAndroid Build Coastguard Worker     files: Vec<FwCfgFile>,
132*bb4ee6a4SAndroid Build Coastguard Worker     cur_item_type: FwCfgItemType,
133*bb4ee6a4SAndroid Build Coastguard Worker     cur_entry: u16,
134*bb4ee6a4SAndroid Build Coastguard Worker     cur_offset: usize,
135*bb4ee6a4SAndroid Build Coastguard Worker     file_names: HashSet<String>,
136*bb4ee6a4SAndroid Build Coastguard Worker }
137*bb4ee6a4SAndroid Build Coastguard Worker 
138*bb4ee6a4SAndroid Build Coastguard Worker impl FwCfgDevice {
new(file_slots: usize, fw_cfg_parameters: Vec<FwCfgParameters>) -> Result<FwCfgDevice>139*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(file_slots: usize, fw_cfg_parameters: Vec<FwCfgParameters>) -> Result<FwCfgDevice> {
140*bb4ee6a4SAndroid Build Coastguard Worker         let mut device = FwCfgDevice {
141*bb4ee6a4SAndroid Build Coastguard Worker             file_slots,
142*bb4ee6a4SAndroid Build Coastguard Worker             entries: [
143*bb4ee6a4SAndroid Build Coastguard Worker                 vec![
144*bb4ee6a4SAndroid Build Coastguard Worker                     FwCfgEntry {
145*bb4ee6a4SAndroid Build Coastguard Worker                         allow_write: false,
146*bb4ee6a4SAndroid Build Coastguard Worker                         data: vec![]
147*bb4ee6a4SAndroid Build Coastguard Worker                     };
148*bb4ee6a4SAndroid Build Coastguard Worker                     FW_CFG_FILE_FIRST
149*bb4ee6a4SAndroid Build Coastguard Worker                 ],
150*bb4ee6a4SAndroid Build Coastguard Worker                 Vec::new(),
151*bb4ee6a4SAndroid Build Coastguard Worker             ],
152*bb4ee6a4SAndroid Build Coastguard Worker             files: Vec::new(),
153*bb4ee6a4SAndroid Build Coastguard Worker             cur_item_type: FwCfgItemType::GenericItem,
154*bb4ee6a4SAndroid Build Coastguard Worker             cur_entry: 0,
155*bb4ee6a4SAndroid Build Coastguard Worker             cur_offset: 0,
156*bb4ee6a4SAndroid Build Coastguard Worker             file_names: HashSet::new(),
157*bb4ee6a4SAndroid Build Coastguard Worker         };
158*bb4ee6a4SAndroid Build Coastguard Worker 
159*bb4ee6a4SAndroid Build Coastguard Worker         for param in fw_cfg_parameters {
160*bb4ee6a4SAndroid Build Coastguard Worker             let data = match (&param.string, &param.path) {
161*bb4ee6a4SAndroid Build Coastguard Worker                 (Some(string), None) => string.as_bytes().to_vec(),
162*bb4ee6a4SAndroid Build Coastguard Worker                 (None, Some(path)) => {
163*bb4ee6a4SAndroid Build Coastguard Worker                     fs::read(path).map_err(|e| Error::FileOpen(path.clone(), e))?
164*bb4ee6a4SAndroid Build Coastguard Worker                 }
165*bb4ee6a4SAndroid Build Coastguard Worker                 _ => return Err(Error::StringOrPathRequired),
166*bb4ee6a4SAndroid Build Coastguard Worker             };
167*bb4ee6a4SAndroid Build Coastguard Worker 
168*bb4ee6a4SAndroid Build Coastguard Worker             // The file added from the command line will be a generic item. QEMU does not
169*bb4ee6a4SAndroid Build Coastguard Worker             // give users the option to specify whether the user-specified blob is
170*bb4ee6a4SAndroid Build Coastguard Worker             // arch-specific, so we won't either.
171*bb4ee6a4SAndroid Build Coastguard Worker             device.add_file(&param.name, data, FwCfgItemType::GenericItem)?
172*bb4ee6a4SAndroid Build Coastguard Worker         }
173*bb4ee6a4SAndroid Build Coastguard Worker 
174*bb4ee6a4SAndroid Build Coastguard Worker         device.add_bytes(FW_CFG_SIGNATURE.to_vec(), FwCfgItemType::Signature);
175*bb4ee6a4SAndroid Build Coastguard Worker         device.add_bytes(FW_CFG_REVISION.to_vec(), FwCfgItemType::RevisionVector);
176*bb4ee6a4SAndroid Build Coastguard Worker 
177*bb4ee6a4SAndroid Build Coastguard Worker         Ok(device)
178*bb4ee6a4SAndroid Build Coastguard Worker     }
179*bb4ee6a4SAndroid Build Coastguard Worker 
180*bb4ee6a4SAndroid Build Coastguard Worker     /// Adds a file to the device.
181*bb4ee6a4SAndroid Build Coastguard Worker     ///
182*bb4ee6a4SAndroid Build Coastguard Worker     /// # Arguments
183*bb4ee6a4SAndroid Build Coastguard Worker     ///
184*bb4ee6a4SAndroid Build Coastguard Worker     /// - `filename`: Name of file. Must be valid a Unix-style filename
185*bb4ee6a4SAndroid Build Coastguard Worker     /// - `data`: File data as bytes
add_file( &mut self, filename: &str, data: Vec<u8>, item_type: FwCfgItemType, ) -> Result<()>186*bb4ee6a4SAndroid Build Coastguard Worker     pub fn add_file(
187*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
188*bb4ee6a4SAndroid Build Coastguard Worker         filename: &str,
189*bb4ee6a4SAndroid Build Coastguard Worker         data: Vec<u8>,
190*bb4ee6a4SAndroid Build Coastguard Worker         item_type: FwCfgItemType,
191*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<()> {
192*bb4ee6a4SAndroid Build Coastguard Worker         // Adds a data blob to the device under the name filename. This entails creating an
193*bb4ee6a4SAndroid Build Coastguard Worker         // FwCfgEntry and its associated FwCfgFile and adding them to FwCfgDevice.
194*bb4ee6a4SAndroid Build Coastguard Worker 
195*bb4ee6a4SAndroid Build Coastguard Worker         if self.files.len() >= FW_CFG_MAX_FILE_SLOTS || self.files.len() >= self.file_slots {
196*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::InsufficientFileSlots);
197*bb4ee6a4SAndroid Build Coastguard Worker         }
198*bb4ee6a4SAndroid Build Coastguard Worker 
199*bb4ee6a4SAndroid Build Coastguard Worker         if filename.len() > FW_CFG_FILENAME_SIZE - 1 {
200*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::FileNameTooLong);
201*bb4ee6a4SAndroid Build Coastguard Worker         }
202*bb4ee6a4SAndroid Build Coastguard Worker 
203*bb4ee6a4SAndroid Build Coastguard Worker         // No need to worry about endianess in this function. We will deal with this in read(). We
204*bb4ee6a4SAndroid Build Coastguard Worker         // are only using FwCfgFile internally.
205*bb4ee6a4SAndroid Build Coastguard Worker         let index = self.entries[item_type.value()].len();
206*bb4ee6a4SAndroid Build Coastguard Worker 
207*bb4ee6a4SAndroid Build Coastguard Worker         if self.file_names.contains(filename) {
208*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::FileAlreadyExists);
209*bb4ee6a4SAndroid Build Coastguard Worker         }
210*bb4ee6a4SAndroid Build Coastguard Worker 
211*bb4ee6a4SAndroid Build Coastguard Worker         // Since the size field of an entry is stored as a u32, the largest file that can be stored
212*bb4ee6a4SAndroid Build Coastguard Worker         // in the device is 2^32 - 1 ~ 4GB
213*bb4ee6a4SAndroid Build Coastguard Worker         let size: u32 = data.len().try_into().map_err(|_| Error::SizeOverflow)?;
214*bb4ee6a4SAndroid Build Coastguard Worker 
215*bb4ee6a4SAndroid Build Coastguard Worker         let mut select: u16 = (index).try_into().map_err(|_| Error::IndexOverflow)?;
216*bb4ee6a4SAndroid Build Coastguard Worker 
217*bb4ee6a4SAndroid Build Coastguard Worker         if item_type == FwCfgItemType::ArchSpecificItem {
218*bb4ee6a4SAndroid Build Coastguard Worker             select |= FW_CFG_SELECTOR_ARCH_MASK;
219*bb4ee6a4SAndroid Build Coastguard Worker         }
220*bb4ee6a4SAndroid Build Coastguard Worker 
221*bb4ee6a4SAndroid Build Coastguard Worker         let new_file = FwCfgFile {
222*bb4ee6a4SAndroid Build Coastguard Worker             size,
223*bb4ee6a4SAndroid Build Coastguard Worker             select,
224*bb4ee6a4SAndroid Build Coastguard Worker             name: filename.to_owned(),
225*bb4ee6a4SAndroid Build Coastguard Worker         };
226*bb4ee6a4SAndroid Build Coastguard Worker 
227*bb4ee6a4SAndroid Build Coastguard Worker         self.add_bytes(data, item_type);
228*bb4ee6a4SAndroid Build Coastguard Worker         self.files.push(new_file);
229*bb4ee6a4SAndroid Build Coastguard Worker         self.file_names.insert(filename.to_string());
230*bb4ee6a4SAndroid Build Coastguard Worker         // We need to update the file_dir entry every time we insert a new file.
231*bb4ee6a4SAndroid Build Coastguard Worker         self.update_file_dir_entry();
232*bb4ee6a4SAndroid Build Coastguard Worker 
233*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
234*bb4ee6a4SAndroid Build Coastguard Worker     }
235*bb4ee6a4SAndroid Build Coastguard Worker 
add_bytes(&mut self, data: Vec<u8>, item_type: FwCfgItemType)236*bb4ee6a4SAndroid Build Coastguard Worker     fn add_bytes(&mut self, data: Vec<u8>, item_type: FwCfgItemType) {
237*bb4ee6a4SAndroid Build Coastguard Worker         // Add a FwCfgEntry to FwCfgDevice's entries array
238*bb4ee6a4SAndroid Build Coastguard Worker 
239*bb4ee6a4SAndroid Build Coastguard Worker         let new_entry = FwCfgEntry {
240*bb4ee6a4SAndroid Build Coastguard Worker             allow_write: false,
241*bb4ee6a4SAndroid Build Coastguard Worker             data,
242*bb4ee6a4SAndroid Build Coastguard Worker         };
243*bb4ee6a4SAndroid Build Coastguard Worker 
244*bb4ee6a4SAndroid Build Coastguard Worker         match item_type {
245*bb4ee6a4SAndroid Build Coastguard Worker             FwCfgItemType::GenericItem | FwCfgItemType::ArchSpecificItem => {
246*bb4ee6a4SAndroid Build Coastguard Worker                 self.entries[item_type.value()].push(new_entry)
247*bb4ee6a4SAndroid Build Coastguard Worker             }
248*bb4ee6a4SAndroid Build Coastguard Worker             FwCfgItemType::FileDir => {
249*bb4ee6a4SAndroid Build Coastguard Worker                 self.entries[item_type.value()][FW_CFG_FILE_DIR_SELECTOR as usize] = new_entry
250*bb4ee6a4SAndroid Build Coastguard Worker             }
251*bb4ee6a4SAndroid Build Coastguard Worker             FwCfgItemType::Signature => {
252*bb4ee6a4SAndroid Build Coastguard Worker                 self.entries[item_type.value()][FW_CFG_SIGNATURE_SELECTOR as usize] = new_entry
253*bb4ee6a4SAndroid Build Coastguard Worker             }
254*bb4ee6a4SAndroid Build Coastguard Worker             FwCfgItemType::RevisionVector => {
255*bb4ee6a4SAndroid Build Coastguard Worker                 self.entries[item_type.value()][FW_CFG_REVISION_SELECTOR as usize] = new_entry
256*bb4ee6a4SAndroid Build Coastguard Worker             }
257*bb4ee6a4SAndroid Build Coastguard Worker         }
258*bb4ee6a4SAndroid Build Coastguard Worker     }
259*bb4ee6a4SAndroid Build Coastguard Worker 
update_file_dir_entry(&mut self)260*bb4ee6a4SAndroid Build Coastguard Worker     fn update_file_dir_entry(&mut self) {
261*bb4ee6a4SAndroid Build Coastguard Worker         let mut raw_file_dir: Vec<u8> = Vec::new();
262*bb4ee6a4SAndroid Build Coastguard Worker         // casting to u32 should not be problematic. insert_file() assures that there can be no
263*bb4ee6a4SAndroid Build Coastguard Worker         // more than 2^14 items in the device.
264*bb4ee6a4SAndroid Build Coastguard Worker         let files_dir_count = self.files.len() as u32;
265*bb4ee6a4SAndroid Build Coastguard Worker         raw_file_dir.extend_from_slice(&files_dir_count.to_be_bytes());
266*bb4ee6a4SAndroid Build Coastguard Worker 
267*bb4ee6a4SAndroid Build Coastguard Worker         for file in &self.files {
268*bb4ee6a4SAndroid Build Coastguard Worker             raw_file_dir.extend_from_slice(&file.size.to_be_bytes());
269*bb4ee6a4SAndroid Build Coastguard Worker             raw_file_dir.extend_from_slice(&file.select.to_be_bytes());
270*bb4ee6a4SAndroid Build Coastguard Worker             // The caller expects a "reserved" field to be present on each FwCfgFile. Since
271*bb4ee6a4SAndroid Build Coastguard Worker             // we always set the field to zero, we don't bother to store it on FwCfgDevice and
272*bb4ee6a4SAndroid Build Coastguard Worker             // return zero unconditionally.
273*bb4ee6a4SAndroid Build Coastguard Worker             raw_file_dir.extend_from_slice(&[0, 0]);
274*bb4ee6a4SAndroid Build Coastguard Worker             raw_file_dir.extend_from_slice(file.name.as_bytes());
275*bb4ee6a4SAndroid Build Coastguard Worker             // Padding for c-style char[]
276*bb4ee6a4SAndroid Build Coastguard Worker             raw_file_dir.extend(repeat(0).take(FW_CFG_FILENAME_SIZE - file.name.as_bytes().len()));
277*bb4ee6a4SAndroid Build Coastguard Worker         }
278*bb4ee6a4SAndroid Build Coastguard Worker 
279*bb4ee6a4SAndroid Build Coastguard Worker         self.add_bytes(raw_file_dir, FwCfgItemType::FileDir);
280*bb4ee6a4SAndroid Build Coastguard Worker     }
281*bb4ee6a4SAndroid Build Coastguard Worker }
282*bb4ee6a4SAndroid Build Coastguard Worker 
283*bb4ee6a4SAndroid Build Coastguard Worker // We implement two 8-bit registers: a Selector(Control) Register and a Data Register
284*bb4ee6a4SAndroid Build Coastguard Worker impl BusDevice for FwCfgDevice {
device_id(&self) -> DeviceId285*bb4ee6a4SAndroid Build Coastguard Worker     fn device_id(&self) -> DeviceId {
286*bb4ee6a4SAndroid Build Coastguard Worker         super::CrosvmDeviceId::FwCfg.into()
287*bb4ee6a4SAndroid Build Coastguard Worker     }
288*bb4ee6a4SAndroid Build Coastguard Worker 
debug_label(&self) -> String289*bb4ee6a4SAndroid Build Coastguard Worker     fn debug_label(&self) -> String {
290*bb4ee6a4SAndroid Build Coastguard Worker         "FwCfg".to_owned()
291*bb4ee6a4SAndroid Build Coastguard Worker     }
292*bb4ee6a4SAndroid Build Coastguard Worker 
293*bb4ee6a4SAndroid Build Coastguard Worker     // Read a byte from the FwCfgDevice. The byte read is based on the current state of the device.
read(&mut self, info: BusAccessInfo, data: &mut [u8])294*bb4ee6a4SAndroid Build Coastguard Worker     fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
295*bb4ee6a4SAndroid Build Coastguard Worker         if data.len() != 1 {
296*bb4ee6a4SAndroid Build Coastguard Worker             return;
297*bb4ee6a4SAndroid Build Coastguard Worker         }
298*bb4ee6a4SAndroid Build Coastguard Worker 
299*bb4ee6a4SAndroid Build Coastguard Worker         // Attemping to read anything other than the data port is a NOP
300*bb4ee6a4SAndroid Build Coastguard Worker         if info.offset == FW_CFG_DATA_PORT_OFFSET {
301*bb4ee6a4SAndroid Build Coastguard Worker             let entries_index = self.cur_entry as usize;
302*bb4ee6a4SAndroid Build Coastguard Worker             // If the caller attempts to read bytes past the current entry, read returns
303*bb4ee6a4SAndroid Build Coastguard Worker             // zero
304*bb4ee6a4SAndroid Build Coastguard Worker             if self.cur_offset
305*bb4ee6a4SAndroid Build Coastguard Worker                 >= self.entries[self.cur_item_type.value()][entries_index]
306*bb4ee6a4SAndroid Build Coastguard Worker                     .data
307*bb4ee6a4SAndroid Build Coastguard Worker                     .len()
308*bb4ee6a4SAndroid Build Coastguard Worker             {
309*bb4ee6a4SAndroid Build Coastguard Worker                 data[0] = 0x00;
310*bb4ee6a4SAndroid Build Coastguard Worker                 return;
311*bb4ee6a4SAndroid Build Coastguard Worker             }
312*bb4ee6a4SAndroid Build Coastguard Worker             data[0] = self.entries[self.cur_item_type.value()][entries_index].data[self.cur_offset];
313*bb4ee6a4SAndroid Build Coastguard Worker             self.cur_offset += 1;
314*bb4ee6a4SAndroid Build Coastguard Worker         }
315*bb4ee6a4SAndroid Build Coastguard Worker     }
316*bb4ee6a4SAndroid Build Coastguard Worker 
317*bb4ee6a4SAndroid Build Coastguard Worker     // Write to the FwCfgDevice. Used to set the select register.
write(&mut self, info: BusAccessInfo, data: &[u8])318*bb4ee6a4SAndroid Build Coastguard Worker     fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
319*bb4ee6a4SAndroid Build Coastguard Worker         // Attempting to write to any port other than the data port is a NOP
320*bb4ee6a4SAndroid Build Coastguard Worker         if info.offset == FW_CFG_SELECTOR_PORT_OFFSET {
321*bb4ee6a4SAndroid Build Coastguard Worker             if data.len() != 2 {
322*bb4ee6a4SAndroid Build Coastguard Worker                 return;
323*bb4ee6a4SAndroid Build Coastguard Worker             }
324*bb4ee6a4SAndroid Build Coastguard Worker 
325*bb4ee6a4SAndroid Build Coastguard Worker             let Ok(selector) = data.try_into().map(u16::from_le_bytes) else {
326*bb4ee6a4SAndroid Build Coastguard Worker                 return;
327*bb4ee6a4SAndroid Build Coastguard Worker             };
328*bb4ee6a4SAndroid Build Coastguard Worker 
329*bb4ee6a4SAndroid Build Coastguard Worker             self.cur_offset = 0;
330*bb4ee6a4SAndroid Build Coastguard Worker 
331*bb4ee6a4SAndroid Build Coastguard Worker             match selector {
332*bb4ee6a4SAndroid Build Coastguard Worker                 FW_CFG_FILE_DIR_SELECTOR => {
333*bb4ee6a4SAndroid Build Coastguard Worker                     self.cur_entry = FW_CFG_FILE_DIR_SELECTOR;
334*bb4ee6a4SAndroid Build Coastguard Worker                 }
335*bb4ee6a4SAndroid Build Coastguard Worker                 FW_CFG_REVISION_SELECTOR => {
336*bb4ee6a4SAndroid Build Coastguard Worker                     self.cur_entry = FW_CFG_REVISION_SELECTOR;
337*bb4ee6a4SAndroid Build Coastguard Worker                 }
338*bb4ee6a4SAndroid Build Coastguard Worker                 FW_CFG_SIGNATURE_SELECTOR => {
339*bb4ee6a4SAndroid Build Coastguard Worker                     self.cur_entry = FW_CFG_SIGNATURE_SELECTOR;
340*bb4ee6a4SAndroid Build Coastguard Worker                 }
341*bb4ee6a4SAndroid Build Coastguard Worker                 _ => {
342*bb4ee6a4SAndroid Build Coastguard Worker                     let entries_index = selector as usize;
343*bb4ee6a4SAndroid Build Coastguard Worker 
344*bb4ee6a4SAndroid Build Coastguard Worker                     // Checks if the 15th bit is set. The bit indicates whether the fw_cfg item
345*bb4ee6a4SAndroid Build Coastguard Worker                     // selected is archetecture specific.
346*bb4ee6a4SAndroid Build Coastguard Worker                     if (FW_CFG_SELECTOR_ARCH_MASK & selector) > 0 {
347*bb4ee6a4SAndroid Build Coastguard Worker                         self.cur_item_type = FwCfgItemType::ArchSpecificItem;
348*bb4ee6a4SAndroid Build Coastguard Worker                     } else {
349*bb4ee6a4SAndroid Build Coastguard Worker                         self.cur_item_type = FwCfgItemType::GenericItem;
350*bb4ee6a4SAndroid Build Coastguard Worker                     }
351*bb4ee6a4SAndroid Build Coastguard Worker 
352*bb4ee6a4SAndroid Build Coastguard Worker                     // Check if the selector key is valid.
353*bb4ee6a4SAndroid Build Coastguard Worker                     if self.entries[self.cur_item_type.value()].len() <= entries_index {
354*bb4ee6a4SAndroid Build Coastguard Worker                         return;
355*bb4ee6a4SAndroid Build Coastguard Worker                     }
356*bb4ee6a4SAndroid Build Coastguard Worker 
357*bb4ee6a4SAndroid Build Coastguard Worker                     // Checks if the 14th bit is set. The bit indicates whether the fw_cfg item
358*bb4ee6a4SAndroid Build Coastguard Worker                     // selected is going to be written to or only read via the data port. Since
359*bb4ee6a4SAndroid Build Coastguard Worker                     // writes to the data port have been deprecated as of Qemu v2.4, we don't
360*bb4ee6a4SAndroid Build Coastguard Worker                     // support them either. This code is only included for clarity.
361*bb4ee6a4SAndroid Build Coastguard Worker                     self.entries[self.cur_item_type.value()][entries_index].allow_write =
362*bb4ee6a4SAndroid Build Coastguard Worker                         (FW_CFG_SELECTOR_RW_MASK & selector) > 0;
363*bb4ee6a4SAndroid Build Coastguard Worker 
364*bb4ee6a4SAndroid Build Coastguard Worker                     // Checks if the 15th bit is set. The bit indicates whether the fw_cfg item
365*bb4ee6a4SAndroid Build Coastguard Worker                     // selected is archetecture specific.
366*bb4ee6a4SAndroid Build Coastguard Worker                     if (FW_CFG_SELECTOR_ARCH_MASK & selector) > 0 {
367*bb4ee6a4SAndroid Build Coastguard Worker                         self.cur_item_type = FwCfgItemType::ArchSpecificItem;
368*bb4ee6a4SAndroid Build Coastguard Worker                     } else {
369*bb4ee6a4SAndroid Build Coastguard Worker                         self.cur_item_type = FwCfgItemType::GenericItem;
370*bb4ee6a4SAndroid Build Coastguard Worker                     }
371*bb4ee6a4SAndroid Build Coastguard Worker 
372*bb4ee6a4SAndroid Build Coastguard Worker                     // Only the lower 14 bits are used for actual indexing. The 14th bit
373*bb4ee6a4SAndroid Build Coastguard Worker                     // determines whether the data item will be written to or only read
374*bb4ee6a4SAndroid Build Coastguard Worker                     // from the data port. The 15th bit determines whether the selected
375*bb4ee6a4SAndroid Build Coastguard Worker                     // configuration item is architecture specific. Therefore, we mask the 14th
376*bb4ee6a4SAndroid Build Coastguard Worker                     // and 15th bit off.
377*bb4ee6a4SAndroid Build Coastguard Worker                     self.cur_entry = selector & FW_CFG_SELECTOR_SELECT_MASK;
378*bb4ee6a4SAndroid Build Coastguard Worker                 }
379*bb4ee6a4SAndroid Build Coastguard Worker             }
380*bb4ee6a4SAndroid Build Coastguard Worker         }
381*bb4ee6a4SAndroid Build Coastguard Worker     }
382*bb4ee6a4SAndroid Build Coastguard Worker }
383*bb4ee6a4SAndroid Build Coastguard Worker 
384*bb4ee6a4SAndroid Build Coastguard Worker impl Suspendable for FwCfgDevice {
sleep(&mut self) -> anyhow::Result<()>385*bb4ee6a4SAndroid Build Coastguard Worker     fn sleep(&mut self) -> anyhow::Result<()> {
386*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
387*bb4ee6a4SAndroid Build Coastguard Worker     }
388*bb4ee6a4SAndroid Build Coastguard Worker 
wake(&mut self) -> anyhow::Result<()>389*bb4ee6a4SAndroid Build Coastguard Worker     fn wake(&mut self) -> anyhow::Result<()> {
390*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
391*bb4ee6a4SAndroid Build Coastguard Worker     }
392*bb4ee6a4SAndroid Build Coastguard Worker }
393*bb4ee6a4SAndroid Build Coastguard Worker 
394*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
395*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
396*bb4ee6a4SAndroid Build Coastguard Worker     use serde_keyvalue::*;
397*bb4ee6a4SAndroid Build Coastguard Worker 
398*bb4ee6a4SAndroid Build Coastguard Worker     use super::*;
399*bb4ee6a4SAndroid Build Coastguard Worker     use crate::FW_CFG_BASE_PORT;
400*bb4ee6a4SAndroid Build Coastguard Worker 
401*bb4ee6a4SAndroid Build Coastguard Worker     const MAGIC_BYTE: u8 = 111;
402*bb4ee6a4SAndroid Build Coastguard Worker     const MAGIC_BYTE_ALT: u8 = 222;
403*bb4ee6a4SAndroid Build Coastguard Worker     const FILENAME: &str = "/test/device/crosvmval";
404*bb4ee6a4SAndroid Build Coastguard Worker     const FILENAMES: [&str; 6] = [
405*bb4ee6a4SAndroid Build Coastguard Worker         "test/hello.txt",
406*bb4ee6a4SAndroid Build Coastguard Worker         "user/data/mydata.txt",
407*bb4ee6a4SAndroid Build Coastguard Worker         "bruschetta/user/foo",
408*bb4ee6a4SAndroid Build Coastguard Worker         "valid_unix/me/home/dir/back.txt",
409*bb4ee6a4SAndroid Build Coastguard Worker         "/dev/null",
410*bb4ee6a4SAndroid Build Coastguard Worker         "google/unix/sys/maple.txt",
411*bb4ee6a4SAndroid Build Coastguard Worker     ];
412*bb4ee6a4SAndroid Build Coastguard Worker 
default_params() -> Vec<FwCfgParameters>413*bb4ee6a4SAndroid Build Coastguard Worker     fn default_params() -> Vec<FwCfgParameters> {
414*bb4ee6a4SAndroid Build Coastguard Worker         Vec::new()
415*bb4ee6a4SAndroid Build Coastguard Worker     }
416*bb4ee6a4SAndroid Build Coastguard Worker 
get_contents() -> [Vec<u8>; 6]417*bb4ee6a4SAndroid Build Coastguard Worker     fn get_contents() -> [Vec<u8>; 6] {
418*bb4ee6a4SAndroid Build Coastguard Worker         [
419*bb4ee6a4SAndroid Build Coastguard Worker             b"CROSVM".to_vec(),
420*bb4ee6a4SAndroid Build Coastguard Worker             b"GOOGLE".to_vec(),
421*bb4ee6a4SAndroid Build Coastguard Worker             b"FWCONFIG".to_vec(),
422*bb4ee6a4SAndroid Build Coastguard Worker             b"PIZZA".to_vec(),
423*bb4ee6a4SAndroid Build Coastguard Worker             b"CHROMEOS".to_vec(),
424*bb4ee6a4SAndroid Build Coastguard Worker             b"42".to_vec(),
425*bb4ee6a4SAndroid Build Coastguard Worker         ]
426*bb4ee6a4SAndroid Build Coastguard Worker     }
427*bb4ee6a4SAndroid Build Coastguard Worker 
make_device( filenames: &[&str], contents: &[Vec<u8>], params: &[FwCfgParameters], file_slots: &usize, ) -> Result<FwCfgDevice>428*bb4ee6a4SAndroid Build Coastguard Worker     fn make_device(
429*bb4ee6a4SAndroid Build Coastguard Worker         filenames: &[&str],
430*bb4ee6a4SAndroid Build Coastguard Worker         contents: &[Vec<u8>],
431*bb4ee6a4SAndroid Build Coastguard Worker         params: &[FwCfgParameters],
432*bb4ee6a4SAndroid Build Coastguard Worker         file_slots: &usize,
433*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<FwCfgDevice> {
434*bb4ee6a4SAndroid Build Coastguard Worker         let mut device = FwCfgDevice::new(*file_slots, params.to_owned())?;
435*bb4ee6a4SAndroid Build Coastguard Worker         let count = filenames.len();
436*bb4ee6a4SAndroid Build Coastguard Worker 
437*bb4ee6a4SAndroid Build Coastguard Worker         for i in 0..count {
438*bb4ee6a4SAndroid Build Coastguard Worker             device.add_file(
439*bb4ee6a4SAndroid Build Coastguard Worker                 filenames[i],
440*bb4ee6a4SAndroid Build Coastguard Worker                 contents[i].clone(),
441*bb4ee6a4SAndroid Build Coastguard Worker                 FwCfgItemType::GenericItem,
442*bb4ee6a4SAndroid Build Coastguard Worker             )?;
443*bb4ee6a4SAndroid Build Coastguard Worker         }
444*bb4ee6a4SAndroid Build Coastguard Worker 
445*bb4ee6a4SAndroid Build Coastguard Worker         Ok(device)
446*bb4ee6a4SAndroid Build Coastguard Worker     }
447*bb4ee6a4SAndroid Build Coastguard Worker 
from_fw_cfg_arg(options: &str) -> std::result::Result<FwCfgParameters, ParseError>448*bb4ee6a4SAndroid Build Coastguard Worker     fn from_fw_cfg_arg(options: &str) -> std::result::Result<FwCfgParameters, ParseError> {
449*bb4ee6a4SAndroid Build Coastguard Worker         from_key_values(options)
450*bb4ee6a4SAndroid Build Coastguard Worker     }
451*bb4ee6a4SAndroid Build Coastguard Worker 
read_u32(device: &mut FwCfgDevice, bai: BusAccessInfo, data: &mut [u8]) -> u32452*bb4ee6a4SAndroid Build Coastguard Worker     fn read_u32(device: &mut FwCfgDevice, bai: BusAccessInfo, data: &mut [u8]) -> u32 {
453*bb4ee6a4SAndroid Build Coastguard Worker         let mut bytes: [u8; 4] = [0, 0, 0, 0];
454*bb4ee6a4SAndroid Build Coastguard Worker         device.read(bai, data);
455*bb4ee6a4SAndroid Build Coastguard Worker         bytes[0] = data[0];
456*bb4ee6a4SAndroid Build Coastguard Worker         device.read(bai, data);
457*bb4ee6a4SAndroid Build Coastguard Worker         bytes[1] = data[0];
458*bb4ee6a4SAndroid Build Coastguard Worker         device.read(bai, data);
459*bb4ee6a4SAndroid Build Coastguard Worker         bytes[2] = data[0];
460*bb4ee6a4SAndroid Build Coastguard Worker         device.read(bai, data);
461*bb4ee6a4SAndroid Build Coastguard Worker         bytes[3] = data[0];
462*bb4ee6a4SAndroid Build Coastguard Worker 
463*bb4ee6a4SAndroid Build Coastguard Worker         u32::from_be_bytes(bytes)
464*bb4ee6a4SAndroid Build Coastguard Worker     }
465*bb4ee6a4SAndroid Build Coastguard Worker 
read_u16(device: &mut FwCfgDevice, bai: BusAccessInfo, data: &mut [u8]) -> u16466*bb4ee6a4SAndroid Build Coastguard Worker     fn read_u16(device: &mut FwCfgDevice, bai: BusAccessInfo, data: &mut [u8]) -> u16 {
467*bb4ee6a4SAndroid Build Coastguard Worker         let mut bytes: [u8; 2] = [0, 0];
468*bb4ee6a4SAndroid Build Coastguard Worker         device.read(bai, data);
469*bb4ee6a4SAndroid Build Coastguard Worker         bytes[0] = data[0];
470*bb4ee6a4SAndroid Build Coastguard Worker         device.read(bai, data);
471*bb4ee6a4SAndroid Build Coastguard Worker         bytes[1] = data[0];
472*bb4ee6a4SAndroid Build Coastguard Worker 
473*bb4ee6a4SAndroid Build Coastguard Worker         u16::from_be_bytes(bytes)
474*bb4ee6a4SAndroid Build Coastguard Worker     }
475*bb4ee6a4SAndroid Build Coastguard Worker 
read_u8(device: &mut FwCfgDevice, bai: BusAccessInfo, data: &mut [u8]) -> u8476*bb4ee6a4SAndroid Build Coastguard Worker     fn read_u8(device: &mut FwCfgDevice, bai: BusAccessInfo, data: &mut [u8]) -> u8 {
477*bb4ee6a4SAndroid Build Coastguard Worker         let mut bytes: [u8; 1] = [0];
478*bb4ee6a4SAndroid Build Coastguard Worker         device.read(bai, data);
479*bb4ee6a4SAndroid Build Coastguard Worker         bytes[0] = data[0];
480*bb4ee6a4SAndroid Build Coastguard Worker         u8::from_be_bytes(bytes)
481*bb4ee6a4SAndroid Build Coastguard Worker     }
482*bb4ee6a4SAndroid Build Coastguard Worker 
read_char_56(device: &mut FwCfgDevice, bai: BusAccessInfo, data: &mut [u8]) -> String483*bb4ee6a4SAndroid Build Coastguard Worker     fn read_char_56(device: &mut FwCfgDevice, bai: BusAccessInfo, data: &mut [u8]) -> String {
484*bb4ee6a4SAndroid Build Coastguard Worker         let mut c: char = read_u8(device, bai, data) as char;
485*bb4ee6a4SAndroid Build Coastguard Worker         let mut count = 1; //start at 1 b/c called read_u8 above
486*bb4ee6a4SAndroid Build Coastguard Worker         let mut name: String = String::new();
487*bb4ee6a4SAndroid Build Coastguard Worker         while c != '\0' {
488*bb4ee6a4SAndroid Build Coastguard Worker             name.push(c);
489*bb4ee6a4SAndroid Build Coastguard Worker             c = read_u8(device, bai, data) as char;
490*bb4ee6a4SAndroid Build Coastguard Worker             count += 1;
491*bb4ee6a4SAndroid Build Coastguard Worker         }
492*bb4ee6a4SAndroid Build Coastguard Worker         while count < FW_CFG_FILENAME_SIZE {
493*bb4ee6a4SAndroid Build Coastguard Worker             read_u8(device, bai, data);
494*bb4ee6a4SAndroid Build Coastguard Worker             count += 1;
495*bb4ee6a4SAndroid Build Coastguard Worker         }
496*bb4ee6a4SAndroid Build Coastguard Worker         name
497*bb4ee6a4SAndroid Build Coastguard Worker     }
498*bb4ee6a4SAndroid Build Coastguard Worker 
get_entry( device: &mut FwCfgDevice, mut bai: BusAccessInfo, size: usize, selector: u16, ) -> Vec<u8>499*bb4ee6a4SAndroid Build Coastguard Worker     fn get_entry(
500*bb4ee6a4SAndroid Build Coastguard Worker         device: &mut FwCfgDevice,
501*bb4ee6a4SAndroid Build Coastguard Worker         mut bai: BusAccessInfo,
502*bb4ee6a4SAndroid Build Coastguard Worker         size: usize,
503*bb4ee6a4SAndroid Build Coastguard Worker         selector: u16,
504*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Vec<u8> {
505*bb4ee6a4SAndroid Build Coastguard Worker         let mut data: Vec<u8> = vec![0];
506*bb4ee6a4SAndroid Build Coastguard Worker         let mut blob: Vec<u8> = Vec::new();
507*bb4ee6a4SAndroid Build Coastguard Worker 
508*bb4ee6a4SAndroid Build Coastguard Worker         bai.address = FW_CFG_BASE_PORT;
509*bb4ee6a4SAndroid Build Coastguard Worker         bai.offset = FW_CFG_SELECTOR_PORT_OFFSET;
510*bb4ee6a4SAndroid Build Coastguard Worker         let selector: [u8; 2] = selector.to_le_bytes();
511*bb4ee6a4SAndroid Build Coastguard Worker         device.write(bai, &selector);
512*bb4ee6a4SAndroid Build Coastguard Worker 
513*bb4ee6a4SAndroid Build Coastguard Worker         bai.offset = FW_CFG_DATA_PORT_OFFSET;
514*bb4ee6a4SAndroid Build Coastguard Worker 
515*bb4ee6a4SAndroid Build Coastguard Worker         for _i in 0..size {
516*bb4ee6a4SAndroid Build Coastguard Worker             read_u8(device, bai, &mut data[..]);
517*bb4ee6a4SAndroid Build Coastguard Worker             blob.push(data[0]);
518*bb4ee6a4SAndroid Build Coastguard Worker         }
519*bb4ee6a4SAndroid Build Coastguard Worker 
520*bb4ee6a4SAndroid Build Coastguard Worker         blob
521*bb4ee6a4SAndroid Build Coastguard Worker     }
522*bb4ee6a4SAndroid Build Coastguard Worker 
assert_read_entries(filenames: &[&str], device: &mut FwCfgDevice, bai: BusAccessInfo)523*bb4ee6a4SAndroid Build Coastguard Worker     fn assert_read_entries(filenames: &[&str], device: &mut FwCfgDevice, bai: BusAccessInfo) {
524*bb4ee6a4SAndroid Build Coastguard Worker         let data_len = device.entries[0][0 + FW_CFG_FILE_FIRST].data.len();
525*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
526*bb4ee6a4SAndroid Build Coastguard Worker             get_entry(device, bai, data_len, (0 + FW_CFG_FILE_FIRST) as u16),
527*bb4ee6a4SAndroid Build Coastguard Worker             device.entries[0][0 + FW_CFG_FILE_FIRST].data
528*bb4ee6a4SAndroid Build Coastguard Worker         );
529*bb4ee6a4SAndroid Build Coastguard Worker 
530*bb4ee6a4SAndroid Build Coastguard Worker         for i in (FW_CFG_FILE_FIRST + 1)..filenames.len() {
531*bb4ee6a4SAndroid Build Coastguard Worker             let data_len = device.entries[0][i].data.len();
532*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(
533*bb4ee6a4SAndroid Build Coastguard Worker                 get_entry(device, bai, data_len, (i + FW_CFG_FILE_FIRST) as u16),
534*bb4ee6a4SAndroid Build Coastguard Worker                 device.entries[0][i].data
535*bb4ee6a4SAndroid Build Coastguard Worker             );
536*bb4ee6a4SAndroid Build Coastguard Worker         }
537*bb4ee6a4SAndroid Build Coastguard Worker     }
538*bb4ee6a4SAndroid Build Coastguard Worker 
assert_read_file_dir( filenames: &[&str], contents: &[Vec<u8>], device: &mut FwCfgDevice, bai: BusAccessInfo, )539*bb4ee6a4SAndroid Build Coastguard Worker     fn assert_read_file_dir(
540*bb4ee6a4SAndroid Build Coastguard Worker         filenames: &[&str],
541*bb4ee6a4SAndroid Build Coastguard Worker         contents: &[Vec<u8>],
542*bb4ee6a4SAndroid Build Coastguard Worker         device: &mut FwCfgDevice,
543*bb4ee6a4SAndroid Build Coastguard Worker         bai: BusAccessInfo,
544*bb4ee6a4SAndroid Build Coastguard Worker     ) {
545*bb4ee6a4SAndroid Build Coastguard Worker         let mut data: Vec<u8> = vec![0];
546*bb4ee6a4SAndroid Build Coastguard Worker         let file_count = read_u32(device, bai, &mut data[..]);
547*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(file_count, filenames.len() as u32);
548*bb4ee6a4SAndroid Build Coastguard Worker 
549*bb4ee6a4SAndroid Build Coastguard Worker         for i in 0..filenames.len() {
550*bb4ee6a4SAndroid Build Coastguard Worker             let file_size = read_u32(device, bai, &mut data[..]);
551*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(file_size, contents[i].len() as u32);
552*bb4ee6a4SAndroid Build Coastguard Worker 
553*bb4ee6a4SAndroid Build Coastguard Worker             let file_select = read_u16(device, bai, &mut data[..]);
554*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(file_select - (FW_CFG_FILE_FIRST as u16), i as u16);
555*bb4ee6a4SAndroid Build Coastguard Worker 
556*bb4ee6a4SAndroid Build Coastguard Worker             let file_reserved = read_u16(device, bai, &mut data[..]);
557*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(file_reserved, 0);
558*bb4ee6a4SAndroid Build Coastguard Worker 
559*bb4ee6a4SAndroid Build Coastguard Worker             let file_name = read_char_56(device, bai, &mut data[..]);
560*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(file_name, FILENAMES[i]);
561*bb4ee6a4SAndroid Build Coastguard Worker         }
562*bb4ee6a4SAndroid Build Coastguard Worker     }
setup_read( filenames: &[&str], contents: &[Vec<u8>], selector: u16, ) -> (FwCfgDevice, BusAccessInfo)563*bb4ee6a4SAndroid Build Coastguard Worker     fn setup_read(
564*bb4ee6a4SAndroid Build Coastguard Worker         filenames: &[&str],
565*bb4ee6a4SAndroid Build Coastguard Worker         contents: &[Vec<u8>],
566*bb4ee6a4SAndroid Build Coastguard Worker         selector: u16,
567*bb4ee6a4SAndroid Build Coastguard Worker     ) -> (FwCfgDevice, BusAccessInfo) {
568*bb4ee6a4SAndroid Build Coastguard Worker         let mut device = make_device(
569*bb4ee6a4SAndroid Build Coastguard Worker             filenames,
570*bb4ee6a4SAndroid Build Coastguard Worker             contents,
571*bb4ee6a4SAndroid Build Coastguard Worker             &default_params(),
572*bb4ee6a4SAndroid Build Coastguard Worker             &(filenames.len() + 5),
573*bb4ee6a4SAndroid Build Coastguard Worker         )
574*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
575*bb4ee6a4SAndroid Build Coastguard Worker         let mut bai = BusAccessInfo {
576*bb4ee6a4SAndroid Build Coastguard Worker             offset: FW_CFG_SELECTOR_PORT_OFFSET,
577*bb4ee6a4SAndroid Build Coastguard Worker             address: FW_CFG_BASE_PORT,
578*bb4ee6a4SAndroid Build Coastguard Worker             id: 0,
579*bb4ee6a4SAndroid Build Coastguard Worker         };
580*bb4ee6a4SAndroid Build Coastguard Worker         let selector: [u8; 2] = selector.to_le_bytes();
581*bb4ee6a4SAndroid Build Coastguard Worker         device.write(bai, &selector);
582*bb4ee6a4SAndroid Build Coastguard Worker         bai.offset = FW_CFG_DATA_PORT_OFFSET;
583*bb4ee6a4SAndroid Build Coastguard Worker 
584*bb4ee6a4SAndroid Build Coastguard Worker         (device, bai)
585*bb4ee6a4SAndroid Build Coastguard Worker     }
586*bb4ee6a4SAndroid Build Coastguard Worker 
587*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
588*bb4ee6a4SAndroid Build Coastguard Worker     // Attempt to build FwCfgParams from key value pairs
params_from_key_values()589*bb4ee6a4SAndroid Build Coastguard Worker     fn params_from_key_values() {
590*bb4ee6a4SAndroid Build Coastguard Worker         from_fw_cfg_arg("").expect_err("parsing empty string should fail");
591*bb4ee6a4SAndroid Build Coastguard Worker 
592*bb4ee6a4SAndroid Build Coastguard Worker         let params = from_fw_cfg_arg("name=foo,path=/path/to/input").unwrap();
593*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
594*bb4ee6a4SAndroid Build Coastguard Worker             params,
595*bb4ee6a4SAndroid Build Coastguard Worker             FwCfgParameters {
596*bb4ee6a4SAndroid Build Coastguard Worker                 name: "foo".into(),
597*bb4ee6a4SAndroid Build Coastguard Worker                 path: Some("/path/to/input".into()),
598*bb4ee6a4SAndroid Build Coastguard Worker                 string: None,
599*bb4ee6a4SAndroid Build Coastguard Worker             }
600*bb4ee6a4SAndroid Build Coastguard Worker         );
601*bb4ee6a4SAndroid Build Coastguard Worker 
602*bb4ee6a4SAndroid Build Coastguard Worker         let params = from_fw_cfg_arg("name=bar,string=testdata").unwrap();
603*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
604*bb4ee6a4SAndroid Build Coastguard Worker             params,
605*bb4ee6a4SAndroid Build Coastguard Worker             FwCfgParameters {
606*bb4ee6a4SAndroid Build Coastguard Worker                 name: "bar".into(),
607*bb4ee6a4SAndroid Build Coastguard Worker                 string: Some("testdata".into()),
608*bb4ee6a4SAndroid Build Coastguard Worker                 path: None,
609*bb4ee6a4SAndroid Build Coastguard Worker             }
610*bb4ee6a4SAndroid Build Coastguard Worker         );
611*bb4ee6a4SAndroid Build Coastguard Worker     }
612*bb4ee6a4SAndroid Build Coastguard Worker 
613*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
614*bb4ee6a4SAndroid Build Coastguard Worker     // Try to cause underflow by using a selector less than FW_CFG_FILE_FIRST but not one of the
615*bb4ee6a4SAndroid Build Coastguard Worker     // special selectors
attempt_underflow_read()616*bb4ee6a4SAndroid Build Coastguard Worker     fn attempt_underflow_read() {
617*bb4ee6a4SAndroid Build Coastguard Worker         let (_device, _bai) = setup_read(
618*bb4ee6a4SAndroid Build Coastguard Worker             &FILENAMES,
619*bb4ee6a4SAndroid Build Coastguard Worker             &get_contents(),
620*bb4ee6a4SAndroid Build Coastguard Worker             (FW_CFG_FILE_FIRST - 0x05) as u16,
621*bb4ee6a4SAndroid Build Coastguard Worker         );
622*bb4ee6a4SAndroid Build Coastguard Worker     }
623*bb4ee6a4SAndroid Build Coastguard Worker 
624*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
625*bb4ee6a4SAndroid Build Coastguard Worker     // Write a simple one byte file and confirm that an entry is properly created
write_one_byte_file()626*bb4ee6a4SAndroid Build Coastguard Worker     fn write_one_byte_file() {
627*bb4ee6a4SAndroid Build Coastguard Worker         let mut fw_cfg = FwCfgDevice::new(100, default_params()).unwrap();
628*bb4ee6a4SAndroid Build Coastguard Worker         let data = vec![MAGIC_BYTE];
629*bb4ee6a4SAndroid Build Coastguard Worker         fw_cfg
630*bb4ee6a4SAndroid Build Coastguard Worker             .add_file(FILENAME, data, FwCfgItemType::GenericItem)
631*bb4ee6a4SAndroid Build Coastguard Worker             .expect("File insert failed");
632*bb4ee6a4SAndroid Build Coastguard Worker         let ind = fw_cfg.entries[0].len();
633*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
634*bb4ee6a4SAndroid Build Coastguard Worker             ind,
635*bb4ee6a4SAndroid Build Coastguard Worker             FW_CFG_FILE_FIRST + 1,
636*bb4ee6a4SAndroid Build Coastguard Worker             "Insertion into fw_cfg failed: Index is wrong. expected {}, got {},
637*bb4ee6a4SAndroid Build Coastguard Worker                  ",
638*bb4ee6a4SAndroid Build Coastguard Worker             FW_CFG_FILE_FIRST + 1,
639*bb4ee6a4SAndroid Build Coastguard Worker             ind
640*bb4ee6a4SAndroid Build Coastguard Worker         );
641*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
642*bb4ee6a4SAndroid Build Coastguard Worker             fw_cfg.entries[0][ind - 1].data,
643*bb4ee6a4SAndroid Build Coastguard Worker             vec![MAGIC_BYTE],
644*bb4ee6a4SAndroid Build Coastguard Worker             "Insertion failed: unexpected fw_cfg entry values"
645*bb4ee6a4SAndroid Build Coastguard Worker         );
646*bb4ee6a4SAndroid Build Coastguard Worker     }
647*bb4ee6a4SAndroid Build Coastguard Worker 
648*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
649*bb4ee6a4SAndroid Build Coastguard Worker     // Write a simple four byte file and confirm that an entry is properly created
write_four_byte_file()650*bb4ee6a4SAndroid Build Coastguard Worker     fn write_four_byte_file() {
651*bb4ee6a4SAndroid Build Coastguard Worker         let mut fw_cfg = FwCfgDevice::new(100, default_params()).unwrap();
652*bb4ee6a4SAndroid Build Coastguard Worker         let data = vec![MAGIC_BYTE, MAGIC_BYTE_ALT, MAGIC_BYTE, MAGIC_BYTE_ALT];
653*bb4ee6a4SAndroid Build Coastguard Worker         fw_cfg
654*bb4ee6a4SAndroid Build Coastguard Worker             .add_file(FILENAME, data, FwCfgItemType::GenericItem)
655*bb4ee6a4SAndroid Build Coastguard Worker             .expect("File insert failed");
656*bb4ee6a4SAndroid Build Coastguard Worker         let ind = fw_cfg.entries[0].len();
657*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
658*bb4ee6a4SAndroid Build Coastguard Worker             ind,
659*bb4ee6a4SAndroid Build Coastguard Worker             FW_CFG_FILE_FIRST + 1,
660*bb4ee6a4SAndroid Build Coastguard Worker             "Insertion into fw_cfg failed: Index is wrong. expected {}, got {}",
661*bb4ee6a4SAndroid Build Coastguard Worker             FW_CFG_FILE_FIRST + 1,
662*bb4ee6a4SAndroid Build Coastguard Worker             ind
663*bb4ee6a4SAndroid Build Coastguard Worker         );
664*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
665*bb4ee6a4SAndroid Build Coastguard Worker             fw_cfg.entries[0][ind - 1].data,
666*bb4ee6a4SAndroid Build Coastguard Worker             vec![MAGIC_BYTE, MAGIC_BYTE_ALT, MAGIC_BYTE, MAGIC_BYTE_ALT],
667*bb4ee6a4SAndroid Build Coastguard Worker             "Insertion failed: unexpected fw_cfg entry values"
668*bb4ee6a4SAndroid Build Coastguard Worker         );
669*bb4ee6a4SAndroid Build Coastguard Worker     }
670*bb4ee6a4SAndroid Build Coastguard Worker 
671*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
672*bb4ee6a4SAndroid Build Coastguard Worker     #[should_panic]
673*bb4ee6a4SAndroid Build Coastguard Worker     // Attempt to add a file to an fw_cfg device w/ no fileslots and assert that nothing gets
674*bb4ee6a4SAndroid Build Coastguard Worker     // inserted
write_file_one_slot_expect_nop()675*bb4ee6a4SAndroid Build Coastguard Worker     fn write_file_one_slot_expect_nop() {
676*bb4ee6a4SAndroid Build Coastguard Worker         let mut fw_cfg = FwCfgDevice::new(0, default_params()).unwrap();
677*bb4ee6a4SAndroid Build Coastguard Worker         let data = vec![MAGIC_BYTE];
678*bb4ee6a4SAndroid Build Coastguard Worker         fw_cfg
679*bb4ee6a4SAndroid Build Coastguard Worker             .add_file(FILENAME, data, FwCfgItemType::GenericItem)
680*bb4ee6a4SAndroid Build Coastguard Worker             .expect("File insert failed");
681*bb4ee6a4SAndroid Build Coastguard Worker     }
682*bb4ee6a4SAndroid Build Coastguard Worker 
683*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
684*bb4ee6a4SAndroid Build Coastguard Worker     #[should_panic]
685*bb4ee6a4SAndroid Build Coastguard Worker     // Attempt to add two files to an fw_cfg w/ only one fileslot and assert only first insert
686*bb4ee6a4SAndroid Build Coastguard Worker     // succeeds.
write_two_files_no_slots_expect_nop_on_second()687*bb4ee6a4SAndroid Build Coastguard Worker     fn write_two_files_no_slots_expect_nop_on_second() {
688*bb4ee6a4SAndroid Build Coastguard Worker         let mut fw_cfg = FwCfgDevice::new(1, default_params()).unwrap();
689*bb4ee6a4SAndroid Build Coastguard Worker         let data = vec![MAGIC_BYTE];
690*bb4ee6a4SAndroid Build Coastguard Worker         let data2 = vec![MAGIC_BYTE_ALT];
691*bb4ee6a4SAndroid Build Coastguard Worker         fw_cfg
692*bb4ee6a4SAndroid Build Coastguard Worker             .add_file(FILENAME, data, FwCfgItemType::GenericItem)
693*bb4ee6a4SAndroid Build Coastguard Worker             .expect("File insert failed");
694*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
695*bb4ee6a4SAndroid Build Coastguard Worker             fw_cfg.entries[0].len(),
696*bb4ee6a4SAndroid Build Coastguard Worker             1,
697*bb4ee6a4SAndroid Build Coastguard Worker             "Insertion into fw_cfg failed: Expected {} elements, got {}",
698*bb4ee6a4SAndroid Build Coastguard Worker             1,
699*bb4ee6a4SAndroid Build Coastguard Worker             fw_cfg.entries[0].len()
700*bb4ee6a4SAndroid Build Coastguard Worker         );
701*bb4ee6a4SAndroid Build Coastguard Worker         fw_cfg
702*bb4ee6a4SAndroid Build Coastguard Worker             .add_file(FILENAME, data2, FwCfgItemType::GenericItem)
703*bb4ee6a4SAndroid Build Coastguard Worker             .expect("File insert failed");
704*bb4ee6a4SAndroid Build Coastguard Worker     }
705*bb4ee6a4SAndroid Build Coastguard Worker 
706*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
707*bb4ee6a4SAndroid Build Coastguard Worker     // Attempt to read a FwCfgDevice's signature
read_fw_cfg_signature()708*bb4ee6a4SAndroid Build Coastguard Worker     fn read_fw_cfg_signature() {
709*bb4ee6a4SAndroid Build Coastguard Worker         let mut data: Vec<u8> = vec![0];
710*bb4ee6a4SAndroid Build Coastguard Worker         let (mut device, bai) = setup_read(&FILENAMES, &get_contents(), FW_CFG_SIGNATURE_SELECTOR);
711*bb4ee6a4SAndroid Build Coastguard Worker         // To logically compare the revison vector to FW_CFG_REVISION byte-by-byte, we must use
712*bb4ee6a4SAndroid Build Coastguard Worker         // to_be_bytes() since we are comparing byte arrays, not integers.
713*bb4ee6a4SAndroid Build Coastguard Worker         let signature = read_u32(&mut device, bai, &mut data[..]).to_be_bytes();
714*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(signature, FW_CFG_SIGNATURE);
715*bb4ee6a4SAndroid Build Coastguard Worker     }
716*bb4ee6a4SAndroid Build Coastguard Worker 
717*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
718*bb4ee6a4SAndroid Build Coastguard Worker     // Attempt to read a FwCfgDevice's revision bit vector
read_fw_cfg_revision()719*bb4ee6a4SAndroid Build Coastguard Worker     fn read_fw_cfg_revision() {
720*bb4ee6a4SAndroid Build Coastguard Worker         let mut data: Vec<u8> = vec![0];
721*bb4ee6a4SAndroid Build Coastguard Worker         let (mut device, bai) = setup_read(&FILENAMES, &get_contents(), FW_CFG_REVISION_SELECTOR);
722*bb4ee6a4SAndroid Build Coastguard Worker         // To logically compare the revison vector to FW_CFG_REVISION byte-by-byte, we must use
723*bb4ee6a4SAndroid Build Coastguard Worker         // to_be_bytes() since we are comparing byte arrays, not integers.
724*bb4ee6a4SAndroid Build Coastguard Worker         let revision = read_u32(&mut device, bai, &mut data[..]).to_be_bytes();
725*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(revision, FW_CFG_REVISION);
726*bb4ee6a4SAndroid Build Coastguard Worker     }
727*bb4ee6a4SAndroid Build Coastguard Worker 
728*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
729*bb4ee6a4SAndroid Build Coastguard Worker     // Attempt to read a FwCfgDevice's file directory
read_file_dir()730*bb4ee6a4SAndroid Build Coastguard Worker     fn read_file_dir() {
731*bb4ee6a4SAndroid Build Coastguard Worker         let contents = get_contents();
732*bb4ee6a4SAndroid Build Coastguard Worker         let (mut device, bai) = setup_read(&FILENAMES, &contents, FW_CFG_FILE_DIR_SELECTOR);
733*bb4ee6a4SAndroid Build Coastguard Worker         assert_read_file_dir(&FILENAMES, &contents, &mut device, bai);
734*bb4ee6a4SAndroid Build Coastguard Worker     }
735*bb4ee6a4SAndroid Build Coastguard Worker 
736*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
737*bb4ee6a4SAndroid Build Coastguard Worker     // Attempt to read all of a FwCfgDevice's entries
read_fw_cfg_entries()738*bb4ee6a4SAndroid Build Coastguard Worker     fn read_fw_cfg_entries() {
739*bb4ee6a4SAndroid Build Coastguard Worker         let contents = get_contents();
740*bb4ee6a4SAndroid Build Coastguard Worker         let (mut device, bai) = setup_read(&FILENAMES, &contents, (0 + FW_CFG_FILE_FIRST) as u16);
741*bb4ee6a4SAndroid Build Coastguard Worker 
742*bb4ee6a4SAndroid Build Coastguard Worker         assert_read_entries(&FILENAMES, &mut device, bai);
743*bb4ee6a4SAndroid Build Coastguard Worker     }
744*bb4ee6a4SAndroid Build Coastguard Worker 
745*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
746*bb4ee6a4SAndroid Build Coastguard Worker     // Attempt to read revision, file dir, and entries in random order to make
747*bb4ee6a4SAndroid Build Coastguard Worker     // sure that proper state is maintained.
read_whole_device()748*bb4ee6a4SAndroid Build Coastguard Worker     fn read_whole_device() {
749*bb4ee6a4SAndroid Build Coastguard Worker         let contents = get_contents();
750*bb4ee6a4SAndroid Build Coastguard Worker         let mut data: Vec<u8> = vec![0];
751*bb4ee6a4SAndroid Build Coastguard Worker 
752*bb4ee6a4SAndroid Build Coastguard Worker         let (mut device, mut bai) = setup_read(&FILENAMES, &contents, FW_CFG_REVISION_SELECTOR);
753*bb4ee6a4SAndroid Build Coastguard Worker 
754*bb4ee6a4SAndroid Build Coastguard Worker         let revision = read_u32(&mut device, bai, &mut data[..]).to_be_bytes();
755*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(revision, FW_CFG_REVISION);
756*bb4ee6a4SAndroid Build Coastguard Worker 
757*bb4ee6a4SAndroid Build Coastguard Worker         let i = FILENAMES.len() - 1;
758*bb4ee6a4SAndroid Build Coastguard Worker         let data_len = device.entries[0][i].data.len();
759*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
760*bb4ee6a4SAndroid Build Coastguard Worker             get_entry(&mut device, bai, data_len, (i + FW_CFG_FILE_FIRST) as u16),
761*bb4ee6a4SAndroid Build Coastguard Worker             device.entries[0][i].data
762*bb4ee6a4SAndroid Build Coastguard Worker         );
763*bb4ee6a4SAndroid Build Coastguard Worker 
764*bb4ee6a4SAndroid Build Coastguard Worker         bai.address = FW_CFG_BASE_PORT;
765*bb4ee6a4SAndroid Build Coastguard Worker         bai.offset = FW_CFG_SELECTOR_PORT_OFFSET;
766*bb4ee6a4SAndroid Build Coastguard Worker         device.write(bai, &FW_CFG_FILE_DIR_SELECTOR.to_le_bytes());
767*bb4ee6a4SAndroid Build Coastguard Worker         bai.offset = FW_CFG_DATA_PORT_OFFSET;
768*bb4ee6a4SAndroid Build Coastguard Worker 
769*bb4ee6a4SAndroid Build Coastguard Worker         assert_read_file_dir(&FILENAMES, &contents, &mut device, bai);
770*bb4ee6a4SAndroid Build Coastguard Worker 
771*bb4ee6a4SAndroid Build Coastguard Worker         let data_len = device.entries[0][FW_CFG_FILE_FIRST + 0].data.len();
772*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
773*bb4ee6a4SAndroid Build Coastguard Worker             get_entry(&mut device, bai, data_len, (0 + FW_CFG_FILE_FIRST) as u16),
774*bb4ee6a4SAndroid Build Coastguard Worker             device.entries[0][FW_CFG_FILE_FIRST + 0].data
775*bb4ee6a4SAndroid Build Coastguard Worker         );
776*bb4ee6a4SAndroid Build Coastguard Worker     }
777*bb4ee6a4SAndroid Build Coastguard Worker 
778*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
779*bb4ee6a4SAndroid Build Coastguard Worker     // Assert that the device maintains proper state after reads of random length.
read_incorrect_bytes()780*bb4ee6a4SAndroid Build Coastguard Worker     fn read_incorrect_bytes() {
781*bb4ee6a4SAndroid Build Coastguard Worker         let contents = get_contents();
782*bb4ee6a4SAndroid Build Coastguard Worker         let mut data: Vec<u8> = vec![0];
783*bb4ee6a4SAndroid Build Coastguard Worker         let (mut device, mut bai) =
784*bb4ee6a4SAndroid Build Coastguard Worker             setup_read(&FILENAMES, &contents, (0 + FW_CFG_FILE_FIRST) as u16);
785*bb4ee6a4SAndroid Build Coastguard Worker 
786*bb4ee6a4SAndroid Build Coastguard Worker         for _i in 1..1000 {
787*bb4ee6a4SAndroid Build Coastguard Worker             let _random_bytes = read_u32(&mut device, bai, &mut data[..]);
788*bb4ee6a4SAndroid Build Coastguard Worker         }
789*bb4ee6a4SAndroid Build Coastguard Worker 
790*bb4ee6a4SAndroid Build Coastguard Worker         bai.address = FW_CFG_BASE_PORT;
791*bb4ee6a4SAndroid Build Coastguard Worker         device.write(bai, &FW_CFG_FILE_DIR_SELECTOR.to_le_bytes());
792*bb4ee6a4SAndroid Build Coastguard Worker         bai.offset = FW_CFG_DATA_PORT_OFFSET;
793*bb4ee6a4SAndroid Build Coastguard Worker 
794*bb4ee6a4SAndroid Build Coastguard Worker         for _i in 1..10000 {
795*bb4ee6a4SAndroid Build Coastguard Worker             let mut data: Vec<u8> = vec![0];
796*bb4ee6a4SAndroid Build Coastguard Worker             let _random_bytes = read_u32(&mut device, bai, &mut data[..]);
797*bb4ee6a4SAndroid Build Coastguard Worker         }
798*bb4ee6a4SAndroid Build Coastguard Worker 
799*bb4ee6a4SAndroid Build Coastguard Worker         bai.address = FW_CFG_BASE_PORT;
800*bb4ee6a4SAndroid Build Coastguard Worker         bai.offset = FW_CFG_SELECTOR_PORT_OFFSET;
801*bb4ee6a4SAndroid Build Coastguard Worker         device.write(bai, &FW_CFG_FILE_DIR_SELECTOR.to_le_bytes());
802*bb4ee6a4SAndroid Build Coastguard Worker         bai.offset = FW_CFG_DATA_PORT_OFFSET;
803*bb4ee6a4SAndroid Build Coastguard Worker 
804*bb4ee6a4SAndroid Build Coastguard Worker         assert_read_file_dir(&FILENAMES, &contents, &mut device, bai);
805*bb4ee6a4SAndroid Build Coastguard Worker 
806*bb4ee6a4SAndroid Build Coastguard Worker         let i = FILENAMES.len() - 1;
807*bb4ee6a4SAndroid Build Coastguard Worker 
808*bb4ee6a4SAndroid Build Coastguard Worker         bai.address = FW_CFG_BASE_PORT;
809*bb4ee6a4SAndroid Build Coastguard Worker         bai.offset = FW_CFG_SELECTOR_PORT_OFFSET;
810*bb4ee6a4SAndroid Build Coastguard Worker         device.write(bai, &(FW_CFG_FILE_FIRST + i).to_le_bytes());
811*bb4ee6a4SAndroid Build Coastguard Worker         bai.offset = FW_CFG_DATA_PORT_OFFSET;
812*bb4ee6a4SAndroid Build Coastguard Worker 
813*bb4ee6a4SAndroid Build Coastguard Worker         for _i in 1..1000 {
814*bb4ee6a4SAndroid Build Coastguard Worker             let _random_bytes = read_u32(&mut device, bai, &mut data[..]);
815*bb4ee6a4SAndroid Build Coastguard Worker         }
816*bb4ee6a4SAndroid Build Coastguard Worker 
817*bb4ee6a4SAndroid Build Coastguard Worker         assert_read_entries(&FILENAMES, &mut device, bai);
818*bb4ee6a4SAndroid Build Coastguard Worker     }
819*bb4ee6a4SAndroid Build Coastguard Worker }
820