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.Linq; 8 using System; 9 using Antmicro.Renode.Peripherals.CPU; 10 using Antmicro.Renode.Logging; 11 using ELFSharp.ELF; 12 13 namespace Antmicro.Renode.Utilities.GDB.Commands 14 { 15 internal class WriteRegisterCommand : Command 16 { WriteRegisterCommand(CommandsManager manager)17 public WriteRegisterCommand(CommandsManager manager) : base(manager) 18 { 19 } 20 21 [Execute("P")] Execute( [Argument(Encoding = ArgumentAttribute.ArgumentEncoding.HexNumber, Separator = B)]int registerNumber, [Argument(Encoding = ArgumentAttribute.ArgumentEncoding.HexBytesString)]byte[] value)22 public PacketData Execute( 23 [Argument(Encoding = ArgumentAttribute.ArgumentEncoding.HexNumber, Separator = '=')]int registerNumber, 24 [Argument(Encoding = ArgumentAttribute.ArgumentEncoding.HexBytesString)]byte[] value) 25 { 26 var isLittleEndian = manager.Cpu.Endianness == Endianess.LittleEndian; 27 var reg = manager.Cpu.GetRegisters().SingleOrDefault(x => x.Index == registerNumber); 28 if(reg.Width == 0) 29 { 30 manager.Cpu.Log(LogLevel.Warning, "Writing to register #{0} failed, register doesn't exit.", registerNumber); 31 return PacketData.ErrorReply(); 32 } 33 34 // register may have been reported with bigger Width, try to truncate the value 35 var width = reg.Width / 8; 36 if(value.Length > width) 37 { 38 // split value into excess and proper value 39 var excess = value.Skip(isLittleEndian ? width : 0).Take(value.Length - width); 40 value = value.Skip(isLittleEndian ? 0 : value.Length - width).Take(width).ToArray(); 41 42 // Allow excess to be filled with zeros and (for two's complement support) 0xff when msb is set. 43 // All bytes in excess need to be the same and checked, 44 // use sample byte to test value and check if all bytes equal to the sample. 45 var sampleByte = excess.First(); 46 var msb = value[isLittleEndian ? value.Length - 1 : 0] >> 7; 47 if(!(sampleByte == 0 || (sampleByte == 0xff && msb == 1)) || excess.Any(b => b != sampleByte)) 48 { 49 manager.Cpu.Log(LogLevel.Warning, "Writing to register #{0} failed, sent value doesn't fit in {1} bits.", registerNumber, reg.Width); 50 return PacketData.ErrorReply(); 51 } 52 } 53 54 manager.Cpu.SetRegister(registerNumber, reg.ValueFromBytes(value, manager.Cpu.Endianness)); 55 return PacketData.Success; 56 } 57 } 58 } 59