1 //
2 // Copyright (c) 2010-2025 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 System.Linq;
11 using Antmicro.Renode.Core;
12 using Antmicro.Renode.Exceptions;
13 using Antmicro.Renode.Core.Structure;
14 using Antmicro.Renode.Utilities;
15 using Antmicro.Renode.Peripherals.CPU;
16 using Antmicro.Renode.Peripherals.Memory;
17 using ELFSharp.ELF;
18 
19 using Range = Antmicro.Renode.Core.Range;
20 
21 namespace Antmicro.Renode.Peripherals.Bus
22 {
23     public interface IBusController: IPeripheralContainer<IBusPeripheral, BusRangeRegistration>, IPeripheralRegister<IKnownSize, BusPointRegistration>,
24         IPeripheralRegister<ICPU, CPURegistrationPoint>, IPeripheralRegister<IBusPeripheral, BusMultiRegistration>, IPeripheralRegister<IPeripheral, NullRegistrationPoint>,
25         IPeripheralRegister<IBusPeripheral, BusParametrizedRegistration>, ICanLoadFiles, IPeripheral, IMultibyteWritePeripheral
26     {
ReadByte(ulong address, IPeripheral context = null, ulong? cpuState = null)27         byte ReadByte(ulong address, IPeripheral context = null, ulong? cpuState = null);
ReadByteWithState(ulong address, IPeripheral context, IContextState stateObj)28         byte ReadByteWithState(ulong address, IPeripheral context, IContextState stateObj);
WriteByte(ulong address, byte value, IPeripheral context = null, ulong? cpuState = null)29         void WriteByte(ulong address, byte value, IPeripheral context = null, ulong? cpuState = null);
WriteByteWithState(ulong address, byte value, IPeripheral context, IContextState stateObj)30         void WriteByteWithState(ulong address, byte value, IPeripheral context, IContextState stateObj);
31 
ReadWord(ulong address, IPeripheral context = null, ulong? cpuState = null)32         ushort ReadWord(ulong address, IPeripheral context = null, ulong? cpuState = null);
ReadWordWithState(ulong address, IPeripheral context, IContextState stateObj)33         ushort ReadWordWithState(ulong address, IPeripheral context, IContextState stateObj);
WriteWord(ulong address, ushort value, IPeripheral context = null, ulong? cpuState = null)34         void WriteWord(ulong address, ushort value, IPeripheral context = null, ulong? cpuState = null);
WriteWordWithState(ulong address, ushort value, IPeripheral context, IContextState stateObj)35         void WriteWordWithState(ulong address, ushort value, IPeripheral context, IContextState stateObj);
36 
ReadDoubleWord(ulong address, IPeripheral context = null, ulong? cpuState = null)37         uint ReadDoubleWord(ulong address, IPeripheral context = null, ulong? cpuState = null);
ReadDoubleWordWithState(ulong address, IPeripheral context, IContextState stateObj)38         uint ReadDoubleWordWithState(ulong address, IPeripheral context, IContextState stateObj);
WriteDoubleWord(ulong address, uint value, IPeripheral context = null, ulong? cpuState = null)39         void WriteDoubleWord(ulong address, uint value, IPeripheral context = null, ulong? cpuState = null);
WriteDoubleWordWithState(ulong address, uint value, IPeripheral context, IContextState stateObj)40         void WriteDoubleWordWithState(ulong address, uint value, IPeripheral context, IContextState stateObj);
41 
ReadQuadWord(ulong address, IPeripheral context = null, ulong? cpuState = null)42         ulong ReadQuadWord(ulong address, IPeripheral context = null, ulong? cpuState = null);
ReadQuadWordWithState(ulong address, IPeripheral context, IContextState stateObj)43         ulong ReadQuadWordWithState(ulong address, IPeripheral context, IContextState stateObj);
WriteQuadWord(ulong address, ulong value, IPeripheral context = null, ulong? cpuState = null)44         void WriteQuadWord(ulong address, ulong value, IPeripheral context = null, ulong? cpuState = null);
WriteQuadWordWithState(ulong address, ulong value, IPeripheral context, IContextState stateObj)45         void WriteQuadWordWithState(ulong address, ulong value, IPeripheral context, IContextState stateObj);
46 
ReadBytes(ulong address, int count, byte[] destination, int startIndex, bool onlyMemory = false, IPeripheral context = null)47         void ReadBytes(ulong address, int count, byte[] destination, int startIndex, bool onlyMemory = false, IPeripheral context = null);
ReadBytes(ulong address, int count, bool onlyMemory = false, IPeripheral context = null)48         byte[] ReadBytes(ulong address, int count, bool onlyMemory = false, IPeripheral context = null);
49 
WriteBytes(byte[] bytes, ulong address, bool onlyMemory = false, IPeripheral context = null)50         void WriteBytes(byte[] bytes, ulong address, bool onlyMemory = false, IPeripheral context = null);
WriteBytes(byte[] bytes, ulong address, int startingIndex, long count, bool onlyMemory = false, IPeripheral context = null)51         void WriteBytes(byte[] bytes, ulong address, int startingIndex, long count, bool onlyMemory = false, IPeripheral context = null);
WriteBytes(byte[] bytes, ulong address, long count, bool onlyMemory = false, IPeripheral context = null)52         void WriteBytes(byte[] bytes, ulong address, long count, bool onlyMemory = false, IPeripheral context = null);
53 
ZeroRange(Range range, IPeripheral context = null)54         void ZeroRange(Range range, IPeripheral context = null);
TryConvertStateToUlongForContext(IPeripheral context, IContextState stateObj, out ulong? state)55         bool TryConvertStateToUlongForContext(IPeripheral context, IContextState stateObj, out ulong? state);
56 
WhatIsAt(ulong address, IPeripheral context = null)57         IBusRegistered<IBusPeripheral> WhatIsAt(ulong address, IPeripheral context = null);
WhatPeripheralIsAt(ulong address, IPeripheral context = null)58         IPeripheral WhatPeripheralIsAt(ulong address, IPeripheral context = null);
59 
IsAddressRangeLocked(Range range, IPeripheral context = null)60         bool IsAddressRangeLocked(Range range, IPeripheral context = null);
SetAddressRangeLocked(Range range, bool locked, IPeripheral context = null)61         void SetAddressRangeLocked(Range range, bool locked, IPeripheral context = null);
62 
SetPeripheralEnabled(IPeripheral peripheral, bool value)63         void SetPeripheralEnabled(IPeripheral peripheral, bool value);
IsPeripheralEnabled(IPeripheral peripheral)64         bool IsPeripheralEnabled(IPeripheral peripheral);
65 
GetCPUs()66         IEnumerable<ICPU> GetCPUs();
GetCPUSlot(ICPU cpu)67         int GetCPUSlot(ICPU cpu);
GetCurrentCPU()68         ICPU GetCurrentCPU();
GetAllContextKeys()69         IEnumerable<IPeripheral> GetAllContextKeys();
GetRegisteredPeripherals(IPeripheral context = null)70         IEnumerable<IBusRegistered<IBusPeripheral>> GetRegisteredPeripherals(IPeripheral context = null);
GetRegistrationsForPeripheralType(IPeripheral context = null)71         IEnumerable<IBusRegistered<IBusPeripheral>> GetRegistrationsForPeripheralType<T>(IPeripheral context = null);
TryGetCurrentCPU(out ICPU cpu)72         bool TryGetCurrentCPU(out ICPU cpu);
TryGetCurrentContextState(out IPeripheralWithTransactionState context, out T stateObj)73         bool TryGetCurrentContextState<T>(out IPeripheralWithTransactionState context, out T stateObj);
74 
UnregisterFromAddress(ulong address, ICPU context = null)75         void UnregisterFromAddress(ulong address, ICPU context = null);
MoveRegistrationWithinContext(IBusPeripheral peripheral, BusRangeRegistration newRegistration, ICPU context, Func<IEnumerable<IBusRegistered<IBusPeripheral>>, IBusRegistered<IBusPeripheral>> selector = null)76         void MoveRegistrationWithinContext(IBusPeripheral peripheral, BusRangeRegistration newRegistration, ICPU context, Func<IEnumerable<IBusRegistered<IBusPeripheral>>, IBusRegistered<IBusPeripheral>> selector = null);
77 
AddWatchpointHook(ulong address, SysbusAccessWidth width, Access access, BusHookDelegate hook)78         void AddWatchpointHook(ulong address, SysbusAccessWidth width, Access access, BusHookDelegate hook);
RemoveWatchpointHook(ulong address, BusHookDelegate hook)79         void RemoveWatchpointHook(ulong address, BusHookDelegate hook);
TryGetWatchpointsAt(ulong address, Access access, out List<BusHookHandler> result)80         bool TryGetWatchpointsAt(ulong address, Access access, out List<BusHookHandler> result);
RemoveAllWatchpointHooks(ulong address)81         void RemoveAllWatchpointHooks(ulong address);
82 
SetHookAfterPeripheralRead(IBusPeripheral peripheral, Func<T, long, T> hook, Range? subrange = null)83         void SetHookAfterPeripheralRead<T>(IBusPeripheral peripheral, Func<T, long, T> hook, Range? subrange = null);
SetHookBeforePeripheralWrite(IBusPeripheral peripheral, Func<T, long, T> hook, Range? subrange = null)84         void SetHookBeforePeripheralWrite<T>(IBusPeripheral peripheral, Func<T, long, T> hook, Range? subrange = null);
ClearHookAfterPeripheralRead(IBusPeripheral peripheral)85         void ClearHookAfterPeripheralRead<T>(IBusPeripheral peripheral);
86 
FindSymbolAt(ulong offset, ICPU context = null)87         string FindSymbolAt(ulong offset, ICPU context = null);
88 
TryGetAllSymbolAddresses(string symbolName, out IEnumerable<ulong> symbolAddresses, ICPU context = null)89         bool TryGetAllSymbolAddresses(string symbolName, out IEnumerable<ulong> symbolAddresses, ICPU context = null);
TryFindSymbolAt(ulong offset, out string name, out Symbol symbol, ICPU context = null)90         bool TryFindSymbolAt(ulong offset, out string name, out Symbol symbol, ICPU context = null);
DecorateWithCPUNameAndPC(string str)91         string DecorateWithCPUNameAndPC(string str);
92 
MapMemory(IMappedSegment segment, IBusPeripheral owner, bool relative = true, ICPUWithMappedMemory context = null)93         void MapMemory(IMappedSegment segment, IBusPeripheral owner, bool relative = true, ICPUWithMappedMemory context = null);
FindMemory(ulong address, ICPU context = null)94         IBusRegistered<MappedMemory> FindMemory(ulong address, ICPU context = null);
IsMemory(ulong address, ICPU context = null)95         bool IsMemory(ulong address, ICPU context = null);
96 
Tag(Range range, string tag, ulong defaultValue = 0, bool pausing = false)97         void Tag(Range range, string tag, ulong defaultValue = 0, bool pausing = false);
98 
ApplySVD(string path)99         void ApplySVD(string path);
100 
LoadSymbolsFrom(IELF elf, bool useVirtualAddress = false, ulong? textAddress = null, ICPU context = null)101         void LoadSymbolsFrom(IELF elf, bool useVirtualAddress = false, ulong? textAddress = null, ICPU context = null);
LoadUImage(ReadFilePath fileName, IInitableCPU cpu = null)102         void LoadUImage(ReadFilePath fileName, IInitableCPU cpu = null);
103 
GetLookup(ICPU context = null)104         SymbolLookup GetLookup(ICPU context = null);
105 
EnableAllTranslations(bool enable = true)106         void EnableAllTranslations(bool enable = true);
EnableAllTranslations(IBusPeripheral busPeripheral, bool enable = true)107         void EnableAllTranslations(IBusPeripheral busPeripheral, bool enable = true);
108 
109         IMachine Machine { get; }
110 
111         bool IsMultiCore { get; }
112 
113         Endianess Endianess { get; }
114 
115         event Action<IMachine> OnSymbolsChanged;
116     }
117 
118     public static class BusControllerExtensions
119     {
EnablePeripheral(this IBusController bus, IPeripheral peripheral)120         public static void EnablePeripheral(this IBusController bus, IPeripheral peripheral)
121         {
122             bus.SetPeripheralEnabled(peripheral, true);
123         }
124 
DisablePeripheral(this IBusController bus, IPeripheral peripheral)125         public static void DisablePeripheral(this IBusController bus, IPeripheral peripheral)
126         {
127             bus.SetPeripheralEnabled(peripheral, false);
128         }
129 
MoveBusMultiRegistrationWithinContext(this IBusController bus, IBusPeripheral peripheral, BusMultiRegistration newRegistration, ICPU cpu)130         public static void MoveBusMultiRegistrationWithinContext(this IBusController bus, IBusPeripheral peripheral, BusMultiRegistration newRegistration, ICPU cpu)
131         {
132             var regionName = newRegistration.ConnectionRegionName;
133             bus.MoveRegistrationWithinContext(peripheral, newRegistration, cpu,
134                 selector: busRegisteredEnumerable =>
135                 {
136                     return busRegisteredEnumerable.Where(
137                             busRegistered => (busRegistered.RegistrationPoint is BusMultiRegistration multiRegistration) && multiRegistration.ConnectionRegionName == regionName
138                         ).Single();
139                 }
140             );
141         }
142 
ZeroRange(this IBusController bus, long from, long size, ICPU context = null)143         public static void ZeroRange(this IBusController bus, long from, long size, ICPU context = null)
144         {
145             bus.ZeroRange(from.By(size), context);
146         }
147 
GetSymbolAddress(this IBusController bus, string symbolName, int index, ICPU context = null)148         public static ulong GetSymbolAddress(this IBusController bus, string symbolName, int index, ICPU context = null)
149         {
150             if(!bus.TryGetAllSymbolAddresses(symbolName, out var addressesEnumerable, context))
151             {
152                 throw new RecoverableException($"Could not find any address for symbol: {symbolName}");
153             }
154             var addresses = addressesEnumerable.ToArray();
155             if(index < 0 || index >= addresses.Length)
156             {
157                 var msg = (addresses.Length == 1)
158                     ? "there is only one address"
159                     : "there are only {addresses.Length} addresses";
160 
161                 throw new RecoverableException($"Wrong index {index}: {msg} (0-based index) for '{symbolName}'");
162             }
163             return addresses[index];
164         }
165 
GetSymbolAddress(this IBusController bus, string symbolName, ICPU context = null)166         public static ulong GetSymbolAddress(this IBusController bus, string symbolName, ICPU context = null)
167         {
168             if(!bus.TryGetAllSymbolAddresses(symbolName, out var addressesEnumerable, context))
169             {
170                 throw new RecoverableException($"Could not find any address for symbol: {symbolName}");
171             }
172             var addresses = addressesEnumerable.ToArray();
173             if(addresses.Length != 1)
174             {
175                 throw new RecoverableException($"Found {addresses.Length} possible addresses for the symbol. Select which one you're interested in by providing a 0-based index or use the `GetAllSymbolAddresses` method");
176             }
177             return addresses[0];
178         }
179 
180         // Specifying `textAddress` will override the address of the program text - the symbols will be applied
181         // as if the first loaded segment started at the specified address. This is equivalent to the ADDR parameter
182         // to GDB's add-symbol-file.
LoadSymbolsFrom(this IBusController bus, ReadFilePath fileName, bool useVirtualAddress = false, ulong? textAddress = null, ICPU context = null)183         public static void LoadSymbolsFrom(this IBusController bus, ReadFilePath fileName, bool useVirtualAddress = false, ulong? textAddress = null, ICPU context = null)
184         {
185             using(var elf = ELFUtils.LoadELF(fileName))
186             {
187                 bus.LoadSymbolsFrom(elf, useVirtualAddress, textAddress, context);
188             }
189         }
190     }
191 }
192