[sw, rom_ext_signer] Introduce unittests for `update_static_fields`
The test function:
- Manually initialises the config structure
- Uses the dev/test blank image file as an input
- Makes sure that this file is actually blank
- Uses the initialised config structure to update the fields
- Makes sure that the correct fields have been updated, and
no other portions of the image were modified
`Cargo test` is expected to be triggered via normal meason build,
otherwise the unittest will no knowledge of the environment
variables.
Signed-off-by: Silvestrs Timofejevs <silvestrst@lowrisc.org>
diff --git a/sw/host/rom_ext_image_tools/signer/dev/usage_constraints.bin b/sw/host/rom_ext_image_tools/signer/dev/usage_constraints.bin
index 7640dad..9648fd7 100644
--- a/sw/host/rom_ext_image_tools/signer/dev/usage_constraints.bin
+++ b/sw/host/rom_ext_image_tools/signer/dev/usage_constraints.bin
@@ -1 +1 @@
-¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
\ No newline at end of file
+¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
\ No newline at end of file
diff --git a/sw/host/rom_ext_image_tools/signer/image/src/image.rs b/sw/host/rom_ext_image_tools/signer/image/src/image.rs
index 50fcf33..ffec48c 100644
--- a/sw/host/rom_ext_image_tools/signer/image/src/image.rs
+++ b/sw/host/rom_ext_image_tools/signer/image/src/image.rs
@@ -189,19 +189,171 @@
}
}
+fn str_to_u64(val: &str) -> u64 {
+ match val.strip_prefix("0x") {
+ Some(s) => u64::from_str_radix(s, 16),
+ None => u64::from_str_radix(val, 10),
+ }
+ .expect("Failed to parse string to u64!")
+}
+
/// Converts hex/decimal uint string into a little endian byte vector.
///
-/// Note: only understands unsigned u64 and u32 integers.
+/// Note: only understands values up to u64::MAX.
fn str_to_vec_u8(s: &str) -> Vec<u8> {
- let value = match s.starts_with("0x") {
- true => u64::from_str_radix(s.trim_start_matches("0x"), 16)
- .expect("Failed to parse string to u64!"),
- false => s.parse::<u64>().expect("Failed to parse string to u64!"),
- };
+ match str_to_u64(s).to_le_bytes() {
+ [a, b, c, d, 0, 0, 0, 0] => vec![a, b, c, d],
+ bytes => bytes.to_vec(),
+ }
+}
- if value <= (u32::MAX as u64) {
- (value as u32).to_le_bytes().to_vec()
- } else {
- value.to_le_bytes().to_vec()
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use std::collections::HashMap;
+ use std::env;
+
+ use rom_ext_config::parser::Extension;
+ use rom_ext_config::parser::InputFiles;
+
+ static DEV_RELATIVE_PATH: &str = "sw/host/rom_ext_image_tools/signer/dev";
+
+ #[test]
+ fn test_update_static_fields() {
+ let source_root = env::var("MESON_SOURCE_ROOT")
+ .expect("Failed, ENV variable not set!");
+
+ let dev_path = Path::new(&source_root).join(DEV_RELATIVE_PATH);
+ let full_path = |path| dev_path.join(path);
+
+ let config = ParsedConfig {
+ input_files: InputFiles {
+ image_path: full_path("rom_ext_blank_image.bin"),
+ private_key_der_path: PathBuf::from(""),
+ usage_constraints_path: full_path("usage_constraints.bin"),
+ system_state_value_path: PathBuf::from(""),
+ },
+ peripheral_lockdown_info: PeripheralLockdownInfo { value: 0 },
+ manifest_identifier: String::from("0x11111111"),
+ image_version: String::from("0x22222222"),
+ extensions: [
+ Extension {
+ offset: String::from("0x33333333"),
+ checksum: String::from("0x44444444"),
+ },
+ Extension {
+ offset: String::from("0x55555555"),
+ checksum: String::from("0x55555555"),
+ },
+ Extension {
+ offset: String::from("0x66666666"),
+ checksum: String::from("0x66666666"),
+ },
+ Extension {
+ offset: String::from("0x77777777"),
+ checksum: String::from("0x77777777"),
+ },
+ ],
+ };
+
+ let mut test_items: HashMap<usize, Vec<u8>> = HashMap::new();
+
+ let mut add_test_item = |key, val: Vec<u8>, expected_size| {
+ assert_eq!(val.len(), expected_size as usize);
+ test_items.insert(key as usize, val);
+ };
+
+ add_test_item(
+ manifest::ROM_EXT_MANIFEST_IDENTIFIER_OFFSET,
+ str_to_vec_u8(&config.manifest_identifier),
+ manifest::ROM_EXT_MANIFEST_IDENTIFIER_SIZE_BYTES,
+ );
+ add_test_item(
+ manifest::ROM_EXT_IMAGE_VERSION_OFFSET,
+ str_to_vec_u8(&config.image_version),
+ manifest::ROM_EXT_IMAGE_VERSION_SIZE_BYTES,
+ );
+ add_test_item(
+ manifest::ROM_EXT_EXTENSION0_OFFSET_OFFSET,
+ str_to_vec_u8(&config.extensions[0].offset),
+ manifest::ROM_EXT_EXTENSION0_OFFSET_SIZE_BYTES,
+ );
+ add_test_item(
+ manifest::ROM_EXT_EXTENSION1_OFFSET_OFFSET,
+ str_to_vec_u8(&config.extensions[1].offset),
+ manifest::ROM_EXT_EXTENSION1_OFFSET_SIZE_BYTES,
+ );
+ add_test_item(
+ manifest::ROM_EXT_EXTENSION2_OFFSET_OFFSET,
+ str_to_vec_u8(&config.extensions[2].offset),
+ manifest::ROM_EXT_EXTENSION2_OFFSET_SIZE_BYTES,
+ );
+ add_test_item(
+ manifest::ROM_EXT_EXTENSION3_OFFSET_OFFSET,
+ str_to_vec_u8(&config.extensions[3].offset),
+ manifest::ROM_EXT_EXTENSION3_OFFSET_SIZE_BYTES,
+ );
+ add_test_item(
+ manifest::ROM_EXT_EXTENSION0_CHECKSUM_OFFSET,
+ str_to_vec_u8(&config.extensions[0].checksum),
+ manifest::ROM_EXT_EXTENSION0_CHECKSUM_SIZE_BYTES,
+ );
+ add_test_item(
+ manifest::ROM_EXT_EXTENSION1_CHECKSUM_OFFSET,
+ str_to_vec_u8(&config.extensions[1].checksum),
+ manifest::ROM_EXT_EXTENSION1_CHECKSUM_SIZE_BYTES,
+ );
+ add_test_item(
+ manifest::ROM_EXT_EXTENSION2_CHECKSUM_OFFSET,
+ str_to_vec_u8(&config.extensions[2].checksum),
+ manifest::ROM_EXT_EXTENSION2_CHECKSUM_SIZE_BYTES,
+ );
+ add_test_item(
+ manifest::ROM_EXT_EXTENSION3_CHECKSUM_OFFSET,
+ str_to_vec_u8(&config.extensions[3].checksum),
+ manifest::ROM_EXT_EXTENSION3_CHECKSUM_SIZE_BYTES,
+ );
+ add_test_item(
+ manifest::ROM_EXT_USAGE_CONSTRAINTS_OFFSET,
+ fs::read(&config.input_files.usage_constraints_path)
+ .expect("Failed to read usage constraints!"),
+ manifest::ROM_EXT_USAGE_CONSTRAINTS_SIZE_BYTES,
+ );
+ add_test_item(
+ manifest::ROM_EXT_PERIPHERAL_LOCKDOWN_INFO_OFFSET,
+ [0xA5; 16].to_vec(),
+ manifest::ROM_EXT_PERIPHERAL_LOCKDOWN_INFO_SIZE_BYTES,
+ );
+
+ let mut image = RawImage::new(&config.input_files.image_path);
+
+ // Make sure that the image is blank to start with.
+ assert_eq!(image.data, vec![0; image.data.len()]);
+
+ image.update_static_fields(&config);
+
+ // Iterate through every single byte in the image, if it belongs to a
+ // field under test - compare with the respective `test_tuple` field,
+ // otherwise it should be zero.
+ let mut i = 0;
+ while i < image.data.len() {
+ // Check if the byte is part of the fields under test.
+ match test_items.get(&i) {
+ Some(x) => {
+ // Check that field under test was successfully written
+ // to the image.
+ for byte in x {
+ assert_eq!(*byte, image.data[i], "index = {}", i);
+ i += 1;
+ }
+ }
+ _ => {
+ // Make sure that any other bytes are zero.
+ assert_eq!(image.data[i], 0, "index = {}", i);
+ i += 1;
+ }
+ }
+ }
}
}