@@ -1523,7 +1523,9 @@ impl ModelFpgaSubsystem {
15231523 otp_data. len( ) ,
15241524 ) ) ?;
15251525 }
1526- otp_data[ ..self . otp_init . len ( ) ] . copy_from_slice ( & self . otp_init ) ;
1526+ for i in 0 ..self . otp_init . len ( ) {
1527+ otp_data[ i] |= self . otp_init [ i] ;
1528+ }
15271529 }
15281530
15291531 // Determine the LC state: explicit override takes priority.
@@ -1544,21 +1546,27 @@ impl ModelFpgaSubsystem {
15441546 println ! ( "Provisioning lifecycle partition (State: {})." , lc_state) ;
15451547 let mem = lc_generate_memory ( lc_state, 1 ) ?;
15461548 let offset = OTP_LIFECYCLE_PARTITION_OFFSET ;
1547- otp_data[ offset..offset + mem. len ( ) ] . copy_from_slice ( & mem) ;
1549+ for i in 0 ..mem. len ( ) {
1550+ otp_data[ offset + i] |= mem[ i] ;
1551+ }
15481552 }
15491553
15501554 // Provision default LC tokens.
15511555 println ! ( "Provisioning SECRET_LC_TRANSITION partition." ) ;
15521556 let tokens = & DEFAULT_LIFECYCLE_RAW_TOKENS ;
15531557 let mem = otp_generate_lifecycle_tokens_mem ( tokens) ?;
15541558 let offset = OTP_SECRET_LC_TRANSITION_PARTITION_OFFSET ;
1555- otp_data[ offset..offset + mem. len ( ) ] . copy_from_slice ( & mem) ;
1559+ for i in 0 ..mem. len ( ) {
1560+ otp_data[ offset + i] |= mem[ i] ;
1561+ }
15561562
15571563 // Provision default SW_TEST_UNLOCK partition (manuf debug unlock token).
15581564 println ! ( "Provisioning SW_TEST_UNLOCK partition." ) ;
15591565 let mem = otp_generate_manuf_debug_unlock_token_mem ( & DEFAULT_MANUF_DEBUG_UNLOCK_RAW_TOKEN ) ?;
15601566 let offset = OTP_SW_TEST_UNLOCK_PARTITION_OFFSET ;
1561- otp_data[ offset..offset + mem. len ( ) ] . copy_from_slice ( & mem) ;
1567+ for i in 0 ..mem. len ( ) {
1568+ otp_data[ offset + i] |= mem[ i] ;
1569+ }
15621570
15631571 // Provision default SW_MANUF partition.
15641572 // TODO(timothytrippel): enable provisioning prod debug unlock public key hashes for public
@@ -1587,7 +1595,9 @@ impl ModelFpgaSubsystem {
15871595 ..Default :: default ( )
15881596 } ) ?;
15891597 let offset = OTP_SW_MANUF_PARTITION_OFFSET ;
1590- otp_data[ offset..offset + mem. len ( ) ] . copy_from_slice ( & mem) ;
1598+ for i in 0 ..mem. len ( ) {
1599+ otp_data[ offset + i] |= mem[ i] ;
1600+ }
15911601
15921602 // Provision UDS seed in SECRET_MANUF partition
15931603 println ! ( "Provisioning UDS seed in SECRET_MANUF partition." ) ;
@@ -1598,8 +1608,9 @@ impl ModelFpgaSubsystem {
15981608 . flat_map ( |& word| word. to_le_bytes ( ) )
15991609 . collect ( ) ;
16001610 println ! ( "Setting UDS seed to {:x?}" , HexSlice ( & uds_seed_bytes) ) ;
1601- otp_data[ UDS_SEED_OFFSET ..UDS_SEED_OFFSET + uds_seed_bytes. len ( ) ]
1602- . copy_from_slice ( & uds_seed_bytes) ;
1611+ for i in 0 ..uds_seed_bytes. len ( ) {
1612+ otp_data[ UDS_SEED_OFFSET + i] |= uds_seed_bytes[ i] ;
1613+ }
16031614
16041615 // Provision field entropy in SECRET_MANUF partition
16051616 println ! ( "Provisioning field entropy in SECRET_MANUF partition." ) ;
@@ -1613,16 +1624,18 @@ impl ModelFpgaSubsystem {
16131624 "Setting field entropy to {:x?}" ,
16141625 HexSlice ( & field_entropy_bytes)
16151626 ) ;
1616- otp_data[ FIELD_ENTROPY_OFFSET ..FIELD_ENTROPY_OFFSET + field_entropy_bytes. len ( ) ]
1617- . copy_from_slice ( & field_entropy_bytes) ;
1627+ for i in 0 ..field_entropy_bytes. len ( ) {
1628+ otp_data[ FIELD_ENTROPY_OFFSET + i] |= field_entropy_bytes[ i] ;
1629+ }
16181630
16191631 let vendor_pk_hash = self . fuses . vendor_pk_hash . as_bytes ( ) ;
16201632 println ! (
16211633 "Setting vendor public key hash to {:x?}" ,
16221634 HexSlice ( vendor_pk_hash)
16231635 ) ;
1624- otp_data[ FUSE_VENDOR_PKHASH_OFFSET ..FUSE_VENDOR_PKHASH_OFFSET + vendor_pk_hash. len ( ) ]
1625- . copy_from_slice ( vendor_pk_hash) ;
1636+ for i in 0 ..vendor_pk_hash. len ( ) {
1637+ otp_data[ FUSE_VENDOR_PKHASH_OFFSET + i] |= vendor_pk_hash[ i] ;
1638+ }
16261639
16271640 let vendor_pqc_type = FwVerificationPqcKeyType :: from_u8 ( self . fuses . fuse_pqc_key_type as u8 )
16281641 . unwrap_or ( FwVerificationPqcKeyType :: LMS ) ;
@@ -1634,16 +1647,17 @@ impl ModelFpgaSubsystem {
16341647 FwVerificationPqcKeyType :: MLDSA => 0 ,
16351648 FwVerificationPqcKeyType :: LMS => 1 ,
16361649 } ;
1637- otp_data[ FUSE_PQC_OFFSET ] = val;
1650+ otp_data[ FUSE_PQC_OFFSET ] | = val;
16381651
16391652 // Owner public key hash (48 bytes) lives in VENDOR_HASHES_PROD partition
16401653 let owner_pk_hash = self . fuses . owner_pk_hash . as_bytes ( ) ;
16411654 println ! (
16421655 "Setting owner public key hash to {:x?}" ,
16431656 HexSlice ( owner_pk_hash)
16441657 ) ;
1645- otp_data[ FUSE_OWNER_PKHASH_OFFSET ..FUSE_OWNER_PKHASH_OFFSET + owner_pk_hash. len ( ) ]
1646- . copy_from_slice ( owner_pk_hash) ;
1658+ for i in 0 ..owner_pk_hash. len ( ) {
1659+ otp_data[ FUSE_OWNER_PKHASH_OFFSET + i] |= owner_pk_hash[ i] ;
1660+ }
16471661
16481662 // Owner revocation fields (ECC, LMS, MLDSA) in VENDOR_REVOCATIONS_PROD partition
16491663 // Note: ECC revocation in API is a 4-bit value; store in low bits of u32 here.
@@ -1654,41 +1668,42 @@ impl ModelFpgaSubsystem {
16541668 "Setting owner revocations ecc={:#x} lms={:#x} mldsa={:#x}" ,
16551669 vendor_ecc_revocation, vendor_lms_revocation, vendor_mldsa_revocation
16561670 ) ;
1657- otp_data[ FUSE_VENDOR_ECC_REVOCATION_OFFSET ..FUSE_VENDOR_ECC_REVOCATION_OFFSET + 4 ]
1658- . copy_from_slice ( & vendor_ecc_revocation. to_le_bytes ( ) ) ;
1659- otp_data[ FUSE_VENDOR_LMS_REVOCATION_OFFSET ..FUSE_VENDOR_LMS_REVOCATION_OFFSET + 4 ]
1660- . copy_from_slice ( & vendor_lms_revocation. to_le_bytes ( ) ) ;
1661- otp_data[ FUSE_VENDOR_REVOCATION_OFFSET ..FUSE_VENDOR_REVOCATION_OFFSET + 4 ]
1662- . copy_from_slice ( & vendor_mldsa_revocation. to_le_bytes ( ) ) ;
1671+ for i in 0 ..4 {
1672+ otp_data[ FUSE_VENDOR_ECC_REVOCATION_OFFSET + i] |= vendor_ecc_revocation. to_le_bytes ( ) [ i] ;
1673+ otp_data[ FUSE_VENDOR_LMS_REVOCATION_OFFSET + i] |= vendor_lms_revocation. to_le_bytes ( ) [ i] ;
1674+ otp_data[ FUSE_VENDOR_REVOCATION_OFFSET + i] |= vendor_mldsa_revocation. to_le_bytes ( ) [ i] ;
1675+ }
16631676
16641677 // Firmware/runtime SVN (16 bytes -> 4 words)
16651678 let fw_svn = self . fuses . fw_svn . as_bytes ( ) ;
16661679 println ! ( "Setting runtime FW SVN to {:x?}" , HexSlice ( fw_svn) ) ;
1667- otp_data [ OTP_SVN_PARTITION_RUNTIME_SVN_FIELD_OFFSET
1668- .. OTP_SVN_PARTITION_RUNTIME_SVN_FIELD_OFFSET + fw_svn. len ( ) ]
1669- . copy_from_slice ( fw_svn ) ;
1680+ for i in 0 ..fw_svn . len ( ) {
1681+ otp_data [ OTP_SVN_PARTITION_RUNTIME_SVN_FIELD_OFFSET + i ] |= fw_svn[ i ] ;
1682+ }
16701683
16711684 // SoC manifest SVN (16 bytes -> 4 words)
16721685 let soc_manifest_svn = self . fuses . soc_manifest_svn . as_bytes ( ) ;
16731686 println ! (
16741687 "Setting SoC manifest SVN to {:x?}" ,
16751688 HexSlice ( soc_manifest_svn)
16761689 ) ;
1677- otp_data [ OTP_SVN_PARTITION_SOC_MANIFEST_SVN_FIELD_OFFSET
1678- .. OTP_SVN_PARTITION_SOC_MANIFEST_SVN_FIELD_OFFSET + soc_manifest_svn. len ( ) ]
1679- . copy_from_slice ( soc_manifest_svn ) ;
1690+ for i in 0 ..soc_manifest_svn . len ( ) {
1691+ otp_data [ OTP_SVN_PARTITION_SOC_MANIFEST_SVN_FIELD_OFFSET + i ] |= soc_manifest_svn[ i ] ;
1692+ }
16801693
16811694 println ! ( "Provisioning CPTRA_SS_LOCK_HEK_PROD_0 partition." ) ;
16821695 let hek_seed_bytes = self . fuses . hek_seed . as_bytes ( ) ;
16831696 let offset = OTP_CPTRA_SS_LOCK_HEK_PROD_0_OFFSET ;
1684- otp_data[ offset..offset + hek_seed_bytes. len ( ) ] . copy_from_slice ( hek_seed_bytes) ;
1697+ for i in 0 ..hek_seed_bytes. len ( ) {
1698+ otp_data[ offset + i] |= hek_seed_bytes[ i] ;
1699+ }
16851700
16861701 // Max SOC Manifest SVN (1 byte used)
16871702 println ! (
16881703 "Burning fuse for SOC MAX SVN {}" ,
16891704 self . fuses. soc_manifest_max_svn
16901705 ) ;
1691- otp_data[ OTP_SVN_PARTITION_SOC_MAX_SVN_FIELD_OFFSET ] = self . fuses . soc_manifest_max_svn ;
1706+ otp_data[ OTP_SVN_PARTITION_SOC_MAX_SVN_FIELD_OFFSET ] | = self . fuses . soc_manifest_max_svn ;
16921707
16931708 self . otp_slice ( ) . copy_from_slice ( & otp_data) ;
16941709
@@ -2500,10 +2515,16 @@ impl HwModel for ModelFpgaSubsystem {
25002515 self . realtime_thread_paused . store ( true , Ordering :: Relaxed ) ;
25012516 std:: thread:: sleep ( Duration :: from_millis ( 2 ) ) ;
25022517
2518+ // Save OTP contents prior to AXI reset as it is zeroized by reset.
2519+ let saved_otp = self . otp_slice ( ) . to_vec ( ) ;
2520+
25032521 // Full AXI reset to clear all subsystem state including MCU
25042522 println ! ( "AXI reset" ) ;
25052523 self . axi_reset ( ) ;
25062524
2525+ // Restore OTP contents after AXI reset
2526+ self . otp_slice ( ) . copy_from_slice ( & saved_otp) ;
2527+
25072528 // Re-program all hardware registers cleared by AXI reset
25082529 self . setup_hardware_registers ( ) ;
25092530
0 commit comments