AMemory.cs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. using ChocolArm64.Exceptions;
  2. using ChocolArm64.State;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Runtime.CompilerServices;
  6. namespace ChocolArm64.Memory
  7. {
  8. public unsafe class AMemory
  9. {
  10. private const long ErgMask = (4 << AThreadState.ErgSizeLog2) - 1;
  11. public AMemoryMgr Manager { get; private set; }
  12. private struct ExMonitor
  13. {
  14. public long Position { get; private set; }
  15. private bool ExState;
  16. public ExMonitor(long Position, bool ExState)
  17. {
  18. this.Position = Position;
  19. this.ExState = ExState;
  20. }
  21. public bool HasExclusiveAccess(long Position)
  22. {
  23. return this.Position == Position && ExState;
  24. }
  25. public void Reset()
  26. {
  27. ExState = false;
  28. }
  29. }
  30. private Dictionary<int, ExMonitor> Monitors;
  31. private HashSet<long> ExAddrs;
  32. private byte* RamPtr;
  33. public AMemory(IntPtr Ram, AMemoryAlloc Allocator)
  34. {
  35. Manager = new AMemoryMgr(Allocator);
  36. Monitors = new Dictionary<int, ExMonitor>();
  37. ExAddrs = new HashSet<long>();
  38. RamPtr = (byte*)Ram;
  39. }
  40. public void RemoveMonitor(int ThreadId)
  41. {
  42. lock (Monitors)
  43. {
  44. if (Monitors.TryGetValue(ThreadId, out ExMonitor Monitor))
  45. {
  46. ExAddrs.Remove(Monitor.Position);
  47. }
  48. Monitors.Remove(ThreadId);
  49. }
  50. }
  51. public void SetExclusive(AThreadState ThreadState, long Position)
  52. {
  53. Position &= ~ErgMask;
  54. lock (Monitors)
  55. {
  56. if (Monitors.TryGetValue(ThreadState.ThreadId, out ExMonitor Monitor))
  57. {
  58. ExAddrs.Remove(Monitor.Position);
  59. }
  60. bool ExState = ExAddrs.Add(Position);
  61. Monitor = new ExMonitor(Position, ExState);
  62. if (!Monitors.TryAdd(ThreadState.ThreadId, Monitor))
  63. {
  64. Monitors[ThreadState.ThreadId] = Monitor;
  65. }
  66. }
  67. }
  68. public bool TestExclusive(AThreadState ThreadState, long Position)
  69. {
  70. Position &= ~ErgMask;
  71. lock (Monitors)
  72. {
  73. if (!Monitors.TryGetValue(ThreadState.ThreadId, out ExMonitor Monitor))
  74. {
  75. return false;
  76. }
  77. return Monitor.HasExclusiveAccess(Position);
  78. }
  79. }
  80. public void ClearExclusive(AThreadState ThreadState)
  81. {
  82. lock (Monitors)
  83. {
  84. if (Monitors.TryGetValue(ThreadState.ThreadId, out ExMonitor Monitor))
  85. {
  86. Monitor.Reset();
  87. ExAddrs.Remove(Monitor.Position);
  88. }
  89. }
  90. }
  91. public bool AcquireAddress(long Position)
  92. {
  93. Position &= ~ErgMask;
  94. lock (Monitors)
  95. {
  96. return ExAddrs.Add(Position);
  97. }
  98. }
  99. public void ReleaseAddress(long Position)
  100. {
  101. Position &= ~ErgMask;
  102. lock (Monitors)
  103. {
  104. ExAddrs.Remove(Position);
  105. }
  106. }
  107. public sbyte ReadSByte(long Position) => (sbyte)ReadByte (Position);
  108. public short ReadInt16(long Position) => (short)ReadUInt16(Position);
  109. public int ReadInt32(long Position) => (int)ReadUInt32(Position);
  110. public long ReadInt64(long Position) => (long)ReadUInt64(Position);
  111. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  112. public byte ReadByte(long Position)
  113. {
  114. #if DEBUG
  115. EnsureAccessIsValid(Position, AMemoryPerm.Read);
  116. #endif
  117. return *((byte*)(RamPtr + (uint)Position));
  118. }
  119. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  120. public ushort ReadUInt16(long Position)
  121. {
  122. #if DEBUG
  123. EnsureAccessIsValid(Position, AMemoryPerm.Read);
  124. #endif
  125. return *((ushort*)(RamPtr + (uint)Position));
  126. }
  127. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  128. public uint ReadUInt32(long Position)
  129. {
  130. #if DEBUG
  131. EnsureAccessIsValid(Position, AMemoryPerm.Read);
  132. #endif
  133. return *((uint*)(RamPtr + (uint)Position));
  134. }
  135. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  136. public ulong ReadUInt64(long Position)
  137. {
  138. #if DEBUG
  139. EnsureAccessIsValid(Position, AMemoryPerm.Read);
  140. #endif
  141. return *((ulong*)(RamPtr + (uint)Position));
  142. }
  143. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  144. public AVec ReadVector8(long Position)
  145. {
  146. #if DEBUG
  147. EnsureAccessIsValid(Position, AMemoryPerm.Read);
  148. #endif
  149. return new AVec() { B0 = ReadByte(Position) };
  150. }
  151. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  152. public AVec ReadVector16(long Position)
  153. {
  154. #if DEBUG
  155. EnsureAccessIsValid(Position, AMemoryPerm.Read);
  156. #endif
  157. return new AVec() { H0 = ReadUInt16(Position) };
  158. }
  159. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  160. public AVec ReadVector32(long Position)
  161. {
  162. #if DEBUG
  163. EnsureAccessIsValid(Position, AMemoryPerm.Read);
  164. #endif
  165. return new AVec() { W0 = ReadUInt32(Position) };
  166. }
  167. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  168. public AVec ReadVector64(long Position)
  169. {
  170. #if DEBUG
  171. EnsureAccessIsValid(Position, AMemoryPerm.Read);
  172. #endif
  173. return new AVec() { X0 = ReadUInt64(Position) };
  174. }
  175. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  176. public AVec ReadVector128(long Position)
  177. {
  178. #if DEBUG
  179. EnsureAccessIsValid(Position, AMemoryPerm.Read);
  180. #endif
  181. return new AVec()
  182. {
  183. X0 = ReadUInt64(Position + 0),
  184. X1 = ReadUInt64(Position + 8)
  185. };
  186. }
  187. public void WriteSByte(long Position, sbyte Value) => WriteByte (Position, (byte)Value);
  188. public void WriteInt16(long Position, short Value) => WriteUInt16(Position, (ushort)Value);
  189. public void WriteInt32(long Position, int Value) => WriteUInt32(Position, (uint)Value);
  190. public void WriteInt64(long Position, long Value) => WriteUInt64(Position, (ulong)Value);
  191. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  192. public void WriteByte(long Position, byte Value)
  193. {
  194. #if DEBUG
  195. EnsureAccessIsValid(Position, AMemoryPerm.Write);
  196. #endif
  197. *((byte*)(RamPtr + (uint)Position)) = Value;
  198. }
  199. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  200. public void WriteUInt16(long Position, ushort Value)
  201. {
  202. #if DEBUG
  203. EnsureAccessIsValid(Position, AMemoryPerm.Write);
  204. #endif
  205. *((ushort*)(RamPtr + (uint)Position)) = Value;
  206. }
  207. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  208. public void WriteUInt32(long Position, uint Value)
  209. {
  210. #if DEBUG
  211. EnsureAccessIsValid(Position, AMemoryPerm.Write);
  212. #endif
  213. *((uint*)(RamPtr + (uint)Position)) = Value;
  214. }
  215. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  216. public void WriteUInt64(long Position, ulong Value)
  217. {
  218. #if DEBUG
  219. EnsureAccessIsValid(Position, AMemoryPerm.Write);
  220. #endif
  221. *((ulong*)(RamPtr + (uint)Position)) = Value;
  222. }
  223. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  224. public void WriteVector8(long Position, AVec Value)
  225. {
  226. #if DEBUG
  227. EnsureAccessIsValid(Position, AMemoryPerm.Write);
  228. #endif
  229. WriteByte(Position, Value.B0);
  230. }
  231. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  232. public void WriteVector16(long Position, AVec Value)
  233. {
  234. #if DEBUG
  235. EnsureAccessIsValid(Position, AMemoryPerm.Write);
  236. #endif
  237. WriteUInt16(Position, Value.H0);
  238. }
  239. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  240. public void WriteVector32(long Position, AVec Value)
  241. {
  242. #if DEBUG
  243. EnsureAccessIsValid(Position, AMemoryPerm.Write);
  244. #endif
  245. WriteUInt32(Position, Value.W0);
  246. }
  247. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  248. public void WriteVector64(long Position, AVec Value)
  249. {
  250. #if DEBUG
  251. EnsureAccessIsValid(Position, AMemoryPerm.Write);
  252. #endif
  253. WriteUInt64(Position, Value.X0);
  254. }
  255. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  256. public void WriteVector128(long Position, AVec Value)
  257. {
  258. #if DEBUG
  259. EnsureAccessIsValid(Position, AMemoryPerm.Write);
  260. #endif
  261. WriteUInt64(Position + 0, Value.X0);
  262. WriteUInt64(Position + 8, Value.X1);
  263. }
  264. private void EnsureAccessIsValid(long Position, AMemoryPerm Perm)
  265. {
  266. if (!Manager.IsMapped(Position))
  267. {
  268. throw new VmmPageFaultException(Position);
  269. }
  270. if (!Manager.HasPermission(Position, Perm))
  271. {
  272. throw new VmmAccessViolationException(Position, Perm);
  273. }
  274. }
  275. }
  276. }