diff options
Diffstat (limited to 'src/Ryujinx.Cpu')
| -rw-r--r-- | src/Ryujinx.Cpu/AppleHv/HvCodePatcher.cs | 62 | ||||
| -rw-r--r-- | src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs | 33 | ||||
| -rw-r--r-- | src/Ryujinx.Cpu/Jit/MemoryManager.cs | 21 | ||||
| -rw-r--r-- | src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs | 6 |
4 files changed, 91 insertions, 31 deletions
diff --git a/src/Ryujinx.Cpu/AppleHv/HvCodePatcher.cs b/src/Ryujinx.Cpu/AppleHv/HvCodePatcher.cs new file mode 100644 index 00000000..876597b7 --- /dev/null +++ b/src/Ryujinx.Cpu/AppleHv/HvCodePatcher.cs @@ -0,0 +1,62 @@ +using System; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; + +namespace Ryujinx.Cpu.AppleHv +{ + static class HvCodePatcher + { + private const uint XMask = 0x3f808000u; + private const uint XValue = 0x8000000u; + + private const uint ZrIndex = 31u; + + public static void RewriteUnorderedExclusiveInstructions(Span<byte> code) + { + Span<uint> codeUint = MemoryMarshal.Cast<byte, uint>(code); + Span<Vector128<uint>> codeVector = MemoryMarshal.Cast<byte, Vector128<uint>>(code); + + Vector128<uint> mask = Vector128.Create(XMask); + Vector128<uint> value = Vector128.Create(XValue); + + for (int index = 0; index < codeVector.Length; index++) + { + Vector128<uint> v = codeVector[index]; + + if (Vector128.EqualsAny(Vector128.BitwiseAnd(v, mask), value)) + { + int baseIndex = index * 4; + + for (int instIndex = baseIndex; instIndex < baseIndex + 4; instIndex++) + { + ref uint inst = ref codeUint[instIndex]; + + if ((inst & XMask) != XValue) + { + continue; + } + + bool isPair = (inst & (1u << 21)) != 0; + bool isLoad = (inst & (1u << 22)) != 0; + + uint rt2 = (inst >> 10) & 0x1fu; + uint rs = (inst >> 16) & 0x1fu; + + if (isLoad && rs != ZrIndex) + { + continue; + } + + if (!isPair && rt2 != ZrIndex) + { + continue; + } + + // Set the ordered flag. + inst |= 1u << 15; + } + } + } + } + } +} diff --git a/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs b/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs index d5ce817a..947c3710 100644 --- a/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs +++ b/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs @@ -128,21 +128,6 @@ namespace Ryujinx.Cpu.AppleHv } } -#pragma warning disable IDE0051 // Remove unused private member - /// <summary> - /// Ensures the combination of virtual address and size is part of the addressable space and fully mapped. - /// </summary> - /// <param name="va">Virtual address of the range</param> - /// <param name="size">Size of the range in bytes</param> - private void AssertMapped(ulong va, ulong size) - { - if (!ValidateAddressAndSize(va, size) || !IsRangeMappedImpl(va, size)) - { - throw new InvalidMemoryRegionException($"Not mapped: va=0x{va:X16}, size=0x{size:X16}"); - } - } -#pragma warning restore IDE0051 - /// <inheritdoc/> public void Map(ulong va, ulong pa, ulong size, MemoryMapFlags flags) { @@ -737,6 +722,24 @@ namespace Ryujinx.Cpu.AppleHv } /// <inheritdoc/> + public void Reprotect(ulong va, ulong size, MemoryPermission protection) + { + if (protection.HasFlag(MemoryPermission.Execute)) + { + // Some applications use unordered exclusive memory access instructions + // where it is not valid to do so, leading to memory re-ordering that + // makes the code behave incorrectly on some CPUs. + // To work around this, we force all such accesses to be ordered. + + using WritableRegion writableRegion = GetWritableRegion(va, (int)size); + + HvCodePatcher.RewriteUnorderedExclusiveInstructions(writableRegion.Memory.Span); + } + + // TODO + } + + /// <inheritdoc/> public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection) { // Protection is inverted on software pages, since the default value is 0. diff --git a/src/Ryujinx.Cpu/Jit/MemoryManager.cs b/src/Ryujinx.Cpu/Jit/MemoryManager.cs index 1c27e97f..912e3f7e 100644 --- a/src/Ryujinx.Cpu/Jit/MemoryManager.cs +++ b/src/Ryujinx.Cpu/Jit/MemoryManager.cs @@ -575,22 +575,15 @@ namespace Ryujinx.Cpu.Jit } } -#pragma warning disable IDE0051 // Remove unused private member - private ulong GetPhysicalAddress(ulong va) + private ulong GetPhysicalAddressInternal(ulong va) { - // We return -1L if the virtual address is invalid or unmapped. - if (!ValidateAddress(va) || !IsMapped(va)) - { - return ulong.MaxValue; - } - - return GetPhysicalAddressInternal(va); + return PteToPa(_pageTable.Read<ulong>((va / PageSize) * PteSize) & ~(0xffffUL << 48)) + (va & PageMask); } -#pragma warning restore IDE0051 - private ulong GetPhysicalAddressInternal(ulong va) + /// <inheritdoc/> + public void Reprotect(ulong va, ulong size, MemoryPermission protection) { - return PteToPa(_pageTable.Read<ulong>((va / PageSize) * PteSize) & ~(0xffffUL << 48)) + (va & PageMask); + // TODO } /// <inheritdoc/> @@ -698,9 +691,5 @@ namespace Ryujinx.Cpu.Jit /// Disposes of resources used by the memory manager. /// </summary> protected override void Destroy() => _pageTable.Dispose(); - -#pragma warning disable IDE0051 // Remove unused private member - private static void ThrowInvalidMemoryRegionException(string message) => throw new InvalidMemoryRegionException(message); -#pragma warning restore IDE0051 } } diff --git a/src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs b/src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs index 010a0bc2..6d32787a 100644 --- a/src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs +++ b/src/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs @@ -616,6 +616,12 @@ namespace Ryujinx.Cpu.Jit } /// <inheritdoc/> + public void Reprotect(ulong va, ulong size, MemoryPermission protection) + { + // TODO + } + + /// <inheritdoc/> public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection) { // Protection is inverted on software pages, since the default value is 0. |
