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 
8 using System;
9 using Antmicro.Renode.Core;
10 using Antmicro.Renode.Core.Structure.Registers;
11 using Antmicro.Renode.Logging;
12 using Antmicro.Renode.Peripherals.Bus;
13 using Antmicro.Renode.Utilities.Crypto;
14 
15 namespace Antmicro.Renode.Peripherals.Miscellaneous
16 {
17     public sealed class NRF52840_ECB : BasicDoubleWordPeripheral, IKnownSize, INRFEventProvider
18     {
NRF52840_ECB(IMachine machine)19         public NRF52840_ECB(IMachine machine) : base(machine)
20         {
21             IRQ = new GPIO();
22             DefineRegisters();
23         }
24 
Reset()25         public override void Reset()
26         {
27             base.Reset();
28             UpdateInterrupts();
29         }
30 
31         public long Size => 0x1000;
32 
33         public GPIO IRQ { get; }
34 
35         public event Action<uint> EventTriggered;
36 
DefineRegisters()37         private void DefineRegisters()
38         {
39             Registers.Start.Define(this)
40                 .WithFlag(0, FieldMode.Write, name: "TASKS_START",
41                     writeCallback: (_, __) =>
42                     {
43                         RunEncryption();
44                         eventEnd.Value = true;
45                         EventTriggered?.Invoke((uint)Registers.EventEnd);
46                         UpdateInterrupts();
47                     })
48                 .WithReservedBits(1, 31)
49             ;
50 
51             Registers.EventEnd.Define(this, name: "EVENTS_ENDECB")
52                 .WithFlag(0, out eventEnd, name: "ENDECB")
53                 .WithReservedBits(1, 31)
54                 .WithWriteCallback((_, __) => UpdateInterrupts())
55             ;
56 
57             Registers.InterruptEnableSet.Define(this, name: "INTENSET")
58                 .WithFlag(0, out endInterruptEnabled, FieldMode.Set | FieldMode.Read, name: "ENDECB")
59                 .WithReservedBits(1, 31)
60                 .WithWriteCallback((_, __) => UpdateInterrupts())
61             ;
62 
63             Registers.InterruptEnableClear.Define(this, name: "INTENCLR")
64                 .WithFlag(0,
65                     writeCallback: (_, value) => endInterruptEnabled.Value &= !value,
66                     valueProviderCallback: _ => endInterruptEnabled.Value, name: "ENDECB")
67                 .WithReservedBits(1, 31)
68                 .WithWriteCallback((_, __) => UpdateInterrupts())
69             ;
70 
71             Registers.DataPtr.Define(this)
72                 .WithValueField(0, 32, out dataPointer, name: "ECBDATAPTR")
73             ;
74         }
75 
RunEncryption()76         private void RunEncryption()
77         {
78             this.Log(LogLevel.Debug, "Running the encryption process; key at 0x{0:X}, cleartext at 0x{1:X}", dataPointer.Value, dataPointer.Value + KeySize);
79 
80             var key = sysbus.ReadBytes(dataPointer.Value, KeySize);
81             var clearText = sysbus.ReadBytes(dataPointer.Value + KeySize, ClearTextSize);
82             var clearTextBlock = Block.UsingBytes(clearText);
83 
84             using(var aes = AesProvider.GetEcbProvider(key))
85             {
86                 aes.EncryptBlockInSitu(clearTextBlock);
87             }
88 
89             sysbus.WriteBytes(clearText, dataPointer.Value + KeySize + ClearTextSize);
90         }
91 
UpdateInterrupts()92         private void UpdateInterrupts()
93         {
94             var flag = false;
95 
96             flag |= endInterruptEnabled.Value & eventEnd.Value;
97 
98             IRQ.Set(flag);
99         }
100 
101         private IFlagRegisterField eventEnd;
102         private IFlagRegisterField endInterruptEnabled;
103         private IValueRegisterField dataPointer;
104 
105         private const int KeySize = 16;
106         private const int ClearTextSize = 16;
107 
108         private enum Registers
109         {
110             Start = 0x0,
111             Stop = 0x4,
112             EventEnd = 0x100,
113             EventError = 0x104,
114             InterruptEnableSet = 0x304,
115             InterruptEnableClear = 0x308,
116             DataPtr = 0x504,
117         }
118     }
119 }
120