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.Collections.Generic;
9 using Antmicro.Renode.Core;
10 using Antmicro.Renode.Peripherals.CPU;
11 using Antmicro.Renode.Peripherals.Memory;
12 
13 namespace Antmicro.Renode.Peripherals.Miscellaneous
14 {
15     public class OpenTitan_ScrambledMemory
16     {
OpenTitan_ScrambledMemory(IMachine machine, long size)17         public OpenTitan_ScrambledMemory(IMachine machine, long size)
18         {
19             if(size % PageSize != 0)
20             {
21                 size += (PageSize - (size % PageSize));
22             }
23 
24             this.machine = machine;
25             underlyingMemory = new MappedMemory(machine, size);
26             writtenOffsets = new HashSet<long>();
27         }
28 
ReadDoubleWord(long offset)29         public uint ReadDoubleWord(long offset)
30         {
31             if(!CheckAccess(offset, 4))
32             {
33                 return 0;
34             }
35             return underlyingMemory.ReadDoubleWord(offset);
36         }
37 
WriteDoubleWord(long offset, uint value)38         public void WriteDoubleWord(long offset, uint value)
39         {
40             MarkWritten(offset, 4);
41             underlyingMemory.WriteDoubleWord(offset, value);
42         }
43 
WriteBytes(long offset, byte[] value)44         public void WriteBytes(long offset, byte[] value)
45         {
46             MarkWritten(offset, value.Length);
47             underlyingMemory.WriteBytes(offset, value);
48         }
49 
ReadBytes(long offset, int count, byte[] destination, int startIndex)50         public void ReadBytes(long offset, int count, byte[] destination, int startIndex)
51         {
52             if(!CheckAccess(offset , count))
53             {
54                 return;
55             }
56             underlyingMemory.ReadBytes(offset, count, destination, startIndex);
57         }
58 
ZeroAll()59         public void ZeroAll()
60         {
61             wasCleared = true;
62             writtenOffsets.Clear();
63             underlyingMemory.ZeroAll();
64         }
65 
66         public long Size => underlyingMemory.Size;
67 
68         public IEnumerable<IMappedSegment> MappedSegments => underlyingMemory.MappedSegments;
69 
MarkWritten(long offset, int size = 1)70         private void MarkWritten(long offset, int size = 1)
71         {
72             for(var i = 0; i < size; i++)
73             {
74                 writtenOffsets.Add(offset + i);
75             }
76         }
77 
CheckAccess(long offset, int size = 1)78         private bool CheckAccess(long offset, int size = 1)
79         {
80             if(wasCleared && !writtenOffsets.Contains(offset))
81             {
82                 if(machine.SystemBus.TryGetCurrentCPU(out var cpu) && cpu is ICPUWithNMI ibexCPU)
83                 {
84                     // https://github.com/lowRISC/opentitan/blob/f243e6802143374741739d2c164c4f2f61697669/sw/device/lib/runtime/ibex.h#LL48C5-L48C5
85                     ibexCPU.OnNMI(0, true, 0xffffffe0); // Load integrity error internal interrupt
86                 }
87                 return false;
88             }
89             return true;
90         }
91 
92         private bool wasCleared;
93 
94         private readonly IMachine machine;
95         private readonly MappedMemory underlyingMemory;
96         private readonly HashSet<long> writtenOffsets;
97 
98         private const long PageSize = 0x1000;
99     }
100 }
101