1 //
2 // Copyright (c) 2010-2025 Antmicro
3 // Copyright (c) 2022-2025 Silicon Labs
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 
9 using System;
10 using System.Collections.Generic;
11 using Antmicro.Renode.Utilities;
12 using Antmicro.Renode.Exceptions;
13 using Antmicro.Renode.Core.Structure.Registers;
14 using Antmicro.Renode.Peripherals.Bus;
15 using Antmicro.Renode.Peripherals.Memory;
16 using Antmicro.Renode.Peripherals.Miscellaneous;
17 using Antmicro.Renode.Peripherals.Miscellaneous.SiLabs;
18 using Antmicro.Renode.Logging;
19 
20 namespace Antmicro.Renode.Peripherals.Miscellaneous.SiLabs
21 {
22     [AllowedTranslations(AllowedTranslation.ByteToDoubleWord | AllowedTranslation.WordToDoubleWord)]
23     public class EFR32xG2_LockbitsData : IDoubleWordPeripheral, IKnownSize
24     {
EFR32xG2_LockbitsData(uint size, String cbkeDataCertificate = null, String cbkeDataCaPublicKey = null, String cbkeDataPrivateKey = null, String cbkeDataFlags = null, String securityConfig = null, String installationCodeFlags = null, String installationCodeValue = null, String installationCodeCrc = null, String secureBootloaderKey = null, String cbke283k1DataCertificate = null, String cbke283k1DataCaPublicKey = null, String cbke283k1DataPrivateKey = null, String ccbke283k1DataFlags = null, String bootloadAesKey = null, String signedBootloaderKeyX = null, String signedBootloaderKeyY = null, String threadJoinKey = null, byte threadJoinKeyLength = 0, String nvm3CryptoKey = null, String zWavePrivateKey = null, String zWavePublicKey = null, String zWaveQrCode = null, String zWaveInitialized = null, String zWaveQrCodeExtended = null)25         public EFR32xG2_LockbitsData(uint size,
26                             String cbkeDataCertificate = null,
27                             String cbkeDataCaPublicKey = null,
28                             String cbkeDataPrivateKey = null,
29                             String cbkeDataFlags = null,
30                             String securityConfig = null,
31                             String installationCodeFlags = null,
32                             String installationCodeValue = null,
33                             String installationCodeCrc = null,
34                             String secureBootloaderKey = null,
35                             String cbke283k1DataCertificate = null,
36                             String cbke283k1DataCaPublicKey = null,
37                             String cbke283k1DataPrivateKey = null,
38                             String ccbke283k1DataFlags = null,
39                             String bootloadAesKey = null,
40                             String signedBootloaderKeyX = null,
41                             String signedBootloaderKeyY = null,
42                             String threadJoinKey = null,
43                             byte threadJoinKeyLength = 0,
44                             String nvm3CryptoKey = null,
45                             String zWavePrivateKey = null,
46                             String zWavePublicKey = null,
47                             String zWaveQrCode = null,
48                             String zWaveInitialized = null,
49                             String zWaveQrCodeExtended = null)
50         {
51             if ((size & 0x3) > 0)
52             {
53                 throw new ConstructionException("Size must be a multiple of 4");
54             }
55             this.size = size;
56 
57             memory = new byte[size];
58             for(uint i = 0; i < size; i++)
59             {
60                 memory[i] = 0xFF;
61             }
62 
63             if (cbkeDataCertificate != null)
64             {
65                 ParseHexStringArgument("cbke data certificate", cbkeDataCertificate, 48, (uint)DataOffset.CbkeData);
66             }
67             if (cbkeDataCaPublicKey != null)
68             {
69                 ParseHexStringArgument("cbke data public key", cbkeDataCaPublicKey, 22, (uint)DataOffset.CbkeData + 48);
70             }
71             if (cbkeDataPrivateKey != null)
72             {
73                 ParseHexStringArgument("cbke data private key", cbkeDataPrivateKey, 21, (uint)DataOffset.CbkeData + 48 + 22);
74             }
75             if (cbkeDataFlags != null)
76             {
77                 ParseHexStringArgument("cbke data flags", cbkeDataFlags, 1, (uint)DataOffset.CbkeData + 48 + 22 + 21);
78             }
79             if (securityConfig != null)
80             {
81                 ParseHexStringArgument("security config", securityConfig, 2, (uint)DataOffset.SecurityConfig);
82             }
83             if (installationCodeFlags != null)
84             {
85                 ParseHexStringArgument("installation code flags", installationCodeFlags, 2, (uint)DataOffset.InstallationCode);
86             }
87             if (installationCodeValue != null)
88             {
89                 ParseHexStringArgument("installation code value", installationCodeValue, 16, (uint)DataOffset.InstallationCode + 2);
90             }
91             if (installationCodeCrc != null)
92             {
93                 ParseHexStringArgument("installation code CRC", installationCodeCrc, 2, (uint)DataOffset.InstallationCode + 2 + 16);
94             }
95             if (secureBootloaderKey != null)
96             {
97                 ParseHexStringArgument("secure bootloader key", secureBootloaderKey, 16, (uint)DataOffset.SecureBootloaderKey);
98             }
99             if (cbke283k1DataCertificate != null)
100             {
101                 ParseHexStringArgument("cbke 283k certificate", cbke283k1DataCertificate, 74, (uint)DataOffset.Cbke283k1Data);
102             }
103             if (cbke283k1DataCaPublicKey != null)
104             {
105                 ParseHexStringArgument("cbke 283k public key", cbke283k1DataCaPublicKey, 37, (uint)DataOffset.Cbke283k1Data + 74);
106             }
107             if (cbke283k1DataPrivateKey != null)
108             {
109                 ParseHexStringArgument("cbke 283k private key", cbke283k1DataPrivateKey, 36, (uint)DataOffset.Cbke283k1Data + 74 + 37);
110             }
111             if (ccbke283k1DataFlags != null)
112             {
113                 ParseHexStringArgument("cbke 283k flags", ccbke283k1DataFlags, 1, (uint)DataOffset.Cbke283k1Data + 74 + 37 + 36);
114             }
115             if (bootloadAesKey != null)
116             {
117                 ParseHexStringArgument("bootloader AES key", bootloadAesKey, 16, (uint)DataOffset.BootloadAesKey);
118             }
119             if (signedBootloaderKeyX != null)
120             {
121                 ParseHexStringArgument("signed bootloader key X", signedBootloaderKeyX, 32, (uint)DataOffset.SignedBootloaderKeyX);
122             }
123             if (signedBootloaderKeyY != null)
124             {
125                 ParseHexStringArgument("signed bootloader key Y", signedBootloaderKeyY, 32, (uint)DataOffset.SignedBootloaderKeyY);
126             }
127             if (threadJoinKey != null)
128             {
129                 if (threadJoinKeyLength > 32)
130                 {
131                     throw new ConstructionException("threadJoinKeyLength > 32");
132                 }
133                 ParseHexStringArgument("thread join key", threadJoinKey, threadJoinKeyLength, (uint)DataOffset.ThreadJoinKey);
134             }
135             memory[(uint)DataOffset.ThreadJoinKey + 32] = threadJoinKeyLength;
136             if (nvm3CryptoKey != null)
137             {
138                 ParseHexStringArgument("NVM3 crypto key", nvm3CryptoKey, 16, (uint)DataOffset.Nvm3CryptoKey);
139             }
140             if (zWavePrivateKey != null)
141             {
142                 ParseHexStringArgument("Z-Wave private key", zWavePrivateKey, 32, (uint)DataOffset.ZWavePrivateKey);
143             }
144             if (zWavePublicKey != null)
145             {
146                 ParseHexStringArgument("Z-Wave public key", zWavePublicKey, 32, (uint)DataOffset.ZWavePublicKey);
147             }
148             if (zWaveQrCode != null)
149             {
150                 ParseHexStringArgument("Z-Wave QR code", zWaveQrCode, 90, (uint)DataOffset.ZWaveQrCode);
151             }
152             if (zWaveInitialized != null)
153             {
154                 ParseHexStringArgument("Z-Wave initialized", zWaveInitialized, 1, (uint)DataOffset.ZWaveInitialized);
155             }
156             if (zWaveQrCodeExtended != null)
157             {
158                 ParseHexStringArgument("Z-Wave QR code extended", zWaveQrCodeExtended, 90, (uint)DataOffset.ZWaveQrCodeExtended);
159             }
160         }
161 
Reset()162         public void Reset()
163         {
164         }
165 
ReadDoubleWord(long offset)166         public uint ReadDoubleWord(long offset)
167         {
168             if ((offset & 0x3) > 0)
169             {
170                 this.Log(LogLevel.Error, "ReadDoubleWord: Offset must be a multiple of 4");
171                 return 0;
172             }
173 
174             uint ret = (memory[offset]
175                         | ((uint)memory[offset + 1] << 8)
176                         | ((uint)memory[offset + 2] << 16)
177                         | ((uint)memory[offset + 3] << 24));
178             return ret;
179         }
180 
WriteDoubleWord(long offset, uint value)181         public void WriteDoubleWord(long offset, uint value)
182         {
183             if ((offset & 0x3) > 0)
184             {
185                 this.Log(LogLevel.Error, "WriteDoubleWord: Offset must be a multiple of 4");
186                 return;
187             }
188 
189             memory[offset] = (byte)(value & 0xFF);
190             memory[offset + 1] = (byte)((value >> 8) & 0xFF);
191             memory[offset + 2] = (byte)((value >> 16) & 0xFF);
192             memory[offset + 3] = (byte)((value >> 24) & 0xFF);
193         }
194 
ParseHexStringArgument(string fieldName, string value, uint expectedLength, uint destinationOffset)195         private void ParseHexStringArgument(string fieldName, string value, uint expectedLength, uint destinationOffset)
196         {
197             byte[] temp;
198             var lengthInBytes = value.Length / 2;
199 
200             if(lengthInBytes != expectedLength)
201             {
202                 throw new ConstructionException($"Expected `{fieldName}`'s size is {expectedLength} bytes, got {lengthInBytes}");
203             }
204             try
205             {
206                 temp = Misc.HexStringToByteArray(value);
207             }
208             catch
209             {
210                 throw new ConstructionException($"Could not parse `{fieldName}`: Expected hexstring, got: \"{value}\"");
211             }
212 
213             temp.CopyTo(memory, destinationOffset);
214         }
215 
216 
217         private uint size;
218         private byte[] memory;
219         public long Size => (long)size;
220 
221         private enum DataOffset
222         {
223             CbkeData             = 0x204,
224             SecurityConfig       = 0x260,
225             InstallationCode     = 0x270,
226             SecureBootloaderKey  = 0x286,
227             Cbke283k1Data        = 0x298,
228             BootloadAesKey       = 0x32C,
229             SignedBootloaderKeyX = 0x34C,
230             SignedBootloaderKeyY = 0x36C,
231             ThreadJoinKey        = 0x38C,
232             Nvm3CryptoKey        = 0x3B0,
233             ZWavePrivateKey      = 0x3C0,
234             ZWavePublicKey       = 0x3E0,
235             ZWaveQrCode          = 0x400,
236             ZWaveInitialized     = 0x45C,
237             ZWaveQrCodeExtended  = 0x460,
238         }
239     }
240 }
241