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