UnicornAArch64.cs 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. using System;
  2. using UnicornEngine.Const;
  3. namespace Ryujinx.Tests.Unicorn
  4. {
  5. public class UnicornAArch64 : IDisposable
  6. {
  7. internal readonly UnicornEngine.Unicorn uc;
  8. private bool _isDisposed;
  9. public IndexedProperty<int, ulong> X => new(GetX, SetX);
  10. public IndexedProperty<int, SimdValue> Q => new(GetQ, SetQ);
  11. public ulong LR
  12. {
  13. get => GetRegister(Arm64.UC_ARM64_REG_LR);
  14. set => SetRegister(Arm64.UC_ARM64_REG_LR, value);
  15. }
  16. public ulong SP
  17. {
  18. get => GetRegister(Arm64.UC_ARM64_REG_SP);
  19. set => SetRegister(Arm64.UC_ARM64_REG_SP, value);
  20. }
  21. public ulong PC
  22. {
  23. get => GetRegister(Arm64.UC_ARM64_REG_PC);
  24. set => SetRegister(Arm64.UC_ARM64_REG_PC, value);
  25. }
  26. public uint Pstate
  27. {
  28. get => (uint)GetRegister(Arm64.UC_ARM64_REG_PSTATE);
  29. set => SetRegister(Arm64.UC_ARM64_REG_PSTATE, value);
  30. }
  31. public int Fpcr
  32. {
  33. get => (int)GetRegister(Arm64.UC_ARM64_REG_FPCR);
  34. set => SetRegister(Arm64.UC_ARM64_REG_FPCR, (uint)value);
  35. }
  36. public int Fpsr
  37. {
  38. get => (int)GetRegister(Arm64.UC_ARM64_REG_FPSR);
  39. set => SetRegister(Arm64.UC_ARM64_REG_FPSR, (uint)value);
  40. }
  41. public bool OverflowFlag
  42. {
  43. get => (Pstate & 0x10000000u) != 0;
  44. set => Pstate = (Pstate & ~0x10000000u) | (value ? 0x10000000u : 0u);
  45. }
  46. public bool CarryFlag
  47. {
  48. get => (Pstate & 0x20000000u) != 0;
  49. set => Pstate = (Pstate & ~0x20000000u) | (value ? 0x20000000u : 0u);
  50. }
  51. public bool ZeroFlag
  52. {
  53. get => (Pstate & 0x40000000u) != 0;
  54. set => Pstate = (Pstate & ~0x40000000u) | (value ? 0x40000000u : 0u);
  55. }
  56. public bool NegativeFlag
  57. {
  58. get => (Pstate & 0x80000000u) != 0;
  59. set => Pstate = (Pstate & ~0x80000000u) | (value ? 0x80000000u : 0u);
  60. }
  61. public UnicornAArch64()
  62. {
  63. uc = new UnicornEngine.Unicorn(Common.UC_ARCH_ARM64, Common.UC_MODE_LITTLE_ENDIAN);
  64. SetRegister(Arm64.UC_ARM64_REG_CPACR_EL1, 0x00300000);
  65. }
  66. ~UnicornAArch64()
  67. {
  68. Dispose(false);
  69. }
  70. public void Dispose()
  71. {
  72. Dispose(true);
  73. GC.SuppressFinalize(this);
  74. }
  75. protected virtual void Dispose(bool disposing)
  76. {
  77. if (!_isDisposed)
  78. {
  79. uc.Close();
  80. _isDisposed = true;
  81. }
  82. }
  83. public void RunForCount(ulong count)
  84. {
  85. // FIXME: untilAddr should be 0xFFFFFFFFFFFFFFFFul
  86. uc.EmuStart((long)this.PC, -1, 0, (long)count);
  87. }
  88. public void Step()
  89. {
  90. RunForCount(1);
  91. }
  92. private static int[] XRegisters =
  93. {
  94. Arm64.UC_ARM64_REG_X0,
  95. Arm64.UC_ARM64_REG_X1,
  96. Arm64.UC_ARM64_REG_X2,
  97. Arm64.UC_ARM64_REG_X3,
  98. Arm64.UC_ARM64_REG_X4,
  99. Arm64.UC_ARM64_REG_X5,
  100. Arm64.UC_ARM64_REG_X6,
  101. Arm64.UC_ARM64_REG_X7,
  102. Arm64.UC_ARM64_REG_X8,
  103. Arm64.UC_ARM64_REG_X9,
  104. Arm64.UC_ARM64_REG_X10,
  105. Arm64.UC_ARM64_REG_X11,
  106. Arm64.UC_ARM64_REG_X12,
  107. Arm64.UC_ARM64_REG_X13,
  108. Arm64.UC_ARM64_REG_X14,
  109. Arm64.UC_ARM64_REG_X15,
  110. Arm64.UC_ARM64_REG_X16,
  111. Arm64.UC_ARM64_REG_X17,
  112. Arm64.UC_ARM64_REG_X18,
  113. Arm64.UC_ARM64_REG_X19,
  114. Arm64.UC_ARM64_REG_X20,
  115. Arm64.UC_ARM64_REG_X21,
  116. Arm64.UC_ARM64_REG_X22,
  117. Arm64.UC_ARM64_REG_X23,
  118. Arm64.UC_ARM64_REG_X24,
  119. Arm64.UC_ARM64_REG_X25,
  120. Arm64.UC_ARM64_REG_X26,
  121. Arm64.UC_ARM64_REG_X27,
  122. Arm64.UC_ARM64_REG_X28,
  123. Arm64.UC_ARM64_REG_X29,
  124. Arm64.UC_ARM64_REG_X30,
  125. };
  126. private static int[] QRegisters =
  127. {
  128. Arm64.UC_ARM64_REG_Q0,
  129. Arm64.UC_ARM64_REG_Q1,
  130. Arm64.UC_ARM64_REG_Q2,
  131. Arm64.UC_ARM64_REG_Q3,
  132. Arm64.UC_ARM64_REG_Q4,
  133. Arm64.UC_ARM64_REG_Q5,
  134. Arm64.UC_ARM64_REG_Q6,
  135. Arm64.UC_ARM64_REG_Q7,
  136. Arm64.UC_ARM64_REG_Q8,
  137. Arm64.UC_ARM64_REG_Q9,
  138. Arm64.UC_ARM64_REG_Q10,
  139. Arm64.UC_ARM64_REG_Q11,
  140. Arm64.UC_ARM64_REG_Q12,
  141. Arm64.UC_ARM64_REG_Q13,
  142. Arm64.UC_ARM64_REG_Q14,
  143. Arm64.UC_ARM64_REG_Q15,
  144. Arm64.UC_ARM64_REG_Q16,
  145. Arm64.UC_ARM64_REG_Q17,
  146. Arm64.UC_ARM64_REG_Q18,
  147. Arm64.UC_ARM64_REG_Q19,
  148. Arm64.UC_ARM64_REG_Q20,
  149. Arm64.UC_ARM64_REG_Q21,
  150. Arm64.UC_ARM64_REG_Q22,
  151. Arm64.UC_ARM64_REG_Q23,
  152. Arm64.UC_ARM64_REG_Q24,
  153. Arm64.UC_ARM64_REG_Q25,
  154. Arm64.UC_ARM64_REG_Q26,
  155. Arm64.UC_ARM64_REG_Q27,
  156. Arm64.UC_ARM64_REG_Q28,
  157. Arm64.UC_ARM64_REG_Q29,
  158. Arm64.UC_ARM64_REG_Q30,
  159. Arm64.UC_ARM64_REG_Q31,
  160. };
  161. public ulong GetX(int index)
  162. {
  163. if ((uint)index > 30)
  164. {
  165. throw new ArgumentOutOfRangeException(nameof(index));
  166. }
  167. return GetRegister(XRegisters[index]);
  168. }
  169. public void SetX(int index, ulong value)
  170. {
  171. if ((uint)index > 30)
  172. {
  173. throw new ArgumentOutOfRangeException(nameof(index));
  174. }
  175. SetRegister(XRegisters[index], value);
  176. }
  177. public SimdValue GetQ(int index)
  178. {
  179. if ((uint)index > 31)
  180. {
  181. throw new ArgumentOutOfRangeException(nameof(index));
  182. }
  183. return GetVector(QRegisters[index]);
  184. }
  185. public void SetQ(int index, SimdValue value)
  186. {
  187. if ((uint)index > 31)
  188. {
  189. throw new ArgumentOutOfRangeException(nameof(index));
  190. }
  191. SetVector(QRegisters[index], value);
  192. }
  193. private ulong GetRegister(int register)
  194. {
  195. byte[] data = new byte[8];
  196. uc.RegRead(register, data);
  197. return BitConverter.ToUInt64(data, 0);
  198. }
  199. private void SetRegister(int register, ulong value)
  200. {
  201. byte[] data = BitConverter.GetBytes(value);
  202. uc.RegWrite(register, data);
  203. }
  204. private SimdValue GetVector(int register)
  205. {
  206. byte[] data = new byte[16];
  207. uc.RegRead(register, data);
  208. return new SimdValue(data);
  209. }
  210. private void SetVector(int register, SimdValue value)
  211. {
  212. byte[] data = value.ToArray();
  213. uc.RegWrite(register, data);
  214. }
  215. public byte[] MemoryRead(ulong address, ulong size)
  216. {
  217. byte[] value = new byte[size];
  218. uc.MemRead((long)address, value);
  219. return value;
  220. }
  221. public byte MemoryRead8 (ulong address) => MemoryRead(address, 1)[0];
  222. public ushort MemoryRead16(ulong address) => BitConverter.ToUInt16(MemoryRead(address, 2), 0);
  223. public uint MemoryRead32(ulong address) => BitConverter.ToUInt32(MemoryRead(address, 4), 0);
  224. public ulong MemoryRead64(ulong address) => BitConverter.ToUInt64(MemoryRead(address, 8), 0);
  225. public void MemoryWrite(ulong address, byte[] value)
  226. {
  227. uc.MemWrite((long)address, value);
  228. }
  229. public void MemoryWrite8 (ulong address, byte value) => MemoryWrite(address, new[]{ value });
  230. public void MemoryWrite16(ulong address, short value) => MemoryWrite(address, BitConverter.GetBytes(value));
  231. public void MemoryWrite16(ulong address, ushort value) => MemoryWrite(address, BitConverter.GetBytes(value));
  232. public void MemoryWrite32(ulong address, int value) => MemoryWrite(address, BitConverter.GetBytes(value));
  233. public void MemoryWrite32(ulong address, uint value) => MemoryWrite(address, BitConverter.GetBytes(value));
  234. public void MemoryWrite64(ulong address, long value) => MemoryWrite(address, BitConverter.GetBytes(value));
  235. public void MemoryWrite64(ulong address, ulong value) => MemoryWrite(address, BitConverter.GetBytes(value));
  236. public void MemoryMap(ulong address, ulong size, MemoryPermission permissions)
  237. {
  238. uc.MemMap((long)address, (long)size, (int)permissions);
  239. }
  240. public void MemoryUnmap(ulong address, ulong size)
  241. {
  242. uc.MemUnmap((long)address, (long)size);
  243. }
  244. public void MemoryProtect(ulong address, ulong size, MemoryPermission permissions)
  245. {
  246. uc.MemProtect((long)address, (long)size, (int)permissions);
  247. }
  248. }
  249. }