1 // 2 // Copyright (c) 2010-2024 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System; 8 using System.Collections.Generic; 9 using System.Linq; 10 11 using Antmicro.Renode.Logging; 12 using Antmicro.Renode.Peripherals.CPU; 13 using ELFSharp.ELF; 14 15 namespace Antmicro.Renode.Utilities.GDB.Commands 16 { 17 internal class Trace32Commands : Command 18 { Trace32Commands(CommandsManager manager)19 public Trace32Commands(CommandsManager manager) : base(manager) 20 { 21 } 22 23 [Execute("mspr:")] // get AArch64 system register Execute( [Argument(Separator = B, Encoding = ArgumentAttribute.ArgumentEncoding.HexNumber)]uint trace32Encoding, [Argument(Encoding = ArgumentAttribute.ArgumentEncoding.HexNumber)]int sizeInBytes)24 public PacketData Execute( 25 [Argument(Separator = ',', Encoding = ArgumentAttribute.ArgumentEncoding.HexNumber)]uint trace32Encoding, 26 [Argument(Encoding = ArgumentAttribute.ArgumentEncoding.HexNumber)]int sizeInBytes) 27 { 28 if(!(manager.Cpu is ICPUWithAArch64Support cpu)) 29 { 30 manager.Cpu.Log(LogLevel.Error, "GDBStub: This CPU doesn't support getting AArch64 system registers."); 31 return PacketData.ErrorReply(Error.OperationNotPermitted); 32 } 33 34 // Multiples of 8 can be used to read registers with incrementing encodings. 35 if(sizeInBytes != 4 && (sizeInBytes % 8) != 0) 36 { 37 manager.Cpu.Log(LogLevel.Error, "GDBStub: Invalid size: 0x{0:X}", sizeInBytes); 38 return PacketData.ErrorReply(Error.InvalidArgument); 39 } 40 var registersToRead = sizeInBytes <= 8 ? 1 : sizeInBytes / 8; 41 var valueSize = sizeInBytes <= 8 ? sizeInBytes : 8; 42 43 var bytes = new List<byte>(registersToRead * valueSize); 44 for(var encoding = CreateAArch64Encoding(trace32Encoding); registersToRead > 0; registersToRead--, encoding.Op2++) 45 { 46 if(!cpu.TryGetSystemRegisterValue(encoding, out var value)) 47 { 48 // The 'TryGet' method will log failure details. 49 return PacketData.ErrorReply(Error.InvalidArgument); 50 } 51 bytes = bytes.Append(BitHelper.GetBytesFromValue(value, valueSize, reverse: cpu.Endianness == Endianess.LittleEndian)).ToList(); 52 } 53 return new PacketData(string.Join("", bytes.Select(x => x.ToString("X2")))); 54 } 55 56 [Execute("Mspr:")] // set AArch64 system register Execute( [Argument(Separator = B, Encoding = ArgumentAttribute.ArgumentEncoding.HexNumber)]uint trace32Encoding, [Argument(Separator = B, Encoding = ArgumentAttribute.ArgumentEncoding.DecimalNumber)]int sizeInBytes, [Argument(Encoding = ArgumentAttribute.ArgumentEncoding.HexBytesString)]byte[] valueBytes)57 public PacketData Execute( 58 [Argument(Separator = ',', Encoding = ArgumentAttribute.ArgumentEncoding.HexNumber)]uint trace32Encoding, 59 [Argument(Separator = ':', Encoding = ArgumentAttribute.ArgumentEncoding.DecimalNumber)]int sizeInBytes, 60 [Argument(Encoding = ArgumentAttribute.ArgumentEncoding.HexBytesString)]byte[] valueBytes) 61 { 62 if(!(manager.Cpu is ICPUWithAArch64Support cpu)) 63 { 64 manager.Cpu.Log(LogLevel.Error, "GDBStub: This CPU doesn't support setting AArch64 system registers."); 65 return PacketData.ErrorReply(Error.OperationNotPermitted); 66 } 67 68 if(sizeInBytes != 4 && sizeInBytes != 8) 69 { 70 manager.Cpu.Log(LogLevel.Error, "GDBStub: Invalid size: 0x{0:X}", sizeInBytes); 71 return PacketData.ErrorReply(Error.InvalidArgument); 72 } 73 74 var value = BitHelper.ToUInt64(valueBytes, index: 0, length: sizeInBytes, reverse: cpu.Endianness == Endianess.LittleEndian); 75 if(!cpu.TrySetSystemRegisterValue(CreateAArch64Encoding(trace32Encoding), value)) 76 { 77 // The 'TrySet' method will log failure details. 78 return PacketData.ErrorReply(Error.InvalidArgument); 79 } 80 return PacketData.Success; 81 } 82 CreateAArch64Encoding(uint trace32Encoding)83 private static AArch64SystemRegisterEncoding CreateAArch64Encoding(uint trace32Encoding) 84 { 85 // In Trace32's system register encoding, each hex digit refers to op0, op1... values from MRS/MSR instructions accessing 86 // the given register. For example, 0x30040 refers to op0=3, op1=0, crn=0, crm=4, op2=0 (ID_AA64PFR0_EL1). 87 var nibbles = BitHelper.GetNibbles(trace32Encoding).Reverse().TakeLast(5); 88 89 var op0 = nibbles.ElementAt(0); 90 var op1 = nibbles.ElementAt(1); 91 var crn = nibbles.ElementAt(2); 92 var crm = nibbles.ElementAt(3); 93 var op2 = nibbles.ElementAt(4); 94 return new AArch64SystemRegisterEncoding(op0, op1, crn, crm, op2); 95 } 96 } 97 } 98