Skip to content

Commit

Permalink
[fix] UDS programming fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
mhatrevi committed Feb 28, 2025
1 parent b4c8333 commit b246213
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 21 deletions.
7 changes: 3 additions & 4 deletions rom/dev/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,17 +237,16 @@ The following flows are conducted when the ROM is operating in the manufacturing
#### UDS Provisioning
1. On reset, the ROM checks if the `UDS_PROGRAM_REQ` bit in the `SS_DBG_MANUF_SERVICE_REG_REQ` register is set. If the bit is set, ROM initiates the UDS seed programming flow by setting the `UDS_PROGRAM_IN_PROGRESS` bit in the `SS_DBG_MANUF_SERVICE_REG_RSP` register. If the flow fails at some point past reading the REQ bits, the flow will be aborted and an error returned.

2. ROM then retrieves a 512-bit value from the iTRNG, the UDS Seed programming base address from the `SS_UDS_SEED_PROGRAMMING_BASE_ADDR_L` and `SS_UDS_SEED_PROGRAMMING_BASE_ADDR_H` registers and the Fuse Controller's base address from the `SS_OTP_FC_BASE_ADDR_L` and `SS_OTP_FC_BASE_ADDR_H` registers.
2. ROM then retrieves a 512-bit value from the iTRNG, the UDS Seed programming base address from the `SS_UDS_SEED_BASE_ADDR_L` and `SS_UDS_SEED_BASE_ADDR_H` registers and the Fuse Controller's base address from the `SS_OTP_FC_BASE_ADDR_L` and `SS_OTP_FC_BASE_ADDR_H` registers.

3. ROM then retrieves the UDS granularity from the `CPTRA_HW_CONFIG` register Bit6 to learn if the fuse row is accessible with 32-bit or 64-bit granularity.

4. ROM then performs the following steps until all the 512 bits of the UDS seed are programmed:
1. The ROM verifies the idle state of the DAI by reading the `STATUS` register `DAI_IDLE` bit (Bit 14) of the Fuse Controller, located at offset 0x10 from the Fuse Controller's base address.
1. The ROM verifies the idle state of the DAI by reading the `STATUS` register `DAI_IDLE` bit (Bit-21) of the Fuse Controller, located at offset 0x10 from the Fuse Controller's base address.
2. If the granularity is 32-bit, the ROM writes the next word from the UDS seed to the `DIRECT_ACCESS_WDATA_0` register. If the granularity is 64-bit, the ROM writes the next two words to `the DIRECT_ACCESS_WDATA_0` and `DIRECT_ACCESS_WDATA_1` registers, located at offsets 0x44 and 0x48 respectively from the Fuse Controller's base address.
3. The ROM writes the lower 32 bits of the UDS Seed programming base address to the `DIRECT_ACCESS_ADDRESS` register at offset 0x40.
4. The ROM triggers the UDS seed write command by writing 0x2 to the `DIRECT_ACCESS_CMD` register at offset 0x3C.
5. [OPEN] Handle DAI error.
6. The ROM increments the `DIRECT_ACCESS_ADDRESS` register by 4 for 32-bit granularity or 8 for 64-bit granularity and repeats the process for the remaining words of the UDS seed.
5. The ROM increments the `DIRECT_ACCESS_ADDRESS` register by 4 for 32-bit granularity or 8 for 64-bit granularity and repeats the process for the remaining words of the UDS seed.

5. The ROM continuously polls the Fuse Controller's `STATUS` register until the DAI state returns to idle.

Expand Down
44 changes: 27 additions & 17 deletions rom/dev/src/flow/uds_programming.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ use caliptra_common::cprintln;
use caliptra_drivers::{AxiAddr, CaliptraError, CaliptraResult, Lifecycle};

const STATUS_REG_OFFSET: u64 = 0x10;
const DIRECT_ACCESS_WDATA_0_REG_OFFSET: u64 = 0x44;
const DIRECT_ACCESS_WDATA_1_REG_OFFSET: u64 = 0x48;
const DIRECT_ACCESS_ADDRESS_REG_OFFSET: u64 = 0x40;
const DIRECT_ACCESS_CMD_REG_OFFSET: u64 = 0x3C;
const DAI_IDLE_BIT: u32 = 1 << 14;
const DIRECT_ACCESS_WDATA_0_REG_OFFSET: u64 = 0x60;
const DIRECT_ACCESS_WDATA_1_REG_OFFSET: u64 = 0x64;
const DIRECT_ACCESS_ADDRESS_REG_OFFSET: u64 = 0x5C;
const DIRECT_ACCESS_CMD_REG_OFFSET: u64 = 0x58;
const DAI_IDLE_BIT: u32 = 1 << 21;
const DIRECT_ACCESS_CMD_WRITE: u32 = 0x2;
const DIRECT_ACCESS_CMD_DIGEST: u32 = 0x4;

Expand All @@ -33,8 +33,6 @@ impl UdsProgrammingFlow {
#[inline(never)]
#[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)]
pub fn program_uds(env: &mut RomEnv) -> CaliptraResult<()> {
cprintln!("[uds] ++");

// Check if UDS programming is requested.
if !env.soc_ifc.uds_program_req() {
return Ok(());
Expand All @@ -55,6 +53,7 @@ impl UdsProgrammingFlow {
}

// Update the UDS programming state.
cprintln!("[uds] Updating the UDS programming state");
env.soc_ifc
.set_uds_programming_flow_state(true /* in_progress */);

Expand Down Expand Up @@ -85,13 +84,15 @@ impl UdsProgrammingFlow {
while {
let status_value = env.dma.read_dword(AxiAddr::from(status_reg_addr))?;
(status_value & DAI_IDLE_BIT) == 0
} {
// [TODO][CAP2] Handle errors.
}
} {}

// Write the UDS seed to the DIRECT_ACCESS_WDATA_0 register
// and the DIRECT_ACCESS_WDATA_1 register (for 64-bit granularity).
let wdata_0 = seed[seed_index];
cprintln!(
"[uds] Writing the UDS seed to the DIRECT_ACCESS_WDATA_0: {:x} register, wdata_0: {:#x}",
direct_access_wdata_0_reg_addr, wdata_0
);
env.dma
.write_dword(AxiAddr::from(direct_access_wdata_0_reg_addr), wdata_0)?;
if uds_fuse_row_granularity_64 {
Expand All @@ -100,6 +101,10 @@ impl UdsProgrammingFlow {
}
// 64-bit granularity
let wdata_1 = seed[seed_index + 1];
cprintln!(
"[uds] Writing the UDS seed to the DIRECT_ACCESS_WDATA_1: {:x} register, wdata_1: {:#x}",
direct_access_wdata_1_reg_addr, wdata_1
);
env.dma
.write_dword(AxiAddr::from(direct_access_wdata_1_reg_addr), wdata_1)?;
seed_index += 2;
Expand All @@ -109,12 +114,16 @@ impl UdsProgrammingFlow {
}

// Write the lower 32 bits of the UDS Seed programming destination address to the DIRECT_ACCESS_ADDRESS register.
cprintln!("[uds] Writing the lower 32 bits of the UDS Seed programming destination address: {:x} to the DIRECT_ACCESS_ADDRESS register: {:x}",
uds_seed_dest_address, direct_access_address_reg_addr);
env.dma.write_dword(
AxiAddr::from(direct_access_address_reg_addr),
uds_seed_dest_address,
)?;

// Trigger the UDS seed write command
cprintln!("[uds] Triggering the UDS seed write command, direct_access_cmd_reg_addr: {:x}, command: {:#x}",
direct_access_cmd_reg_addr, DIRECT_ACCESS_CMD_WRITE);
env.dma.write_dword(
AxiAddr::from(direct_access_cmd_reg_addr),
DIRECT_ACCESS_CMD_WRITE,
Expand All @@ -133,18 +142,19 @@ impl UdsProgrammingFlow {
while {
let status_value = env.dma.read_dword(AxiAddr::from(status_reg_addr))?;
(status_value & DAI_IDLE_BIT) == 0
} {
// [TODO][CAP2] Handle errors.
}
} {}

// Write the lower 32 bits of the UDS Seed programming base address to the DIRECT_ACCESS_ADDRESS register.
cprintln!("[uds] Triggering the partition digest operation");
cprintln!("[uds] Triggering the partition digest operation, direct_access_address_reg_addr: {:x}, uds_seed_dest_address: {:#x}",
direct_access_address_reg_addr, env.soc_ifc.uds_seed_dest_base_addr_low());
env.dma.write_dword(
AxiAddr::from(direct_access_address_reg_addr),
env.soc_ifc.uds_seed_dest_base_addr_low(),
)?;

// Trigger the digest calculation command
cprintln!("[uds] Triggering the digest calculation command, direct_access_cmd_reg_addr: {:x}, command: {:#x}",
direct_access_cmd_reg_addr, DIRECT_ACCESS_CMD_DIGEST);
env.dma.write_dword(
AxiAddr::from(direct_access_cmd_reg_addr),
DIRECT_ACCESS_CMD_DIGEST,
Expand All @@ -154,17 +164,17 @@ impl UdsProgrammingFlow {
while {
let status_value = env.dma.read_dword(AxiAddr::from(status_reg_addr))?;
(status_value & DAI_IDLE_BIT) == 0
} {
// [TODO][CAP2] Handle errors.
}
} {}

Ok(())
})();

// Set the UDS programming result.
cprintln!("[uds] Setting the UDS programming result");
env.soc_ifc.set_uds_programming_flow_status(result.is_ok());

// Update the UDS programming state.
cprintln!("[uds] Updating the UDS programming state");
env.soc_ifc
.set_uds_programming_flow_state(false /* in_progress */);

Expand Down

0 comments on commit b246213

Please sign in to comment.