diff options
author | gdkchan <gab.dark.100@gmail.com> | 2019-02-18 20:52:06 -0300 |
---|---|---|
committer | jduncanator <1518948+jduncanator@users.noreply.github.com> | 2019-02-19 10:52:06 +1100 |
commit | 932224f05112180aa5f52162cbbc3a17c339075f (patch) | |
tree | eed53f37bfd78db97d6f8301c021b7de9dd3becf /ChocolArm64/Memory/MemoryManager.cs | |
parent | dd00a4b62d48b7d55a6e66a69a83f09267d34143 (diff) |
ARM exclusive monitor and multicore fixes (#589)
* Implement ARM exclusive load/store with compare exchange insts, and enable multicore by default
* Fix comment typo
* Support Linux and OSX on MemoryAlloc and CompareExchange128, some cleanup
* Use intel syntax on assembly code
* Adjust identation
* Add CPUID check and fix exclusive reservation granule size
* Update schema multicore scheduling default value
* Make the cpu id check code lower case aswell
Diffstat (limited to 'ChocolArm64/Memory/MemoryManager.cs')
-rw-r--r-- | ChocolArm64/Memory/MemoryManager.cs | 176 |
1 files changed, 97 insertions, 79 deletions
diff --git a/ChocolArm64/Memory/MemoryManager.cs b/ChocolArm64/Memory/MemoryManager.cs index 1f212568..afb0f651 100644 --- a/ChocolArm64/Memory/MemoryManager.cs +++ b/ChocolArm64/Memory/MemoryManager.cs @@ -1,16 +1,16 @@ using ChocolArm64.Events; using ChocolArm64.Exceptions; using ChocolArm64.Instructions; -using ChocolArm64.State; using System; using System.Collections.Concurrent; -using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; using System.Threading; +using static ChocolArm64.Memory.CompareExchange128; + namespace ChocolArm64.Memory { public unsafe class MemoryManager : IMemory, IDisposable @@ -30,21 +30,6 @@ namespace ChocolArm64.Memory private const int PtLvl0Bit = PageBits + PtLvl1Bits; private const int PtLvl1Bit = PageBits; - private const long ErgMask = (4 << CpuThreadState.ErgSizeLog2) - 1; - - private class ArmMonitor - { - public long Position; - public bool ExState; - - public bool HasExclusiveAccess(long position) - { - return Position == position && ExState; - } - } - - private Dictionary<int, ArmMonitor> _monitors; - private ConcurrentDictionary<long, IntPtr> _observedPages; public IntPtr Ram { get; private set; } @@ -59,8 +44,6 @@ namespace ChocolArm64.Memory public MemoryManager(IntPtr ram) { - _monitors = new Dictionary<int, ArmMonitor>(); - _observedPages = new ConcurrentDictionary<long, IntPtr>(); Ram = ram; @@ -75,104 +58,139 @@ namespace ChocolArm64.Memory } } - public void RemoveMonitor(int core) + internal bool AtomicCompareExchange2xInt32( + long position, + int expectedLow, + int expectedHigh, + int desiredLow, + int desiredHigh) { - lock (_monitors) - { - ClearExclusive(core); + long expected = (uint)expectedLow; + long desired = (uint)desiredLow; - _monitors.Remove(core); - } + expected |= (long)expectedHigh << 32; + desired |= (long)desiredHigh << 32; + + return AtomicCompareExchangeInt64(position, expected, desired); } - public void SetExclusive(int core, long position) + internal bool AtomicCompareExchangeInt128( + long position, + ulong expectedLow, + ulong expectedHigh, + ulong desiredLow, + ulong desiredHigh) { - position &= ~ErgMask; - - lock (_monitors) + if ((position & 0xf) != 0) { - foreach (ArmMonitor mon in _monitors.Values) - { - if (mon.Position == position && mon.ExState) - { - mon.ExState = false; - } - } + AbortWithAlignmentFault(position); + } - if (!_monitors.TryGetValue(core, out ArmMonitor threadMon)) - { - threadMon = new ArmMonitor(); + IntPtr ptr = new IntPtr(TranslateWrite(position)); - _monitors.Add(core, threadMon); - } + return InterlockedCompareExchange128(ptr, expectedLow, expectedHigh, desiredLow, desiredHigh); + } - threadMon.Position = position; - threadMon.ExState = true; + internal Vector128<float> AtomicReadInt128(long position) + { + if ((position & 0xf) != 0) + { + AbortWithAlignmentFault(position); } + + IntPtr ptr = new IntPtr(Translate(position)); + + InterlockedRead128(ptr, out ulong low, out ulong high); + + Vector128<float> vector = default(Vector128<float>); + + vector = VectorHelper.VectorInsertInt(low, vector, 0, 3); + vector = VectorHelper.VectorInsertInt(high, vector, 1, 3); + + return vector; } - public bool TestExclusive(int core, long position) + public bool AtomicCompareExchangeByte(long position, byte expected, byte desired) { - //Note: Any call to this method also should be followed by a - //call to ClearExclusiveForStore if this method returns true. - position &= ~ErgMask; + int* ptr = (int*)Translate(position); - Monitor.Enter(_monitors); + int currentValue = *ptr; - if (!_monitors.TryGetValue(core, out ArmMonitor threadMon)) - { - Monitor.Exit(_monitors); + int expected32 = (currentValue & ~byte.MaxValue) | expected; + int desired32 = (currentValue & ~byte.MaxValue) | desired; - return false; + return Interlocked.CompareExchange(ref *ptr, desired32, expected32) == expected32; + } + + public bool AtomicCompareExchangeInt16(long position, short expected, short desired) + { + if ((position & 1) != 0) + { + AbortWithAlignmentFault(position); } - bool exState = threadMon.HasExclusiveAccess(position); + int* ptr = (int*)Translate(position); + + int currentValue = *ptr; - if (!exState) + int expected32 = (currentValue & ~ushort.MaxValue) | (ushort)expected; + int desired32 = (currentValue & ~ushort.MaxValue) | (ushort)desired; + + return Interlocked.CompareExchange(ref *ptr, desired32, expected32) == expected32; + } + + public bool AtomicCompareExchangeInt32(long position, int expected, int desired) + { + if ((position & 3) != 0) { - Monitor.Exit(_monitors); + AbortWithAlignmentFault(position); } - return exState; + int* ptr = (int*)TranslateWrite(position); + + return Interlocked.CompareExchange(ref *ptr, desired, expected) == expected; } - public void ClearExclusiveForStore(int core) + public bool AtomicCompareExchangeInt64(long position, long expected, long desired) { - if (_monitors.TryGetValue(core, out ArmMonitor threadMon)) + if ((position & 7) != 0) { - threadMon.ExState = false; + AbortWithAlignmentFault(position); } - Monitor.Exit(_monitors); + long* ptr = (long*)TranslateWrite(position); + + return Interlocked.CompareExchange(ref *ptr, desired, expected) == expected; } - public void ClearExclusive(int core) + public int AtomicIncrementInt32(long position) { - lock (_monitors) + if ((position & 3) != 0) { - if (_monitors.TryGetValue(core, out ArmMonitor threadMon)) - { - threadMon.ExState = false; - } + AbortWithAlignmentFault(position); } + + int* ptr = (int*)TranslateWrite(position); + + return Interlocked.Increment(ref *ptr); } - public void WriteInt32ToSharedAddr(long position, int value) + public int AtomicDecrementInt32(long position) { - long maskedPosition = position & ~ErgMask; - - lock (_monitors) + if ((position & 3) != 0) { - foreach (ArmMonitor mon in _monitors.Values) - { - if (mon.Position == maskedPosition && mon.ExState) - { - mon.ExState = false; - } - } - - WriteInt32(position, value); + AbortWithAlignmentFault(position); } + + int* ptr = (int*)TranslateWrite(position); + + return Interlocked.Decrement(ref *ptr); + } + + private void AbortWithAlignmentFault(long position) + { + //TODO: Abort mode and exception support on the CPU. + throw new InvalidOperationException($"Tried to compare exchange a misaligned address 0x{position:X16}."); } public sbyte ReadSByte(long position) |