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.Linq; 10 using Antmicro.Renode.Core; 11 using Antmicro.Renode.Core.Structure.Registers; 12 using Antmicro.Renode.Logging; 13 using Antmicro.Renode.Utilities; 14 15 namespace Antmicro.Renode.Peripherals.Miscellaneous 16 { 17 public class OpenTitan_LifeCycleController: BasicDoubleWordPeripheral, IKnownSize 18 { OpenTitan_LifeCycleController(IMachine machine, OpenTitan_ResetManager resetManager, OpenTitan_OneTimeProgrammableMemoryController otpController)19 public OpenTitan_LifeCycleController(IMachine machine, OpenTitan_ResetManager resetManager, OpenTitan_OneTimeProgrammableMemoryController otpController) : base(machine) 20 { 21 this.resetManager = resetManager; 22 this.otpController = otpController; 23 24 rmaToken = new byte[TokenRegistersCount * 4] ; 25 deviceId = new byte[DeviceIdRegistersCount * 4]; 26 testExitToken = new byte[TokenRegistersCount * 4] ; 27 testUnlockToken = new byte[TokenRegistersCount * 4] ; 28 token = new byte[TokenRegistersCount * 4]; 29 30 FatalProgAlert = new GPIO(); 31 FatalStateAlert = new GPIO(); 32 FatalBusAlert = new GPIO(); 33 34 DefineRegisters(); 35 Reset(); 36 } 37 Reset()38 public override void Reset() 39 { 40 base.Reset(); 41 FatalProgAlert.Unset(); 42 FatalStateAlert.Unset(); 43 FatalBusAlert.Unset(); 44 45 Array.Clear(token, 0, token.Length); 46 readyFlag.Value = true; 47 } 48 49 public long Size => 0x1000; 50 51 public GPIO FatalProgAlert { get; } 52 public GPIO FatalStateAlert { get; } 53 public GPIO FatalBusAlert { get; } 54 55 public string TestExitToken 56 { 57 set 58 { 59 testExitToken = Misc.HexStringToByteArray(value); 60 } 61 } 62 63 public string TestUnlockToken 64 { 65 set 66 { 67 testUnlockToken = Misc.HexStringToByteArray(value); 68 } 69 } 70 71 public string RMAToken 72 { 73 set 74 { 75 rmaToken = Misc.HexStringToByteArray(value); 76 } 77 } 78 79 public string DeviceId 80 { 81 get 82 { 83 return deviceIdString; 84 } 85 set 86 { 87 // This array was reversed to comply with the OpenTitan tests suite - the spec does not specify this 88 deviceId = Misc.HexStringToByteArray(value).Reverse().ToArray(); 89 var otpDeviceId = otpController.GetOtpItem(OpenTitan_OneTimeProgrammableMemoryController.OtpItem.DeviceId); 90 // Only print the warning message if otpDeviceId is set. 91 if(deviceId != otpDeviceId && !otpDeviceId.All(o => o == 0)) 92 { 93 var otpDeviceIdString = string.Join("", otpDeviceId); 94 this.Log(LogLevel.Warning, "The set DeviceId differs from the one stored in the OTP Controller. Set: {0}, OTP:{1}", 95 value, otpDeviceIdString); 96 } 97 deviceIdString = value; 98 } 99 } 100 DefineRegisters()101 private void DefineRegisters() 102 { 103 Registers.AlertTest.Define(this) 104 .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalProgAlert.Blink(); }, name: "fatal_prog_error") 105 .WithFlag(1, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalStateAlert.Blink(); }, name: "fatal_state_error") 106 .WithFlag(2, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalBusAlert.Blink(); }, name: "fatal_bus_integ_error") 107 .WithIgnoredBits(3, 32 - 3); 108 109 Registers.Status.Define(this) 110 .WithFlag(0, out readyFlag, FieldMode.Read, name: "READY") 111 .WithFlag(1, out transitionSuccesfulFlag, FieldMode.Read, name: "TRANSITION_SUCCESSFUL") 112 .WithFlag(2, out transitionCountErorFlag, FieldMode.Read, name: "TRANSITION_COUNT_ERROR") 113 .WithFlag(3, out transitionErrorFlag, FieldMode.Read, name: "TRANSITION_ERROR") 114 .WithFlag(4, out tokenErrorFlag, FieldMode.Read, name: "TOKEN_ERROR") 115 .WithTaggedFlag("FLASH_RMA_ERROR", 5) 116 .WithTaggedFlag("OTP_ERROR", 6) 117 .WithTaggedFlag("STATE_ERROR", 7) 118 .WithTaggedFlag("OTP_PARTITION_ERROR", 8) 119 .WithIgnoredBits(9, 32 - 9); 120 121 Registers.ClaimTransitionIf.Define(this, (uint)MutexState.MultiBitFalse) 122 .WithEnumField<DoubleWordRegister, MutexState>(0, 8, out mutexState, 123 writeCallback: (_, val) => 124 { 125 if(val == MutexState.MultiBitTrue) 126 { 127 if(mutexClaimed) 128 { 129 mutexState.Value = MutexState.Taken; 130 } 131 else 132 { 133 mutexClaimed = true; 134 transitionRegisterWriteEnable.Value = true; 135 } 136 } 137 }, name: "MUTEX") 138 .WithIgnoredBits(8, 32 - 8); 139 140 Registers.TransitionRegisterWriteEnable.Define(this) 141 .WithFlag(0, out transitionRegisterWriteEnable, name: "TRANSITION_REGWEN") 142 .WithIgnoredBits(1, 32 - 1); 143 144 Registers.TransitionCommand.Define(this) 145 .WithFlag(0, FieldMode.WriteOneToClear, writeCallback: (_, val) => { if(val) ExecuteTransition(); }, name: "START") 146 .WithIgnoredBits(1, 32 - 1); 147 148 Registers.TransitionControl.Define(this) 149 .WithFlag(0, name: "EXT_CLOCK_EN") 150 .WithIgnoredBits(1, 32 - 1); 151 152 Registers.TransitionToken0.DefineMany(this, TokenRegistersCount, (register, idx) => 153 { 154 register.WithValueField(0, 32, 155 writeCallback: (_, val) => Misc.ByteArrayWrite(idx * 4, (uint)val, token), 156 valueProviderCallback: (_) => Misc.ByteArrayRead(idx * 4, token), name: $"TRANSITION_TOKEN_{idx}"); 157 }); 158 159 Registers.TransitionTarget.Define(this) 160 .WithEnumField<DoubleWordRegister, TransitionTargetState>(0, 30, out transitionTarget, name: "STATE") 161 .WithIgnoredBits(30, 2); 162 163 Registers.OtpVendorTestControl.Define(this) 164 .WithValueField(0, 32, name: "OTP_VENDOR_TEST_CTRL"); 165 166 Registers.OtpVendorTestStatus.Define(this) 167 .WithValueField(0, 32, FieldMode.Read, name: "OTP_VENDOR_TEST_STATUS"); 168 169 Registers.LifeCycleState.Define(this) 170 .WithEnumField<DoubleWordRegister, OpenTitan_LifeCycleState>(0, 30, FieldMode.Read, valueProviderCallback: _ => otpController.LifeCycleState, name: "STATE") 171 .WithIgnoredBits(30, 32 - 30); 172 173 Registers.LifeCycleTransitionCounter.Define(this) 174 .WithValueField(0, 5, FieldMode.Read, valueProviderCallback: _ => otpController.LifeCycleTransitionCount, name: "COUNT") 175 .WithIgnoredBits(5, 32 - 5); 176 177 Registers.LifeCycleIdState.Define(this) 178 .WithEnumField<DoubleWordRegister, IdState>(0, 32, FieldMode.Read, name: "STATE"); 179 180 Registers.HardwareRevision.Define(this) 181 .WithTag("CHIP_REV", 0, 16) 182 .WithTag("CHIP_GEN", 16, 16); 183 184 Registers.DeviceId0.DefineMany(this, DeviceIdRegistersCount, (register, idx) => 185 { 186 register.WithValueField(0, 32, FieldMode.Read, valueProviderCallback: _ => Misc.ByteArrayRead(idx * 4, deviceId), name: $"DEVICE_ID_{idx}"); 187 }); 188 189 Registers.ManufacturingState0.DefineMany(this, ManufacturingStateRegistersCount, (register, idx) => 190 { 191 register.WithTag($"MANUF_STATE_{idx}", 0, 32); 192 }); 193 } 194 ExecuteTransition()195 private void ExecuteTransition() 196 { 197 var currentState = otpController.LifeCycleState; 198 var nextState = (OpenTitan_LifeCycleState)transitionTarget.Value; 199 200 ClearStatusFlags(); 201 202 // Every transition attempt increments the count 203 otpController.IncrementTransitionCount(); 204 205 if(!IsTransitionAllowed(currentState, nextState)) 206 { 207 transitionErrorFlag.Value = true; 208 this.Log(LogLevel.Warning, "Transitions between states {0} and {1} is not allowed.", currentState, nextState); 209 return; 210 } 211 if(!IsTransitionTokenValid(currentState, nextState)) 212 { 213 tokenErrorFlag.Value = true; 214 this.Log(LogLevel.Warning, "Invalid token for transition between states {0} and {1}.", currentState, nextState); 215 return; 216 } 217 218 otpController.LifeCycleState = nextState; 219 resetManager.LifeCycleReset(); 220 transitionSuccesfulFlag.Value = true; 221 } 222 ClearStatusFlags()223 private void ClearStatusFlags() 224 { 225 transitionSuccesfulFlag.Value = false; 226 transitionCountErorFlag.Value = false; 227 transitionErrorFlag.Value = false; 228 tokenErrorFlag.Value = false; 229 } 230 IsTransitionAllowed(OpenTitan_LifeCycleState currentState, OpenTitan_LifeCycleState nextState)231 private bool IsTransitionAllowed(OpenTitan_LifeCycleState currentState, OpenTitan_LifeCycleState nextState) 232 { 233 if(nextState == OpenTitan_LifeCycleState.Scrap || 234 currentState == OpenTitan_LifeCycleState.Raw && UnlockedTestStates.Contains(nextState)) 235 { 236 return true; 237 } 238 else if(UnlockedTestStates.Contains(currentState)) 239 { 240 if(LockedTestStates.Contains(nextState) && (nextState > currentState) || 241 nextState == OpenTitan_LifeCycleState.Rma || 242 MissionStates.Contains(nextState)) 243 { 244 return true; 245 } 246 } 247 else if((currentState == OpenTitan_LifeCycleState.Dev || currentState == OpenTitan_LifeCycleState.Prod) && 248 nextState == OpenTitan_LifeCycleState.Rma) 249 { 250 return true; 251 } 252 return false; 253 } 254 IsTransitionTokenValid(OpenTitan_LifeCycleState currentState, OpenTitan_LifeCycleState nextState)255 private bool IsTransitionTokenValid(OpenTitan_LifeCycleState currentState, OpenTitan_LifeCycleState nextState) 256 { 257 if(LockedTestStates.Contains(currentState) && UnlockedTestStates.Contains(nextState)) 258 { 259 return token.SequenceEqual(testUnlockToken); 260 } 261 else if(UnlockedTestStates.Contains(currentState) && MissionStates.Contains(nextState)) 262 { 263 return token.SequenceEqual(testExitToken); 264 } 265 else if(MissionStates.Contains(currentState) && nextState == OpenTitan_LifeCycleState.Rma) 266 { 267 return token.SequenceEqual(rmaToken); 268 } 269 // No token required for this transition 270 return true; 271 } 272 273 IEnumRegisterField<TransitionTargetState> transitionTarget; 274 IEnumRegisterField<MutexState> mutexState; 275 IFlagRegisterField readyFlag; 276 IFlagRegisterField transitionSuccesfulFlag; 277 IFlagRegisterField transitionRegisterWriteEnable; 278 IFlagRegisterField transitionCountErorFlag; 279 IFlagRegisterField transitionErrorFlag; 280 IFlagRegisterField tokenErrorFlag; 281 282 private byte[] token; 283 private byte[] rmaToken; 284 private byte[] deviceId; 285 private byte[] testExitToken; 286 private byte[] testUnlockToken; 287 288 private bool mutexClaimed; 289 private string deviceIdString; 290 private readonly OpenTitan_ResetManager resetManager; 291 private readonly OpenTitan_OneTimeProgrammableMemoryController otpController; 292 293 private readonly OpenTitan_LifeCycleState[] MissionStates = { OpenTitan_LifeCycleState.Dev, OpenTitan_LifeCycleState.Prod, OpenTitan_LifeCycleState.Prod_end }; 294 private readonly OpenTitan_LifeCycleState[] LockedTestStates = { OpenTitan_LifeCycleState.TestLocked0, OpenTitan_LifeCycleState.TestLocked1, OpenTitan_LifeCycleState.TestLocked2, OpenTitan_LifeCycleState.TestLocked3, OpenTitan_LifeCycleState.TestLocked4, OpenTitan_LifeCycleState.TestLocked5, OpenTitan_LifeCycleState.TestLocked6 }; 295 private readonly OpenTitan_LifeCycleState[] UnlockedTestStates = { OpenTitan_LifeCycleState.TestUnlocked0, OpenTitan_LifeCycleState.TestUnlocked1, OpenTitan_LifeCycleState.TestUnlocked2, OpenTitan_LifeCycleState.TestUnlocked3, OpenTitan_LifeCycleState.TestUnlocked4, OpenTitan_LifeCycleState.TestUnlocked5, OpenTitan_LifeCycleState.TestUnlocked6, OpenTitan_LifeCycleState.TestUnlocked7 }; 296 297 private const uint TokenRegistersCount = 4; 298 private const uint DeviceIdRegistersCount = 8; 299 private const uint ManufacturingStateRegistersCount = 8; 300 301 #pragma warning disable format 302 private enum IdState 303 { 304 Blank = 0x00000000, 305 Personalized = 0x11111111, 306 Invalid = 0x22222222, 307 } 308 309 private enum MutexState 310 { 311 MultiBitTrue = MultiBitBool8.True, 312 MultiBitFalse = MultiBitBool8.False, 313 Taken = 0x00, 314 } 315 316 // This is only a subset of the OpenTitan_LifeCycleState 317 private enum TransitionTargetState 318 { 319 Raw = OpenTitan_LifeCycleState.Raw , // Raw life cycle state after fabrication where all functions are disabled. 320 TestUnlocked0 = OpenTitan_LifeCycleState.TestUnlocked0 , // Unlocked test state where debug functions are enabled. 321 TestLocked0 = OpenTitan_LifeCycleState.TestLocked0 , // Locked test state where where all functions are disabled. 322 TestUnlocked1 = OpenTitan_LifeCycleState.TestUnlocked1 , // Unlocked test state where debug functions are enabled. 323 TestLocked1 = OpenTitan_LifeCycleState.TestLocked1 , // Locked test state where where all functions are disabled. 324 TestUnlocked2 = OpenTitan_LifeCycleState.TestUnlocked2 , // Unlocked test state where debug functions are enabled. 325 TestLocked2 = OpenTitan_LifeCycleState.TestLocked2 , // Locked test state where debug all functions are disabled. 326 TestUnlocked3 = OpenTitan_LifeCycleState.TestUnlocked3 , // Unlocked test state where debug functions are enabled. 327 TestLocked3 = OpenTitan_LifeCycleState.TestLocked3 , // Locked test state where debug all functions are disabled. 328 TestUnlocked4 = OpenTitan_LifeCycleState.TestUnlocked4 , // Unlocked test state where debug functions are enabled. 329 TestLocked4 = OpenTitan_LifeCycleState.TestLocked4 , // Locked test state where debug all functions are disabled. 330 TestUnlocked5 = OpenTitan_LifeCycleState.TestUnlocked5 , // Unlocked test state where debug functions are enabled. 331 TestLocked5 = OpenTitan_LifeCycleState.TestLocked5 , // Locked test state where debug all functions are disabled. 332 TestUnlocked6 = OpenTitan_LifeCycleState.TestUnlocked6 , // Unlocked test state where debug functions are enabled. 333 TestLocked6 = OpenTitan_LifeCycleState.TestLocked6 , // Locked test state where debug all functions are disabled. 334 TestUnlocked7 = OpenTitan_LifeCycleState.TestUnlocked7 , // Unlocked test state where debug functions are enabled. 335 Dev = OpenTitan_LifeCycleState.Dev , // Development life cycle state where limited debug functionality is available. 336 Prod = OpenTitan_LifeCycleState.Prod , // Production life cycle state. 337 Prod_end = OpenTitan_LifeCycleState.Prod_end , // Same as PROD, but transition into RMA is not possible from this state. 338 Rma = OpenTitan_LifeCycleState.Rma , // RMA life cycle state. 339 Scrap = OpenTitan_LifeCycleState.Scrap , // SCRAP life cycle state where all functions are disabled. 340 } 341 342 public enum Registers 343 { 344 AlertTest = 0x00, 345 Status = 0x04, 346 ClaimTransitionIf = 0x08, 347 TransitionRegisterWriteEnable = 0x0C, 348 TransitionCommand = 0x10, 349 TransitionControl = 0x14, 350 TransitionToken0 = 0x18, 351 TransitionToken1 = 0x1C, 352 TransitionToken2 = 0x20, 353 TransitionToken3 = 0x24, 354 TransitionTarget = 0x28, 355 OtpVendorTestControl = 0x2C, 356 OtpVendorTestStatus = 0x30, 357 LifeCycleState = 0x34, 358 LifeCycleTransitionCounter = 0x38, 359 LifeCycleIdState = 0x3C, 360 HardwareRevision = 0x40, 361 DeviceId0 = 0x44, 362 DeviceId1 = 0x48, 363 DeviceId2 = 0x4C, 364 DeviceId3 = 0x50, 365 DeviceId4 = 0x54, 366 DeviceId5 = 0x58, 367 DeviceId6 = 0x5C, 368 DeviceId7 = 0x60, 369 ManufacturingState0 = 0x64, 370 ManufacturingState1 = 0x68, 371 ManufacturingState2 = 0x6C, 372 ManufacturingState3 = 0x70, 373 ManufacturingState4 = 0x74, 374 ManufacturingState5 = 0x78, 375 ManufacturingState6 = 0x7C, 376 ManufacturingState7 = 0x80, 377 } 378 #pragma warning restore format 379 } 380 } 381