[opentitantool] Add usr_access_set, usr_access_timestamp, rm_crc
Signed-off-by: Alphan Ulusoy <alphan@google.com>
diff --git a/sw/host/opentitanlib/src/util/usr_access.rs b/sw/host/opentitanlib/src/util/usr_access.rs
index c1a2c8a..b60a904 100644
--- a/sw/host/opentitanlib/src/util/usr_access.rs
+++ b/sw/host/opentitanlib/src/util/usr_access.rs
@@ -7,7 +7,11 @@
use std::convert::TryInto;
use thiserror::Error;
+use chrono::{Datelike, Timelike, Utc};
+
const WRITE_USR_ACCESS: [u8; 4] = [0x30, 0x01, 0xa0, 0x01];
+const WRITE_CRC_REG: [u8; 4] = [0x30, 0x00, 0x00, 0x01];
+const NOOP: [u8; 4] = [0x20, 0x00, 0x00, 0x00];
#[derive(Error, Debug, Serialize, Deserialize)]
pub enum Error {
@@ -25,6 +29,41 @@
* 4)
}
+/// Searches for the following pattern in the bitstream
+///
+/// 0x30000001 (write the following word to the CRC register and check)
+/// 0xXXXXXXXX (value to write to the CRC register)
+/// 0x20000000 (NOOP)
+/// 0x20000000 (NOOP)
+///
+/// and replaces it with
+///
+/// 0x20000000 (NOOP)
+/// 0x20000000 (NOOP)
+/// 0x20000000 (NOOP)
+/// 0x20000000 (NOOP)
+///
+/// to remove the CRC check during FPGA configuration.
+fn remove_crc(bitstream: &mut [u8]) {
+ let mut start = 0;
+ while start < bitstream.len() {
+ match find_cmd(&bitstream[start..], &WRITE_CRC_REG) {
+ Ok(mut i) => {
+ i += start;
+ if (i + 16) <= bitstream.len()
+ && bitstream[i + 8..i + 12] == NOOP
+ && bitstream[i + 12..i + 16] == NOOP
+ {
+ log::info!("Replaced WRITE_CRC_REG command at {:#x} with NOOP", i);
+ bitstream[i..i + 4].copy_from_slice(&NOOP);
+ bitstream[i + 4..i + 8].copy_from_slice(&NOOP);
+ }
+ start = i + 16;
+ }
+ _ => return,
+ }
+ }
+}
pub fn usr_access_get(bitstream: &[u8]) -> Result<u32> {
let i = find_cmd(&bitstream, &WRITE_USR_ACCESS)?;
@@ -37,3 +76,34 @@
Ok(usr_access)
}
+/// Returns a 32-bit timestamp suitable to be used as a USR_ACCESS value:
+///
+/// |-------+-------+-------+-------------------------+-------+--------+--------|
+/// | Bits: | 31:27 | 26:23 | 22:17 | 16:12 | 11:6 | 5:0 |
+/// |-------+-------+-------+-------------------------+-------+--------+--------|
+/// | Data: | Day | Month | Year (since 2000, 0-63) | Hour | Minute | Second |
+/// |-------+-------+-------+-------------------------+-------+--------+--------|
+///
+/// From
+/// https://www.xilinx.com/content/dam/xilinx/support/documents/application_notes/xapp1232-bitstream-id-with-usr_access.pdf
+pub fn usr_access_timestamp() -> u32 {
+ let now = Utc::now();
+ now.day() << 27
+ | now.month() << 23
+ | now.year_ce().1.checked_sub(2000u32).unwrap() << 17
+ | now.hour() << 12
+ | now.minute() << 6
+ | now.second()
+}
+
+pub fn usr_access_set(bitstream: &mut [u8], val: u32) -> Result<()> {
+ let i = find_cmd(bitstream, &WRITE_USR_ACCESS)?;
+ log::info!(
+ "Bitstream file old USR_ACCESS value: {:#x}",
+ u32::from_be_bytes(bitstream[i + 4..i + 8].try_into()?)
+ );
+ bitstream[i + 4..i + 8].copy_from_slice(&val.to_be_bytes());
+ log::info!("Bitstream file new USR_ACCESS value: {:#x}", val);
+ remove_crc(bitstream);
+ Ok(())
+}