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 Antmicro.Renode.Core;
8 using Antmicro.Renode.Core.Structure.Registers;
9 using Antmicro.Renode.Logging;
10 using Antmicro.Renode.Peripherals.Bus;
11 using System;
12 using System.Collections.Generic;
13 
14 namespace Antmicro.Renode.Peripherals.Miscellaneous.Crypto
15 {
16     public class AthenaX5200 : IDoubleWordPeripheral, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IKnownSize
17     {
AthenaX5200(IMachine machine)18         public AthenaX5200(IMachine machine)
19         {
20             memoryManager = new InternalMemoryManager();
21             RegistersCollection = new DoubleWordRegisterCollection(this);
22             rsaServiceProvider = new RSAServiceProvider(memoryManager);
23             aesServiceProvider = new AESServiceProvider(memoryManager, machine.GetSystemBus(this));
24             msgAuthServiceProvider = new MessageAuthenticationServiceProvider(memoryManager, machine.GetSystemBus(this));
25             dsaServiceProvider = new DSAServiceProvider(memoryManager, machine.GetSystemBus(this));
26 
27             Registers.CSR.Define(this)
28                 .WithFlag(0,
29                     writeCallback: (_, val) =>
30                     {
31                         if(val)
32                         {
33                             Reset();
34                         }
35                         coreReset = val;
36                     },
37                     valueProviderCallback: _ => coreReset, name: "RESET")
38                 .WithFlag(1, FieldMode.Write, writeCallback: (_, val) =>
39                     {
40                         if(val)
41                         {
42                             isCompleted = false;
43                         }
44                     }, name: "CLEAR_COMPLETE")
45                 .WithFlag(2, FieldMode.Read, valueProviderCallback: _ => isCompleted, name: "COMPLETE")
46                 .WithTag("BUSY", 3, 1)
47                 .WithFlag(4, out coreExecuteCommand, name: "EXECUTE_COMMAND")
48                 .WithReservedBits(5, 3)
49                 .WithEnumField(8, 8, out operation)
50                 .WithReservedBits(16, 3)
51                 .WithTag("PKX_OFFSET", 19, 1)
52                 .WithReservedBits(20, 12)
53                 .WithWriteCallback((_, __) =>
54                 {
55                     if(!coreExecuteCommand.Value)
56                     {
57                         return;
58                     }
59                     if(!commands.TryGetValue(operation.Value, out var command))
60                     {
61                         this.Log(LogLevel.Error, "Unknown command: [{0}].", operation.Value);
62                         return;
63                     }
64                     this.Log(LogLevel.Noisy, "Executing command: [{0}]", operation.Value);
65                     command();
66                     isCompleted = true;
67                     coreExecuteCommand.Value = false;
68                 });
69 
70             commands = new Dictionary<JumpTable, Action>
71             {
72                 { JumpTable.PrecomputeValueRSA, EmptyHandler },
73                 { JumpTable.InstantiateDRBG, InstantiateDRBG },
74                 { JumpTable.GenerateBlocksFromDRBG, GenerateBlocksWithDRBG },
75                 { JumpTable.UninstantiateDRBG, UninstantiateDRBG },
76                 { JumpTable.ModularExponentationRSA, rsaServiceProvider.ModularExponentation },
77                 { JumpTable.ModularReductionRSA, rsaServiceProvider.ModularReduction },
78                 { JumpTable.DecryptCipherRSA, rsaServiceProvider.DecryptData },
79                 { JumpTable.RunAES, aesServiceProvider.PerformAESOperation },
80                 { JumpTable.RunAES_DMA, aesServiceProvider.PerformAESOperationDMA },
81                 { JumpTable.RunGCM, msgAuthServiceProvider.PerformGCMMessageAuthentication },
82                 { JumpTable.RunGCMNew, msgAuthServiceProvider.PerformGCMMessageAuthentication },
83                 { JumpTable.RunSHA, msgAuthServiceProvider.PerformSHA },
84                 { JumpTable.RunSHADMA, msgAuthServiceProvider.PerformSHADMA },
85                 { JumpTable.RunHMACSHA, msgAuthServiceProvider.PerformHMACSHA },
86                 { JumpTable.RunDSA_Sign, dsaServiceProvider.SignDMA },
87             };
88 
89             Reset();
90         }
91 
ReadDoubleWord(long offset)92         public uint ReadDoubleWord(long offset)
93         {
94             return memoryManager.TryReadDoubleWord(offset, out uint result)
95                 ? result
96                 : RegistersCollection.Read(offset);
97         }
98 
WriteDoubleWord(long offset, uint value)99         public void WriteDoubleWord(long offset, uint value)
100         {
101             if(!memoryManager.TryWriteDoubleWord(offset, value))
102             {
103                 RegistersCollection.Write(offset, value);
104             }
105         }
106 
Reset()107         public void Reset()
108         {
109             memoryManager.ResetMemories();
110             RegistersCollection.Reset();
111             msgAuthServiceProvider.Reset();
112             rsaServiceProvider.Reset();
113             aesServiceProvider.Reset();
114             randomGenerator?.Reset();
115             isCompleted = false;
116             coreReset = false;
117         }
118 
119         public long Size => 0x1000000;
120         public DoubleWordRegisterCollection RegistersCollection { get; }
121 
EmptyHandler()122         private void EmptyHandler()
123         {
124             // There are commands in which no processing is needed,
125             // but we want to report in the Status Register that it has completed.
126         }
127 
InstantiateDRBG()128         private void InstantiateDRBG()
129         {
130             if(randomGenerator != null)
131             {
132                 this.Log(LogLevel.Error, "RNG subsystem already instantiated. Aborting!");
133                 return;
134             }
135             randomGenerator = new PseudorandomBitGenerator(memoryManager);
136         }
137 
GenerateBlocksWithDRBG()138         private void GenerateBlocksWithDRBG()
139         {
140             if(randomGenerator == null)
141             {
142                 this.Log(LogLevel.Error, "RNG subsystem is not instantiated. Aborting!");
143                 return;
144             }
145             randomGenerator.Generate();
146         }
147 
UninstantiateDRBG()148         private void UninstantiateDRBG()
149         {
150             if(randomGenerator == null)
151             {
152                 this.Log(LogLevel.Error, "RNG subsystem is not instantiated. Aborting!");
153                 return;
154             }
155             randomGenerator = null;
156         }
157 
158         private bool coreReset;
159         private bool isCompleted;
160         private PseudorandomBitGenerator randomGenerator;
161 
162         private readonly InternalMemoryManager memoryManager;
163         private readonly Dictionary<JumpTable, Action> commands;
164         private readonly IEnumRegisterField<JumpTable> operation;
165         private readonly IFlagRegisterField coreExecuteCommand;
166         private readonly RSAServiceProvider rsaServiceProvider;
167         private readonly AESServiceProvider aesServiceProvider;
168         private readonly MessageAuthenticationServiceProvider msgAuthServiceProvider;
169         private readonly DSAServiceProvider dsaServiceProvider;
170 
171         private enum JumpTable
172         {
173             // gaps in addressing - only a few commands are implemented
174             PrecomputeValueRSA = 0x0,
175             ModularExponentationRSA = 0x2,
176             ModularReductionRSA = 0x12,
177             RunSHA = 0x1E,
178             RunAES = 0x20,
179             RunGCM = 0x24,
180             InstantiateDRBG = 0x2C,
181             GenerateBlocksFromDRBG = 0x30,
182             RunAES_DMA = 0x38,
183             UninstantiateDRBG = 0x32,
184             RunHMACSHA = 0x36,
185             RunSHADMA = 0x3C,
186             RunDSA_Sign = 0x40,
187             DecryptCipherRSA = 0x4E,
188             RunGCMNew = 0x5A
189         }
190 
191         private enum Registers : uint
192         {
193             CSR = 0x7F80
194         }
195     }
196 }
197