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 using System; 8 using System.Linq; 9 using System.Collections.Generic; 10 using Org.BouncyCastle.Crypto.Digests; 11 using Antmicro.Renode.Core; 12 using Antmicro.Renode.Core.Structure.Registers; 13 using Antmicro.Renode.Logging; 14 using Antmicro.Renode.Utilities; 15 16 namespace Antmicro.Renode.Peripherals.Miscellaneous 17 { 18 public class OpenTitan_EntropySource: BasicDoubleWordPeripheral, IKnownSize 19 { OpenTitan_EntropySource(IMachine machine)20 public OpenTitan_EntropySource(IMachine machine): base(machine) 21 { 22 entropySource = EmulationManager.Instance.CurrentEmulation.RandomGenerator; 23 sha3Conditioner = new Sha3Conditioner(); 24 25 observeFifo = new Queue<uint>(ObserveFifoDepth); 26 preConditionerPackerFifo = new Queue<uint>(PreConditionerPackerFifoDepth); 27 preEsfinalPackerFifo = new Queue<uint>(PreEsfinalPackerFifoDepth); 28 esfinalFifo = new Queue<uint>(EsfinalFifoDepth); 29 entropyUnpackerFifo = new Queue<uint>(EntropyUnpackerFifoDepth); 30 hardwareOutputFifo = new Queue<uint>(EntropyUnpackerFifoDepth); 31 32 RecoverableAlert = new GPIO(); 33 FatalAlert = new GPIO(); 34 35 EsEntropyValidIRQ = new GPIO(); 36 EsHealthTestFailedIRQ = new GPIO(); 37 EsObserveFifoReadyIRQ = new GPIO(); 38 EsFatalErrIRQ = new GPIO(); 39 40 DefineRegisters(); 41 Reset(); 42 } 43 44 // it is for intermodule communication between the entropy source and the CSRNG RequestEntropySourceData()45 public byte[] RequestEntropySourceData() 46 { 47 var data = new List<byte>(); 48 if(PathSelect == Route.HardwareInterface) 49 { 50 this.Log(LogLevel.Debug, "Requesting entropy data from the hardware interface"); 51 if(hardwareOutputFifo.Count == 0) 52 { 53 FillBuffers(); 54 } 55 while(hardwareOutputFifo.Count > 0) 56 { 57 data.AddRange(BitConverter.GetBytes(hardwareOutputFifo.Dequeue())); 58 } 59 } 60 61 return data.ToArray(); 62 } 63 Reset()64 public override void Reset() 65 { 66 base.Reset(); 67 ResetBuffers(); 68 sha3Conditioner.Reset(); 69 } 70 71 public long Size => 0x100; 72 FillBuffers()73 private void FillBuffers() 74 { 75 // In the real device, the buffers are filled with entropy data from the PTRNG source. 76 // In the emulation, we fill the buffers with random data on demand. 77 for(var i = 0; i < ObserveFifoDepth; i++) 78 { 79 GenerateEntropyData(); 80 } 81 } 82 GenerateEntropyData()83 private void GenerateEntropyData() 84 { 85 var value = (uint)entropySource.Next(); 86 87 RunHealthTests(value); 88 ObserveDataPath(value); 89 InsertIntoEntropyFlow(value, Mode.Normal); 90 } 91 RunHealthTests(uint value)92 private void RunHealthTests(uint value) 93 { 94 // It is a mock implementation: no health tests are currently performed. 95 // TODO: Implement the following tests: Adaptive Proportion, Repetition Count, Bucket, Markov, Mailbox. 96 mainMachineState.Value = StateMachine.ContHTRunning; 97 } 98 ObserveDataPath(uint value)99 private void ObserveDataPath(uint value) 100 { 101 if(ModeOverride != Mode.FirmwareOverride) 102 { 103 return; 104 } 105 106 if(observeFifo.Count == ObserveFifoDepth) 107 { 108 this.Log(LogLevel.Warning, "Observe FIFO is full"); 109 observeFifoOverflowStatus.Value = true; 110 // We don't update interrupts here because it doesn't generate interrupt directly. 111 } 112 else 113 { 114 observeFifo.Enqueue(value); 115 } 116 117 if(observeFifo.Count >= (int)observeFifoThreshold.Value) 118 { 119 observeFifoReadyInterruptState.Value = true; 120 UpdateInterrupts(); 121 } 122 } 123 InsertIntoEntropyFlow(uint value, Mode mode)124 private void InsertIntoEntropyFlow(uint value, Mode mode) 125 { 126 if(mode != ModeSelect) 127 { 128 return; 129 } 130 131 switch(BypassModeSelect) 132 { 133 case BypassMode.Sha3ConditionedEntropy: 134 preConditionerPackerFifo.Enqueue(value); 135 if(preConditionerPackerFifo.Count == PreConditionerPackerFifoDepth) 136 { 137 var data = preConditionerPackerFifo.DequeueAll(); 138 sha3Conditioner.AddData(data); 139 } 140 break; 141 case BypassMode.RawEntropy: 142 if(preEsfinalPackerFifo.Count < PreEsfinalPackerFifoDepth) 143 { 144 preEsfinalPackerFifo.Enqueue(value); 145 } 146 else 147 { 148 this.Log(LogLevel.Warning, "Dropping entropy data due to full FIFO"); 149 } 150 break; 151 } 152 153 OutputPath(); 154 } 155 OutputPath()156 private void OutputPath() 157 { 158 switch(BypassModeSelect) 159 { 160 case BypassMode.Sha3ConditionedEntropy: 161 if(sha3Conditioner.HasConditionedData && esfinalFifo.Count <= EsfinalFifoDepth - sha3Conditioner.Sha3OutputLengthBits / 32) 162 { 163 var conditionedData = sha3Conditioner.GetConditionedData(); 164 esfinalFifo.EnqueueRange(conditionedData); 165 } 166 break; 167 case BypassMode.RawEntropy: 168 if(preEsfinalPackerFifo.Count == PreEsfinalPackerFifoDepth && esfinalFifo.Count <= EsfinalFifoDepth - PreEsfinalPackerFifoDepth) 169 { 170 esfinalFifo.EnqueueRange(preEsfinalPackerFifo.DequeueAll()); 171 } 172 break; 173 } 174 175 switch(PathSelect) 176 { 177 case Route.HardwareInterface: 178 HardwareInterfacePath(); 179 break; 180 case Route.FirmwareInterface: 181 FirmwareInterfacePath(); 182 break; 183 } 184 } 185 HardwareInterfacePath()186 private void HardwareInterfacePath() 187 { 188 if(hardwareOutputFifo.Count == 0 && esfinalFifo.Count >= EntropyUnpackerFifoDepth) 189 { 190 var entropyData = esfinalFifo.DequeueRange(EntropyUnpackerFifoDepth); 191 hardwareOutputFifo.EnqueueRange(entropyData); 192 } 193 } 194 FirmwareInterfacePath()195 private void FirmwareInterfacePath() 196 { 197 if(entropyUnpackerFifo.Count == 0 && esfinalFifo.Count >= EntropyUnpackerFifoDepth) 198 { 199 entropyUnpackerFifo.EnqueueRange(esfinalFifo.DequeueRange(EntropyUnpackerFifoDepth)); 200 } 201 202 if(entropyUnpackerFifo.Count > 0) 203 { 204 entropyValidInterruptState.Value = true; 205 UpdateInterrupts(); 206 } 207 } 208 DefineRegisters()209 private void DefineRegisters() 210 { 211 Registers.InterruptState.Define(this) 212 .WithFlag(0, out entropyValidInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "es_entropy_valid", writeCallback: (_, val) => 213 { 214 if(val && entropyUnpackerFifo.Count > 0) 215 { 216 // if there is still entropy available, the interrupt state is set again. 217 entropyValidInterruptState.Value = true; 218 } 219 }) 220 .WithFlag(1, out healthTestFailedInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "es_health_test_failed") 221 .WithFlag(2, out observeFifoReadyInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "es_observe_fifo_ready", writeCallback: (_, val) => 222 { 223 if(val && observeFifo.Count >= (int)observeFifoThreshold.Value) 224 { 225 observeFifoReadyInterruptState.Value = true; 226 } 227 }) 228 .WithFlag(3, out fatalErrorInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "es_fatal_err") 229 .WithReservedBits(4, 28) 230 .WithWriteCallback((_, __) => UpdateInterrupts()); 231 232 Registers.InterruptEnable.Define(this) 233 .WithFlag(0, out entropyValidInterruptEnable, name: "es_entropy_valid") 234 .WithFlag(1, out healthTestFailedInterruptEnable, name: "es_health_test_failed") 235 .WithFlag(2, out observeFifoReadyInterruptEnable, name: "es_observe_fifo_ready") 236 .WithFlag(3, out fatalErrorInterruptEnable, name: "es_fatal_err") 237 .WithReservedBits(4, 28) 238 .WithWriteCallback((_, __) => UpdateInterrupts()); 239 240 Registers.InterruptTest.Define(this) 241 .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { if(val) entropyValidInterruptState.Value = true; }, name: "es_entropy_valid") 242 .WithFlag(1, FieldMode.Write, writeCallback: (_, val) => { if(val) healthTestFailedInterruptState.Value = true; }, name: "es_health_test_failed") 243 .WithFlag(2, FieldMode.Write, writeCallback: (_, val) => { if(val) observeFifoReadyInterruptState.Value = true; }, name: "es_observe_fifo_ready") 244 .WithFlag(3, FieldMode.Write, writeCallback: (_, val) => { if(val) fatalErrorInterruptState.Value = true; }, name: "es_fatal_err") 245 .WithReservedBits(4, 28) 246 .WithWriteCallback((_, __) => UpdateInterrupts()); 247 248 Registers.AlertTest.Define(this) 249 .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { if(val) RecoverableAlert.Blink(); }, name: "recov_alert") 250 .WithFlag(1, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalAlert.Blink(); }, name: "fatal_alert") 251 .WithReservedBits(2, 30); 252 253 // Some registers are protected from writes by the means of write enable registers. 254 // It is a security countermeasure that adds checks before writing to the registers. 255 // Sometimes the write enable register is not taken into account in the model and marked as Tag, 256 // because it is not needed for the functional simulation. 257 Registers.RegisterWriteEnableForModuleEnable.Define(this, 0x1) 258 .WithFlag(0, out moduleEnableRegisterWriteEnable, FieldMode.Read | FieldMode.WriteZeroToClear, name: "ME_REGWEN") 259 .WithReservedBits(1, 31); 260 261 Registers.RegisterWriteEnableForControlAndThresholds.Define(this, 0x1) 262 .WithTaggedFlag("SW_REGUPD", 0) 263 .WithReservedBits(1, 31); 264 265 Registers.RegisterWriteEnableForAllControls.Define(this, 0x1) 266 .WithTaggedFlag("REGWEN", 0) 267 .WithReservedBits(1, 31); 268 269 Registers.Revision.Define(this, 0x10303) 270 .WithTag("ABI_REVISION", 0, 8) 271 .WithTag("HW_REVISION", 8, 8) 272 .WithTag("CHIP_TYPE", 16, 8) 273 .WithReservedBits(24, 8); 274 275 Registers.ModuleEnable.Define(this, 0x9) 276 .WithEnumField(0, 4, out moduleEnable, name: "MODULE_ENABLE", writeCallback: (_, val) => 277 { 278 if(moduleEnableRegisterWriteEnable.Value == false) 279 { 280 return; 281 } 282 283 if(val == MultiBitBool4.True) 284 { 285 this.Log(LogLevel.Noisy, "Enabling module"); 286 FillBuffers(); 287 } 288 else 289 { 290 this.Log(LogLevel.Noisy, "Disabling module"); 291 Reset(); 292 } 293 }) 294 .WithReservedBits(4, 28); 295 296 Registers.Configuration.Define(this, 0x909099) 297 .WithTag("FIPS_ENABLE", 0, 4) 298 .WithEnumField(4, 4, out entropyDataRegisterEnable, name: "ENTROPY_DATA_REG_ENABLE") 299 .WithTag("THRESHOLD_SCOPE", 12, 4) 300 .WithTag("RNG_BIT_ENABLE", 20, 4) 301 .WithTag("RNG_BIT_SEL", 24, 2) 302 .WithReservedBits(26, 6); 303 304 Registers.EntropyControl.Define(this, 0x99) 305 .WithEnumField(0, 4, out routeSelect, name: "ES_ROUTE") 306 .WithEnumField(4, 4, out bypassModeSelect, name: "ES_TYPE") 307 .WithReservedBits(8, 24); 308 309 Registers.EntropyDataBits.Define(this) 310 .WithValueField(0, 32, FieldMode.Read, name: "ENTROPY_DATA", valueProviderCallback: (_) => 311 { 312 if(entropyDataRegisterEnable.Value != MultiBitBool4.True) 313 { 314 this.Log(LogLevel.Warning, "Entropy data register is disabled"); 315 return 0; 316 } 317 318 if(entropyUnpackerFifo.Count == 0) 319 { 320 FillBuffers(); 321 this.Log(LogLevel.Debug, "Entropy generated on demand"); 322 } 323 324 if(!entropyUnpackerFifo.TryDequeue(out var value)) 325 { 326 this.Log(LogLevel.Warning, "No entropy data available"); 327 } 328 329 return value; 330 }); 331 332 // The randomness tests registers 333 334 Registers.HealthTestWindows.Define(this, 0x600200) 335 .WithTag("FIPS_WINDOW", 0, 16) 336 .WithTag("BYPASS_WINDOW", 16, 16); 337 338 Registers.RepetitionCountTestThresholds.Define(this, 0xffffffff) 339 .WithTag("FIPS_THRESH", 0, 16) 340 .WithTag("BYPASS_THRESH", 16, 16); 341 342 Registers.RepetitionCountSymbolTestThresholds.Define(this, 0xffffffff) 343 .WithTag("FIPS_THRESH", 0, 16) 344 .WithTag("BYPASS_THRESH", 16, 16); 345 346 Registers.AdaptiveProportionTestHighThresholds.Define(this, 0xffffffff) 347 .WithTag("FIPS_THRESH", 0, 16) 348 .WithTag("BYPASS_THRESH", 16, 16); 349 350 Registers.AdaptiveProportionTestLowThresholds.Define(this) 351 .WithTag("FIPS_THRESH", 0, 16) 352 .WithTag("BYPASS_THRESH", 16, 16); 353 354 Registers.BucketTestThresholds.Define(this, 0xffffffff) 355 .WithTag("FIPS_THRESH", 0, 16) 356 .WithTag("BYPASS_THRESH", 16, 16); 357 358 Registers.MarkovTestHighThresholds.Define(this, 0xffffffff) 359 .WithTag("FIPS_THRESH", 0, 16) 360 .WithTag("BYPASS_THRESH", 16, 16); 361 362 Registers.MarkovTestLowThresholds.Define(this) 363 .WithTag("FIPS_THRESH", 0, 16) 364 .WithTag("BYPASS_THRESH", 16, 16); 365 366 Registers.ExternalHealthTestHighThresholds.Define(this, 0xffffffff) 367 .WithTag("FIPS_THRESH", 0, 16) 368 .WithTag("BYPASS_THRESH", 16, 16); 369 370 Registers.ExternalHealthTestLowThresholds.Define(this) 371 .WithTag("FIPS_THRESH", 0, 16) 372 .WithTag("BYPASS_THRESH", 16, 16); 373 374 Registers.RepetitionCountTestHighWatermarks.Define(this) 375 .WithTag("FIPS_WATERMARK", 0, 16) 376 .WithTag("BYPASS_WATERMARK", 16, 16); 377 378 Registers.RepetitionCountSymbolTestHighWatermarks.Define(this) 379 .WithTag("FIPS_WATERMARK", 0, 16) 380 .WithTag("BYPASS_WATERMARK", 16, 16); 381 382 Registers.AdaptiveProportionTestHighWatermarks.Define(this) 383 .WithTag("FIPS_WATERMARK", 0, 16) 384 .WithTag("BYPASS_WATERMARK", 16, 16); 385 386 Registers.AdaptiveProportionTestLowWatermarks.Define(this, 0xffffffff) 387 .WithTag("FIPS_WATERMARK", 0, 16) 388 .WithTag("BYPASS_WATERMARK", 16, 16); 389 390 Registers.ExternalHealthTestHighWatermarks.Define(this) 391 .WithTag("FIPS_WATERMARK", 0, 16) 392 .WithTag("BYPASS_WATERMARK", 16, 16); 393 394 Registers.ExternalHealthTestLowWatermarks.Define(this, 0xffffffff) 395 .WithTag("FIPS_WATERMARK", 0, 16) 396 .WithTag("BYPASS_WATERMARK", 16, 16); 397 398 Registers.BucketTestHighWatermarks.Define(this) 399 .WithTag("FIPS_WATERMARK", 0, 16) 400 .WithTag("BYPASS_WATERMARK", 16, 16); 401 402 Registers.MarkovTestHighWatermarks.Define(this) 403 .WithTag("FIPS_WATERMARK", 0, 16) 404 .WithTag("BYPASS_WATERMARK", 16, 16); 405 406 Registers.MarkovTestLowWatermarks.Define(this, 0xffffffff) 407 .WithTag("FIPS_WATERMARK", 0, 16) 408 .WithTag("BYPASS_WATERMARK", 16, 16); 409 410 Registers.RepetitionCountTestFailureCounter.Define(this) 411 .WithTag("REPCNT_TOTAL_FAILS", 0, 32); 412 413 Registers.RepetitionCountSymbolTestFailureCounter.Define(this) 414 .WithTag("REPCNTS_TOTAL_FAILS", 0, 32); 415 416 Registers.AdaptiveProportionHighTestFailureCounter.Define(this) 417 .WithTag("ADAPTP_HI_TOTAL_FAILS", 0, 32); 418 419 Registers.AdaptiveProportionLowTestFailureCounter.Define(this) 420 .WithTag("ADAPTP_LO_TOTAL_FAILS", 0, 32); 421 422 Registers.BucketTestFailureCounter.Define(this) 423 .WithTag("BUCKET_TOTAL_FAILS", 0, 32); 424 425 Registers.MarkovHighTestFailureCounter.Define(this) 426 .WithTag("MARKOV_HI_TOTAL_FAILS", 0, 32); 427 428 Registers.MarkovLowTestFailureCounter.Define(this) 429 .WithTag("MARKOV_LO_TOTAL_FAILS", 0, 32); 430 431 Registers.ExternalHealthTestHighThresholdFailureCounter.Define(this) 432 .WithTag("EXTHT_HI_TOTAL_FAILS", 0, 32); 433 434 Registers.ExternalHealthTestLowThresholdFailureCounter.Define(this) 435 .WithTag("EXTHT_LO_TOTAL_FAILS", 0, 32); 436 437 Registers.AlertThreshold.Define(this, 0xfffd0002) 438 .WithTag("ALERT_THRESHOLD", 0, 16) 439 .WithTag("ALERT_THRESHOLD_INV", 16, 16); 440 441 Registers.AlertSummaryFailureCounts.Define(this) 442 .WithTag("ANY_FAIL_COUNT", 0, 16) 443 .WithReservedBits(16, 16); 444 445 Registers.AlertFailureCounts.Define(this) 446 .WithTag("REPCNT_FAIL_COUNT", 4, 4) 447 .WithTag("ADAPTP_HI_FAIL_COUNT", 8, 4) 448 .WithTag("ADAPTP_LO_FAIL_COUNT", 12, 4) 449 .WithTag("BUCKET_FAIL_COUNT", 16, 4) 450 .WithTag("MARKOV_HI_FAIL_COUNT", 20, 4) 451 .WithTag("MARKOV_LO_FAIL_COUNT", 24, 4) 452 .WithTag("REPCNTS_FAIL_COUNT", 28, 4); 453 454 Registers.ExternalHealthTestAlertFailureCounts.Define(this) 455 .WithTag("EXTHT_HI_FAIL_COUNT", 0, 4) 456 .WithTag("EXTHT_LO_FAIL_COUNT", 4, 4) 457 .WithReservedBits(8, 24); 458 459 // End of the randomness test registers 460 461 Registers.FirmwareOverrideControl.Define(this, 0x99) 462 .WithEnumField(0, 4, out firmwareOverrideMode, name: "FW_OV_MODE") 463 .WithEnumField(4, 4, out firmwareOverrideEntropyInsert, name: "FW_OV_ENTROPY_INSERT") 464 .WithReservedBits(8, 24); 465 466 Registers.FirmwareOverrideSHA3BlockStartControl.Define(this, 0x9) 467 .WithEnumField(0, 4, out firmwareOverrideInsertStart , name: "FW_OV_INSERT_START", writeCallback: (_, value) => 468 { 469 if(value == MultiBitBool4.True) 470 { 471 this.Log(LogLevel.Noisy, "Starting the SHA3 process - ready to accept data in write FIFO"); 472 } 473 else if(value == MultiBitBool4.False) 474 { 475 this.Log(LogLevel.Noisy, "Finishing the SHA3 process - no more data will be accepted in write FIFO"); 476 sha3Conditioner.FinishProcessing(); 477 OutputPath(); 478 } 479 }) 480 .WithReservedBits(4, 28); 481 482 Registers.FirmwareOverrideFIFOWriteFullStatus.Define(this) 483 .WithFlag(0, out writeFifoFullStatus, FieldMode.Read, name: "FW_OV_WR_FIFO_FULL") 484 .WithReservedBits(1, 31); 485 486 Registers.FirmwareOverrideObserveFIFOOverflowStatus.Define(this) 487 .WithFlag(0, out observeFifoOverflowStatus, FieldMode.Read | FieldMode.WriteZeroToClear, name: "FW_OV_RD_FIFO_OVERFLOW") 488 .WithReservedBits(1, 31); 489 490 Registers.FirmwareOverrideObserveFIFORead.Define(this) 491 .WithValueField(0, 32, FieldMode.Read, name: "FW_OV_RD_DATA", valueProviderCallback: (_) => 492 { 493 if(ModeOverride != Mode.FirmwareOverride) 494 { 495 this.Log(LogLevel.Warning, "Trying to read from the Observe FIFO while the firmware override mode is disabled"); 496 return 0; 497 } 498 499 if(observeFifo.Count == 0) 500 { 501 FillBuffers(); 502 this.Log(LogLevel.Debug, "Entropy generated on demand"); 503 } 504 505 if(!observeFifo.TryDequeue(out var value)) 506 { 507 this.Log(LogLevel.Warning, "No data in the observe FIFO"); 508 } 509 510 return value; 511 }); 512 513 Registers.FirmwareOverrideFIFOWrite.Define(this) 514 .WithValueField(0, 32, FieldMode.Write, name: "FW_OV_WR_DATA") 515 .WithWriteCallback((_, value) => 516 { 517 if(ModeOverride != Mode.FirmwareOverride || ModeSelect != Mode.FirmwareOverride) 518 { 519 this.Log(LogLevel.Warning, "Attempt to write to FIFO while not in firmware override mode and entropy insert mode"); 520 return; 521 } 522 523 if(writeFifoFullStatus.Value) 524 { 525 this.Log(LogLevel.Warning, "Attempt to write to full FIFO"); 526 return; 527 } 528 529 InsertIntoEntropyFlow(value, Mode.FirmwareOverride); 530 }); 531 532 Registers.ObserveFIFOThreshold.Define(this, 0x20) 533 .WithValueField(0, 7, out observeFifoThreshold, name: "OBSERVE_FIFO_THRESH") 534 .WithReservedBits(7, 25); 535 536 Registers.ObserveFIFODepth.Define(this) 537 .WithValueField(0, 7, FieldMode.Read, valueProviderCallback: (_) => (uint)observeFifo.Count, name: "OBSERVE_FIFO_DEPTH") 538 .WithReservedBits(7, 25); 539 540 Registers.DebugStatus.Define(this, 0x10000) 541 .WithTag("ENTROPY_FIFO_DEPTH", 0, 3) 542 .WithTag("SHA3_FSM", 3, 3) 543 .WithTaggedFlag("SHA3_BLOCK_PR", 6) 544 .WithTaggedFlag("SHA3_SQUEEZING", 7) 545 .WithTaggedFlag("SHA3_ABSORBED", 8) 546 .WithTaggedFlag("SHA3_ERR", 9) 547 .WithTaggedFlag("MAIN_SM_IDLE", 16) 548 .WithTaggedFlag("MAIN_SM_BOOT_DONE", 17) 549 .WithReservedBits(18, 14); 550 551 Registers.RecoverableAlertStatus.Define(this) 552 .WithTaggedFlag("FIPS_ENABLE_FIELD_ALERT", 0) 553 .WithTaggedFlag("ENTROPY_DATA_REG_EN_FIELD_ALERT", 1) 554 .WithTaggedFlag("MODULE_ENABLE_FIELD_ALERT", 2) 555 .WithTaggedFlag("THRESHOLD_SCOPE_FIELD_ALERT", 3) 556 .WithTaggedFlag("RNG_BIT_ENABLE_FIELD_ALERT", 5) 557 .WithTaggedFlag("FW_OV_SHA3_START_FIELD_ALERT", 7) 558 .WithTaggedFlag("FW_OV_MODE_FIELD_ALERT", 8) 559 .WithTaggedFlag("FW_OV_ENTROPY_INSERT_FIELD_ALERT", 9) 560 .WithTaggedFlag("ES_ROUTE_FIELD_ALERT", 10) 561 .WithTaggedFlag("ES_TYPE_FIELD_ALERT", 11) 562 .WithTaggedFlag("ES_MAIN_SM_ALERT", 12) 563 .WithTaggedFlag("ES_BUS_CMP_ALERT", 13) 564 .WithTaggedFlag("ES_THRESH_CFG_ALERT", 14) 565 .WithReservedBits(15, 17); 566 567 Registers.HardwareDetectionOfErrorConditionsStatus.Define(this) 568 .WithTaggedFlag("SFIFO_ESRNG_ERR", 0) 569 .WithTaggedFlag("SFIFO_OBSERVE_ERR", 1) 570 .WithTaggedFlag("SFIFO_ESFINAL_ERR", 2) 571 .WithTaggedFlag("ES_ACK_SM_ERR", 20) 572 .WithTaggedFlag("ES_MAIN_SM_ERR", 21) 573 .WithTaggedFlag("ES_CNTR_ERR", 22) 574 .WithTaggedFlag("FIFO_WRITE_ERR", 28) 575 .WithTaggedFlag("FIFO_READ_ERR", 29) 576 .WithTaggedFlag("FIFO_STATE_ERR", 30) 577 .WithReservedBits(31, 1); 578 579 Registers.TestErrorConditions.Define(this) 580 .WithTag("ERR_CODE_TEST", 0, 5) 581 .WithReservedBits(5, 27); 582 583 Registers.MainStateMachineStateDebug.Define(this, 0xf5) 584 .WithEnumField(0, 9, out mainMachineState, FieldMode.Read, name: "MAIN_SM_STATE") 585 .WithReservedBits(9, 23); 586 } 587 UpdateInterrupts()588 private void UpdateInterrupts() 589 { 590 EsEntropyValidIRQ.Set(entropyValidInterruptState.Value && entropyValidInterruptEnable.Value); 591 EsHealthTestFailedIRQ.Set(healthTestFailedInterruptState.Value && healthTestFailedInterruptEnable.Value); 592 EsObserveFifoReadyIRQ.Set(observeFifoReadyInterruptState.Value && observeFifoReadyInterruptEnable.Value); 593 EsFatalErrIRQ.Set(fatalErrorInterruptState.Value && fatalErrorInterruptEnable.Value); 594 } 595 ResetBuffers()596 private void ResetBuffers() 597 { 598 observeFifo.Clear(); 599 preConditionerPackerFifo.Clear(); 600 preEsfinalPackerFifo.Clear(); 601 esfinalFifo.Clear(); 602 entropyUnpackerFifo.Clear(); 603 hardwareOutputFifo.Clear(); 604 } 605 606 public GPIO EsEntropyValidIRQ { get; } 607 public GPIO EsHealthTestFailedIRQ { get; } 608 public GPIO EsObserveFifoReadyIRQ { get; } 609 public GPIO EsFatalErrIRQ { get; } 610 611 public GPIO RecoverableAlert { get; } 612 public GPIO FatalAlert { get; } 613 614 private readonly PseudorandomNumberGenerator entropySource; 615 private readonly Sha3Conditioner sha3Conditioner; 616 617 private readonly Queue<uint> observeFifo; 618 private readonly Queue<uint> preConditionerPackerFifo; 619 private readonly Queue<uint> preEsfinalPackerFifo; 620 private readonly Queue<uint> esfinalFifo; 621 private readonly Queue<uint> entropyUnpackerFifo; 622 private readonly Queue<uint> hardwareOutputFifo; 623 624 private IValueRegisterField observeFifoThreshold; 625 private IFlagRegisterField entropyValidInterruptState; 626 private IFlagRegisterField healthTestFailedInterruptState; 627 private IFlagRegisterField observeFifoReadyInterruptState; 628 private IFlagRegisterField fatalErrorInterruptState; 629 private IFlagRegisterField entropyValidInterruptEnable; 630 private IFlagRegisterField healthTestFailedInterruptEnable; 631 private IFlagRegisterField observeFifoReadyInterruptEnable; 632 private IFlagRegisterField fatalErrorInterruptEnable; 633 private IFlagRegisterField moduleEnableRegisterWriteEnable; 634 private IEnumRegisterField<MultiBitBool4> entropyDataRegisterEnable; 635 private IEnumRegisterField<MultiBitBool4> moduleEnable; 636 private IEnumRegisterField<MultiBitBool4> firmwareOverrideMode; 637 private IEnumRegisterField<MultiBitBool4> firmwareOverrideEntropyInsert; 638 private IEnumRegisterField<MultiBitBool4> firmwareOverrideInsertStart; 639 private IEnumRegisterField<StateMachine> mainMachineState; 640 private IFlagRegisterField observeFifoOverflowStatus; 641 private IEnumRegisterField<MultiBitBool4> routeSelect; 642 private IEnumRegisterField<MultiBitBool4> bypassModeSelect; 643 private IFlagRegisterField writeFifoFullStatus; 644 645 private Mode ModeOverride => firmwareOverrideMode.Value == MultiBitBool4.True ? Mode.FirmwareOverride : Mode.Normal; 646 private Mode ModeSelect => firmwareOverrideEntropyInsert.Value == MultiBitBool4.True ? Mode.FirmwareOverride : Mode.Normal; 647 private Route PathSelect => routeSelect.Value == MultiBitBool4.True ? Route.FirmwareInterface : Route.HardwareInterface; 648 private BypassMode BypassModeSelect => bypassModeSelect.Value == MultiBitBool4.True ? BypassMode.RawEntropy : BypassMode.Sha3ConditionedEntropy; 649 650 // Depth is in 32-bit units 651 private const int ObserveFifoDepth = 64; 652 private const int PreConditionerPackerFifoDepth = 2; 653 private const int PreEsfinalPackerFifoDepth = 12; 654 private const int EsfinalFifoDepth = 48; 655 private const int EntropyUnpackerFifoDepth = 12; 656 657 private class Sha3Conditioner 658 { Sha3Conditioner(int outputLength = 384)659 public Sha3Conditioner(int outputLength = 384) 660 { 661 sha3 = new Sha3Digest(outputLength); 662 Sha3OutputLengthBits = outputLength; 663 conditionerFifo = new Queue<uint>(); 664 conditionedDataFifo = new Queue<uint>(); 665 } 666 AddData(uint[] data)667 public void AddData(uint[] data) 668 { 669 conditionerFifo.EnqueueRange(data); 670 if(conditionerFifo.Count >= CompressionBlockSizeBits / 32) 671 { 672 // The compression operation, by default, will compress every 2048 tested bits into 384 full-entropy bits 673 FinishProcessing(); 674 } 675 } 676 FinishProcessing()677 public void FinishProcessing() 678 { 679 var entropyBytes = conditionerFifo.DequeueAll().SelectMany(BitConverter.GetBytes).ToArray(); 680 sha3.BlockUpdate(entropyBytes, 0, entropyBytes.Length); 681 682 var hash = new byte[Sha3OutputLengthBits / 8]; 683 var written = sha3.DoFinal(hash, 0); 684 685 var output = new uint[Sha3OutputLengthBits / 32]; 686 for(var i = 0; i < output.Length; i++) 687 { 688 output[i] = BitConverter.ToUInt32(hash, i * 4); 689 conditionedDataFifo.Enqueue(output[i]); 690 } 691 } 692 GetConditionedData()693 public uint[] GetConditionedData() 694 { 695 return conditionedDataFifo.DequeueAll(); 696 } 697 Reset()698 public void Reset() 699 { 700 conditionerFifo.Clear(); 701 conditionedDataFifo.Clear(); 702 sha3.Reset(); 703 } 704 705 public bool HasConditionedData => conditionedDataFifo.Count >= Sha3OutputLengthBits / 32; 706 707 public int Sha3OutputLengthBits { get; } 708 709 private readonly Queue<uint> conditionerFifo; 710 private readonly Queue<uint> conditionedDataFifo; 711 private readonly Sha3Digest sha3; 712 713 private const int CompressionBlockSizeBits = 2048; 714 } 715 716 private enum Mode 717 { 718 Normal, 719 FirmwareOverride 720 } 721 722 private enum BypassMode 723 { 724 Sha3ConditionedEntropy, 725 RawEntropy 726 } 727 728 private enum Route 729 { 730 HardwareInterface, 731 FirmwareInterface 732 } 733 734 // https://github.com/lowRISC/opentitan/blob/master/hw/ip/entropy_src/rtl/entropy_src_main_sm_pkg.sv 735 private enum StateMachine 736 { 737 Idle = 0b011110101, // idle 738 BootHTRunning = 0b111010010, // boot mode, wait for health test done pulse 739 BootPostHTChk = 0b101101110, // boot mode, wait for post health test packer not empty state 740 BootPhaseDone = 0b010001110, // boot mode, stay here until master enable is off 741 StartupHTStart = 0b000101100, // startup mode, pulse the sha3 start input 742 StartupPhase1 = 0b100000001, // startup mode, look for first test pass/fail 743 StartupPass1 = 0b110100101, // startup mode, look for first test pass/fail, done if pass 744 StartupFail1 = 0b000010111, // startup mode, look for second fail, alert if fail 745 ContHTStart = 0b001000000, // continuous test mode, pulse the sha3 start input 746 ContHTRunning = 0b110100010, // continuous test mode, wait for health test done pulse 747 FWInsertStart = 0b011000011, // fw ov mode, start the sha3 block 748 FWInsertMsg = 0b001011001, // fw ov mode, insert fw message into sha3 block 749 Sha3MsgDone = 0b100001111, // sha3 mode, all input messages added, ready to process 750 Sha3Prep = 0b011111000, // sha3 mode, request csrng arb to reduce power 751 Sha3Process = 0b010111111, // sha3 mode, pulse the sha3 process input 752 Sha3Valid = 0b101110001, // sha3 mode, wait for sha3 valid indication 753 Sha3Done = 0b110011000, // sha3 mode, capture sha3 result, pulse done input 754 Sha3Quiesce = 0b111001101, // sha3 mode, goto alert state or continuous check mode 755 AlertState = 0b111111011, // if some alert condition occurs, pulse an alert indication 756 AlertHang = 0b101011100, // after pulsing alert signal, hang here until sw handles 757 Error = 0b100111101 // illegal state reached and hang 758 } 759 760 public enum Registers 761 { 762 InterruptState = 0x0, 763 InterruptEnable = 0x4, 764 InterruptTest = 0x8, 765 AlertTest = 0xc, 766 RegisterWriteEnableForModuleEnable = 0x10, 767 RegisterWriteEnableForControlAndThresholds = 0x14, 768 RegisterWriteEnableForAllControls = 0x18, 769 Revision = 0x1c, 770 ModuleEnable = 0x20, 771 Configuration = 0x24, 772 EntropyControl = 0x28, 773 EntropyDataBits = 0x2c, 774 HealthTestWindows = 0x30, 775 RepetitionCountTestThresholds = 0x34, 776 RepetitionCountSymbolTestThresholds = 0x38, 777 AdaptiveProportionTestHighThresholds = 0x3c, 778 AdaptiveProportionTestLowThresholds = 0x40, 779 BucketTestThresholds = 0x44, 780 MarkovTestHighThresholds = 0x48, 781 MarkovTestLowThresholds = 0x4c, 782 ExternalHealthTestHighThresholds = 0x50, 783 ExternalHealthTestLowThresholds = 0x54, 784 RepetitionCountTestHighWatermarks = 0x58, 785 RepetitionCountSymbolTestHighWatermarks = 0x5c, 786 AdaptiveProportionTestHighWatermarks = 0x60, 787 AdaptiveProportionTestLowWatermarks = 0x64, 788 ExternalHealthTestHighWatermarks = 0x68, 789 ExternalHealthTestLowWatermarks = 0x6c, 790 BucketTestHighWatermarks = 0x70, 791 MarkovTestHighWatermarks = 0x74, 792 MarkovTestLowWatermarks = 0x78, 793 RepetitionCountTestFailureCounter = 0x7c, 794 RepetitionCountSymbolTestFailureCounter = 0x80, 795 AdaptiveProportionHighTestFailureCounter = 0x84, 796 AdaptiveProportionLowTestFailureCounter = 0x88, 797 BucketTestFailureCounter = 0x8c, 798 MarkovHighTestFailureCounter = 0x90, 799 MarkovLowTestFailureCounter = 0x94, 800 ExternalHealthTestHighThresholdFailureCounter = 0x98, 801 ExternalHealthTestLowThresholdFailureCounter = 0x9c, 802 AlertThreshold = 0xa0, 803 AlertSummaryFailureCounts = 0xa4, 804 AlertFailureCounts = 0xa8, 805 ExternalHealthTestAlertFailureCounts = 0xac, 806 FirmwareOverrideControl = 0xb0, 807 FirmwareOverrideSHA3BlockStartControl = 0xb4, 808 FirmwareOverrideFIFOWriteFullStatus = 0xb8, 809 FirmwareOverrideObserveFIFOOverflowStatus = 0xbc, 810 FirmwareOverrideObserveFIFORead = 0xc0, 811 FirmwareOverrideFIFOWrite = 0xc4, 812 ObserveFIFOThreshold = 0xc8, 813 ObserveFIFODepth = 0xcc, 814 DebugStatus = 0xd0, 815 RecoverableAlertStatus = 0xd4, 816 HardwareDetectionOfErrorConditionsStatus = 0xd8, 817 TestErrorConditions = 0xdc, 818 MainStateMachineStateDebug = 0xe0, 819 } 820 } 821 } 822