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; 9 using System.Collections.Generic; 10 using Antmicro.Renode.Logging; 11 using Antmicro.Renode.Peripherals.CPU; 12 13 namespace Antmicro.Renode.Peripherals.Bus 14 { 15 public class WindowMMUBusController : BusControllerProxy 16 { WindowMMUBusController(IEmulationElement emulationParent, IBusController parentController)17 public WindowMMUBusController(IEmulationElement emulationParent, IBusController parentController) : base(parentController) 18 { 19 this.emulationParent = emulationParent; 20 Windows = new List<MMUWindow>(); 21 } 22 AssertWindowsAreValid()23 public void AssertWindowsAreValid() 24 { 25 for(var i = 0; i < Windows.Count; i++) 26 { 27 Windows[i].AssertIsValid(); 28 for(var j = 0; j < Windows.Count; j++) 29 { 30 if(i != j && Windows[i].ContainsAddress(Windows[j].Start) && Windows[j].Length > 0) 31 { 32 emulationParent.Log(LogLevel.Error, "MMUWindows (with indicies {0} and {1}) overlap each other.", i, j); 33 } 34 } 35 } 36 } 37 38 public event Action<ulong, BusAccessPrivileges, int?> OnFault; 39 40 public List<MMUWindow> Windows { get; } 41 ValidateOperation(ref ulong address, BusAccessPrivileges accessType, IPeripheral context = null)42 protected override bool ValidateOperation(ref ulong address, BusAccessPrivileges accessType, IPeripheral context = null) 43 { 44 if(TryFindWindowIndex(address, out var index)) 45 { 46 var privileges = Windows[index].Privileges; 47 if((privileges & accessType) == accessType) 48 { 49 address = Windows[index].TranslateAddress(address); 50 return true; 51 } 52 MMUFaultHandler(address, accessType, index); 53 } 54 else 55 { 56 MMUFaultHandler(address, accessType, null); 57 } 58 return false; 59 } 60 TryFindWindowIndex(ulong address, out int index)61 private bool TryFindWindowIndex(ulong address, out int index) 62 { 63 for(index = 0; index < Windows.Count; index++) 64 { 65 if(Windows[index].ContainsAddress(address)) 66 { 67 if(Windows[index].Valid) 68 { 69 return true; 70 } 71 else 72 { 73 emulationParent.Log(LogLevel.Warning, "The window at index {0} match the address, but isn't validated sucesfully.", index); 74 } 75 } 76 } 77 index = -1; 78 return false; 79 } 80 MMUFaultHandler(ulong address, BusAccessPrivileges accessType, int? windowIndex)81 private void MMUFaultHandler(ulong address, BusAccessPrivileges accessType, int? windowIndex) 82 { 83 emulationParent.Log(LogLevel.Noisy, "IOMMU fault at 0x{0:X} when trying to access as {1}", address, accessType); 84 OnFault?.Invoke(address, accessType, windowIndex); 85 86 if(windowIndex == null) 87 { 88 emulationParent.Log(LogLevel.Error, "IOMMU fault - the address 0x{0:X} is not specified in any of the existing ranges", address); 89 } 90 } 91 92 private readonly IEmulationElement emulationParent; 93 94 public class MMUWindow 95 { MMUWindow(IEmulationElement emulationParent)96 public MMUWindow(IEmulationElement emulationParent) 97 { 98 this.emulationParent = emulationParent; 99 } 100 ContainsAddress(ulong address)101 public bool ContainsAddress(ulong address) 102 { 103 return address >= Start && address < End; 104 } 105 AssertIsValid()106 public void AssertIsValid() 107 { 108 Valid = true; 109 if(Start > End) 110 { 111 emulationParent.Log(LogLevel.Error, "MMUWindow has start address (0x{0:x}) grater than end address (0x{1:x}).", Start, End); 112 Valid = false; 113 } 114 115 if(Offset < 0 && Start < (ulong)(-Offset)) 116 { 117 emulationParent.Log(LogLevel.Error, "MMUWindow has incorrect offset ({0:d}) in relation to the start address (0x{1:x}).", Offset, Start); 118 Valid = false; 119 } 120 else if(Offset > 0 && End > UInt64.MaxValue - (ulong)Offset) 121 { 122 emulationParent.Log(LogLevel.Error, "MMUWindow has incorrect offset ({0:d}) in relation to the end address (0x{1:x}).", Offset, End); 123 Valid = false; 124 } 125 126 } 127 TranslateAddress(ulong address)128 public ulong TranslateAddress(ulong address) 129 { 130 if(Offset < 0) 131 { 132 return checked(address - (ulong)(-Offset)); 133 } 134 else 135 { 136 return checked(address + (ulong)Offset); 137 } 138 } 139 140 public ulong Start { get; set; } 141 public ulong End { get; set; } 142 public ulong Length => checked(End - Start); 143 public long Offset { get; set; } 144 public BusAccessPrivileges Privileges { get; set; } 145 public bool Valid { get; private set; } 146 147 private readonly IEmulationElement emulationParent; 148 } 149 } 150 } 151