[opentitanlib] Add OTP hex file generation.
Signed-off-by: Jon Flatley <jflat@google.com>
diff --git a/sw/host/opentitanlib/BUILD b/sw/host/opentitanlib/BUILD
index 626e5c5..7caaad3 100644
--- a/sw/host/opentitanlib/BUILD
+++ b/sw/host/opentitanlib/BUILD
@@ -21,6 +21,13 @@
"src/io/spi.rs",
"src/io/uart.rs",
"src/lib.rs",
+ "src/otp/lc_state.rs",
+ "src/otp/mod.rs",
+ "src/otp/num_de.rs",
+ "src/otp/otp.rs",
+ "src/otp/otp_img.rs",
+ "src/otp/otp_mmap.rs",
+ "src/otp/vmem_serialize.rs",
"src/spiflash/flash.rs",
"src/spiflash/mod.rs",
"src/spiflash/sfdp.rs",
@@ -48,8 +55,8 @@
"src/util/file.rs",
"src/util/image.rs",
"src/util/mod.rs",
- "src/util/present.rs",
"src/util/parse_int.rs",
+ "src/util/present.rs",
"src/util/usb.rs",
"src/util/voltage.rs",
],
diff --git a/sw/host/opentitanlib/Cargo.toml b/sw/host/opentitanlib/Cargo.toml
index b29e2f2..9490a3b 100644
--- a/sw/host/opentitanlib/Cargo.toml
+++ b/sw/host/opentitanlib/Cargo.toml
@@ -35,6 +35,8 @@
serde = { version="1", features=["serde_derive"] }
serde_json = "1"
+deser-hjson = "1.0.2"
+rand = "0.8.4"
erased-serde = "0.3.12"
opentitantool_derive = {path = "opentitantool_derive"}
diff --git a/sw/host/opentitanlib/src/lib.rs b/sw/host/opentitanlib/src/lib.rs
index 38e9c55..71ddeab 100644
--- a/sw/host/opentitanlib/src/lib.rs
+++ b/sw/host/opentitanlib/src/lib.rs
@@ -5,6 +5,7 @@
pub mod app;
pub mod bootstrap;
pub mod io;
+pub mod otp;
pub mod spiflash;
pub mod transport;
pub mod util;
diff --git a/sw/host/opentitanlib/src/otp/lc_state.rs b/sw/host/opentitanlib/src/otp/lc_state.rs
new file mode 100644
index 0000000..813d8da
--- /dev/null
+++ b/sw/host/opentitanlib/src/otp/lc_state.rs
@@ -0,0 +1,110 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+use anyhow::{bail, Result};
+use serde::Deserialize;
+use std::fs;
+use std::path::Path;
+
+/// SECDED matrix used for ECC in OTP.
+#[derive(Deserialize, Debug)]
+pub struct LcSecded {
+ /// The number of bits of data covered by ECC.
+ data_width: usize,
+ /// The number of ECC bits.
+ ecc_width: usize,
+ /// ECC matrix used for computing ECC bits.
+ ecc_matrix: Vec<Vec<u8>>,
+}
+
+/// The internal representation of lc_ctrl_state, used in OTP operations.
+#[derive(Deserialize, Debug)]
+pub struct LcState {
+ secded: LcSecded,
+}
+
+impl LcSecded {
+ pub fn new(in_file: &Path) -> Result<LcSecded> {
+ let json_text = fs::read_to_string(in_file)?;
+ let res: LcState = deser_hjson::from_str(&json_text)?;
+ if res.secded.ecc_matrix.len() != res.secded.ecc_width {
+ bail!("Bad ecc matrix length {}", res.secded.ecc_matrix.len());
+ }
+ Ok(res.secded)
+ }
+
+ fn bit_index(data: &[u8], index: usize) -> bool {
+ let byte = index / 8;
+ let bit = index % 8;
+ data[byte] & (1 << bit) != 0
+ }
+
+ pub fn ecc_encode(&self, mut data: Vec<u8>) -> Result<Vec<u8>> {
+ if data.len() * 8 != self.data_width {
+ bail!("Bad data length for ecc {}", data.len() * 8);
+ }
+ let data_len = data.len();
+ data.resize(data_len + self.ecc_byte_len(), 0);
+ for (i, matrix) in self.ecc_matrix.iter().enumerate() {
+ let mut bit = false;
+ for j in matrix {
+ bit ^= Self::bit_index(&data, *j as usize);
+ }
+ if bit {
+ let byte = i / 8 + data_len;
+ let bit = i % 8;
+ data[byte] |= 1 << bit;
+ }
+ }
+
+ Ok(data)
+ }
+
+ pub fn ecc_byte_len(&self) -> usize {
+ if self.ecc_width == 0 {
+ 0
+ } else {
+ (self.ecc_width - 1) / 8 + 1
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use anyhow::Result;
+ use deser_hjson::from_str;
+ use std::fs::read_to_string;
+
+ #[test]
+ fn test_lc_state_deserialize() -> Result<()> {
+ let _: LcState = from_str(&read_to_string("tests/lc_ctrl_state.hjson")?)?;
+ Ok(())
+ }
+
+ #[test]
+ fn test_ecc_encode() {
+ let secded = LcSecded {
+ data_width: 16,
+ ecc_width: 6,
+ ecc_matrix: vec![
+ vec![0, 1, 3, 4, 6, 8, 10, 11, 13, 15], // ECC bit 0
+ vec![0, 2, 3, 5, 6, 9, 10, 12, 13], // ECC bit 1
+ vec![1, 2, 3, 7, 8, 9, 10, 14, 15], // ECC bit 2
+ vec![4, 5, 6, 7, 8, 9, 10], // ECC bit 3
+ vec![11, 12, 13, 14, 15], // ECC bit 4
+ vec![
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ ], // Parity bit
+ ],
+ };
+
+ let zero: Vec<u8> = vec![0, 0];
+ let a5a5: Vec<u8> = vec![0xa5, 0xa5];
+ let fcc5: Vec<u8> = vec![0xfc, 0xc5];
+ assert_eq!(vec![0u8, 0, 0], secded.ecc_encode(zero).unwrap());
+ assert_eq!(vec![0xa5u8, 0xa5, 0x27], secded.ecc_encode(a5a5).unwrap());
+ assert_eq!(vec![0x0fcu8, 0xc5, 0x06], secded.ecc_encode(fcc5).unwrap())
+ }
+}
diff --git a/sw/host/opentitanlib/src/otp/mod.rs b/sw/host/opentitanlib/src/otp/mod.rs
new file mode 100644
index 0000000..8465483
--- /dev/null
+++ b/sw/host/opentitanlib/src/otp/mod.rs
@@ -0,0 +1,37 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+pub mod lc_state;
+pub mod otp;
+pub mod otp_img;
+pub mod otp_mmap;
+pub mod vmem_serialize;
+
+mod num_de;
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use anyhow::Result;
+ use std::path::Path;
+
+ #[test]
+ fn test_vmem_serialize() -> Result<()> {
+ let mut otp_mmap = otp_mmap::OtpMap::new(Path::new("tests/otp_ctrl_mmap.hjson"))?;
+ let mut otp_img = otp_img::OtpImg::new(Path::new("tests/otp_ctrl_img_dev.hjson"))?;
+ let lc_state = lc_state::LcSecded::new(Path::new("tests/lc_ctrl_state.hjson"))?;
+ let vmem = otp_mmap.make_vmem(&mut otp_img)?;
+ let keys = otp_mmap.generate_keys(&otp_img);
+ let result = vmem.generate(keys, &lc_state)?;
+ let expected = std::fs::read_to_string(Path::new("tests/output.vmem"))?;
+ let expected = expected
+ .split("\n")
+ .filter(|s| !s.is_empty())
+ .collect::<Vec<&str>>();
+
+ assert_eq!(result, expected);
+
+ Ok(())
+ }
+}
diff --git a/sw/host/opentitanlib/src/otp/num_de.rs b/sw/host/opentitanlib/src/otp/num_de.rs
new file mode 100644
index 0000000..d621e9e
--- /dev/null
+++ b/sw/host/opentitanlib/src/otp/num_de.rs
@@ -0,0 +1,228 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+/// Deserialization utilities for certain values in OTP HJSON files.
+///
+/// The OTP HJSON files have some strange values:
+///
+/// Integers, sometimes wrapped in strings, with inconsistent formatting and meta values, such as:
+/// - value: "0x739"
+/// - key_size: "16"
+/// - seed: "10556718629619452145"
+/// - seed: 01931961561863975174 // This is a decimal integer, not octal.
+/// - value: "<random>"
+///
+/// Additionally, some values have sizes defined within the config files themselves, such as the
+/// keys. This module exists to handle these peculiar cases.
+use anyhow::Result;
+use rand::RngCore;
+use serde::de::{self, Deserializer, Unexpected};
+use serde::ser::Serializer;
+use serde::{Deserialize, Serialize};
+use std::any::type_name;
+use std::fmt;
+use std::marker::PhantomData;
+use std::ops::Deref;
+
+use crate::util::parse_int::{ParseInt, ParseIntError};
+
+pub fn _serialize<S, T>(_r: T, _ser: S) -> Result<S::Ok, S::Error>
+where
+ S: Serializer,
+ T: Serialize + Copy,
+{
+ unimplemented!();
+}
+
+/// Deserialize numeric types from HJSON config files.
+pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
+where
+ D: Deserializer<'de>,
+ T: ParseInt,
+{
+ struct Visitor<U>(PhantomData<U>);
+
+ impl<'a, U: ParseInt> de::Visitor<'a> for Visitor<U> {
+ type Value = U;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_fmt(format_args!("a string that parses to {}", type_name::<U>()))
+ }
+
+ fn visit_string<E>(self, mut name: String) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ if name.starts_with("false") {
+ name = "0".to_owned()
+ } else if name.starts_with("true") {
+ name = "1".to_owned()
+ }
+
+ let trimmed = if name.starts_with("0x") {
+ &name
+ } else {
+ let trimmed = name[0..name.len() - 1].trim_start_matches('0');
+ &name[name.len() - trimmed.len() - 1..]
+ };
+
+ match U::from_str(trimmed) {
+ Ok(value) => Ok(value),
+ Err(_) => Err(de::Error::invalid_value(Unexpected::Str(trimmed), &self)),
+ }
+ }
+
+ fn visit_str<E>(self, name: &str) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ self.visit_string(name.to_owned())
+ }
+
+ fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ if v {
+ self.visit_str("1")
+ } else {
+ self.visit_str("0")
+ }
+ }
+ }
+
+ deserializer.deserialize_string(Visitor {
+ 0: PhantomData::<T>,
+ })
+}
+
+/// Placeholder type for values that cannot be resolved during deserialization.
+#[derive(Debug, PartialEq, Clone)]
+enum DeferredInit {
+ Initialized(Vec<u8>),
+ Random,
+}
+
+#[derive(Debug, Clone, Deserialize)]
+pub struct DeferredValue(#[serde(with = "self")] DeferredInit);
+
+impl DeferredValue {
+ pub fn resolve(&self, size: usize, rng: &mut dyn RngCore) -> Vec<u8> {
+ match self.0.clone() {
+ DeferredInit::Initialized(mut vec) => {
+ vec.resize(size, 0);
+ vec
+ }
+ DeferredInit::Random => {
+ let mut vec = vec![0u8; size];
+ rng.fill_bytes(&mut vec);
+ vec
+ }
+ }
+ }
+
+ pub fn is_initialized(&self) -> bool {
+ matches!(self.0, DeferredInit::Initialized(_))
+ }
+}
+
+impl ParseInt for DeferredInit {
+ type FromStrRadixErr = ParseIntError;
+
+ fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
+ Ok(DeferredInit::Initialized(Vec::<u8>::from_str_radix(
+ src, radix,
+ )?))
+ }
+
+ fn from_str(src: &str) -> Result<Self, ParseIntError> {
+ if src == "<random>" {
+ Ok(DeferredInit::Random)
+ } else {
+ Ok(DeferredInit::Initialized(Vec::<u8>::from_str(src)?))
+ }
+ }
+}
+
+impl Deref for DeferredValue {
+ type Target = [u8];
+
+ fn deref(&self) -> &Self::Target {
+ match &self.0 {
+ DeferredInit::Initialized(val) => val,
+ _ => panic!("Value has not been initialized"),
+ }
+ }
+}
+
+/// Wrapper type to force deserialization assuming octal encoding.
+#[derive(Deserialize, Debug)]
+pub struct OctEncoded<T: ParseInt>(#[serde(with = "self")] T);
+
+/// Wrapper type to force deserialization assuming decimal encoding.
+#[derive(Deserialize, Debug)]
+pub struct DecEncoded<T: ParseInt>(#[serde(with = "self")] T);
+
+/// Wrapper type to force deserialization assuming hexadecimal encoding.
+#[derive(Deserialize, Debug)]
+pub struct HexEncoded<T: ParseInt>(#[serde(with = "self")] T);
+
+macro_rules! impl_parse_int_enc {
+ ($ty:ident, $radix:expr) => {
+ impl<T: ParseInt> std::ops::Deref for $ty<T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+ }
+
+ impl<T: ParseInt> ParseInt for $ty<T> {
+ type FromStrRadixErr = T::FromStrRadixErr;
+
+ fn from_str_radix(src: &str, radix: u32) -> Result<Self, T::FromStrRadixErr> {
+ Ok(Self(T::from_str_radix(src, radix)?))
+ }
+
+ fn from_str(src: &str) -> Result<Self, ParseIntError> {
+ Self::from_str_radix(src, $radix).map_err(|e| e.into())
+ }
+ }
+ };
+}
+
+impl_parse_int_enc!(OctEncoded, 8);
+impl_parse_int_enc!(DecEncoded, 10);
+impl_parse_int_enc!(HexEncoded, 16);
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use serde::Deserialize;
+
+ #[test]
+ fn de_u8() -> Result<()> {
+ #[derive(Debug, Deserialize)]
+ struct TestData {
+ #[serde(with = "super")]
+ oct: OctEncoded<u8>,
+ #[serde(with = "super")]
+ dec: DecEncoded<u8>,
+ #[serde(with = "super")]
+ hex: HexEncoded<u8>,
+ }
+
+ let data: TestData = deser_hjson::from_str(stringify!(
+ {
+ oct: "77",
+ dec: "77",
+ hex: "77"
+ }))?;
+
+ assert_eq!(*data.oct, 63);
+ assert_eq!(*data.dec, 77);
+ assert_eq!(*data.hex, 119);
+ Ok(())
+ }
+}
diff --git a/sw/host/opentitanlib/src/otp/otp.rs b/sw/host/opentitanlib/src/otp/otp.rs
new file mode 100644
index 0000000..c11fea0
--- /dev/null
+++ b/sw/host/opentitanlib/src/otp/otp.rs
@@ -0,0 +1,44 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+use crate::util::parse_int::{ParseInt, ParseIntError};
+
+use anyhow::Result;
+
+impl ParseInt for Vec<u8> {
+ type FromStrRadixErr = ParseIntError;
+
+ fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
+ let mut bytes = vec![];
+ for digit_bytes in src.as_bytes().rchunks(2) {
+ let digits = std::str::from_utf8(digit_bytes).unwrap();
+ bytes.push(u8::from_str_radix(digits, radix)?);
+ }
+ Ok(bytes)
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use std::convert::TryInto;
+ #[test]
+ fn byte_field_test() {
+ assert_eq!(Vec::from_str("0x1"), Ok(vec![0x1]));
+ assert_eq!(
+ Vec::from_str("0x4b4b4b4b4b4ba5a5"),
+ Ok(vec![0xa5, 0xa5, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b])
+ );
+ assert_eq!(
+ u64::from_ne_bytes(
+ Vec::from_str("0x4b4b4b4b4b4ba5a5")
+ .unwrap()
+ .try_into()
+ .unwrap()
+ ),
+ u64::from_str("0x4b4b4b4b4b4ba5a5").unwrap()
+ );
+ assert!(Vec::from_str("-1").is_err());
+ }
+}
diff --git a/sw/host/opentitanlib/src/otp/otp_img.rs b/sw/host/opentitanlib/src/otp/otp_img.rs
new file mode 100644
index 0000000..fe05775
--- /dev/null
+++ b/sw/host/opentitanlib/src/otp/otp_img.rs
@@ -0,0 +1,60 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+use serde::Deserialize;
+
+use std::path::Path;
+
+use crate::otp::num_de::{DecEncoded, DeferredValue};
+use anyhow::Result;
+use rand::rngs::StdRng;
+use rand::SeedableRng;
+
+const OTP_IMG_SEED_DIVERSIFIER: u64 = 1941661965323525198146u128 as u64;
+
+#[derive(Deserialize, Debug)]
+pub struct OtpImgItem {
+ pub name: String,
+ pub value: DeferredValue,
+}
+
+#[derive(Deserialize, Debug)]
+pub struct OtpImgPartition {
+ pub name: String,
+ pub items: Option<Vec<OtpImgItem>>,
+}
+
+#[derive(Deserialize, Debug)]
+pub struct OtpImg {
+ pub seed: DecEncoded<u64>,
+ pub partitions: Vec<OtpImgPartition>,
+}
+
+impl OtpImgPartition {
+ pub fn get_item(&mut self, name: &str) -> Option<&mut OtpImgItem> {
+ self.items
+ .as_mut()
+ .and_then(|items| items.iter_mut().find(|i| i.name == name))
+ }
+}
+
+impl OtpImg {
+ pub fn new(in_file: &Path) -> Result<OtpImg> {
+ let json_text = std::fs::read_to_string(in_file)?;
+ let res: OtpImg = deser_hjson::from_str(&json_text)?;
+ Ok(res)
+ }
+
+ pub fn get_partition(&mut self, name: &str) -> Option<&mut OtpImgPartition> {
+ self.partitions.iter_mut().find(|p| p.name == name)
+ }
+
+ pub fn partition(&self) -> &[OtpImgPartition] {
+ &self.partitions
+ }
+
+ pub fn get_rng(&self) -> StdRng {
+ StdRng::seed_from_u64(OTP_IMG_SEED_DIVERSIFIER + *self.seed)
+ }
+}
diff --git a/sw/host/opentitanlib/src/otp/otp_mmap.rs b/sw/host/opentitanlib/src/otp/otp_mmap.rs
new file mode 100644
index 0000000..e6960c3
--- /dev/null
+++ b/sw/host/opentitanlib/src/otp/otp_mmap.rs
@@ -0,0 +1,207 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+use crate::otp::num_de::{self, DeferredValue};
+use crate::otp::otp_img::OtpImg;
+use crate::otp::vmem_serialize::*;
+
+use anyhow::{anyhow, bail, Result};
+use serde::Deserialize;
+use std::collections::HashMap;
+use std::convert::TryInto;
+use std::fs;
+use std::path::Path;
+
+#[derive(Deserialize, Debug)]
+struct OtpMapConfig {
+ #[serde(with = "num_de")]
+ width: usize,
+ #[serde(with = "num_de")]
+ depth: usize,
+}
+
+#[derive(Deserialize, Debug)]
+struct OtpMapKey {
+ name: String,
+ value: DeferredValue,
+}
+
+#[derive(Deserialize, Debug)]
+struct OtpMapDigest {
+ name: String,
+ iv_value: DeferredValue,
+ cnst_value: DeferredValue,
+}
+
+#[derive(Deserialize, Debug)]
+struct OtpMapScrambling {
+ #[serde(with = "num_de")]
+ key_size: usize,
+ #[serde(with = "num_de")]
+ iv_size: usize,
+ #[serde(with = "num_de")]
+ cnst_size: usize,
+ keys: Vec<OtpMapKey>,
+ digests: Vec<OtpMapDigest>,
+}
+
+#[derive(Deserialize, Debug)]
+struct OtpMapItem {
+ name: String,
+ #[serde(with = "num_de")]
+ size: usize,
+ #[serde(default)]
+ isdigest: bool,
+ inv_default: Option<DeferredValue>,
+}
+
+#[derive(Deserialize, Debug)]
+pub struct OtpMapPartition {
+ name: String,
+ secret: bool,
+ #[serde(default, with = "num_de")]
+ size: usize,
+ sw_digest: bool,
+ hw_digest: bool,
+ key_sel: String,
+ items: Vec<OtpMapItem>,
+}
+
+#[derive(Deserialize, Debug)]
+pub struct OtpMap {
+ seed: String,
+ otp: OtpMapConfig,
+ scrambling: OtpMapScrambling,
+ partitions: Vec<OtpMapPartition>,
+}
+
+impl OtpMap {
+ pub fn new(in_file: &Path) -> Result<OtpMap> {
+ let json_text = fs::read_to_string(in_file)?;
+ let res: OtpMap = deser_hjson::from_str(&json_text)?;
+ Ok(res)
+ }
+
+ pub fn generate_keys(&self, img: &OtpImg) -> HashMap<String, Vec<u8>> {
+ let mut rng = img.get_rng();
+ let mut map = HashMap::new();
+ for key in &self.scrambling.keys {
+ let value = key.value.resolve(self.scrambling.key_size, &mut rng);
+ map.insert(key.name.clone(), value);
+ }
+ map
+ }
+
+ pub fn make_vmem(&mut self, img: &mut OtpImg) -> Result<VmemImage> {
+ // Seeded RNG needed for "<random>" values.
+ let mut rng = img.get_rng();
+ let mut vmem_partitions = Vec::<VmemPartition>::new();
+ for partition in &self.partitions {
+ let key_name = match partition.key_sel.as_str() {
+ "NoKey" => None,
+ key => Some(key.to_owned()),
+ };
+
+ let digest_type = if !partition.sw_digest && !partition.hw_digest {
+ DigestType::Unlocked
+ } else if partition.sw_digest && !partition.hw_digest {
+ DigestType::Software
+ } else if !partition.sw_digest && partition.hw_digest {
+ // Extra information needed to compute HW digests.
+ let iv_size = self.scrambling.iv_size;
+ let cnst_size = self.scrambling.cnst_size;
+ let digest_info = self
+ .scrambling
+ .digests
+ .iter_mut()
+ .find(|v| v.name == "CnstyDigest")
+ .ok_or(anyhow!("Couldn't find digest info"))?;
+
+ const IV_SIZE: usize = std::mem::size_of::<DigestIV>();
+ const CNST_SIZE: usize = std::mem::size_of::<DigestCnst>();
+ let iv_value: [u8; IV_SIZE] = digest_info
+ .iv_value
+ .resolve(iv_size, &mut rng)
+ .try_into()
+ .map_err(|_| anyhow!("Bad IV size {}", iv_size))?;
+ let cnst_value: [u8; CNST_SIZE] = digest_info
+ .cnst_value
+ .resolve(cnst_size, &mut rng)
+ .try_into()
+ .map_err(|_| anyhow!("Bad scrambling constant size {}", cnst_size))?;
+ DigestType::Hardware(
+ DigestIV::from_ne_bytes(iv_value),
+ DigestCnst::from_ne_bytes(cnst_value),
+ )
+ } else {
+ bail!("Invalid digest configuration");
+ };
+
+ let mut vmem_partition = VmemPartition::new(
+ partition.name.clone(),
+ partition.size,
+ digest_type,
+ key_name,
+ );
+
+ // Fetch the img definition for partition, this contains the associated values for
+ // paritition items.
+ let mut img_partition = img.get_partition(&partition.name);
+
+ let mut offset = 0usize;
+
+ // Resolve all values and convert to Vmem representation.
+ for item in &partition.items {
+ let img_item_value = match &mut img_partition {
+ Some(v) => {
+ let item_value = v.get_item(&item.name);
+ match item_value {
+ Some(v) => v.value.resolve(item.size, &mut rng),
+ None => vec![0u8; item.size],
+ }
+ }
+ None => vec![0u8; item.size],
+ };
+ let vmem_item = VmemItem::new(img_item_value, offset, item.name.clone());
+ offset += item.size;
+ vmem_partition.push_item(vmem_item);
+ }
+ if partition.size == 0 {
+ const SCRAMBLE_BLOCK_WIDTH: usize = 8;
+ const DIGEST_SIZE: usize = 8;
+ let mut size = SCRAMBLE_BLOCK_WIDTH
+ * ((offset + SCRAMBLE_BLOCK_WIDTH - 1) / SCRAMBLE_BLOCK_WIDTH);
+ if partition.hw_digest || partition.sw_digest {
+ size += DIGEST_SIZE;
+ }
+ vmem_partition.set_size(size);
+ }
+ vmem_partitions.push(vmem_partition);
+ }
+ Ok(VmemImage::new(
+ vmem_partitions,
+ self.otp.width,
+ self.otp.depth,
+ ))
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use std::fs::read_to_string;
+
+ #[test]
+ fn test_mmap_deserialize() {
+ let _: OtpMap =
+ deser_hjson::from_str(&read_to_string("tests/otp_ctrl_mmap.hjson").unwrap()).unwrap();
+ }
+
+ #[test]
+ fn test_img_deserialize() {
+ let _: OtpImg =
+ deser_hjson::from_str(&read_to_string("tests/otp_ctrl_img_dev.hjson").unwrap())
+ .unwrap();
+ }
+}
diff --git a/sw/host/opentitanlib/src/otp/vmem_serialize.rs b/sw/host/opentitanlib/src/otp/vmem_serialize.rs
new file mode 100644
index 0000000..077b46a
--- /dev/null
+++ b/sw/host/opentitanlib/src/otp/vmem_serialize.rs
@@ -0,0 +1,279 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+use crate::otp::lc_state::LcSecded;
+use crate::util::present::Present;
+
+use std::collections::HashMap;
+use std::convert::TryInto;
+use std::fmt::Write;
+
+use anyhow::{anyhow, bail, ensure, Result};
+
+use zerocopy::AsBytes;
+
+enum ItemType {
+ Bytes(Vec<u8>),
+ Unvalued(usize),
+}
+
+/// The hex representation of an OTP item.
+pub struct VmemItem {
+ value: ItemType,
+ offset: usize,
+ name: String,
+}
+
+impl VmemItem {
+ pub fn new(bytes: Vec<u8>, offset: usize, name: String) -> VmemItem {
+ VmemItem {
+ value: ItemType::Bytes(bytes),
+ offset,
+ name,
+ }
+ }
+
+ pub fn new_unvalued(size: usize, offset: usize, name: String) -> VmemItem {
+ VmemItem {
+ value: ItemType::Unvalued(size),
+ offset,
+ name,
+ }
+ }
+
+ pub fn size(&self) -> usize {
+ match &self.value {
+ ItemType::Bytes(b) => b.len(),
+ ItemType::Unvalued(size) => *size,
+ }
+ }
+}
+
+pub type DigestIV = u64;
+pub type DigestCnst = u128;
+
+/// Digest information for an OTP partition.
+#[derive(PartialEq)]
+pub enum DigestType {
+ Unlocked,
+ Software,
+ Hardware(DigestIV, DigestCnst),
+}
+
+/// The hex representation of an OTP partition.
+pub struct VmemPartition {
+ /// Items associated with this partition.
+ items: Vec<VmemItem>,
+ /// The name of this partition.
+ /// Used in annotations.
+ name: String,
+ /// The type of digest used for this partition.
+ /// For software digests, the value of the digest is provided and appended to the list of
+ /// items. For hardware digests, we must compute the digest value and append to the list of
+ /// items.
+ digest_type: DigestType,
+ /// Partition size.
+ size: usize,
+ /// The key name for this parition.
+ /// If specified, the serializer will attempt to scramble this parition using the key named in
+ /// this field.
+ key_name: Option<String>,
+}
+
+impl VmemPartition {
+ pub fn new(
+ name: String,
+ size: usize,
+ digest_type: DigestType,
+ key_name: Option<String>,
+ ) -> VmemPartition {
+ VmemPartition {
+ items: Vec::new(),
+ name,
+ digest_type,
+ size,
+ key_name,
+ }
+ }
+
+ /// Set the size of the partition.
+ ///
+ /// For partitions that don't specify their size, this is used to set the size of the partition
+ /// including the digest.
+ pub fn set_size(&mut self, size: usize) {
+ self.size = size;
+ }
+
+ /// Add an item to this partition.
+ pub fn push_item(&mut self, item: VmemItem) {
+ self.items.push(item);
+ }
+
+ /// Produces a tuple containing OTP HEX lines with annotations.
+ fn write_to_buffer(&self, keys: &HashMap<String, Vec<u8>>) -> Result<(Vec<u8>, Vec<String>)> {
+ if self.size % 8 != 0 {
+ bail!("Partition {} must be 64-bit alligned", self.name);
+ }
+
+ let mut defined = vec![false; self.size];
+ let mut annotations: Vec<String> = vec!["unallocated".to_owned(); self.size];
+
+ let mut data_bytes: Vec<u8> = vec![0; self.size];
+
+ for item in &self.items {
+ let end = item.offset + item.size();
+ annotations[item.offset..end].fill(format!("{}: {}", self.name, item.name).to_string());
+ let defined = &mut defined[item.offset..end];
+ if let Some(collision) = defined.iter().position(|defined| *defined) {
+ bail!(
+ "Unexpected item collision with item {} at 0x{:x}",
+ item.name,
+ collision
+ );
+ }
+ defined.fill(true);
+ if let ItemType::Bytes(bytes) = &item.value {
+ data_bytes[item.offset..end].copy_from_slice(bytes);
+ }
+ }
+
+ let mut data_blocks = Vec::<u64>::new();
+ let mut data_blocks_defined = Vec::<bool>::new();
+ for (k, chunk) in data_bytes.chunks(8).enumerate() {
+ data_blocks.push(u64::from_le_bytes(chunk.try_into().unwrap()));
+ let byte_offset = k * 8;
+ data_blocks_defined.push(
+ defined[byte_offset..byte_offset + 8]
+ .iter()
+ .fold(false, |a, &b| a || b),
+ );
+ }
+
+ if let Some(key_name) = &self.key_name {
+ let key = keys
+ .get(key_name)
+ .ok_or_else(|| anyhow!("Key not found {}", key_name))?;
+
+ let cipher = Present::try_new(key.clone())?;
+
+ for i in 0..data_blocks.len() {
+ if data_blocks_defined[i] {
+ data_blocks[i] = cipher.encrypt_block(data_blocks[i]);
+ }
+ }
+ }
+
+ if let DigestType::Hardware(iv, fin_const) = self.digest_type {
+ ensure!(
+ matches!(data_blocks.last(), None | Some(0)),
+ "Digest of partition {} cannot be overridden manually",
+ self.name
+ );
+ let last = data_blocks.len() - 1;
+ data_blocks[last] = present_digest_64(&data_blocks[0..last], iv, fin_const);
+ }
+
+ let data = data_blocks.as_bytes().to_vec();
+
+ if data.len() != self.size {
+ Err(anyhow!("Partition {} size mismatch", self.name))
+ } else {
+ Ok((data, annotations))
+ }
+ }
+}
+
+pub struct VmemImage {
+ partitions: Vec<VmemPartition>,
+ width: usize,
+ depth: usize,
+}
+
+impl VmemImage {
+ pub fn new(partitions: Vec<VmemPartition>, width: usize, depth: usize) -> VmemImage {
+ VmemImage {
+ partitions,
+ width,
+ depth,
+ }
+ }
+ pub fn generate(
+ &self,
+ keys: HashMap<String, Vec<u8>>,
+ secded: &LcSecded,
+ ) -> Result<Vec<String>> {
+ let mut data: Vec<u8> = vec![0; self.width * self.depth];
+ let mut annotations: Vec<String> = vec![Default::default(); data.len()];
+ let mut offset = 0;
+ for partition in &self.partitions {
+ let (part_data, part_annotation) = partition.write_to_buffer(&keys)?;
+ let end = offset + partition.size;
+ if end > data.len() {
+ bail!(
+ "Partition {} out of bounds, ends at 0x{:x}",
+ partition.name,
+ end
+ );
+ }
+ data[offset..end].clone_from_slice(&part_data);
+ annotations[offset..end].clone_from_slice(&part_annotation);
+ offset += partition.size;
+ }
+
+ let width_ecc = self.width + secded.ecc_byte_len();
+ let num_words = data.len() / self.width;
+
+ let mut output = vec![format!(
+ "// OTP memory hexfile with {} x {}bit layout",
+ self.depth,
+ width_ecc * 8
+ )];
+
+ for i in 0..num_words {
+ let mut word = Vec::<u8>::new();
+ let mut word_annotation = Vec::<String>::new();
+ for j in 0..self.width {
+ let idx = i * self.width + j;
+ word.push(data[idx]);
+ if !word_annotation.contains(&annotations[idx]) {
+ word_annotation.push(annotations[idx].clone());
+ }
+ }
+ let word_with_ecc = secded.ecc_encode(word)?;
+ let mut word_str = String::new();
+ for byte in word_with_ecc.iter().rev() {
+ write!(word_str, "{:02x}", byte)?;
+ }
+ output.push(format!(
+ "{} // {:06x}: {}",
+ word_str,
+ i * self.width,
+ word_annotation.join(", ")
+ ));
+ }
+
+ Ok(output)
+ }
+}
+
+fn present_digest_64(message: &[u64], iv: DigestIV, fin_const: DigestCnst) -> u64 {
+ let mut state = iv;
+ for i in (0..message.len() + 2).step_by(2) {
+ let b128: [u8; 16] = if i + 1 < message.len() {
+ (message[i] as u128) << 64 | message[i + 1] as u128
+ } else if i < message.len() {
+ (message[i] as u128) << 64 | message[i] as u128
+ } else {
+ fin_const
+ }
+ .as_bytes()
+ .try_into()
+ .unwrap();
+
+ let cipher = Present::new_128(&b128);
+ state ^= cipher.encrypt_block(state);
+ }
+
+ state
+}
diff --git a/sw/host/opentitanlib/src/util/mod.rs b/sw/host/opentitanlib/src/util/mod.rs
index 4d655de..1c3c7bf 100644
--- a/sw/host/opentitanlib/src/util/mod.rs
+++ b/sw/host/opentitanlib/src/util/mod.rs
@@ -7,8 +7,8 @@
pub mod file;
pub mod image;
pub mod parse_int;
-pub mod usb;
pub mod present;
+pub mod usb;
pub mod voltage;
/// The `collection` macro provides syntax for hash and set literals.
diff --git a/sw/host/opentitanlib/src/util/parse_int.rs b/sw/host/opentitanlib/src/util/parse_int.rs
index 1308013..6da3d48 100644
--- a/sw/host/opentitanlib/src/util/parse_int.rs
+++ b/sw/host/opentitanlib/src/util/parse_int.rs
@@ -73,6 +73,8 @@
impl_parse_int!(u32);
impl_parse_int!(i64);
impl_parse_int!(u64);
+impl_parse_int!(i128);
+impl_parse_int!(u128);
impl_parse_int!(isize);
impl_parse_int!(usize);
diff --git a/sw/host/opentitanlib/tests/lc_ctrl_state.hjson b/sw/host/opentitanlib/tests/lc_ctrl_state.hjson
new file mode 100644
index 0000000..c463f41
--- /dev/null
+++ b/sw/host/opentitanlib/tests/lc_ctrl_state.hjson
@@ -0,0 +1,104 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Use the gen-lc-state-enc.py script to regenerate the SV package:
+//
+// $ ./util/design/gen-lc-state-enc.py
+
+{
+ // Seed to be used for generation of partition item default values.
+ // Can be overridden on the command line with the --seed switch.
+ seed: 10167336684108184581
+
+ // Secded used in prim_generic_otp.sv
+ // SECDED matrix used for ECC in OTP
+ secded : {
+ data_width : 16,
+ ecc_width : 6,
+ ecc_matrix : [
+ // This is a standard extended Hamming code for 16bit
+ [0, 1, 3, 4, 6, 8, 10, 11, 13, 15], // ECC bit 0
+ [0, 2, 3, 5, 6, 9, 10, 12, 13], // ECC bit 1
+ [1, 2, 3, 7, 8, 9, 10, 14, 15], // ECC bit 2
+ [4, 5, 6, 7, 8, 9, 10], // ECC bit 3
+ [11, 12, 13, 14, 15], // ECC bit 4
+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], // Parity bit
+ ]
+ }
+
+ // Additional Hamming weight and distance requirements.
+ // Note that the life cycle words are 16 + 6 = 22 bits wide total.
+ min_hw : 5,
+ max_hw : 17,
+ min_hd : 5
+
+ // LC token size in bit
+ token_size : 128
+ tokens : [
+ {
+ name: "AllZeroToken"
+ value: "0x0"
+ }
+ {
+ name: "RndCnstRawUnlockToken"
+ value: "<random>"
+ }
+ ]
+
+ // Life cycle state definition.
+ // From least to most significant OTP word in ascending order.
+ lc_state : {
+ RAW : [ '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',],
+ TEST_UNLOCKED0 : ['B0', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'A10', 'A11', 'A12', 'A13', 'A14', 'A15', 'A16', 'A17', 'A18', 'A19',],
+ TEST_LOCKED0 : ['B0', 'B1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'A10', 'A11', 'A12', 'A13', 'A14', 'A15', 'A16', 'A17', 'A18', 'A19',],
+ TEST_UNLOCKED1 : ['B0', 'B1', 'B2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'A10', 'A11', 'A12', 'A13', 'A14', 'A15', 'A16', 'A17', 'A18', 'A19',],
+ TEST_LOCKED1 : ['B0', 'B1', 'B2', 'B3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'A10', 'A11', 'A12', 'A13', 'A14', 'A15', 'A16', 'A17', 'A18', 'A19',],
+ TEST_UNLOCKED2 : ['B0', 'B1', 'B2', 'B3', 'B4', 'A5', 'A6', 'A7', 'A8', 'A9', 'A10', 'A11', 'A12', 'A13', 'A14', 'A15', 'A16', 'A17', 'A18', 'A19',],
+ TEST_LOCKED2 : ['B0', 'B1', 'B2', 'B3', 'B4', 'B5', 'A6', 'A7', 'A8', 'A9', 'A10', 'A11', 'A12', 'A13', 'A14', 'A15', 'A16', 'A17', 'A18', 'A19',],
+ TEST_UNLOCKED3 : ['B0', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'A7', 'A8', 'A9', 'A10', 'A11', 'A12', 'A13', 'A14', 'A15', 'A16', 'A17', 'A18', 'A19',],
+ TEST_LOCKED3 : ['B0', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'A8', 'A9', 'A10', 'A11', 'A12', 'A13', 'A14', 'A15', 'A16', 'A17', 'A18', 'A19',],
+ TEST_UNLOCKED4 : ['B0', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'A9', 'A10', 'A11', 'A12', 'A13', 'A14', 'A15', 'A16', 'A17', 'A18', 'A19',],
+ TEST_LOCKED4 : ['B0', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9', 'A10', 'A11', 'A12', 'A13', 'A14', 'A15', 'A16', 'A17', 'A18', 'A19',],
+ TEST_UNLOCKED5 : ['B0', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9', 'B10', 'A11', 'A12', 'A13', 'A14', 'A15', 'A16', 'A17', 'A18', 'A19',],
+ TEST_LOCKED5 : ['B0', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9', 'B10', 'B11', 'A12', 'A13', 'A14', 'A15', 'A16', 'A17', 'A18', 'A19',],
+ TEST_UNLOCKED6 : ['B0', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9', 'B10', 'B11', 'B12', 'A13', 'A14', 'A15', 'A16', 'A17', 'A18', 'A19',],
+ TEST_LOCKED6 : ['B0', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9', 'B10', 'B11', 'B12', 'B13', 'A14', 'A15', 'A16', 'A17', 'A18', 'A19',],
+ TEST_UNLOCKED7 : ['B0', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9', 'B10', 'B11', 'B12', 'B13', 'B14', 'A15', 'A16', 'A17', 'A18', 'A19',],
+ DEV : ['B0', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9', 'B10', 'B11', 'B12', 'B13', 'B14', 'B15', 'A16', 'A17', 'A18', 'A19',],
+ PROD : ['B0', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9', 'B10', 'B11', 'B12', 'B13', 'B14', 'A15', 'B16', 'A17', 'A18', 'A19',],
+ PROD_END : ['B0', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9', 'B10', 'B11', 'B12', 'B13', 'B14', 'A15', 'A16', 'B17', 'A18', 'A19',],
+ RMA : ['B0', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9', 'B10', 'B11', 'B12', 'B13', 'B14', 'B15', 'B16', 'A17', 'B18', 'B19',],
+ SCRAP : ['B0', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9', 'B10', 'B11', 'B12', 'B13', 'B14', 'B15', 'B16', 'B17', 'B18', 'B19',]
+ }
+
+ // Life cycle state transition counter definition.
+ // From least to most significant OTP word in ascending order.
+ lc_cnt : {
+ 0 : [ '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'],
+ 1 : ['D0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9', 'C10', 'C11', 'C12', 'C13', 'C14', 'C15', 'C16', 'C17', 'C18', 'C19', 'C20', 'C21', 'C22', 'C23'],
+ 2 : ['D0', 'D1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9', 'C10', 'C11', 'C12', 'C13', 'C14', 'C15', 'C16', 'C17', 'C18', 'C19', 'C20', 'C21', 'C22', 'C23'],
+ 3 : ['D0', 'D1', 'D2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9', 'C10', 'C11', 'C12', 'C13', 'C14', 'C15', 'C16', 'C17', 'C18', 'C19', 'C20', 'C21', 'C22', 'C23'],
+ 4 : ['D0', 'D1', 'D2', 'D3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9', 'C10', 'C11', 'C12', 'C13', 'C14', 'C15', 'C16', 'C17', 'C18', 'C19', 'C20', 'C21', 'C22', 'C23'],
+ 5 : ['D0', 'D1', 'D2', 'D3', 'D4', 'C5', 'C6', 'C7', 'C8', 'C9', 'C10', 'C11', 'C12', 'C13', 'C14', 'C15', 'C16', 'C17', 'C18', 'C19', 'C20', 'C21', 'C22', 'C23'],
+ 6 : ['D0', 'D1', 'D2', 'D3', 'D4', 'D5', 'C6', 'C7', 'C8', 'C9', 'C10', 'C11', 'C12', 'C13', 'C14', 'C15', 'C16', 'C17', 'C18', 'C19', 'C20', 'C21', 'C22', 'C23'],
+ 7 : ['D0', 'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'C7', 'C8', 'C9', 'C10', 'C11', 'C12', 'C13', 'C14', 'C15', 'C16', 'C17', 'C18', 'C19', 'C20', 'C21', 'C22', 'C23'],
+ 8 : ['D0', 'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'C8', 'C9', 'C10', 'C11', 'C12', 'C13', 'C14', 'C15', 'C16', 'C17', 'C18', 'C19', 'C20', 'C21', 'C22', 'C23'],
+ 9 : ['D0', 'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'C9', 'C10', 'C11', 'C12', 'C13', 'C14', 'C15', 'C16', 'C17', 'C18', 'C19', 'C20', 'C21', 'C22', 'C23'],
+ 10 : ['D0', 'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9', 'C10', 'C11', 'C12', 'C13', 'C14', 'C15', 'C16', 'C17', 'C18', 'C19', 'C20', 'C21', 'C22', 'C23'],
+ 11 : ['D0', 'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9', 'D10', 'C11', 'C12', 'C13', 'C14', 'C15', 'C16', 'C17', 'C18', 'C19', 'C20', 'C21', 'C22', 'C23'],
+ 12 : ['D0', 'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9', 'D10', 'D11', 'C12', 'C13', 'C14', 'C15', 'C16', 'C17', 'C18', 'C19', 'C20', 'C21', 'C22', 'C23'],
+ 13 : ['D0', 'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9', 'D10', 'D11', 'D12', 'C13', 'C14', 'C15', 'C16', 'C17', 'C18', 'C19', 'C20', 'C21', 'C22', 'C23'],
+ 14 : ['D0', 'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9', 'D10', 'D11', 'D12', 'D13', 'C14', 'C15', 'C16', 'C17', 'C18', 'C19', 'C20', 'C21', 'C22', 'C23'],
+ 15 : ['D0', 'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9', 'D10', 'D11', 'D12', 'D13', 'D14', 'C15', 'C16', 'C17', 'C18', 'C19', 'C20', 'C21', 'C22', 'C23'],
+ 16 : ['D0', 'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9', 'D10', 'D11', 'D12', 'D13', 'D14', 'D15', 'C16', 'C17', 'C18', 'C19', 'C20', 'C21', 'C22', 'C23'],
+ 17 : ['D0', 'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9', 'D10', 'D11', 'D12', 'D13', 'D14', 'D15', 'D16', 'C17', 'C18', 'C19', 'C20', 'C21', 'C22', 'C23'],
+ 18 : ['D0', 'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9', 'D10', 'D11', 'D12', 'D13', 'D14', 'D15', 'D16', 'D17', 'C18', 'C19', 'C20', 'C21', 'C22', 'C23'],
+ 19 : ['D0', 'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9', 'D10', 'D11', 'D12', 'D13', 'D14', 'D15', 'D16', 'D17', 'D18', 'C19', 'C20', 'C21', 'C22', 'C23'],
+ 20 : ['D0', 'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9', 'D10', 'D11', 'D12', 'D13', 'D14', 'D15', 'D16', 'D17', 'D18', 'D19', 'C20', 'C21', 'C22', 'C23'],
+ 21 : ['D0', 'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9', 'D10', 'D11', 'D12', 'D13', 'D14', 'D15', 'D16', 'D17', 'D18', 'D19', 'D20', 'C21', 'C22', 'C23'],
+ 22 : ['D0', 'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9', 'D10', 'D11', 'D12', 'D13', 'D14', 'D15', 'D16', 'D17', 'D18', 'D19', 'D20', 'D21', 'C22', 'C23'],
+ 23 : ['D0', 'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9', 'D10', 'D11', 'D12', 'D13', 'D14', 'D15', 'D16', 'D17', 'D18', 'D19', 'D20', 'D21', 'D22', 'C23'],
+ 24 : ['D0', 'D1', 'D2', 'D3', 'D4', 'D5', 'D6', 'D7', 'D8', 'D9', 'D10', 'D11', 'D12', 'D13', 'D14', 'D15', 'D16', 'D17', 'D18', 'D19', 'D20', 'D21', 'D22', 'D23'],
+ }
+}
diff --git a/sw/host/opentitanlib/tests/otp_ctrl_img_dev.hjson b/sw/host/opentitanlib/tests/otp_ctrl_img_dev.hjson
new file mode 100644
index 0000000..82cc173
--- /dev/null
+++ b/sw/host/opentitanlib/tests/otp_ctrl_img_dev.hjson
@@ -0,0 +1,129 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Use the gen-otp-img.py script to convert this configuration into
+// a hex file for preloading the OTP in FPGA synthesis or simulation.
+//
+
+{
+ // Seed to be used for generation of partition randomized values.
+ // Can be overridden on the command line with the --seed switch.
+ seed: 01931961561863975174
+
+ // The partition and item names must correspond with the OTP memory map.
+ partitions: [
+ {
+ name: "CREATOR_SW_CFG",
+ items: [
+ {
+ name: "CREATOR_SW_CFG_DIGEST",
+ value: "0x0",
+ },
+ {
+ name: "CREATOR_SW_CFG_USE_SW_RSA_VERIFY",
+ // Use software mod_exp implementation for signature
+ // verification. See the definition of `hardened_bool_t` in
+ // sw/device/lib/base/hardened.h.
+ value: "0x739",
+ },
+ {
+ name: "CREATOR_SW_CFG_KEY_IS_VALID",
+ // Mark the first two keys as valid and remaining as
+ // invalid since we have currently only two keys. See the
+ // definition of `hardened_byte_bool_t` in
+ // sw/device/lib/base/hardened.h.
+ value: "0x4b4b4b4b4b4ba5a5",
+ }
+ ],
+ }
+ {
+ name: "OWNER_SW_CFG",
+ items: [
+ {
+ name: "OWNER_SW_CFG_DIGEST",
+ value: "0x0",
+ }
+ ],
+ }
+ {
+ name: "HW_CFG",
+ // If set to true, this computes the HW digest value
+ // and locks the partition.
+ lock: "True",
+ items: [
+ {
+ name: "DEVICE_ID",
+ value: "<random>",
+ },
+ {
+ name: "EN_CSRNG_SW_APP_READ",
+ value: "0x0",
+ },
+ {
+ name: "EN_ENTROPY_SRC_FW_READ",
+ value: "0x1",
+ },
+ ],
+ }
+ {
+ name: "SECRET0",
+ lock: "True",
+ items: [
+ {
+ name: "TEST_UNLOCK_TOKEN",
+ value: "<random>",
+ }
+ {
+ name: "TEST_EXIT_TOKEN",
+ value: "<random>",
+ }
+ ],
+ }
+ {
+ name: "SECRET1",
+ lock: "True",
+ items: [
+ {
+ name: "FLASH_ADDR_KEY_SEED",
+ value: "<random>",
+ }
+ {
+ name: "FLASH_DATA_KEY_SEED",
+ value: "<random>",
+ }
+ {
+ name: "SRAM_DATA_KEY_SEED",
+ value: "<random>",
+ }
+ ],
+ }
+ {
+ name: "SECRET2",
+ lock: "False",
+ items: [
+ {
+ name: "RMA_TOKEN",
+ value: "<random>",
+ }
+ {
+ name: "CREATOR_ROOT_KEY_SHARE0",
+ value: "<random>",
+ }
+ {
+ name: "CREATOR_ROOT_KEY_SHARE1",
+ value: "<random>",
+ }
+ ],
+ }
+ {
+ name: "LIFE_CYCLE",
+ // Can be one of the following strings:
+ // RAW, TEST_UNLOCKED0-3, TEST_LOCKED0-2, DEV, PROD, PROD_END, RMA, SCRAP
+ state: "DEV",
+ // Can range from 0 to 16.
+ // Note that a value of 0 is only permissible in RAW state.
+ count: "5"
+ }
+ ]
+}
diff --git a/sw/host/opentitanlib/tests/otp_ctrl_mmap.hjson b/sw/host/opentitanlib/tests/otp_ctrl_mmap.hjson
new file mode 100644
index 0000000..fe14f1d
--- /dev/null
+++ b/sw/host/opentitanlib/tests/otp_ctrl_mmap.hjson
@@ -0,0 +1,414 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Use the gen-otp-mmap.py script to update dependent files (like documentation
+// tables the comportable hjson and metadata SV package):
+//
+// $ ./util/design/gen-otp-mmap.py
+//
+// Make sure to regenerate the CSRs after converting the memory map:
+//
+// $ cd ${PROJ_ROOT}
+// $ make -C hw regs
+//
+
+{
+ // Seed to be used for generation of partition item default values.
+ // Can be overridden on the command line with the --seed switch.
+ seed: "10556718629619452145"
+
+ otp: {
+ width: "2", // bytes
+ depth: "1024"
+ }
+
+ // Definition of scrambling and digest constants and keys.
+ scrambling: {
+ key_size: "16",
+ iv_size: "8",
+ cnst_size: "16",
+ keys: [
+ {
+ name: "Secret0Key",
+ value: "<random>",
+ }
+ {
+ name: "Secret1Key",
+ value: "<random>",
+ }
+ {
+ name: "Secret2Key",
+ value: "<random>",
+ }
+ ]
+ digests: [
+ // This is the consistency digest used by all partitions.
+ {
+ name: "CnstyDigest",
+ iv_value: "<random>",
+ cnst_value: "<random>",
+ }
+ // The other digest configurations below are used for
+ // key derivation and token hashing.
+ {
+ name: "FlashDataKey",
+ iv_value: "<random>",
+ cnst_value: "<random>",
+ }
+ {
+ name: "FlashAddrKey",
+ iv_value: "<random>",
+ cnst_value: "<random>",
+ }
+ {
+ name: "SramDataKey",
+ iv_value: "<random>",
+ cnst_value: "<random>",
+ }
+ ]
+ }
+
+ // The enumeration order below defines the address map of the OTP controller,
+ // if the offsets are not defined explicitly via the "offset" key.
+ // Note that the digest items are added automatically to the address map.
+ partitions: [
+ {
+ name: "VENDOR_TEST",
+ variant: "Unbuffered",
+ size: "64", // in bytes
+ secret: false,
+ sw_digest: true,
+ hw_digest: false,
+ write_lock: "Digest",
+ read_lock: "CSR",
+ key_sel: "NoKey",
+ ecc_fatal: false, // Do not send out a fatal alert upon detection of uncorrectable ECC errors.
+ bkout_type: false, // Do not generate a breakout type for this partition.
+ items: [
+ {
+ name: "SCRATCH",
+ size: "56"
+ }
+ ],
+ desc: '''Vendor test partition for OTP smoke checks
+ during manufacturing. The OTP wrapper control logic inside prim_otp is allowed
+ to read/write to this region. ECC uncorrectable errors seen on the functional
+ prim_otp interface will not lead to an alert for this partition.
+ '''
+ }
+ {
+ name: "CREATOR_SW_CFG",
+ variant: "Unbuffered",
+ absorb: true,
+ size: "768", // in bytes
+ secret: false,
+ sw_digest: true,
+ hw_digest: false,
+ write_lock: "Digest",
+ read_lock: "CSR",
+ key_sel: "NoKey",
+ ecc_fatal: true, // Uncorrectable ECC errors trigger a fatal alert.
+ bkout_type: false, // Do not generate a breakout type for this partition.
+ items: [
+ {
+ name: "CREATOR_SW_CFG_AST_CFG",
+ size: "128"
+ }
+ {
+ name: "CREATOR_SW_CFG_AST_INIT_EN",
+ size: "4"
+ }
+ {
+ name: "CREATOR_SW_CFG_ROM_EXT_SKU",
+ size: "4"
+ }
+ {
+ name: "CREATOR_SW_CFG_USE_SW_RSA_VERIFY",
+ size: "4"
+ }
+ {
+ name: "CREATOR_SW_CFG_KEY_IS_VALID",
+ size: "8"
+ }
+ {
+ name: "CREATOR_SW_CFG_FLASH_DATA_DEFAULT_CFG",
+ size: "4"
+ }
+ {
+ name: "CREATOR_SW_CFG_FLASH_INFO_BOOT_DATA_CFG",
+ size: "4"
+ }
+ {
+ name: "CREATOR_SW_CFG_RNG_EN",
+ size: "4"
+ }
+ ],
+ desc: '''Software configuration partition for
+ device-specific calibration data (Clock, LDO,
+ RNG, device identity).
+ '''
+ }
+ {
+ name: "OWNER_SW_CFG",
+ variant: "Unbuffered",
+ absorb: true,
+ size: "768", // in bytes
+ secret: false,
+ sw_digest: true,
+ hw_digest: false,
+ write_lock: "Digest",
+ read_lock: "CSR",
+ key_sel: "NoKey",
+ ecc_fatal: true,
+ bkout_type: false,
+ items: [
+ {
+ name: "ROM_ERROR_REPORTING",
+ size: "4"
+ }
+ {
+ name: "ROM_BOOTSTRAP_EN",
+ size: "4"
+ }
+ {
+ name: "ROM_FAULT_RESPONSE",
+ size: "4"
+ }
+ {
+ name: "ROM_ALERT_CLASS_EN",
+ size: "4"
+ }
+ {
+ name: "ROM_ALERT_ESCALATION",
+ size: "4"
+ }
+ {
+ name: "ROM_ALERT_CLASSIFICATION",
+ size: "320"
+ }
+ {
+ name: "ROM_LOCAL_ALERT_CLASSIFICATION",
+ size: "64"
+ }
+ {
+ name: "ROM_ALERT_ACCUM_THRESH",
+ size: "16"
+ }
+ {
+ name: "ROM_ALERT_TIMEOUT_CYCLES",
+ size: "16"
+ }
+ {
+ name: "ROM_ALERT_PHASE_CYCLES",
+ size: "64"
+ }
+ ],
+ desc: '''Software configuration partition for
+ data that changes software behavior, specifically
+ in the ROM. E.g., enabling defensive features in
+ ROM or selecting failure modes if verification fails.
+ '''
+ }
+ {
+ name: "HW_CFG",
+ variant: "Buffered",
+ secret: false,
+ sw_digest: false,
+ hw_digest: true,
+ write_lock: "Digest",
+ read_lock: "None",
+ key_sel: "NoKey",
+ ecc_fatal: true,
+ bkout_type: true,
+ items: [
+ {
+ name: "DEVICE_ID",
+ size: "32",
+ // Default value to be output in case partition has not
+ // initialized or is in error state. If not specified,
+ // a value of '0 will be used.
+ inv_default: "<random>",
+ },
+ {
+ name: "MANUF_STATE",
+ size: "32",
+ inv_default: "<random>",
+ },
+ {
+ name: "EN_SRAM_IFETCH",
+ size: "1",
+ ismubi: true,
+ inv_default: false
+ },
+ {
+ name: "EN_CSRNG_SW_APP_READ",
+ size: "1",
+ ismubi: true,
+ inv_default: false
+ },
+ {
+ name: "EN_ENTROPY_SRC_FW_READ",
+ size: "1",
+ ismubi: true,
+ inv_default: false
+ },
+ {
+ name: "EN_ENTROPY_SRC_FW_OVER",
+ size: "1",
+ ismubi: true,
+ inv_default: false
+ },
+ ],
+ desc: '''
+ EN_SRAM_IFETCH: Enable / disable execute from SRAM CSR switch.
+ EN_CSRNG_SW_APP_READ: This input efuse is used to enable access
+ to the NIST internal state per instance.
+ EN_ENTROPY_SRC_FW_READ: This input efuse is used to enable access
+ to the ENTROPY_DATA register directly.
+ EN_ENTROPY_SRC_FW_OVER: This input efuse is used to enable access
+ to the firmware override FIFO and other related functions.
+ '''
+ }
+ {
+ name: "SECRET0",
+ variant: "Buffered",
+ secret: true,
+ sw_digest: false,
+ hw_digest: true,
+ write_lock: "Digest",
+ read_lock: "Digest",
+ key_sel: "Secret0Key",
+ ecc_fatal: true,
+ bkout_type: false,
+ items: [
+ {
+ name: "TEST_UNLOCK_TOKEN",
+ // This will generate a random default to be output in
+ // case partition has not initialized or is in error state.
+ // If not specified, a value of '0 will be used.
+ inv_default: "<random>",
+ size: "16"
+ }
+ {
+ name: "TEST_EXIT_TOKEN",
+ inv_default: "<random>",
+ size: "16"
+ }
+ ],
+ desc: '''Test unlock tokens.
+ '''
+ }
+ {
+ name: "SECRET1",
+ variant: "Buffered",
+ secret: true,
+ sw_digest: false,
+ hw_digest: true,
+ write_lock: "Digest",
+ read_lock: "Digest",
+ key_sel: "Secret1Key",
+ ecc_fatal: true,
+ bkout_type: false,
+ items: [
+ {
+ name: "FLASH_ADDR_KEY_SEED",
+ inv_default: "<random>",
+ size: "32"
+ }
+ {
+ name: "FLASH_DATA_KEY_SEED",
+ inv_default: "<random>",
+ size: "32"
+ }
+ {
+ name: "SRAM_DATA_KEY_SEED",
+ inv_default: "<random>",
+ size: "16"
+ }
+ ],
+ desc: '''SRAM and FLASH scrambling key roots
+ used for scrambling key derivation.
+ '''
+ }
+ {
+ name: "SECRET2",
+ variant: "Buffered",
+ secret: true,
+ sw_digest: false,
+ hw_digest: true,
+ write_lock: "Digest",
+ read_lock: "Digest",
+ key_sel: "Secret2Key",
+ ecc_fatal: true,
+ bkout_type: false,
+ items: [
+ {
+ name: "RMA_TOKEN",
+ inv_default: "<random>",
+ size: "16"
+ }
+ {
+ name: "CREATOR_ROOT_KEY_SHARE0",
+ inv_default: "<random>",
+ size: "32"
+ }
+ {
+ name: "CREATOR_ROOT_KEY_SHARE1",
+ inv_default: "<random>",
+ size: "32"
+ }
+ ],
+ desc: '''RMA unlock token and creator root key.
+ '''
+ }
+ {
+ name: "LIFE_CYCLE",
+ variant: "LifeCycle",
+ secret: false,
+ sw_digest: false,
+ hw_digest: false,
+ write_lock: "None",
+ read_lock: "None",
+ key_sel: "NoKey",
+ ecc_fatal: true,
+ bkout_type: false,
+ items: [
+ // The life cycle transition count is specified
+ // first such that any programming attempt of the life cycle
+ // partition through the LCI will always write the transition
+ // counter words first when programming an updated state vector.
+ // This is an additional safeguard, to the sequencing in the
+ // life cycle controller to ensure that the counter is always written
+ // before any state update. I.e., the life cycle controller
+ // already splits the counter and state updates into two
+ // supsequent requests through the LCI, where the first request
+ // only contains the updated transition counter, and the second
+ // request the updated transition counter and state.
+ {
+ name: "LC_TRANSITION_CNT",
+ inv_default: "<random>",
+ size: "48"
+ }
+ {
+ name: "LC_STATE",
+ inv_default: "<random>",
+ size: "40"
+ }
+ ],
+ desc: '''Life-cycle related bits. This
+ partition cannot be locked as the life cycle
+ state needs to be able to advance to RMA in-field.
+ Note that while this partition is not marked secret
+ (i.e. it is not scrambled) it is not readable
+ nor writeable via the DAI. Only the LC controller
+ can access this partition, and even via the LC
+ controller it is not possible to read the
+ raw manufacturing life cycle state in encoded form,
+ since that encoding is considered a netlist secret.
+ The LC controller only exposes a decoded version of
+ this state.
+ '''
+ }
+ ]
+}
diff --git a/sw/host/opentitanlib/tests/output.vmem b/sw/host/opentitanlib/tests/output.vmem
new file mode 100644
index 0000000..0a5bf0b
--- /dev/null
+++ b/sw/host/opentitanlib/tests/output.vmem
@@ -0,0 +1,1025 @@
+// OTP memory hexfile with 1024 x 24bit layout
+000000 // 000000: VENDOR_TEST: SCRATCH
+000000 // 000002: VENDOR_TEST: SCRATCH
+000000 // 000004: VENDOR_TEST: SCRATCH
+000000 // 000006: VENDOR_TEST: SCRATCH
+000000 // 000008: VENDOR_TEST: SCRATCH
+000000 // 00000a: VENDOR_TEST: SCRATCH
+000000 // 00000c: VENDOR_TEST: SCRATCH
+000000 // 00000e: VENDOR_TEST: SCRATCH
+000000 // 000010: VENDOR_TEST: SCRATCH
+000000 // 000012: VENDOR_TEST: SCRATCH
+000000 // 000014: VENDOR_TEST: SCRATCH
+000000 // 000016: VENDOR_TEST: SCRATCH
+000000 // 000018: VENDOR_TEST: SCRATCH
+000000 // 00001a: VENDOR_TEST: SCRATCH
+000000 // 00001c: VENDOR_TEST: SCRATCH
+000000 // 00001e: VENDOR_TEST: SCRATCH
+000000 // 000020: VENDOR_TEST: SCRATCH
+000000 // 000022: VENDOR_TEST: SCRATCH
+000000 // 000024: VENDOR_TEST: SCRATCH
+000000 // 000026: VENDOR_TEST: SCRATCH
+000000 // 000028: VENDOR_TEST: SCRATCH
+000000 // 00002a: VENDOR_TEST: SCRATCH
+000000 // 00002c: VENDOR_TEST: SCRATCH
+000000 // 00002e: VENDOR_TEST: SCRATCH
+000000 // 000030: VENDOR_TEST: SCRATCH
+000000 // 000032: VENDOR_TEST: SCRATCH
+000000 // 000034: VENDOR_TEST: SCRATCH
+000000 // 000036: VENDOR_TEST: SCRATCH
+000000 // 000038: unallocated
+000000 // 00003a: unallocated
+000000 // 00003c: unallocated
+000000 // 00003e: unallocated
+000000 // 000040: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000042: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000044: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000046: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000048: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 00004a: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 00004c: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 00004e: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000050: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000052: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000054: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000056: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000058: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 00005a: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 00005c: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 00005e: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000060: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000062: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000064: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000066: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000068: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 00006a: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 00006c: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 00006e: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000070: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000072: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000074: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000076: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000078: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 00007a: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 00007c: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 00007e: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000080: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000082: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000084: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000086: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000088: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 00008a: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 00008c: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 00008e: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000090: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000092: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000094: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000096: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 000098: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 00009a: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 00009c: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 00009e: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 0000a0: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 0000a2: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 0000a4: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 0000a6: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 0000a8: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 0000aa: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 0000ac: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 0000ae: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 0000b0: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 0000b2: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 0000b4: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 0000b6: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 0000b8: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 0000ba: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 0000bc: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 0000be: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_CFG
+000000 // 0000c0: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_INIT_EN
+000000 // 0000c2: CREATOR_SW_CFG: CREATOR_SW_CFG_AST_INIT_EN
+000000 // 0000c4: CREATOR_SW_CFG: CREATOR_SW_CFG_ROM_EXT_SKU
+000000 // 0000c6: CREATOR_SW_CFG: CREATOR_SW_CFG_ROM_EXT_SKU
+0b0739 // 0000c8: CREATOR_SW_CFG: CREATOR_SW_CFG_USE_SW_RSA_VERIFY
+000000 // 0000ca: CREATOR_SW_CFG: CREATOR_SW_CFG_USE_SW_RSA_VERIFY
+27a5a5 // 0000cc: CREATOR_SW_CFG: CREATOR_SW_CFG_KEY_IS_VALID
+0c4b4b // 0000ce: CREATOR_SW_CFG: CREATOR_SW_CFG_KEY_IS_VALID
+0c4b4b // 0000d0: CREATOR_SW_CFG: CREATOR_SW_CFG_KEY_IS_VALID
+0c4b4b // 0000d2: CREATOR_SW_CFG: CREATOR_SW_CFG_KEY_IS_VALID
+000000 // 0000d4: CREATOR_SW_CFG: CREATOR_SW_CFG_FLASH_DATA_DEFAULT_CFG
+000000 // 0000d6: CREATOR_SW_CFG: CREATOR_SW_CFG_FLASH_DATA_DEFAULT_CFG
+000000 // 0000d8: CREATOR_SW_CFG: CREATOR_SW_CFG_FLASH_INFO_BOOT_DATA_CFG
+000000 // 0000da: CREATOR_SW_CFG: CREATOR_SW_CFG_FLASH_INFO_BOOT_DATA_CFG
+000000 // 0000dc: CREATOR_SW_CFG: CREATOR_SW_CFG_RNG_EN
+000000 // 0000de: CREATOR_SW_CFG: CREATOR_SW_CFG_RNG_EN
+000000 // 0000e0: unallocated
+000000 // 0000e2: unallocated
+000000 // 0000e4: unallocated
+000000 // 0000e6: unallocated
+000000 // 0000e8: unallocated
+000000 // 0000ea: unallocated
+000000 // 0000ec: unallocated
+000000 // 0000ee: unallocated
+000000 // 0000f0: unallocated
+000000 // 0000f2: unallocated
+000000 // 0000f4: unallocated
+000000 // 0000f6: unallocated
+000000 // 0000f8: unallocated
+000000 // 0000fa: unallocated
+000000 // 0000fc: unallocated
+000000 // 0000fe: unallocated
+000000 // 000100: unallocated
+000000 // 000102: unallocated
+000000 // 000104: unallocated
+000000 // 000106: unallocated
+000000 // 000108: unallocated
+000000 // 00010a: unallocated
+000000 // 00010c: unallocated
+000000 // 00010e: unallocated
+000000 // 000110: unallocated
+000000 // 000112: unallocated
+000000 // 000114: unallocated
+000000 // 000116: unallocated
+000000 // 000118: unallocated
+000000 // 00011a: unallocated
+000000 // 00011c: unallocated
+000000 // 00011e: unallocated
+000000 // 000120: unallocated
+000000 // 000122: unallocated
+000000 // 000124: unallocated
+000000 // 000126: unallocated
+000000 // 000128: unallocated
+000000 // 00012a: unallocated
+000000 // 00012c: unallocated
+000000 // 00012e: unallocated
+000000 // 000130: unallocated
+000000 // 000132: unallocated
+000000 // 000134: unallocated
+000000 // 000136: unallocated
+000000 // 000138: unallocated
+000000 // 00013a: unallocated
+000000 // 00013c: unallocated
+000000 // 00013e: unallocated
+000000 // 000140: unallocated
+000000 // 000142: unallocated
+000000 // 000144: unallocated
+000000 // 000146: unallocated
+000000 // 000148: unallocated
+000000 // 00014a: unallocated
+000000 // 00014c: unallocated
+000000 // 00014e: unallocated
+000000 // 000150: unallocated
+000000 // 000152: unallocated
+000000 // 000154: unallocated
+000000 // 000156: unallocated
+000000 // 000158: unallocated
+000000 // 00015a: unallocated
+000000 // 00015c: unallocated
+000000 // 00015e: unallocated
+000000 // 000160: unallocated
+000000 // 000162: unallocated
+000000 // 000164: unallocated
+000000 // 000166: unallocated
+000000 // 000168: unallocated
+000000 // 00016a: unallocated
+000000 // 00016c: unallocated
+000000 // 00016e: unallocated
+000000 // 000170: unallocated
+000000 // 000172: unallocated
+000000 // 000174: unallocated
+000000 // 000176: unallocated
+000000 // 000178: unallocated
+000000 // 00017a: unallocated
+000000 // 00017c: unallocated
+000000 // 00017e: unallocated
+000000 // 000180: unallocated
+000000 // 000182: unallocated
+000000 // 000184: unallocated
+000000 // 000186: unallocated
+000000 // 000188: unallocated
+000000 // 00018a: unallocated
+000000 // 00018c: unallocated
+000000 // 00018e: unallocated
+000000 // 000190: unallocated
+000000 // 000192: unallocated
+000000 // 000194: unallocated
+000000 // 000196: unallocated
+000000 // 000198: unallocated
+000000 // 00019a: unallocated
+000000 // 00019c: unallocated
+000000 // 00019e: unallocated
+000000 // 0001a0: unallocated
+000000 // 0001a2: unallocated
+000000 // 0001a4: unallocated
+000000 // 0001a6: unallocated
+000000 // 0001a8: unallocated
+000000 // 0001aa: unallocated
+000000 // 0001ac: unallocated
+000000 // 0001ae: unallocated
+000000 // 0001b0: unallocated
+000000 // 0001b2: unallocated
+000000 // 0001b4: unallocated
+000000 // 0001b6: unallocated
+000000 // 0001b8: unallocated
+000000 // 0001ba: unallocated
+000000 // 0001bc: unallocated
+000000 // 0001be: unallocated
+000000 // 0001c0: unallocated
+000000 // 0001c2: unallocated
+000000 // 0001c4: unallocated
+000000 // 0001c6: unallocated
+000000 // 0001c8: unallocated
+000000 // 0001ca: unallocated
+000000 // 0001cc: unallocated
+000000 // 0001ce: unallocated
+000000 // 0001d0: unallocated
+000000 // 0001d2: unallocated
+000000 // 0001d4: unallocated
+000000 // 0001d6: unallocated
+000000 // 0001d8: unallocated
+000000 // 0001da: unallocated
+000000 // 0001dc: unallocated
+000000 // 0001de: unallocated
+000000 // 0001e0: unallocated
+000000 // 0001e2: unallocated
+000000 // 0001e4: unallocated
+000000 // 0001e6: unallocated
+000000 // 0001e8: unallocated
+000000 // 0001ea: unallocated
+000000 // 0001ec: unallocated
+000000 // 0001ee: unallocated
+000000 // 0001f0: unallocated
+000000 // 0001f2: unallocated
+000000 // 0001f4: unallocated
+000000 // 0001f6: unallocated
+000000 // 0001f8: unallocated
+000000 // 0001fa: unallocated
+000000 // 0001fc: unallocated
+000000 // 0001fe: unallocated
+000000 // 000200: unallocated
+000000 // 000202: unallocated
+000000 // 000204: unallocated
+000000 // 000206: unallocated
+000000 // 000208: unallocated
+000000 // 00020a: unallocated
+000000 // 00020c: unallocated
+000000 // 00020e: unallocated
+000000 // 000210: unallocated
+000000 // 000212: unallocated
+000000 // 000214: unallocated
+000000 // 000216: unallocated
+000000 // 000218: unallocated
+000000 // 00021a: unallocated
+000000 // 00021c: unallocated
+000000 // 00021e: unallocated
+000000 // 000220: unallocated
+000000 // 000222: unallocated
+000000 // 000224: unallocated
+000000 // 000226: unallocated
+000000 // 000228: unallocated
+000000 // 00022a: unallocated
+000000 // 00022c: unallocated
+000000 // 00022e: unallocated
+000000 // 000230: unallocated
+000000 // 000232: unallocated
+000000 // 000234: unallocated
+000000 // 000236: unallocated
+000000 // 000238: unallocated
+000000 // 00023a: unallocated
+000000 // 00023c: unallocated
+000000 // 00023e: unallocated
+000000 // 000240: unallocated
+000000 // 000242: unallocated
+000000 // 000244: unallocated
+000000 // 000246: unallocated
+000000 // 000248: unallocated
+000000 // 00024a: unallocated
+000000 // 00024c: unallocated
+000000 // 00024e: unallocated
+000000 // 000250: unallocated
+000000 // 000252: unallocated
+000000 // 000254: unallocated
+000000 // 000256: unallocated
+000000 // 000258: unallocated
+000000 // 00025a: unallocated
+000000 // 00025c: unallocated
+000000 // 00025e: unallocated
+000000 // 000260: unallocated
+000000 // 000262: unallocated
+000000 // 000264: unallocated
+000000 // 000266: unallocated
+000000 // 000268: unallocated
+000000 // 00026a: unallocated
+000000 // 00026c: unallocated
+000000 // 00026e: unallocated
+000000 // 000270: unallocated
+000000 // 000272: unallocated
+000000 // 000274: unallocated
+000000 // 000276: unallocated
+000000 // 000278: unallocated
+000000 // 00027a: unallocated
+000000 // 00027c: unallocated
+000000 // 00027e: unallocated
+000000 // 000280: unallocated
+000000 // 000282: unallocated
+000000 // 000284: unallocated
+000000 // 000286: unallocated
+000000 // 000288: unallocated
+000000 // 00028a: unallocated
+000000 // 00028c: unallocated
+000000 // 00028e: unallocated
+000000 // 000290: unallocated
+000000 // 000292: unallocated
+000000 // 000294: unallocated
+000000 // 000296: unallocated
+000000 // 000298: unallocated
+000000 // 00029a: unallocated
+000000 // 00029c: unallocated
+000000 // 00029e: unallocated
+000000 // 0002a0: unallocated
+000000 // 0002a2: unallocated
+000000 // 0002a4: unallocated
+000000 // 0002a6: unallocated
+000000 // 0002a8: unallocated
+000000 // 0002aa: unallocated
+000000 // 0002ac: unallocated
+000000 // 0002ae: unallocated
+000000 // 0002b0: unallocated
+000000 // 0002b2: unallocated
+000000 // 0002b4: unallocated
+000000 // 0002b6: unallocated
+000000 // 0002b8: unallocated
+000000 // 0002ba: unallocated
+000000 // 0002bc: unallocated
+000000 // 0002be: unallocated
+000000 // 0002c0: unallocated
+000000 // 0002c2: unallocated
+000000 // 0002c4: unallocated
+000000 // 0002c6: unallocated
+000000 // 0002c8: unallocated
+000000 // 0002ca: unallocated
+000000 // 0002cc: unallocated
+000000 // 0002ce: unallocated
+000000 // 0002d0: unallocated
+000000 // 0002d2: unallocated
+000000 // 0002d4: unallocated
+000000 // 0002d6: unallocated
+000000 // 0002d8: unallocated
+000000 // 0002da: unallocated
+000000 // 0002dc: unallocated
+000000 // 0002de: unallocated
+000000 // 0002e0: unallocated
+000000 // 0002e2: unallocated
+000000 // 0002e4: unallocated
+000000 // 0002e6: unallocated
+000000 // 0002e8: unallocated
+000000 // 0002ea: unallocated
+000000 // 0002ec: unallocated
+000000 // 0002ee: unallocated
+000000 // 0002f0: unallocated
+000000 // 0002f2: unallocated
+000000 // 0002f4: unallocated
+000000 // 0002f6: unallocated
+000000 // 0002f8: unallocated
+000000 // 0002fa: unallocated
+000000 // 0002fc: unallocated
+000000 // 0002fe: unallocated
+000000 // 000300: unallocated
+000000 // 000302: unallocated
+000000 // 000304: unallocated
+000000 // 000306: unallocated
+000000 // 000308: unallocated
+000000 // 00030a: unallocated
+000000 // 00030c: unallocated
+000000 // 00030e: unallocated
+000000 // 000310: unallocated
+000000 // 000312: unallocated
+000000 // 000314: unallocated
+000000 // 000316: unallocated
+000000 // 000318: unallocated
+000000 // 00031a: unallocated
+000000 // 00031c: unallocated
+000000 // 00031e: unallocated
+000000 // 000320: unallocated
+000000 // 000322: unallocated
+000000 // 000324: unallocated
+000000 // 000326: unallocated
+000000 // 000328: unallocated
+000000 // 00032a: unallocated
+000000 // 00032c: unallocated
+000000 // 00032e: unallocated
+000000 // 000330: unallocated
+000000 // 000332: unallocated
+000000 // 000334: unallocated
+000000 // 000336: unallocated
+000000 // 000338: unallocated
+000000 // 00033a: unallocated
+000000 // 00033c: unallocated
+000000 // 00033e: unallocated
+000000 // 000340: OWNER_SW_CFG: ROM_ERROR_REPORTING
+000000 // 000342: OWNER_SW_CFG: ROM_ERROR_REPORTING
+000000 // 000344: OWNER_SW_CFG: ROM_BOOTSTRAP_EN
+000000 // 000346: OWNER_SW_CFG: ROM_BOOTSTRAP_EN
+000000 // 000348: OWNER_SW_CFG: ROM_FAULT_RESPONSE
+000000 // 00034a: OWNER_SW_CFG: ROM_FAULT_RESPONSE
+000000 // 00034c: OWNER_SW_CFG: ROM_ALERT_CLASS_EN
+000000 // 00034e: OWNER_SW_CFG: ROM_ALERT_CLASS_EN
+000000 // 000350: OWNER_SW_CFG: ROM_ALERT_ESCALATION
+000000 // 000352: OWNER_SW_CFG: ROM_ALERT_ESCALATION
+000000 // 000354: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000356: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000358: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00035a: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00035c: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00035e: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000360: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000362: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000364: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000366: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000368: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00036a: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00036c: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00036e: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000370: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000372: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000374: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000376: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000378: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00037a: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00037c: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00037e: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000380: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000382: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000384: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000386: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000388: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00038a: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00038c: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00038e: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000390: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000392: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000394: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000396: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000398: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00039a: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00039c: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00039e: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003a0: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003a2: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003a4: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003a6: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003a8: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003aa: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003ac: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003ae: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003b0: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003b2: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003b4: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003b6: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003b8: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003ba: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003bc: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003be: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003c0: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003c2: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003c4: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003c6: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003c8: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003ca: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003cc: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003ce: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003d0: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003d2: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003d4: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003d6: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003d8: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003da: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003dc: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003de: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003e0: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003e2: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003e4: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003e6: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003e8: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003ea: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003ec: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003ee: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003f0: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003f2: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003f4: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003f6: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003f8: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003fa: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003fc: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 0003fe: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000400: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000402: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000404: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000406: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000408: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00040a: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00040c: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00040e: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000410: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000412: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000414: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000416: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000418: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00041a: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00041c: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00041e: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000420: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000422: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000424: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000426: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000428: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00042a: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00042c: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00042e: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000430: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000432: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000434: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000436: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000438: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00043a: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00043c: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00043e: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000440: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000442: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000444: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000446: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000448: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00044a: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00044c: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00044e: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000450: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000452: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000454: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000456: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000458: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00045a: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00045c: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00045e: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000460: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000462: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000464: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000466: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000468: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00046a: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00046c: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00046e: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000470: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000472: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000474: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000476: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000478: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00047a: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00047c: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00047e: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000480: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000482: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000484: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000486: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000488: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00048a: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00048c: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 00048e: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000490: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000492: OWNER_SW_CFG: ROM_ALERT_CLASSIFICATION
+000000 // 000494: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 000496: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 000498: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 00049a: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 00049c: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 00049e: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004a0: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004a2: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004a4: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004a6: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004a8: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004aa: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004ac: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004ae: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004b0: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004b2: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004b4: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004b6: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004b8: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004ba: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004bc: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004be: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004c0: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004c2: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004c4: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004c6: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004c8: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004ca: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004cc: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004ce: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004d0: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004d2: OWNER_SW_CFG: ROM_LOCAL_ALERT_CLASSIFICATION
+000000 // 0004d4: OWNER_SW_CFG: ROM_ALERT_ACCUM_THRESH
+000000 // 0004d6: OWNER_SW_CFG: ROM_ALERT_ACCUM_THRESH
+000000 // 0004d8: OWNER_SW_CFG: ROM_ALERT_ACCUM_THRESH
+000000 // 0004da: OWNER_SW_CFG: ROM_ALERT_ACCUM_THRESH
+000000 // 0004dc: OWNER_SW_CFG: ROM_ALERT_ACCUM_THRESH
+000000 // 0004de: OWNER_SW_CFG: ROM_ALERT_ACCUM_THRESH
+000000 // 0004e0: OWNER_SW_CFG: ROM_ALERT_ACCUM_THRESH
+000000 // 0004e2: OWNER_SW_CFG: ROM_ALERT_ACCUM_THRESH
+000000 // 0004e4: OWNER_SW_CFG: ROM_ALERT_TIMEOUT_CYCLES
+000000 // 0004e6: OWNER_SW_CFG: ROM_ALERT_TIMEOUT_CYCLES
+000000 // 0004e8: OWNER_SW_CFG: ROM_ALERT_TIMEOUT_CYCLES
+000000 // 0004ea: OWNER_SW_CFG: ROM_ALERT_TIMEOUT_CYCLES
+000000 // 0004ec: OWNER_SW_CFG: ROM_ALERT_TIMEOUT_CYCLES
+000000 // 0004ee: OWNER_SW_CFG: ROM_ALERT_TIMEOUT_CYCLES
+000000 // 0004f0: OWNER_SW_CFG: ROM_ALERT_TIMEOUT_CYCLES
+000000 // 0004f2: OWNER_SW_CFG: ROM_ALERT_TIMEOUT_CYCLES
+000000 // 0004f4: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 0004f6: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 0004f8: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 0004fa: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 0004fc: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 0004fe: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 000500: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 000502: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 000504: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 000506: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 000508: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 00050a: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 00050c: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 00050e: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 000510: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 000512: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 000514: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 000516: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 000518: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 00051a: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 00051c: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 00051e: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 000520: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 000522: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 000524: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 000526: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 000528: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 00052a: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 00052c: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 00052e: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 000530: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 000532: OWNER_SW_CFG: ROM_ALERT_PHASE_CYCLES
+000000 // 000534: unallocated
+000000 // 000536: unallocated
+000000 // 000538: unallocated
+000000 // 00053a: unallocated
+000000 // 00053c: unallocated
+000000 // 00053e: unallocated
+000000 // 000540: unallocated
+000000 // 000542: unallocated
+000000 // 000544: unallocated
+000000 // 000546: unallocated
+000000 // 000548: unallocated
+000000 // 00054a: unallocated
+000000 // 00054c: unallocated
+000000 // 00054e: unallocated
+000000 // 000550: unallocated
+000000 // 000552: unallocated
+000000 // 000554: unallocated
+000000 // 000556: unallocated
+000000 // 000558: unallocated
+000000 // 00055a: unallocated
+000000 // 00055c: unallocated
+000000 // 00055e: unallocated
+000000 // 000560: unallocated
+000000 // 000562: unallocated
+000000 // 000564: unallocated
+000000 // 000566: unallocated
+000000 // 000568: unallocated
+000000 // 00056a: unallocated
+000000 // 00056c: unallocated
+000000 // 00056e: unallocated
+000000 // 000570: unallocated
+000000 // 000572: unallocated
+000000 // 000574: unallocated
+000000 // 000576: unallocated
+000000 // 000578: unallocated
+000000 // 00057a: unallocated
+000000 // 00057c: unallocated
+000000 // 00057e: unallocated
+000000 // 000580: unallocated
+000000 // 000582: unallocated
+000000 // 000584: unallocated
+000000 // 000586: unallocated
+000000 // 000588: unallocated
+000000 // 00058a: unallocated
+000000 // 00058c: unallocated
+000000 // 00058e: unallocated
+000000 // 000590: unallocated
+000000 // 000592: unallocated
+000000 // 000594: unallocated
+000000 // 000596: unallocated
+000000 // 000598: unallocated
+000000 // 00059a: unallocated
+000000 // 00059c: unallocated
+000000 // 00059e: unallocated
+000000 // 0005a0: unallocated
+000000 // 0005a2: unallocated
+000000 // 0005a4: unallocated
+000000 // 0005a6: unallocated
+000000 // 0005a8: unallocated
+000000 // 0005aa: unallocated
+000000 // 0005ac: unallocated
+000000 // 0005ae: unallocated
+000000 // 0005b0: unallocated
+000000 // 0005b2: unallocated
+000000 // 0005b4: unallocated
+000000 // 0005b6: unallocated
+000000 // 0005b8: unallocated
+000000 // 0005ba: unallocated
+000000 // 0005bc: unallocated
+000000 // 0005be: unallocated
+000000 // 0005c0: unallocated
+000000 // 0005c2: unallocated
+000000 // 0005c4: unallocated
+000000 // 0005c6: unallocated
+000000 // 0005c8: unallocated
+000000 // 0005ca: unallocated
+000000 // 0005cc: unallocated
+000000 // 0005ce: unallocated
+000000 // 0005d0: unallocated
+000000 // 0005d2: unallocated
+000000 // 0005d4: unallocated
+000000 // 0005d6: unallocated
+000000 // 0005d8: unallocated
+000000 // 0005da: unallocated
+000000 // 0005dc: unallocated
+000000 // 0005de: unallocated
+000000 // 0005e0: unallocated
+000000 // 0005e2: unallocated
+000000 // 0005e4: unallocated
+000000 // 0005e6: unallocated
+000000 // 0005e8: unallocated
+000000 // 0005ea: unallocated
+000000 // 0005ec: unallocated
+000000 // 0005ee: unallocated
+000000 // 0005f0: unallocated
+000000 // 0005f2: unallocated
+000000 // 0005f4: unallocated
+000000 // 0005f6: unallocated
+000000 // 0005f8: unallocated
+000000 // 0005fa: unallocated
+000000 // 0005fc: unallocated
+000000 // 0005fe: unallocated
+000000 // 000600: unallocated
+000000 // 000602: unallocated
+000000 // 000604: unallocated
+000000 // 000606: unallocated
+000000 // 000608: unallocated
+000000 // 00060a: unallocated
+000000 // 00060c: unallocated
+000000 // 00060e: unallocated
+000000 // 000610: unallocated
+000000 // 000612: unallocated
+000000 // 000614: unallocated
+000000 // 000616: unallocated
+000000 // 000618: unallocated
+000000 // 00061a: unallocated
+000000 // 00061c: unallocated
+000000 // 00061e: unallocated
+000000 // 000620: unallocated
+000000 // 000622: unallocated
+000000 // 000624: unallocated
+000000 // 000626: unallocated
+000000 // 000628: unallocated
+000000 // 00062a: unallocated
+000000 // 00062c: unallocated
+000000 // 00062e: unallocated
+000000 // 000630: unallocated
+000000 // 000632: unallocated
+000000 // 000634: unallocated
+000000 // 000636: unallocated
+000000 // 000638: unallocated
+000000 // 00063a: unallocated
+000000 // 00063c: unallocated
+000000 // 00063e: unallocated
+00e8a5 // 000640: HW_CFG: DEVICE_ID
+05492f // 000642: HW_CFG: DEVICE_ID
+383aa7 // 000644: HW_CFG: DEVICE_ID
+0f3231 // 000646: HW_CFG: DEVICE_ID
+195db1 // 000648: HW_CFG: DEVICE_ID
+311749 // 00064a: HW_CFG: DEVICE_ID
+1687dc // 00064c: HW_CFG: DEVICE_ID
+30fc8d // 00064e: HW_CFG: DEVICE_ID
+0b1a6f // 000650: HW_CFG: DEVICE_ID
+31242f // 000652: HW_CFG: DEVICE_ID
+2b8bb1 // 000654: HW_CFG: DEVICE_ID
+014c1d // 000656: HW_CFG: DEVICE_ID
+139e3f // 000658: HW_CFG: DEVICE_ID
+389b8b // 00065a: HW_CFG: DEVICE_ID
+145d67 // 00065c: HW_CFG: DEVICE_ID
+1b9be6 // 00065e: HW_CFG: DEVICE_ID
+000000 // 000660: HW_CFG: MANUF_STATE
+000000 // 000662: HW_CFG: MANUF_STATE
+000000 // 000664: HW_CFG: MANUF_STATE
+000000 // 000666: HW_CFG: MANUF_STATE
+000000 // 000668: HW_CFG: MANUF_STATE
+000000 // 00066a: HW_CFG: MANUF_STATE
+000000 // 00066c: HW_CFG: MANUF_STATE
+000000 // 00066e: HW_CFG: MANUF_STATE
+000000 // 000670: HW_CFG: MANUF_STATE
+000000 // 000672: HW_CFG: MANUF_STATE
+000000 // 000674: HW_CFG: MANUF_STATE
+000000 // 000676: HW_CFG: MANUF_STATE
+000000 // 000678: HW_CFG: MANUF_STATE
+000000 // 00067a: HW_CFG: MANUF_STATE
+000000 // 00067c: HW_CFG: MANUF_STATE
+000000 // 00067e: HW_CFG: MANUF_STATE
+000000 // 000680: HW_CFG: EN_SRAM_IFETCH, HW_CFG: EN_CSRNG_SW_APP_READ
+230001 // 000682: HW_CFG: EN_ENTROPY_SRC_FW_READ, HW_CFG: EN_ENTROPY_SRC_FW_OVER
+000000 // 000684: unallocated
+000000 // 000686: unallocated
+31848f // 000688: unallocated
+18410c // 00068a: unallocated
+2ca155 // 00068c: unallocated
+2e51cd // 00068e: unallocated
+1c0f67 // 000690: SECRET0: TEST_UNLOCK_TOKEN
+3a154c // 000692: SECRET0: TEST_UNLOCK_TOKEN
+01df22 // 000694: SECRET0: TEST_UNLOCK_TOKEN
+37b22f // 000696: SECRET0: TEST_UNLOCK_TOKEN
+1a39c7 // 000698: SECRET0: TEST_UNLOCK_TOKEN
+1f5d11 // 00069a: SECRET0: TEST_UNLOCK_TOKEN
+021ea4 // 00069c: SECRET0: TEST_UNLOCK_TOKEN
+0802cc // 00069e: SECRET0: TEST_UNLOCK_TOKEN
+0cf7a4 // 0006a0: SECRET0: TEST_EXIT_TOKEN
+25c0ad // 0006a2: SECRET0: TEST_EXIT_TOKEN
+0a2f9b // 0006a4: SECRET0: TEST_EXIT_TOKEN
+1444b7 // 0006a6: SECRET0: TEST_EXIT_TOKEN
+33cdc4 // 0006a8: SECRET0: TEST_EXIT_TOKEN
+0d63b3 // 0006aa: SECRET0: TEST_EXIT_TOKEN
+34e60f // 0006ac: SECRET0: TEST_EXIT_TOKEN
+1b6d25 // 0006ae: SECRET0: TEST_EXIT_TOKEN
+3ed201 // 0006b0: unallocated
+24baea // 0006b2: unallocated
+1720c1 // 0006b4: unallocated
+30cf12 // 0006b6: unallocated
+26c3ad // 0006b8: SECRET1: FLASH_ADDR_KEY_SEED
+18d7ac // 0006ba: SECRET1: FLASH_ADDR_KEY_SEED
+12f85b // 0006bc: SECRET1: FLASH_ADDR_KEY_SEED
+265414 // 0006be: SECRET1: FLASH_ADDR_KEY_SEED
+024efd // 0006c0: SECRET1: FLASH_ADDR_KEY_SEED
+30cea8 // 0006c2: SECRET1: FLASH_ADDR_KEY_SEED
+12b032 // 0006c4: SECRET1: FLASH_ADDR_KEY_SEED
+2e4fab // 0006c6: SECRET1: FLASH_ADDR_KEY_SEED
+3cfe79 // 0006c8: SECRET1: FLASH_ADDR_KEY_SEED
+303ec4 // 0006ca: SECRET1: FLASH_ADDR_KEY_SEED
+0d3156 // 0006cc: SECRET1: FLASH_ADDR_KEY_SEED
+0cbd2b // 0006ce: SECRET1: FLASH_ADDR_KEY_SEED
+399d75 // 0006d0: SECRET1: FLASH_ADDR_KEY_SEED
+0fc5eb // 0006d2: SECRET1: FLASH_ADDR_KEY_SEED
+211da3 // 0006d4: SECRET1: FLASH_ADDR_KEY_SEED
+161185 // 0006d6: SECRET1: FLASH_ADDR_KEY_SEED
+257fe7 // 0006d8: SECRET1: FLASH_DATA_KEY_SEED
+396cf9 // 0006da: SECRET1: FLASH_DATA_KEY_SEED
+2ca570 // 0006dc: SECRET1: FLASH_DATA_KEY_SEED
+3e0d1e // 0006de: SECRET1: FLASH_DATA_KEY_SEED
+0bec0f // 0006e0: SECRET1: FLASH_DATA_KEY_SEED
+2fbffa // 0006e2: SECRET1: FLASH_DATA_KEY_SEED
+20c7d1 // 0006e4: SECRET1: FLASH_DATA_KEY_SEED
+0dbc9a // 0006e6: SECRET1: FLASH_DATA_KEY_SEED
+10991a // 0006e8: SECRET1: FLASH_DATA_KEY_SEED
+1f5a91 // 0006ea: SECRET1: FLASH_DATA_KEY_SEED
+356e57 // 0006ec: SECRET1: FLASH_DATA_KEY_SEED
+231831 // 0006ee: SECRET1: FLASH_DATA_KEY_SEED
+0debe0 // 0006f0: SECRET1: FLASH_DATA_KEY_SEED
+0297ee // 0006f2: SECRET1: FLASH_DATA_KEY_SEED
+3d8762 // 0006f4: SECRET1: FLASH_DATA_KEY_SEED
+258bae // 0006f6: SECRET1: FLASH_DATA_KEY_SEED
+227f7a // 0006f8: SECRET1: SRAM_DATA_KEY_SEED
+1b767f // 0006fa: SECRET1: SRAM_DATA_KEY_SEED
+047b6d // 0006fc: SECRET1: SRAM_DATA_KEY_SEED
+0f7eb2 // 0006fe: SECRET1: SRAM_DATA_KEY_SEED
+34a973 // 000700: SECRET1: SRAM_DATA_KEY_SEED
+11b484 // 000702: SECRET1: SRAM_DATA_KEY_SEED
+0a9687 // 000704: SECRET1: SRAM_DATA_KEY_SEED
+1b86b0 // 000706: SECRET1: SRAM_DATA_KEY_SEED
+11fdc2 // 000708: unallocated
+1b68e0 // 00070a: unallocated
+24eea0 // 00070c: unallocated
+1da8d9 // 00070e: unallocated
+2d62ad // 000710: SECRET2: RMA_TOKEN
+0ddfff // 000712: SECRET2: RMA_TOKEN
+360dfb // 000714: SECRET2: RMA_TOKEN
+1683f9 // 000716: SECRET2: RMA_TOKEN
+3b749e // 000718: SECRET2: RMA_TOKEN
+3d0e44 // 00071a: SECRET2: RMA_TOKEN
+3e7764 // 00071c: SECRET2: RMA_TOKEN
+2d06b1 // 00071e: SECRET2: RMA_TOKEN
+2861ae // 000720: SECRET2: CREATOR_ROOT_KEY_SHARE0
+15cb59 // 000722: SECRET2: CREATOR_ROOT_KEY_SHARE0
+0d3266 // 000724: SECRET2: CREATOR_ROOT_KEY_SHARE0
+1c14c4 // 000726: SECRET2: CREATOR_ROOT_KEY_SHARE0
+2294ef // 000728: SECRET2: CREATOR_ROOT_KEY_SHARE0
+1a170e // 00072a: SECRET2: CREATOR_ROOT_KEY_SHARE0
+1bac30 // 00072c: SECRET2: CREATOR_ROOT_KEY_SHARE0
+375cb0 // 00072e: SECRET2: CREATOR_ROOT_KEY_SHARE0
+3daffd // 000730: SECRET2: CREATOR_ROOT_KEY_SHARE0
+3d46e2 // 000732: SECRET2: CREATOR_ROOT_KEY_SHARE0
+1b5b13 // 000734: SECRET2: CREATOR_ROOT_KEY_SHARE0
+310a8a // 000736: SECRET2: CREATOR_ROOT_KEY_SHARE0
+2c8c63 // 000738: SECRET2: CREATOR_ROOT_KEY_SHARE0
+059536 // 00073a: SECRET2: CREATOR_ROOT_KEY_SHARE0
+3d71cd // 00073c: SECRET2: CREATOR_ROOT_KEY_SHARE0
+360808 // 00073e: SECRET2: CREATOR_ROOT_KEY_SHARE0
+3c7733 // 000740: SECRET2: CREATOR_ROOT_KEY_SHARE1
+3526f1 // 000742: SECRET2: CREATOR_ROOT_KEY_SHARE1
+0462e7 // 000744: SECRET2: CREATOR_ROOT_KEY_SHARE1
+0b976c // 000746: SECRET2: CREATOR_ROOT_KEY_SHARE1
+22bea0 // 000748: SECRET2: CREATOR_ROOT_KEY_SHARE1
+0e48b9 // 00074a: SECRET2: CREATOR_ROOT_KEY_SHARE1
+09c5de // 00074c: SECRET2: CREATOR_ROOT_KEY_SHARE1
+38468b // 00074e: SECRET2: CREATOR_ROOT_KEY_SHARE1
+17741e // 000750: SECRET2: CREATOR_ROOT_KEY_SHARE1
+2ade10 // 000752: SECRET2: CREATOR_ROOT_KEY_SHARE1
+04eefd // 000754: SECRET2: CREATOR_ROOT_KEY_SHARE1
+0391df // 000756: SECRET2: CREATOR_ROOT_KEY_SHARE1
+39fd4c // 000758: SECRET2: CREATOR_ROOT_KEY_SHARE1
+1615fa // 00075a: SECRET2: CREATOR_ROOT_KEY_SHARE1
+3ead88 // 00075c: SECRET2: CREATOR_ROOT_KEY_SHARE1
+1422ee // 00075e: SECRET2: CREATOR_ROOT_KEY_SHARE1
+319ecc // 000760: unallocated
+09f19b // 000762: unallocated
+3a6f5a // 000764: unallocated
+29367c // 000766: unallocated
+000000 // 000768: LIFE_CYCLE: LC_TRANSITION_CNT
+000000 // 00076a: LIFE_CYCLE: LC_TRANSITION_CNT
+000000 // 00076c: LIFE_CYCLE: LC_TRANSITION_CNT
+000000 // 00076e: LIFE_CYCLE: LC_TRANSITION_CNT
+000000 // 000770: LIFE_CYCLE: LC_TRANSITION_CNT
+000000 // 000772: LIFE_CYCLE: LC_TRANSITION_CNT
+000000 // 000774: LIFE_CYCLE: LC_TRANSITION_CNT
+000000 // 000776: LIFE_CYCLE: LC_TRANSITION_CNT
+000000 // 000778: LIFE_CYCLE: LC_TRANSITION_CNT
+000000 // 00077a: LIFE_CYCLE: LC_TRANSITION_CNT
+000000 // 00077c: LIFE_CYCLE: LC_TRANSITION_CNT
+000000 // 00077e: LIFE_CYCLE: LC_TRANSITION_CNT
+000000 // 000780: LIFE_CYCLE: LC_TRANSITION_CNT
+000000 // 000782: LIFE_CYCLE: LC_TRANSITION_CNT
+000000 // 000784: LIFE_CYCLE: LC_TRANSITION_CNT
+000000 // 000786: LIFE_CYCLE: LC_TRANSITION_CNT
+000000 // 000788: LIFE_CYCLE: LC_TRANSITION_CNT
+000000 // 00078a: LIFE_CYCLE: LC_TRANSITION_CNT
+000000 // 00078c: LIFE_CYCLE: LC_TRANSITION_CNT
+000000 // 00078e: LIFE_CYCLE: LC_TRANSITION_CNT
+000000 // 000790: LIFE_CYCLE: LC_TRANSITION_CNT
+000000 // 000792: LIFE_CYCLE: LC_TRANSITION_CNT
+000000 // 000794: LIFE_CYCLE: LC_TRANSITION_CNT
+000000 // 000796: LIFE_CYCLE: LC_TRANSITION_CNT
+000000 // 000798: LIFE_CYCLE: LC_STATE
+000000 // 00079a: LIFE_CYCLE: LC_STATE
+000000 // 00079c: LIFE_CYCLE: LC_STATE
+000000 // 00079e: LIFE_CYCLE: LC_STATE
+000000 // 0007a0: LIFE_CYCLE: LC_STATE
+000000 // 0007a2: LIFE_CYCLE: LC_STATE
+000000 // 0007a4: LIFE_CYCLE: LC_STATE
+000000 // 0007a6: LIFE_CYCLE: LC_STATE
+000000 // 0007a8: LIFE_CYCLE: LC_STATE
+000000 // 0007aa: LIFE_CYCLE: LC_STATE
+000000 // 0007ac: LIFE_CYCLE: LC_STATE
+000000 // 0007ae: LIFE_CYCLE: LC_STATE
+000000 // 0007b0: LIFE_CYCLE: LC_STATE
+000000 // 0007b2: LIFE_CYCLE: LC_STATE
+000000 // 0007b4: LIFE_CYCLE: LC_STATE
+000000 // 0007b6: LIFE_CYCLE: LC_STATE
+000000 // 0007b8: LIFE_CYCLE: LC_STATE
+000000 // 0007ba: LIFE_CYCLE: LC_STATE
+000000 // 0007bc: LIFE_CYCLE: LC_STATE
+000000 // 0007be: LIFE_CYCLE: LC_STATE
+000000 // 0007c0:
+000000 // 0007c2:
+000000 // 0007c4:
+000000 // 0007c6:
+000000 // 0007c8:
+000000 // 0007ca:
+000000 // 0007cc:
+000000 // 0007ce:
+000000 // 0007d0:
+000000 // 0007d2:
+000000 // 0007d4:
+000000 // 0007d6:
+000000 // 0007d8:
+000000 // 0007da:
+000000 // 0007dc:
+000000 // 0007de:
+000000 // 0007e0:
+000000 // 0007e2:
+000000 // 0007e4:
+000000 // 0007e6:
+000000 // 0007e8:
+000000 // 0007ea:
+000000 // 0007ec:
+000000 // 0007ee:
+000000 // 0007f0:
+000000 // 0007f2:
+000000 // 0007f4:
+000000 // 0007f6:
+000000 // 0007f8:
+000000 // 0007fa:
+000000 // 0007fc:
+000000 // 0007fe: