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