1 // 2 // Copyright (c) 2010-2023 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 8 using System; 9 using System.Collections.Generic; 10 using System.Linq; 11 using System.Reflection; 12 using Antmicro.Renode.Core; 13 using Antmicro.Renode.Core.Structure.Registers; 14 using Antmicro.Renode.Exceptions; 15 using Antmicro.Renode.Logging; 16 using Antmicro.Renode.Peripherals.Memory; 17 using Antmicro.Renode.Utilities; 18 19 namespace Antmicro.Renode.Peripherals.Miscellaneous 20 { 21 public class OpenTitan_OneTimeProgrammableMemoryController: BasicDoubleWordPeripheral, IKnownSize 22 { OpenTitan_OneTimeProgrammableMemoryController(IMachine machine)23 public OpenTitan_OneTimeProgrammableMemoryController(IMachine machine) : base(machine) 24 { 25 memoryLock = new Object(); 26 transitionCountLock = new Object(); 27 DefineRegisters(); 28 29 FatalMacroAlert = new GPIO(); 30 FatalCheckErrorAlert = new GPIO(); 31 FatalBusAlert = new GPIO(); 32 FatalPrimitiveOtpAlert = new GPIO(); 33 RecoverablePrimitiveOtpAlert = new GPIO(); 34 35 aValues = new ushort[ABValuesWordsCount]; 36 bValues = new ushort[ABValuesWordsCount]; 37 cValues = new ushort[CDValuesWordsCount]; 38 dValues = new ushort[CDValuesWordsCount]; 39 40 InitPositionConsumedToLifeCycleMapping(); 41 underlyingMemory = new ArrayMemory(0x1000); 42 43 Reset(); 44 } 45 Reset()46 public override void Reset() 47 { 48 base.Reset(); 49 FatalMacroAlert.Unset(); 50 FatalCheckErrorAlert.Unset(); 51 FatalBusAlert.Unset(); 52 FatalPrimitiveOtpAlert.Unset(); 53 RecoverablePrimitiveOtpAlert.Unset(); 54 55 daiIdleFlag.Value = true; 56 cachedLifeCycleState = null; 57 cachedTransitionCount = null; 58 } 59 LoadVmem(ReadFilePath filename)60 public void LoadVmem(ReadFilePath filename) 61 { 62 try 63 { 64 var reader = new VmemReader(filename); 65 lock(memoryLock) 66 { 67 foreach(var pair in reader.GetIndexDataPairs()) 68 { 69 // VmemReader returns 4 byte values, but the two first contains only the ECC which we don't need 70 var offset = pair.Item1 * 2; 71 underlyingMemory.WriteWord(offset, (ushort)pair.Item2); 72 } 73 } 74 } 75 catch(Exception e) 76 { 77 throw new RecoverableException($"Exception while loading file {filename}: {e.Message}"); 78 } 79 } 80 GetOtpItem(OtpItem item)81 public byte[] GetOtpItem(OtpItem item) 82 { 83 var itemLength = GetItemSizeAttribute(item); 84 lock(memoryLock) 85 { 86 return underlyingMemory.ReadBytes((uint)item, itemLength.ByteLength); 87 } 88 } 89 IncrementTransitionCount()90 public int IncrementTransitionCount() 91 { 92 lock(transitionCountLock) 93 { 94 var currentCount = LifeCycleTransitionCount; 95 if(currentCount == MaximumTransitionsCount) 96 { 97 this.Log(LogLevel.Warning, "Transitions count already reached its limit of {0} transitions. Trying to increment it now is illegal.", MaximumTransitionsCount); 98 return -1; 99 100 } 101 LifeCycleTransitionCount = (ushort)(currentCount + 1); 102 } 103 return LifeCycleTransitionCount; 104 } 105 106 public long Size => 0x1800; 107 108 public GPIO FatalMacroAlert { get; } 109 public GPIO FatalCheckErrorAlert { get; } 110 public GPIO FatalBusAlert { get; } 111 public GPIO FatalPrimitiveOtpAlert { get; } 112 public GPIO RecoverablePrimitiveOtpAlert { get; } 113 114 public string AValuesChain 115 { 116 set 117 { 118 aValues = SplitValueChainIntoWordsArray(value); 119 } 120 } 121 122 public string BValuesChain 123 { 124 set 125 { 126 bValues = SplitValueChainIntoWordsArray(value); 127 } 128 } 129 130 public string CValuesChain 131 { 132 set 133 { 134 cValues = SplitValueChainIntoWordsArray(value); 135 } 136 } 137 138 public string DValuesChain 139 { 140 set 141 { 142 dValues = SplitValueChainIntoWordsArray(value); 143 } 144 } 145 146 public OpenTitan_LifeCycleState LifeCycleState 147 { 148 set 149 { 150 EncodeLifeCycleState(value); 151 cachedLifeCycleState = value; 152 } 153 get 154 { 155 if(!cachedLifeCycleState.HasValue) 156 { 157 OpenTitan_LifeCycleState state; 158 cachedLifeCycleState = TryDecodeLifeCycleState(out state) ? state : OpenTitan_LifeCycleState.Invalid; 159 } 160 return cachedLifeCycleState.Value; 161 } 162 } 163 164 public ushort LifeCycleTransitionCount 165 { 166 private set 167 { 168 cachedTransitionCount = value; 169 EncodeLifeCycleTransitionCount(value); 170 } 171 get 172 { 173 if(!cachedTransitionCount.HasValue) 174 { 175 cachedTransitionCount = DecodeLifeCycleTransitionCount(); 176 } 177 return cachedTransitionCount.Value; 178 } 179 } 180 DefineRegisters()181 private void DefineRegisters() 182 { 183 Registers.InterruptState.Define(this) 184 .WithTaggedFlag("otp_operation_done", 0) 185 .WithTaggedFlag("otp_error", 1) 186 .WithIgnoredBits(2, 30); 187 Registers.InterruptEnable.Define(this) 188 .WithTaggedFlag("otp_operation_done", 0) 189 .WithTaggedFlag("otp_error", 1) 190 .WithIgnoredBits(2, 30); 191 Registers.InterruptTest.Define(this) 192 .WithTaggedFlag("otp_operation_done", 0) 193 .WithTaggedFlag("otp_error", 1) 194 .WithIgnoredBits(2, 30); 195 Registers.AlertTest.Define(this) 196 .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalMacroAlert.Blink(); }, name: "fatal_macro_error") 197 .WithFlag(1, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalCheckErrorAlert.Blink(); }, name: "fatal_check_error") 198 .WithFlag(2, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalBusAlert.Blink(); }, name: "fatal_bus_integ_error") 199 .WithFlag(3, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalPrimitiveOtpAlert.Blink(); }, name: "fatal_prim_otp_alert") 200 .WithFlag(4, FieldMode.Write, writeCallback: (_, val) => { if(val) RecoverablePrimitiveOtpAlert.Blink(); }, name: "recov_prim_otp_alert") 201 .WithIgnoredBits(5, 27); 202 Registers.Status.Define(this) 203 .WithFlag(0, out vendorPartitionErrorFlag, FieldMode.Read, name: "VENDOR_TEST_ERROR") 204 .WithFlag(1, out creatorPartitionErrorFlag, FieldMode.Read, name: "CREATOR_SW_CFG_ERROR") 205 .WithFlag(2, out ownerPartitionErrorFlag, FieldMode.Read, name: "OWNER_SW_CFG_ERROR") 206 .WithFlag(3, out hardwarePartitionErrorFlag, FieldMode.Read, name: "HW_CFG_ERROR") 207 .WithFlag(4, out secret0PartitionErrorFlag, FieldMode.Read, name: "SECRET0_ERROR") 208 .WithFlag(5, out secret1PartitionErrorFlag, FieldMode.Read, name: "SECRET1_ERROR") 209 .WithFlag(6, out secret2PartitionErrorFlag, FieldMode.Read, name: "SECRET2_ERROR") 210 .WithFlag(7, out lifeCyclePartitionErrorFlag, FieldMode.Read, name: "LIFE_CYCLE_ERROR") 211 .WithFlag(8, out daiErrorFlag, FieldMode.Read, name: "DAI_ERROR") 212 .WithTaggedFlag("LCI_ERROR", 9) 213 .WithTaggedFlag("TIMEOUT_ERROR", 10) 214 .WithTaggedFlag("LFSR_FSM_ERROR", 11) 215 .WithTaggedFlag("SCRAMBLING_FSM_ERROR", 12) 216 .WithTaggedFlag("KEY_DERIV_FSM_ERROR", 13) 217 .WithTaggedFlag("KEY_DERIV_FSM_ERROR", 14) 218 .WithFlag(15, out daiIdleFlag, FieldMode.Read, name: "DAI_IDLE") 219 .WithTaggedFlag("CHECK_PENDING", 16) 220 .WithReservedBits(17, 32 - 17); 221 Registers.ErrorCode.Define(this) 222 .WithEnumField<DoubleWordRegister, Error>(0, 3, out vendorPartitionError, FieldMode.Read, name: "ERR_CODE_0") 223 .WithEnumField<DoubleWordRegister, Error>(3, 3, out creatorPartitionError, FieldMode.Read, name: "ERR_CODE_1") 224 .WithEnumField<DoubleWordRegister, Error>(6, 3, out ownerPartitionError, FieldMode.Read, name: "ERR_CODE_2") 225 .WithEnumField<DoubleWordRegister, Error>(9, 3, out hardwarePartitionError, FieldMode.Read, name: "ERR_CODE_3") 226 .WithEnumField<DoubleWordRegister, Error>(12, 3, out secret0PartitionError, FieldMode.Read, name: "ERR_CODE_4") 227 .WithEnumField<DoubleWordRegister, Error>(15, 3, out secret1PartitionError, FieldMode.Read, name: "ERR_CODE_5") 228 .WithEnumField<DoubleWordRegister, Error>(18, 3, out secret2PartitionError, FieldMode.Read, name: "ERR_CODE_6") 229 .WithEnumField<DoubleWordRegister, Error>(21, 3, out lifeCyclePartitionError, FieldMode.Read, name: "ERR_CODE_7") 230 .WithEnumField<DoubleWordRegister, Error>(24, 3, out daiError, FieldMode.Read, name: "ERR_CODE_8") 231 .WithTag("ERR_CODE_9", 27, 3) 232 .WithReservedBits(30, 2); 233 Registers.DirectAccesssRegisterEnable.Define(this, 0x1) 234 .WithFlag(0, FieldMode.Read, name: "DIRECT_ACCESS_REGWEN") 235 .WithReservedBits(1, 31); 236 Registers.DirectAccessCommand.Define(this) 237 .WithFlag(0, FieldMode.WriteOneToClear, writeCallback: (_, val) => { if(val) ExecuteDirectRead(); }, name: "RD") 238 .WithTaggedFlag("WR", 1) 239 .WithTaggedFlag("DIGEST", 2) 240 .WithReservedBits(3, 32 - 3); 241 Registers.DirectAccessAddress.Define(this) 242 .WithValueField(0, 11, out accessAddress, writeCallback: (_, val) => 243 { 244 this.NoisyLog("Direct access address set to: 0x{0:X} [{1}]", val, (OtpItem)val); 245 }, name: "DIRECT_ACCESSS_ADDRESS") 246 .WithReservedBits(11, 32 - 11); 247 Registers.DirectAccessWriteData_0.Define(this) 248 .WithTag("DIRECT_ACCESS_WDATA_0", 0, 32); 249 Registers.DirectAccessWriteData_1.Define(this) 250 .WithTag("DIRECT_ACCESS_WDATA_1", 0, 32); 251 Registers.DirectAccessReadData_0.Define(this, 0) 252 .WithValueField(0, 32, out readData0, FieldMode.Read, name: "DIRECT_ACCESS_RDATA_0"); 253 Registers.DirectAccessReadData_1.Define(this, 0) 254 .WithValueField(0, 32, out readData1, FieldMode.Read, name: "DIRECT_ACCESS_RDATA_1"); 255 Registers.CheckTriggerRegisterWriteEnable.Define(this) 256 .WithTaggedFlag("CHECK_TRIGGER_REGWEN", 0) 257 .WithIgnoredBits(1, 31); 258 Registers.CheckTrigger.Define(this) 259 .WithTaggedFlag("INREGRITY", 0) 260 .WithTaggedFlag("CONSISTENCY", 1) 261 .WithIgnoredBits(2, 30); 262 Registers.CheckRegistersWriteEnable.Define(this, 0x1) 263 .WithFlag(0, FieldMode.Read | FieldMode.WriteZeroToClear, name: "CHECK_REGWEN") 264 .WithReservedBits(1, 31); 265 Registers.CheckTimeout.Define(this) 266 .WithTag("CHECK_TIMEOUT", 0, 32); 267 Registers.IntegrityCheckPeriod.Define(this) 268 .WithTag("INTEGRITY_CHECK_PERIOD", 0, 32); 269 Registers.ConsistencyCheckPeriod.Define(this) 270 .WithTag("CONSISTENCY_CHECK_PERIOD", 0, 32); 271 Registers.VendorTestReadLock.Define(this, 0x1) 272 .WithFlag(0, out vendorPartitionUnlockedFlag, FieldMode.WriteZeroToClear, name: "VENDOR_TEST_READ_LOCK") 273 .WithIgnoredBits(1, 31); 274 Registers.CreatorSoftwareConfigReadLock.Define(this, 0x1) 275 .WithFlag(0, out creatorPartitionUnlockedFlag, FieldMode.WriteZeroToClear, name: "VENDOR_TEST_READ_LOCK") 276 .WithIgnoredBits(1, 31); 277 Registers.OwnerSoftwareConfigReadLock.Define(this, 0x1) 278 .WithFlag(0, out ownerPartitionUnlockedFlag, FieldMode.WriteZeroToClear, name: "VENDOR_TEST_READ_LOCK") 279 .WithIgnoredBits(1, 31); 280 Registers.VendorTestDigest0.Define(this) 281 .WithTag("VENDOR_TEST_DIGEST_0", 0, 32); 282 Registers.VendorTestDigest1.Define(this) 283 .WithTag("VENDOR_TEST_DIGEST_1", 0, 32); 284 Registers.CreatorSoftwareConfigDigest0.Define(this) 285 .WithTag("CREATOR_SW_CFG_DIGEST_0", 0, 32); 286 Registers.CreatorSoftwareConfigDigest1.Define(this) 287 .WithTag("CREATOR_SW_CFG_DIGEST_1", 0, 32); 288 Registers.OwnerSoftwareConfigDigest0.Define(this) 289 .WithTag("OWNER_SW_CFG_DIGEST_0", 0, 32); 290 Registers.OwnerSoftwareConfigDigest1.Define(this) 291 .WithTag("OWNER_SW_CFG_DIGEST_1", 0, 32); 292 Registers.HardwareConfigDigest0.Define(this) 293 .WithTag("HW_CFG_DIGEST_0", 0, 32); 294 Registers.HardwareConfigDigest1.Define(this) 295 .WithTag("HW_CFG_DIGEST_1", 0, 32); 296 Registers.Secret0Digest0.Define(this) 297 .WithTag("SECRET0_DIGEST0", 0, 32); 298 Registers.Secret0Digest1.Define(this) 299 .WithTag("SECRET0_DIGEST1", 0, 32); 300 Registers.Secret1Digest0.Define(this) 301 .WithTag("SECRET1_DIGEST0", 0, 32); 302 Registers.Secret1Digest1.Define(this) 303 .WithTag("SECRET1_DIGEST1", 0, 32); 304 Registers.Secret2Digest0.Define(this) 305 .WithTag("SECRET2_DIGEST0", 0, 32); 306 Registers.Secret2Digest1.Define(this) 307 .WithTag("SECRET2_DIGEST1", 0, 32); 308 Registers.SoftwareConfiguredWindowStart.Define32Many(this, 512, (register, index) => 309 { 310 register 311 .WithFlag(0, valueProviderCallback: _ => true) 312 .WithReservedBits(1, 31) 313 ; 314 }); 315 } 316 ExecuteDirectRead()317 private void ExecuteDirectRead() 318 { 319 this.NoisyLog("Starting the DAI read"); 320 321 OtpItem item; 322 OtpPartition partition; 323 int itemOffset, partitionOffset; 324 var readAddress = (uint)accessAddress.Value; 325 326 if(!TryGetOtpPartitionAndItem(readAddress, out item, out partition, out itemOffset, out partitionOffset)) 327 { 328 this.Log(LogLevel.Error, "Failed to find an OTP Partition or OTP Item at the address 0x{0:X}", readAddress); 329 return; 330 } 331 332 if(!IsPartitionReadable(partition)) 333 { 334 this.Log(LogLevel.Warning, "The DAI read failed due to the parition being locked"); 335 RaisePartitionError(Error.Access, partition); 336 daiError.Value = Error.Access; 337 daiErrorFlag.Value = true; 338 return; 339 } 340 341 this.NoisyLog("Executing read from the {0}+0x{1:X} on the partition {2}+0x{3:X}", item, itemOffset, partition, partitionOffset); 342 343 var itemAttribute = GetItemSizeAttribute(item); 344 DirectReadInner(readAddress, itemAttribute.Is64Bit); 345 daiIdleFlag.Value = true; 346 } 347 DirectReadInner(uint readAddress, bool is64BitItem)348 private void DirectReadInner(uint readAddress, bool is64BitItem) 349 { 350 lock(memoryLock) 351 { 352 readData0.Value = underlyingMemory.ReadDoubleWord(readAddress); 353 if(is64BitItem) 354 { 355 readData1.Value = underlyingMemory.ReadDoubleWord(readAddress + 0x4); 356 } 357 } 358 } 359 TryGetOtpPartitionAndItem(uint readAddress, out OtpItem item, out OtpPartition partition, out int itemOffset, out int partitionOffset)360 private bool TryGetOtpPartitionAndItem(uint readAddress, out OtpItem item, out OtpPartition partition, out int itemOffset, out int partitionOffset) 361 { 362 itemOffset = 0; 363 partitionOffset = 0; 364 item = default(OtpItem); 365 partition = default(OtpPartition); 366 367 return Misc.TryFindPreceedingEnumItem(readAddress, out item, out itemOffset) && 368 Misc.TryFindPreceedingEnumItem(readAddress, out partition, out partitionOffset); 369 } 370 IsPartitionReadable(OtpPartition partition)371 private bool IsPartitionReadable(OtpPartition partition) 372 { 373 switch(partition) 374 { 375 case OtpPartition.VendorTest: 376 return vendorPartitionUnlockedFlag.Value; 377 case OtpPartition.CreatorSoftwareConfig: 378 return creatorPartitionUnlockedFlag.Value; 379 case OtpPartition.OwnerSoftwareConfig: 380 return ownerPartitionUnlockedFlag.Value; 381 default: 382 return true; 383 } 384 } 385 RaisePartitionError(Error error, OtpPartition partition)386 private void RaisePartitionError(Error error, OtpPartition partition) 387 { 388 switch(partition) 389 { 390 case OtpPartition.VendorTest: 391 vendorPartitionError.Value = error; 392 vendorPartitionErrorFlag.Value = true; 393 break; 394 case OtpPartition.OwnerSoftwareConfig: 395 ownerPartitionError.Value = error; 396 ownerPartitionErrorFlag.Value = true; 397 break; 398 case OtpPartition.CreatorSoftwareConfig: 399 creatorPartitionError.Value = error; 400 creatorPartitionErrorFlag.Value = true; 401 break; 402 case OtpPartition.HardwareConfig: 403 hardwarePartitionError.Value = error; 404 hardwarePartitionErrorFlag.Value = true; 405 break; 406 case OtpPartition.Secret0: 407 secret0PartitionError.Value = error; 408 secret0PartitionErrorFlag.Value = true; 409 break; 410 case OtpPartition.Secret1: 411 secret1PartitionError.Value = error; 412 secret1PartitionErrorFlag.Value = true; 413 break; 414 case OtpPartition.Secret2: 415 secret2PartitionError.Value = error; 416 secret2PartitionErrorFlag.Value = true; 417 break; 418 case OtpPartition.LifeCycle: 419 lifeCyclePartitionError.Value = error; 420 lifeCyclePartitionErrorFlag.Value = true; 421 break; 422 default: 423 throw new ArgumentException($"Unknown partition {partition}"); 424 } 425 } 426 GetItemSizeAttribute(OtpItem item)427 private ItemSizeAttribute GetItemSizeAttribute(OtpItem item) 428 { 429 var type = item.GetType(); 430 var name = Enum.GetName(type, item); 431 return type.GetField(name).GetCustomAttribute<ItemSizeAttribute>(); 432 } 433 SplitValueChainIntoWordsArray(string valueChain)434 private ushort[] SplitValueChainIntoWordsArray(string valueChain) 435 { 436 ushort[] outputArray; 437 if(!Misc.TryParseHexString(valueChain, out outputArray, sizeof(ushort))) 438 { 439 throw new ConstructionException($"Values chain string must consist of ordered 4 character hex values. Length incorrect"); 440 } 441 return outputArray; 442 } 443 444 /* 445 * The LifeCycleStateTransitionCount is decoded/encoded using 24 words that are intially written with some combination of Cx/Dx values. 446 * Each transition cause one Cn value to be overwritten with Dn value when doing the n'th transition. 447 * Ex. when doing 6th transition the 6th word gets overwritten with D6 value. No more than 24 transitions are possible 448 * */ DecodeLifeCycleTransitionCount()449 private ushort DecodeLifeCycleTransitionCount() 450 { 451 var transitionCount = GetOtpItem(OtpItem.LifeCycleTransitionCount); 452 if(transitionCount.All(x => x == 0)) 453 { 454 return 0; 455 } 456 var positionsConsumed = GetConsumedPositionsMap(cValues, dValues, transitionCount); 457 var stroke = MaximumTransitionsCount - Misc.CountTrailingZeroes(positionsConsumed); 458 459 return (ushort)stroke; 460 } 461 EncodeLifeCycleTransitionCount(uint newCount)462 private void EncodeLifeCycleTransitionCount(uint newCount) 463 { 464 // Need to consume only the last position,as the rest should already be set 465 var strokeIndex = newCount - 1; 466 var writeOffset = (uint)OtpItem.LifeCycleTransitionCount + strokeIndex * 2; 467 lock(memoryLock) 468 { 469 underlyingMemory.WriteWord(writeOffset, (ushort)dValues[strokeIndex]); 470 } 471 } 472 /* End of LifeCycleTransitionCount functions 473 */ 474 475 /* 476 * The LifeCycleState is decoded/encoded using 20 words that are intially written with some combination of Ax/Bx values. 477 * Those values are organized in such a way that by advncing the state we consume the Ax val by overwriting it by Bx val, 478 * future transition to an allowed state is not possible without knowing the Ax values. 479 */ TryDecodeLifeCycleState(out OpenTitan_LifeCycleState state)480 private bool TryDecodeLifeCycleState(out OpenTitan_LifeCycleState state) 481 { 482 var lifeCycleState = GetOtpItem(OtpItem.LifeCycleState); 483 if(lifeCycleState.All(x => x == 0)) 484 { 485 state = OpenTitan_LifeCycleState.Raw; 486 return true; 487 } 488 var positionsConsumed = GetConsumedPositionsMap(aValues, bValues, lifeCycleState); 489 490 if(!positionsConsumedToLifeCycleState.ContainsKey(positionsConsumed)) 491 { 492 this.Log(LogLevel.Error, "Unable to convert the consumed positions [{0}] to the LifeCycleState", Convert.ToString(positionsConsumed, 2).PadLeft(4, '0')); 493 state = default(OpenTitan_LifeCycleState); 494 return false; 495 } 496 state = positionsConsumedToLifeCycleState[positionsConsumed]; 497 return true; 498 } 499 EncodeLifeCycleState(OpenTitan_LifeCycleState state)500 private void EncodeLifeCycleState(OpenTitan_LifeCycleState state) 501 { 502 var positionsConsumed = positionsConsumedToLifeCycleState.FirstOrDefault(x => x.Value == state).Key; 503 var mask = 1 << (aValues.Length - 1); 504 lock(memoryLock) 505 { 506 for(int index = 0; index < aValues.Length; index++) 507 { 508 var currentPositionConsumed = (positionsConsumed & mask) != 0; 509 var writeOffset = (uint)OtpItem.LifeCycleState + index * 2; 510 underlyingMemory.WriteWord(writeOffset, currentPositionConsumed ? bValues[index] : aValues[index]); 511 positionsConsumed <<= 1; 512 } 513 } 514 } 515 InitPositionConsumedToLifeCycleMapping()516 private void InitPositionConsumedToLifeCycleMapping() 517 { 518 positionsConsumedToLifeCycleState = new Dictionary<uint, OpenTitan_LifeCycleState>(); 519 positionsConsumedToLifeCycleState.Add(0x80000, OpenTitan_LifeCycleState.TestUnlocked0); 520 positionsConsumedToLifeCycleState.Add(0xC0000, OpenTitan_LifeCycleState.TestLocked0); 521 positionsConsumedToLifeCycleState.Add(0xE0000, OpenTitan_LifeCycleState.TestUnlocked1); 522 positionsConsumedToLifeCycleState.Add(0xF0000, OpenTitan_LifeCycleState.TestLocked1); 523 positionsConsumedToLifeCycleState.Add(0xF8000, OpenTitan_LifeCycleState.TestUnlocked2); 524 positionsConsumedToLifeCycleState.Add(0xFC000, OpenTitan_LifeCycleState.TestLocked2); 525 positionsConsumedToLifeCycleState.Add(0xFE000, OpenTitan_LifeCycleState.TestUnlocked3); 526 positionsConsumedToLifeCycleState.Add(0xFF000, OpenTitan_LifeCycleState.TestLocked3); 527 positionsConsumedToLifeCycleState.Add(0xFF800, OpenTitan_LifeCycleState.TestUnlocked4); 528 positionsConsumedToLifeCycleState.Add(0xFFC00, OpenTitan_LifeCycleState.TestLocked4); 529 positionsConsumedToLifeCycleState.Add(0xFFE00, OpenTitan_LifeCycleState.TestUnlocked5); 530 positionsConsumedToLifeCycleState.Add(0xFFF00, OpenTitan_LifeCycleState.TestLocked5); 531 positionsConsumedToLifeCycleState.Add(0xFFF80, OpenTitan_LifeCycleState.TestUnlocked6); 532 positionsConsumedToLifeCycleState.Add(0xFFFC0, OpenTitan_LifeCycleState.TestLocked6); 533 positionsConsumedToLifeCycleState.Add(0xFFFE0, OpenTitan_LifeCycleState.TestUnlocked7); 534 positionsConsumedToLifeCycleState.Add(0xFFFF0, OpenTitan_LifeCycleState.Dev); 535 positionsConsumedToLifeCycleState.Add(0xFFFE8, OpenTitan_LifeCycleState.Prod); 536 positionsConsumedToLifeCycleState.Add(0xFFFE4, OpenTitan_LifeCycleState.Prod_end); 537 positionsConsumedToLifeCycleState.Add(0xFFFFB, OpenTitan_LifeCycleState.Rma); 538 positionsConsumedToLifeCycleState.Add(0xFFFFF, OpenTitan_LifeCycleState.Scrap); 539 } 540 541 /* End of LifeCycleState related functions 542 */ 543 GetConsumedPositionsMap(ushort[] unconsumedValues, ushort[] consumedValues, byte[] array)544 private uint GetConsumedPositionsMap(ushort[] unconsumedValues, ushort[] consumedValues, byte[] array) 545 { 546 var valuesCount = consumedValues.Length; 547 if(valuesCount != unconsumedValues.Length) 548 { 549 throw new ArgumentException($"Both unconsumed and consumed values arrays have to be the same length! Unconsumed values length : {unconsumedValues.Length}, consumed values length: {valuesCount}"); 550 } 551 uint output = 0; 552 for(int index = 0; index < valuesCount; index++) 553 { 554 var current = (array[index * 2 + 1] << 8) | array[index * 2]; 555 if(current == unconsumedValues[index]) 556 { 557 output |= 0; 558 } 559 else if(current == consumedValues[index]) 560 { 561 output |= 1; 562 } 563 else 564 { 565 throw new ArgumentException("Given value is now equal to any of the allowed states"); 566 } 567 568 if(index < (valuesCount - 1)) 569 { 570 output <<= 1; 571 } 572 } 573 return output; 574 } 575 576 private IFlagRegisterField creatorPartitionUnlockedFlag; 577 private IFlagRegisterField daiIdleFlag; 578 private IFlagRegisterField ownerPartitionUnlockedFlag; 579 private IFlagRegisterField vendorPartitionUnlockedFlag; 580 private IValueRegisterField accessAddress; 581 private IValueRegisterField readData0; 582 private IValueRegisterField readData1; 583 584 private IEnumRegisterField<Error> vendorPartitionError; 585 private IEnumRegisterField<Error> creatorPartitionError; 586 private IEnumRegisterField<Error> ownerPartitionError; 587 private IEnumRegisterField<Error> hardwarePartitionError; 588 private IEnumRegisterField<Error> secret0PartitionError; 589 private IEnumRegisterField<Error> secret1PartitionError; 590 private IEnumRegisterField<Error> secret2PartitionError; 591 private IEnumRegisterField<Error> lifeCyclePartitionError; 592 private IEnumRegisterField<Error> daiError; 593 594 private IFlagRegisterField vendorPartitionErrorFlag; 595 private IFlagRegisterField creatorPartitionErrorFlag; 596 private IFlagRegisterField ownerPartitionErrorFlag; 597 private IFlagRegisterField hardwarePartitionErrorFlag; 598 private IFlagRegisterField secret0PartitionErrorFlag; 599 private IFlagRegisterField secret1PartitionErrorFlag; 600 private IFlagRegisterField secret2PartitionErrorFlag; 601 private IFlagRegisterField lifeCyclePartitionErrorFlag; 602 private IFlagRegisterField daiErrorFlag; 603 604 private Dictionary<uint, OpenTitan_LifeCycleState> positionsConsumedToLifeCycleState; 605 private OpenTitan_LifeCycleState? cachedLifeCycleState; 606 private ushort? cachedTransitionCount; 607 private object memoryLock; 608 private object transitionCountLock; 609 private ushort[] aValues; 610 private ushort[] bValues; 611 private ushort[] cValues; 612 private ushort[] dValues; 613 614 private readonly ArrayMemory underlyingMemory; 615 616 private const int MaximumTransitionsCount = 24; 617 private const int ABValuesWordsCount = 20; 618 private const int CDValuesWordsCount = 24; 619 620 public enum Registers 621 { 622 InterruptState = 0x0, 623 InterruptEnable = 0x4, 624 InterruptTest = 0x8, 625 AlertTest = 0xc, 626 Status = 0x10, 627 ErrorCode = 0x14, 628 DirectAccesssRegisterEnable = 0x18, 629 DirectAccessCommand = 0x1C, 630 DirectAccessAddress = 0x20, 631 DirectAccessWriteData_0 = 0x24, 632 DirectAccessWriteData_1 = 0x28, 633 DirectAccessReadData_0 = 0x2C, 634 DirectAccessReadData_1 = 0x30, 635 CheckTriggerRegisterWriteEnable = 0x34, 636 CheckTrigger = 0x38, 637 CheckRegistersWriteEnable = 0x3c, 638 CheckTimeout = 0x40, 639 IntegrityCheckPeriod = 0x44, 640 ConsistencyCheckPeriod = 0x48, 641 VendorTestReadLock = 0x4C, 642 CreatorSoftwareConfigReadLock = 0x50, 643 OwnerSoftwareConfigReadLock = 0x54, 644 VendorTestDigest0 = 0x58, 645 VendorTestDigest1 = 0x5C, 646 CreatorSoftwareConfigDigest0 = 0x60, 647 CreatorSoftwareConfigDigest1 = 0x64, 648 OwnerSoftwareConfigDigest0 = 0x68, 649 OwnerSoftwareConfigDigest1 = 0x6C, 650 HardwareConfigDigest0 = 0x70, 651 HardwareConfigDigest1 = 0x74, 652 Secret0Digest0 = 0x78, 653 Secret0Digest1 = 0x7C, 654 Secret1Digest0 = 0x80, 655 Secret1Digest1 = 0x84, 656 Secret2Digest0 = 0x88, 657 Secret2Digest1 = 0x8C, 658 SoftwareConfiguredWindowStart = 0x1000, 659 } 660 661 public enum OtpItem 662 { 663 [ItemSizeAttribute(56)] 664 Scratch = 0x000, 665 666 [ItemSizeAttribute(8, is64Bit: true)] 667 VendorTestDigest = 0x038, 668 669 [ItemSizeAttribute(156)] 670 CreatorSoftwareConfigAstConfig = 0x040, 671 672 [ItemSizeAttribute(4)] 673 CreatorSoftwareConfigAstInitEnable = 0x0DC, 674 675 [ItemSizeAttribute(4)] 676 CreatorSoftwareConfigRomExtSku = 0x0E0, 677 678 [ItemSizeAttribute(4)] 679 CreatorSoftwareConfigUseSwRsaVerify = 0x0E4, 680 681 [ItemSizeAttribute(8)] 682 CreatorSoftwareConfigKeyIsValid = 0x0E8, 683 684 [ItemSizeAttribute(4)] 685 CreatorSoftwareConfigFlashDataDefaultConfig = 0x0F0, 686 687 [ItemSizeAttribute(4)] 688 CreatorSoftwareConfigFlashInfoBootDataConfig = 0x0F4, 689 690 [ItemSizeAttribute(4)] 691 CreatorSoftwareConfigRngEnable = 0x0F8, 692 693 [ItemSizeAttribute(4)] 694 CreatorSoftwareConfigJitterEnable = 0x0FC, 695 696 [ItemSizeAttribute(4)] 697 CreatorSoftwareConfigRetRamResetMask = 0x100, 698 699 [ItemSizeAttribute(8, is64Bit: true)] 700 CreatorSoftwareConfigDigest = 0x358, 701 702 [ItemSizeAttribute(4)] 703 RomErrorReporting = 0x360, 704 705 [ItemSizeAttribute(4)] 706 RomBootstrapEnable = 0x364, 707 708 [ItemSizeAttribute(4)] 709 RomFaultResponse = 0x368, 710 711 [ItemSizeAttribute(4)] 712 RomAlertClassEnable = 0x36C, 713 714 [ItemSizeAttribute(4)] 715 RomAlertEscalation = 0x370, 716 717 [ItemSizeAttribute(320)] 718 RomAlertClassification = 0x374, 719 720 [ItemSizeAttribute(64)] 721 RomLocalAlertClassification = 0x4B4, 722 723 [ItemSizeAttribute(16)] 724 RomAlertAccumThresh = 0x4F4, 725 726 [ItemSizeAttribute(16)] 727 RomAlertTimeoutCycles = 0x504, 728 729 [ItemSizeAttribute(64)] 730 RomAlertPhaseCycles = 0x514, 731 732 [ItemSizeAttribute(4)] 733 RomWatchdogBiteThresholdCycles = 0x554, 734 735 [ItemSizeAttribute(8, is64Bit: true)] 736 OwnerSwCfgDigest = 0x678, 737 738 [ItemSizeAttribute(32)] 739 DeviceId = 0x680, 740 741 [ItemSizeAttribute(32)] 742 ManufacturingState = 0x6A0, 743 744 [ItemSizeAttribute(1)] 745 EnableSramIfetch = 0x6C0, 746 747 [ItemSizeAttribute(1)] 748 EnableCsrngSwAppRead = 0x6C1, 749 750 [ItemSizeAttribute(1)] 751 EnableEntropySrcFwRead = 0x6C2, 752 753 [ItemSizeAttribute(1)] 754 EnableEntropySrcFwOver = 0x6C3, 755 756 [ItemSizeAttribute(8, is64Bit: true)] 757 HwCfgDigest = 0x6C8, 758 759 [ItemSizeAttribute(16, is64Bit: true)] 760 TestUnlockToken = 0x6D0, 761 762 [ItemSizeAttribute(16, is64Bit: true)] 763 TestExitToken = 0x6E0, 764 765 [ItemSizeAttribute(8, is64Bit: true)] 766 Secret0Digest = 0x6F0, 767 768 [ItemSizeAttribute(32, is64Bit: true)] 769 FlashAddressKeySeed = 0x6F8, 770 771 [ItemSizeAttribute(32, is64Bit: true)] 772 FlashDataKeySeed = 0x718, 773 774 [ItemSizeAttribute(16, is64Bit: true)] 775 SramDataKeySeed = 0x738, 776 777 [ItemSizeAttribute(8, is64Bit: true)] 778 Secret1Digest = 0x748, 779 780 [ItemSizeAttribute(16, is64Bit: true)] 781 RmaToken = 0x750, 782 783 [ItemSizeAttribute(32, is64Bit: true)] 784 CreatorRootKeyShare0 = 0x760, 785 786 [ItemSizeAttribute(32, is64Bit: true)] 787 CreatorRootKeyShare1 = 0x780, 788 789 [ItemSizeAttribute(8, is64Bit: true)] 790 Secret2Digest = 0x7A0, 791 792 [ItemSizeAttribute(48)] 793 LifeCycleTransitionCount = 0x7A8, 794 795 [ItemSizeAttribute(40)] 796 LifeCycleState = 0x7D8, 797 } 798 799 private enum OtpPartition 800 { 801 VendorTest = OtpItem.Scratch, 802 CreatorSoftwareConfig = OtpItem.CreatorSoftwareConfigAstConfig, 803 OwnerSoftwareConfig = OtpItem.RomErrorReporting, 804 HardwareConfig = OtpItem.DeviceId, 805 Secret0 = OtpItem.TestUnlockToken, 806 Secret1 = OtpItem.FlashAddressKeySeed, 807 Secret2 = OtpItem.RmaToken, 808 LifeCycle = OtpItem.LifeCycleTransitionCount, 809 } 810 811 private enum Error 812 { 813 No = 0x0, 814 Macro = 0x1, 815 MacroCorrectable = 0x2, 816 MacroUncorrectable = 0x3, 817 MacroWriteBlank = 0x4, 818 Access = 0x5, 819 CheckFail = 0x6, 820 FsmState = 0x7, 821 } 822 823 private class ItemSizeAttribute: Attribute 824 { ItemSizeAttribute(int byteLength, bool is64Bit = false)825 public ItemSizeAttribute(int byteLength, bool is64Bit = false) 826 { 827 Is64Bit = is64Bit; 828 ByteLength = byteLength; 829 } 830 public bool Is64Bit { get; } 831 public int ByteLength { get; } 832 } 833 } 834 } 835