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.Linq; 8 using Antmicro.Renode.Core; 9 using Antmicro.Renode.Core.Structure.Registers; 10 using Antmicro.Renode.Logging; 11 using Antmicro.Renode.Peripherals.Bus; 12 using Antmicro.Renode.Utilities; 13 14 namespace Antmicro.Renode.Peripherals.Miscellaneous 15 { 16 [AllowedTranslations(AllowedTranslation.ByteToDoubleWord | AllowedTranslation.WordToDoubleWord)] 17 public class AmbiqApollo4_Security : BasicDoubleWordPeripheral, IKnownSize 18 { AmbiqApollo4_Security(IMachine machine)19 public AmbiqApollo4_Security(IMachine machine) : base(machine) 20 { 21 systemBus = machine.GetSystemBus(this); 22 DefineRegisters(); 23 } 24 Reset()25 public override void Reset() 26 { 27 crcErrorOccurred = false; 28 } 29 30 public bool LogDataRead { get; set; } 31 public long Size => 0x90; 32 CalculateCrc32()33 private void CalculateCrc32() 34 { 35 var byteLength = (int)wordLength.Value * 4; 36 this.Log(LogLevel.Debug, "Calculating CRC32 for the <0x{0:X8},0x{1:X8}> address range; seed: 0x{2:X8}", address.Value, (long)address.Value + byteLength, crcSeedOrResult.Value); 37 38 if(crcSeedOrResult.Value != ValidCrcSeed) 39 { 40 this.Log(LogLevel.Warning, "The seed is invalid for CRC32 calculation: 0x{0:X8} (should be 0x{1:X8})", crcSeedOrResult.Value, ValidCrcSeed); 41 crcErrorOccurred = true; 42 return; 43 } 44 45 byte[] data; 46 try 47 { 48 data = systemBus.ReadBytes(address.Value, byteLength, onlyMemory: true); 49 if(LogDataRead) 50 { 51 this.Log(LogLevel.Noisy, "Data for CRC32 calculation:\n{0}", data.Select(b => "0x" + b.ToString("X2")).Stringify(limitPerLine: 8)); 52 } 53 54 var result = new CRCEngine(0x04C11DB7, 32, init: (uint)crcSeedOrResult.Value).Calculate(data); 55 56 // The most common CRC-32 algorithm (CRC-32/BZIP2) requires inverting the output (xoring with 0xffffffff). 57 // See the 'xorout' parameter: https://reveng.sourceforge.io/crc-catalogue/all.htm#crc.cat.crc-32-bzip2 58 result = ~result; 59 60 this.Log(LogLevel.Debug, "CRC32 calculation result: 0x{0:X8}", result); 61 crcSeedOrResult.Value = result; 62 } 63 catch(Exceptions.RecoverableException exception) 64 { 65 this.Log(LogLevel.Debug, "Error when reading memory to calculate CRC32: {0}", exception.Message); 66 crcErrorOccurred = true; 67 } 68 69 calculationEnabled.Value = false; 70 } 71 DefineRegisters()72 private void DefineRegisters() 73 { 74 Registers.Control.Define(this) 75 .WithFlag(0, out calculationEnabled, name: "ENABLE") 76 .WithReservedBits(1, 3) 77 .WithEnumField(4, 4, out functionSelect, name: "FUNCTION", changeCallback: (_, newValue) => 78 { 79 if(newValue != Functions.CRC32) 80 { 81 this.Log(LogLevel.Warning, "Unsupported function selected: {0}", newValue); 82 } 83 }) 84 .WithReservedBits(8, 23) 85 .WithFlag(31, FieldMode.Read, name: "CRCERROR", valueProviderCallback: _ => crcErrorOccurred) 86 .WithChangeCallback((_, __) => 87 { 88 if(calculationEnabled.Value && functionSelect.Value == Functions.CRC32) 89 { 90 CalculateCrc32(); 91 } 92 }) 93 // Every write clears the error status. 94 .WithWriteCallback((_, __) => crcErrorOccurred = false) 95 ; 96 97 Registers.SourceAddress.Define(this) 98 .WithValueField(0, 32, out address, name: "ADDR") 99 ; 100 101 Registers.Length.Define(this) 102 .WithReservedBits(0, 2) 103 .WithValueField(2, 22, out wordLength, name: "LEN") 104 .WithReservedBits(24, 8) 105 ; 106 107 Registers.CRCSeedOrResult.Define(this) 108 .WithValueField(0, 32, out crcSeedOrResult, name: "CRC") 109 ; 110 111 Registers.LockControl.Define(this) 112 .WithTag("SELECT", 0, 8) 113 .WithReservedBits(8, 24) 114 ; 115 116 Registers.LockStatus.Define(this) 117 .WithTag("STATUS", 0, 32) 118 ; 119 120 Registers.Key0.Define(this) 121 .WithTag("KEY0", 0, 32) 122 ; 123 124 Registers.Key1.Define(this) 125 .WithTag("KEY1", 0, 32) 126 ; 127 128 Registers.Key2.Define(this) 129 .WithTag("KEY2", 0, 32) 130 ; 131 132 Registers.Key3.Define(this) 133 .WithTag("KEY3", 0, 32) 134 ; 135 } 136 137 private bool crcErrorOccurred; 138 139 private IValueRegisterField address; 140 private IValueRegisterField crcSeedOrResult; 141 private IFlagRegisterField calculationEnabled; 142 private IEnumRegisterField<Functions> functionSelect; 143 private IValueRegisterField wordLength; 144 145 private readonly IBusController systemBus; 146 147 private const uint ValidCrcSeed = 0xFFFFFFFF; 148 149 private enum Functions 150 { 151 CRC32 = 0x0, 152 DMAPseudoRandomNumberStreamFromCRC = 0x1, 153 GenerateDMAStreamFromAddress = 0x2, 154 } 155 156 private enum Registers : long 157 { 158 Control = 0x0, 159 SourceAddress = 0x10, 160 Length = 0x20, 161 CRCSeedOrResult = 0x30, 162 LockControl = 0x78, 163 LockStatus = 0x7C, 164 Key0 = 0x80, 165 Key1 = 0x84, 166 Key2 = 0x88, 167 Key3 = 0x8C, 168 } 169 } 170 } 171