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.Collections.Generic; 9 using Antmicro.Renode.Core; 10 using Antmicro.Renode.Core.Structure.Registers; 11 using Antmicro.Renode.Logging; 12 using Antmicro.Renode.Utilities; 13 14 namespace Antmicro.Renode.Peripherals.Miscellaneous 15 { 16 public class OpenTitan_EntropyDistributionNetwork : BasicDoubleWordPeripheral, IKnownSize 17 { OpenTitan_EntropyDistributionNetwork(IMachine machine, OpenTitan_CSRNG cryptoRandomGenerator)18 public OpenTitan_EntropyDistributionNetwork(IMachine machine, OpenTitan_CSRNG cryptoRandomGenerator) : base(machine) 19 { 20 this.csrng = cryptoRandomGenerator; 21 22 DefineRegisters(); 23 CommandRequestDone = new GPIO(); 24 FatalError = new GPIO(); 25 RecoverableAlert = new GPIO(); 26 FatalAlert = new GPIO(); 27 28 reseedCommands = new Queue<uint>(ReseedCommandFifoCapacity); 29 generateCommands = new Queue<uint>(GenerateCommandFifoCapacity); 30 31 Reset(); 32 } 33 34 // it is for intermodule communication between the peripheral devices and the EDN RequestData()35 public uint RequestData() 36 { 37 if(ednEnable.Value != MultiBitBool4.True) 38 { 39 this.Log(LogLevel.Warning, "EDN is disabled. Returning 0."); 40 return 0; 41 } 42 43 var dataLeft = csrng.RequestData(out var result); 44 45 if(!dataLeft && bootRequestMode.Value == MultiBitBool4.True) 46 { 47 this.Log(LogLevel.Debug, "BOOT_REQ_MODE is on. Issueing a new request."); 48 SendCsrngCommand((uint)bootGenerateCommand.Value); 49 } 50 51 if(!dataLeft && autoRequestModeOn) 52 { 53 this.Log(LogLevel.Debug, "AUTO_REQ_MODE is on. Issueing a new request."); 54 55 if(generateCommands.TryDequeue(out var generateCommand)) 56 { 57 SendCsrngCommand(generateCommand); 58 } 59 else 60 { 61 this.Log(LogLevel.Warning, "No generate commands in the generate command FIFO"); 62 } 63 requestsBetweenReseeds.Value--; 64 65 if(requestsBetweenReseeds.Value == 0) 66 { 67 if(reseedCommands.TryDequeue(out var reseedCommand)) 68 { 69 SendCsrngCommand(reseedCommand); 70 } 71 else 72 { 73 this.Log(LogLevel.Warning, "No reseed commands in the reseed command FIFO"); 74 } 75 requestsBetweenReseeds.Value = maxNumberOfRequestsBetweenReseeds; // reload counter 76 } 77 } 78 79 return result; 80 } 81 Reset()82 public override void Reset() 83 { 84 base.Reset(); 85 } 86 87 public long Size => 0x1000; 88 DefineRegisters()89 private void DefineRegisters() 90 { 91 Registers.InterruptState.Define(this) 92 .WithFlag(0, out commandRequestDoneInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "edn_cmd_req_done") 93 .WithFlag(1, out fatalErrorInterruptState, FieldMode.Read | FieldMode.WriteOneToClear, name: "edn_fatal_err") 94 .WithReservedBits(2, 30) 95 .WithWriteCallback((_, __) => UpdateInterrupts()); 96 97 Registers.InterruptEnable.Define(this) 98 .WithFlag(0, out commandRequestDoneInterruptEnable, name: "edn_cmd_req_done") 99 .WithFlag(1, out fatalErrorInterruptEnable, name: "edn_fatal_err") 100 .WithReservedBits(2, 30) 101 .WithWriteCallback((_, __) => UpdateInterrupts()); 102 103 Registers.InterruptTest.Define(this) 104 .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { if(val) commandRequestDoneInterruptState.Value = true; }, name: "edn_cmd_req_done") 105 .WithFlag(1, FieldMode.Write, writeCallback: (_, val) => { if(val) fatalErrorInterruptState.Value = true; }, name: "edn_fatal_err") 106 .WithReservedBits(2, 30) 107 .WithWriteCallback((_, __) => UpdateInterrupts()); 108 109 Registers.AlertTest.Define(this) 110 .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { if(val) RecoverableAlert.Blink(); }, name: "recov_alert") 111 .WithFlag(1, FieldMode.Write, writeCallback: (_, val) => { if(val) FatalAlert.Blink(); }, name: "fatal_alert") 112 .WithReservedBits(2, 30); 113 114 Registers.RegisterWriteEnableForAllControls.Define(this, 0x1) 115 .WithFlag(0, out allControlsRegisterWriteEnable, FieldMode.Read | FieldMode.WriteZeroToClear, name: "REGWEN") 116 .WithReservedBits(1, 31); 117 118 Registers.Control.Define(this, 0x9999) 119 .WithEnumField(0, 4, out ednEnable, writeCallback: (_, val) => 120 { 121 if(!allControlsRegisterWriteEnable.Value) 122 { 123 this.Log(LogLevel.Warning, "Register write is disabled"); 124 return; 125 } 126 127 if(val != MultiBitBool4.True && val != MultiBitBool4.False) 128 { 129 this.Log(LogLevel.Warning, "Invalid value for EDN_ENABLE"); 130 ednEnableFieldAlert.Value = true; 131 return; 132 } 133 }, name: "EDN_ENABLE") 134 .WithEnumField(4, 4, out bootRequestMode, writeCallback: (_, val) => 135 { 136 if(!allControlsRegisterWriteEnable.Value) 137 { 138 this.Log(LogLevel.Warning, "Register write is disabled"); 139 return; 140 } 141 142 if(val != MultiBitBool4.True && val != MultiBitBool4.False) 143 { 144 this.Log(LogLevel.Warning, "Invalid value for BOOT_REQ_MODE"); 145 bootRequestModeFieldAlert.Value = true; 146 return; 147 } 148 }, name: "BOOT_REQ_MODE") 149 .WithEnumField(8, 4, out autoRequestMode, writeCallback: (_, val) => 150 { 151 if(!allControlsRegisterWriteEnable.Value) 152 { 153 this.Log(LogLevel.Warning, "Register write is disabled"); 154 return; 155 } 156 157 if(val != MultiBitBool4.True && val != MultiBitBool4.False) 158 { 159 this.Log(LogLevel.Warning, "Invalid value for AUTO_REQ_MODE"); 160 autoRequestModeFieldAlert.Value = true; 161 return; 162 } 163 164 if(val == MultiBitBool4.False) 165 { 166 autoRequestModeOn = false; 167 } 168 }, name: "AUTO_REQ_MODE") 169 .WithEnumField(12, 4, out commandFifoReset, writeCallback: (_, val) => 170 { 171 if(!allControlsRegisterWriteEnable.Value) 172 { 173 this.Log(LogLevel.Warning, "Register write is disabled"); 174 return; 175 } 176 177 if(val != MultiBitBool4.True && val != MultiBitBool4.False) 178 { 179 this.Log(LogLevel.Warning, "Invalid value for CMD_FIFO_RST"); 180 commandFifoResetFieldAlert.Value = true; 181 return; 182 } 183 184 if(val == MultiBitBool4.True) 185 { 186 reseedCommands.Clear(); 187 generateCommands.Clear(); 188 } 189 }, name: "CMD_FIFO_RST") 190 .WithReservedBits(16, 16); 191 192 Registers.BootInstantiateCommand.Define(this, 0x901) 193 .WithValueField(0, 32, out bootInstantiateCommand, writeCallback: (_, val) => 194 { 195 if(bootRequestMode.Value != MultiBitBool4.True) 196 { 197 this.Log(LogLevel.Warning, "BOOT_REQ_MODE is disabled. Writing to BOOT_INST_CMD has no effect."); 198 return; 199 } 200 201 SendCsrngCommand((uint)val); 202 }, name: "BOOT_INST_CMD"); 203 204 Registers.BootGenerateCommand.Define(this, 0xfff003) 205 .WithValueField(0, 32, out bootGenerateCommand, writeCallback: (_, val) => 206 { 207 if(bootRequestMode.Value != MultiBitBool4.True) 208 { 209 this.Log(LogLevel.Warning, "BOOT_REQ_MODE is disabled. Writing to BOOT_GEN_CMD has no effect."); 210 return; 211 } 212 213 SendCsrngCommand((uint)val); 214 }, name: "BOOT_GEN_CMD"); 215 216 Registers.CsrngSoftwareCommandRequest.Define(this) 217 .WithValueField(0, 32, FieldMode.Write, writeCallback: (_, val) => 218 { 219 if(autoRequestModeOn) 220 { 221 this.Log(LogLevel.Warning, "Automatic request mode is enabled. Writing to SW_CMD_REQ has no effect."); 222 return; 223 } 224 225 if(autoRequestMode.Value == MultiBitBool4.True) 226 { 227 autoRequestModeOn = true; 228 } 229 230 SendCsrngCommand((uint)val); 231 } 232 , name: "SW_CMD_REQ"); 233 234 Registers.CommandStatus.Define(this) 235 .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => true /* 1 - Ready to accept commands */, name: "CMD_RDY") 236 .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => false /* 0 - Request completed successfully*/, name: "CMD_STS") 237 .WithReservedBits(2, 30); 238 239 Registers.CsrngReseedCommand.Define(this) 240 .WithValueField(0, 32, FieldMode.Write, writeCallback: (_, val) => 241 { 242 if(reseedCommands.Count >= ReseedCommandFifoCapacity) 243 { 244 this.Log(LogLevel.Warning, "Reseed command FIFO is full"); 245 reseedCommandsError.Value = true; 246 fifoWriteError.Value = true; 247 FatalAlert.Blink(); 248 fatalErrorInterruptState.Value = true; 249 UpdateInterrupts(); 250 return; 251 } 252 reseedCommands.Enqueue((uint)val); 253 }, name: "RESEED_CMD"); 254 255 Registers.CsrngGenerateCommand.Define(this) 256 .WithValueField(0, 32, FieldMode.Write, writeCallback: (_, val) => 257 { 258 if(generateCommands.Count >= GenerateCommandFifoCapacity) 259 { 260 this.Log(LogLevel.Warning, "Generate command FIFO is full"); 261 generateCommandsError.Value = true; 262 fifoWriteError.Value = true; 263 FatalAlert.Blink(); 264 fatalErrorInterruptState.Value = true; 265 UpdateInterrupts(); 266 return; 267 } 268 generateCommands.Enqueue((uint)val); 269 }, name: "GENERATE_CMD"); 270 271 Registers.MaximumNumberOfRequestsBetweenReseeds.Define(this) 272 .WithValueField(0, 32, out requestsBetweenReseeds, writeCallback: (_, val) => maxNumberOfRequestsBetweenReseeds = (uint)val, name: "MAX_NUM_REQS_BETWEEN_RESEEDS"); 273 274 Registers.RecoverableAlertStatus.Define(this) 275 .WithFlag(0, out ednEnableFieldAlert, FieldMode.Read | FieldMode.WriteZeroToClear, name: "EDN_ENABLE_FIELD_ALERT") 276 .WithFlag(1, out bootRequestModeFieldAlert, FieldMode.Read | FieldMode.WriteZeroToClear, name: "BOOT_REQ_MODE_FIELD_ALERT") 277 .WithFlag(2, out autoRequestModeFieldAlert, FieldMode.Read | FieldMode.WriteZeroToClear, name: "AUTO_REQ_MODE_FIELD_ALERT") 278 .WithFlag(3, out commandFifoResetFieldAlert, FieldMode.Read | FieldMode.WriteZeroToClear, name: "CMD_FIFO_RST_FIELD_ALERT") 279 .WithReservedBits(4, 8) 280 .WithTaggedFlag("EDN_BUS_CMP_ALERT", 12) 281 .WithReservedBits(13, 19); 282 283 Registers.ErrorCode.Define(this) 284 .WithFlag(0, out reseedCommandsError, FieldMode.Read, name: "SFIFO_RESCMD_ERR") 285 .WithFlag(1, out generateCommandsError, FieldMode.Read, name: "SFIFO_GENCMD_ERR") 286 .WithFlag(2, out outputFifoError, FieldMode.Read, name: "SFIFO_OUTPUT_ERR") 287 .WithReservedBits(3, 17) 288 .WithFlag(20, out ednAckStageIllegalStateError, FieldMode.Read, name: "EDN_ACK_SM_ERR") 289 .WithFlag(21, out ednMainStageIllegalStateError, FieldMode.Read, name: "EDN_MAIN_SM_ERR") 290 .WithFlag(22, out hardenedCounterError, FieldMode.Read, name: "EDN_CNTR_ERR") 291 .WithReservedBits(23, 5) 292 .WithFlag(28, out fifoWriteError, FieldMode.Read, name: "FIFO_WRITE_ERR") 293 .WithFlag(29, out fifoReadError, FieldMode.Read, name: "FIFO_READ_ERR") 294 .WithFlag(30, out fifoStateError, FieldMode.Read, name: "FIFO_STATE_ERR") 295 .WithReservedBits(31, 1); 296 297 Registers.TestErrorConditions.Define(this) 298 .WithValueField(0, 5, writeCallback: (_, val) => 299 { 300 // val = bit number of ErrorCode register to be set 301 switch(val) 302 { 303 case 0: 304 reseedCommandsError.Value = true; 305 break; 306 case 1: 307 generateCommandsError.Value = true; 308 break; 309 case 2: 310 outputFifoError.Value = true; 311 break; 312 case 20: 313 ednAckStageIllegalStateError.Value = true; 314 break; 315 case 21: 316 ednMainStageIllegalStateError.Value = true; 317 break; 318 case 22: 319 hardenedCounterError.Value = true; 320 break; 321 case 28: 322 fifoWriteError.Value = true; 323 break; 324 case 29: 325 fifoReadError.Value = true; 326 break; 327 case 30: 328 fifoStateError.Value = true; 329 break; 330 default: 331 break; 332 } 333 334 switch (val) 335 { 336 case 0: 337 case 1: 338 case 2: 339 case 20: 340 case 21: 341 case 22: 342 fatalErrorInterruptState.Value = true; 343 UpdateInterrupts(); 344 break; 345 default: 346 break; 347 } 348 }, name: "ERR_CODE_TEST") 349 .WithReservedBits(5, 27); 350 351 Registers.MainStateMachineStateDebug.Define(this, (uint)StateMachine.Idle) 352 .WithValueField(0, 9, FieldMode.Read, name: "MAIN_SM_STATE") 353 .WithReservedBits(9, 23); 354 } 355 UpdateInterrupts()356 private void UpdateInterrupts() 357 { 358 CommandRequestDone.Set(commandRequestDoneInterruptState.Value && commandRequestDoneInterruptEnable.Value); 359 FatalError.Set(fatalErrorInterruptState.Value && fatalErrorInterruptEnable.Value); 360 } 361 SendCsrngCommand(uint command)362 private void SendCsrngCommand(uint command) 363 { 364 csrng.EdnSoftwareCommandRequestWrite(command); 365 commandRequestDoneInterruptState.Value = true; 366 UpdateInterrupts(); 367 } 368 369 public GPIO CommandRequestDone { get; } 370 public GPIO FatalError { get; } 371 public GPIO RecoverableAlert { get; } 372 public GPIO FatalAlert { get; } 373 374 private IFlagRegisterField commandRequestDoneInterruptState; 375 private IFlagRegisterField fatalErrorInterruptState; 376 private IFlagRegisterField commandRequestDoneInterruptEnable; 377 private IFlagRegisterField fatalErrorInterruptEnable; 378 private IFlagRegisterField allControlsRegisterWriteEnable; 379 private IEnumRegisterField<MultiBitBool4> ednEnable; 380 private IEnumRegisterField<MultiBitBool4> bootRequestMode; 381 private IEnumRegisterField<MultiBitBool4> autoRequestMode; 382 private IEnumRegisterField<MultiBitBool4> commandFifoReset; 383 private IValueRegisterField requestsBetweenReseeds; 384 private IFlagRegisterField ednEnableFieldAlert; 385 private IFlagRegisterField bootRequestModeFieldAlert; 386 private IFlagRegisterField autoRequestModeFieldAlert; 387 private IFlagRegisterField commandFifoResetFieldAlert; 388 private IValueRegisterField bootInstantiateCommand; 389 private IValueRegisterField bootGenerateCommand; 390 private IFlagRegisterField reseedCommandsError; 391 private IFlagRegisterField generateCommandsError; 392 private IFlagRegisterField outputFifoError; 393 private IFlagRegisterField ednAckStageIllegalStateError; 394 private IFlagRegisterField ednMainStageIllegalStateError; 395 private IFlagRegisterField hardenedCounterError; 396 private IFlagRegisterField fifoWriteError; 397 private IFlagRegisterField fifoReadError; 398 private IFlagRegisterField fifoStateError; 399 400 private readonly Queue<uint> reseedCommands; 401 private readonly Queue<uint> generateCommands; 402 private readonly OpenTitan_CSRNG csrng; 403 404 private bool autoRequestModeOn; 405 private uint maxNumberOfRequestsBetweenReseeds; 406 407 private const int ReseedCommandFifoCapacity = 13; 408 private const int GenerateCommandFifoCapacity = 13; 409 410 // https://github.com/lowRISC/opentitan/blob/master/hw/ip/edn/rtl/edn_pkg.sv 411 private enum StateMachine 412 { 413 Idle = 0b110000101, // idle 414 BootLoadIns = 0b110110111, // boot: load the instantiate command 415 BootLoadGen = 0b000000011, // boot: load the generate command 416 BootInsAckWait = 0b011010010, // boot: wait for instantiate command ack 417 BootCaptGenCnt = 0b010111010, // boot: capture the gen fifo count 418 BootSendGenCmd = 0b011100100, // boot: send the generate command 419 BootGenAckWait = 0b101101100, // boot: wait for generate command ack 420 BootPulse = 0b100001010, // boot: signal a done pulse 421 BootDone = 0b011011111, // boot: stay in done state until reset 422 AutoLoadIns = 0b001110000, // auto: load the instantiate command 423 AutoFirstAckWait = 0b001001101, // auto: wait for first instantiate command ack 424 AutoAckWait = 0b101100011, // auto: wait for instantiate command ack 425 AutoDispatch = 0b110101110, // auto: determine next command to be sent 426 AutoCaptGenCnt = 0b000110101, // auto: capture the gen fifo count 427 AutoSendGenCmd = 0b111111000, // auto: send the generate command 428 AutoCaptReseedCnt = 0b000100110, // auto: capture the reseed fifo count 429 AutoSendReseedCmd = 0b101010110, // auto: send the reseed command 430 SWPortMode = 0b100111001, // swport: no hw request mode 431 Error = 0b010010001 // illegal state reached and hang 432 } 433 434 public enum Registers 435 { 436 InterruptState = 0x0, 437 InterruptEnable = 0x4, 438 InterruptTest = 0x8, 439 AlertTest = 0xc, 440 RegisterWriteEnableForAllControls = 0x10, 441 Control = 0x14, 442 BootInstantiateCommand = 0x18, 443 BootGenerateCommand = 0x1c, 444 CsrngSoftwareCommandRequest = 0x20, 445 CommandStatus = 0x24, 446 CsrngReseedCommand = 0x28, 447 CsrngGenerateCommand = 0x2c, 448 MaximumNumberOfRequestsBetweenReseeds = 0x30, 449 RecoverableAlertStatus = 0x34, 450 ErrorCode = 0x38, 451 TestErrorConditions = 0x3c, 452 MainStateMachineStateDebug = 0x40, 453 } 454 } 455 } 456