1 //
2 // Copyright (c) 2010-2022 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.Core.Structure;
11 using Antmicro.Renode.Core.Structure.Registers;
12 using Antmicro.Renode.Logging;
13 using Antmicro.Renode.Peripherals.Bus;
14 
15 namespace Antmicro.Renode.Peripherals.Miscellaneous
16 {
17     public class WindowIOMMU : SimpleContainer<IBusPeripheral>, IDoubleWordPeripheral, IKnownSize
18     {
WindowIOMMU(IMachine machine)19         public WindowIOMMU(IMachine machine) : base(machine)
20         {
21             IRQ = new GPIO();
22             busController = new WindowMMUBusController(this, machine.GetSystemBus(this));
23             busController.OnFault += OnMMUFault;
24 
25             registers = DefineRegisters();
26         }
27 
Register(IBusPeripheral peripheral, NumberRegistrationPoint<int> registrationPoint)28         public override void Register(IBusPeripheral peripheral, NumberRegistrationPoint<int> registrationPoint)
29         {
30             base.Register(peripheral, registrationPoint);
31             machine.RegisterBusController(peripheral, busController);
32         }
33 
Reset()34         public override void Reset()
35         {
36             registers.Reset();
37         }
38 
ReadDoubleWord(long offset)39         public uint ReadDoubleWord(long offset)
40         {
41             return registers.Read(offset);
42         }
43 
WriteDoubleWord(long offset, uint value)44         public void WriteDoubleWord(long offset, uint value)
45         {
46             // Writing to a Privileges register asserts are MMU windows valid.
47             registers.Write(offset, value);
48         }
49 
50         public GPIO IRQ { get; }
51 
52         public long Size => 0x1000;
53 
OnMMUFault(ulong address, BusAccessPrivileges accessType, int? mmuWindow)54         private void OnMMUFault(ulong address, BusAccessPrivileges accessType, int? mmuWindow)
55         {
56             this.Log(LogLevel.Debug, "IOMMU fault occured. Setting the IRQ");
57             IRQ.Set();
58         }
59 
DefineRegisters()60         private DoubleWordRegisterCollection DefineRegisters()
61         {
62             var registersMap = new Dictionary<long, DoubleWordRegister>();
63 
64             for(int i = 0; i < MaxWindowsCount; i++)
65             {
66                 var index = i;
67                 busController.Windows.Add(new WindowMMUBusController.MMUWindow(this));
68                 registersMap.Add((long)Registers.RangeStartBase + index * 4, new DoubleWordRegister(this)
69                     .WithValueField(0, 32, name: $"RANGE_START[{index}]", writeCallback: (_, value) =>
70                     {
71                         busController.Windows[index].Start = (ulong)value;
72                     }, valueProviderCallback: _ =>
73                     {
74                         return (uint)busController.Windows[index].Start;
75                     }));
76                 registersMap.Add((long)Registers.RangeEndBase + index * 4, new DoubleWordRegister(this)
77                     .WithValueField(0, 32, name: $"RANGE_END[{index}]", writeCallback: (_, value) =>
78                     {
79                         busController.Windows[index].End = (ulong)value;
80                     }, valueProviderCallback: _ =>
81                     {
82                         return (uint)busController.Windows[index].End;
83                     }));
84                 registersMap.Add((long)Registers.OffsetBase + index * 4, new DoubleWordRegister(this)
85                     .WithValueField(0, 32, name: $"OFFSET[{index}]", writeCallback: (_, value) =>
86                     {
87                         busController.Windows[index].Offset = (int)value;
88                     }, valueProviderCallback: _ =>
89                     {
90                         return (uint)busController.Windows[index].Offset;
91                     }));
92                 registersMap.Add((long)Registers.PrivilegesBase + index * 4, new DoubleWordRegister(this)
93                     .WithValueField(0, 32, name: $"PRIVILEGES[{index}]", writeCallback: (_, value) =>
94                     {
95                         busController.Windows[index].Privileges = (BusAccessPrivileges)value;
96                         busController.AssertWindowsAreValid();
97                     }, valueProviderCallback: _ =>
98                     {
99                         return (uint)busController.Windows[index].Privileges;
100                     }));
101             }
102             return new DoubleWordRegisterCollection(this, registersMap);
103         }
104 
105         private readonly WindowMMUBusController busController;
106         private readonly DoubleWordRegisterCollection registers;
107 
108         private enum Registers
109         {
110             RangeStartBase = 0x0,
111             RangeEndBase = 0x400,
112             OffsetBase = 0x800,
113             PrivilegesBase = 0xC00,
114         }
115 
116         private const int MaxWindowsCount = ((int)Registers.RangeEndBase) / 8;
117     }
118 }
119