1 //
2 // Copyright (c) 2010-2024 Antmicro
3 // Copyright (c) 2011-2015 Realtime Embedded
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 using System;
9 using System.Linq;
10 using Antmicro.Renode.Config.Devices;
11 using Antmicro.Renode.Core;
12 using Antmicro.Renode.Peripherals.Bus;
13 using Antmicro.Renode.Peripherals.CPU;
14 using System.Collections.Generic;
15 using Machine = Antmicro.Renode.Core.Machine;
16 using Antmicro.Renode.Core.Structure;
17 using System.IO;
18 using FdtSharp;
19 using Antmicro.Renode.Logging;
20 using System.Text;
21 using Antmicro.Renode.Exceptions;
22 
23 namespace Antmicro.Renode.Utilities
24 {
25     public static class MachineExtensions
26     {
LoadPeripheralsFromJSONFile(this IMachine machine, String fileName)27         public static void LoadPeripheralsFromJSONFile(this IMachine machine, String fileName)
28         {
29             if(!File.Exists(fileName))
30             {
31                 throw new RecoverableException("Cannot load devices configuration from file {0} as it does not exist.".FormatWith(fileName));
32             }
33             new DevicesConfig(File.ReadAllText(fileName), machine);
34         }
35 
LoadPeripheralsFromJSONString(this IMachine machine, String text)36         public static void LoadPeripheralsFromJSONString(this IMachine machine, String text)
37         {
38             new DevicesConfig(text, machine);
39         }
40 
LoadAtags(this IBusController bus, String bootargs, uint memorySize, uint beginAddress)41         public static void LoadAtags(this IBusController bus, String bootargs, uint memorySize, uint beginAddress)
42         {
43             var atags = Misc.CreateAtags(bootargs, memorySize);
44             //Fill ATAGs
45             var addr = beginAddress;
46             foreach(var elem in atags)
47             {
48                 bus.WriteDoubleWord(addr, elem);
49                 addr += 4;
50             }
51         }
52 
LoadFdt(this IBusController sysbus, string file, ulong address, string bootargs = null, bool append = true, string disabledNodes = R, ICPU context = null)53         public static void LoadFdt(this IBusController sysbus, string file, ulong address, string bootargs = null, bool append = true, string disabledNodes = "", ICPU context = null)
54         {
55             if(!File.Exists(file))
56             {
57                 throw new RecoverableException("FDT file {0} not found".FormatWith(file));
58             }
59 
60             var fdtBlob = File.ReadAllBytes(file);
61             if(bootargs == null)
62             {
63                 sysbus.WriteBytes(fdtBlob, address, true, context);
64                 return;
65             }
66             var fdt = new FlattenedDeviceTree(fdtBlob);
67             var chosenNode = fdt.Root.Subnodes.FirstOrDefault(x => x.Name == "chosen");
68             if(chosenNode == null)
69             {
70                 chosenNode = new TreeNode { Name = "chosen" };
71                 fdt.Root.Subnodes.Add(chosenNode);
72             }
73             var bootargsProperty = chosenNode.Properties.FirstOrDefault(x => x.Name == "bootargs");
74             if(bootargsProperty == null)
75             {
76                 bootargsProperty = new Property("bootargs", new byte[] { 0 });
77                 chosenNode.Properties.Add(bootargsProperty);
78             }
79             var oldBootargs = bootargsProperty.GetDataAsString();
80             if(append)
81             {
82                 bootargs = oldBootargs + bootargs;
83             }
84             if(oldBootargs != bootargs)
85             {
86                 sysbus.DebugLog("Bootargs altered from '{0}' to '{1}'.", oldBootargs, bootargs);
87             }
88             bootargsProperty.PutDataAsString(bootargs);
89 
90             var disabledNodeNames = disabledNodes.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
91             byte[] disabledValue = Encoding.ASCII.GetBytes("disabled");
92             foreach(var deviceName in disabledNodeNames)
93             {
94                 TreeNode node = fdt.Root.Descendants.FirstOrDefault(x => x.Name == deviceName);
95                 if(node == null)
96                 {
97                     throw new RecoverableException(String.Format("Device {0} not found.", deviceName));
98                 }
99                 else
100                 {
101                     Property statusProperty = node.Properties.FirstOrDefault(x => x.Name == "status");
102                     if(statusProperty != null)
103                     {
104                         node.Properties.Remove(statusProperty);
105                     }
106                     statusProperty = new Property("status", disabledValue);
107                     node.Properties.Add(statusProperty);
108                 }
109             }
110 
111             fdtBlob = fdt.GetBinaryBlob();
112             sysbus.WriteBytes(fdtBlob, address, true, context);
113         }
114 
WriteASCIIString(this IBusController sysbus, ulong address, string stringToLoad, ICPU context = null)115         public static void WriteASCIIString(this IBusController sysbus, ulong address, string stringToLoad, ICPU context = null)
116         {
117             sysbus.WriteBytes(Encoding.ASCII.GetBytes(stringToLoad), address, true, context);
118         }
119 
GetPeripheralsWithAllRegistrationPoints(this IMachine machine)120         public static Dictionary<PeripheralTreeEntry, IEnumerable<IRegistrationPoint>> GetPeripheralsWithAllRegistrationPoints(this IMachine machine)
121         {
122             var result = new Dictionary<PeripheralTreeEntry, IEnumerable<IRegistrationPoint>>();
123 
124             var peripheralEntries = machine.GetRegisteredPeripherals().ToArray();
125             var sysbusEntry = peripheralEntries.First(x => x.Name == Machine.SystemBusName).Peripheral;
126             foreach(var entryList in peripheralEntries.OrderBy(x => x.Name).GroupBy(x => x.Peripheral))
127             {
128                 var uniqueEntryList = entryList.DistinctBy(x => x.RegistrationPoint).ToArray();
129                 var entry = uniqueEntryList.FirstOrDefault();
130                 if(entry != null)
131                 {
132                     result.Add(entry, uniqueEntryList.Select(x => x.RegistrationPoint).ToList());
133                 }
134                 // The peripherals command will not print the entry under sysbus if its first occurence in entryList is not directly a child of sysbus.
135                 // This check prevents loosing sysbus registration info in peripherals command output.
136                 if(entry.Parent != sysbusEntry)
137                 {
138                     entry = uniqueEntryList.FirstOrDefault(x => x.Parent == sysbusEntry);
139                     if(entry != null)
140                     {
141                         result.Add(entry, uniqueEntryList.Where(x => x.Parent == sysbusEntry).Select(x => x.RegistrationPoint).ToList());
142                     }
143                 }
144             }
145 
146             return result;
147         }
148     }
149 }
150