mirror of
https://git.743378673.xyz/MeloNX/MeloNX.git
synced 2025-06-30 04:16:25 +02:00
bunch of stuff don't push this monstrosity anywhere
actual stuff don't push this monstrosity anywhere
This commit is contained in:
parent
259f5da0fb
commit
59d6ceb9ee
31 changed files with 513 additions and 77 deletions
168
src/Ryujinx.Memory/MachJitWorkaround.cs
Normal file
168
src/Ryujinx.Memory/MachJitWorkaround.cs
Normal file
|
@ -0,0 +1,168 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Ryujinx.Memory
|
||||
{
|
||||
[SupportedOSPlatform("ios")]
|
||||
static unsafe partial class MachJitWorkaround
|
||||
{
|
||||
[LibraryImport("libc")]
|
||||
public static partial int mach_task_self();
|
||||
|
||||
[LibraryImport("libc")]
|
||||
public static partial int mach_make_memory_entry_64(IntPtr target_task, IntPtr* size, IntPtr offset, int permission, IntPtr* object_handle, IntPtr parent_entry);
|
||||
|
||||
[LibraryImport("libc")]
|
||||
public static partial int mach_memory_entry_ownership(IntPtr mem_entry, IntPtr owner, int ledger_tag, int ledger_flags);
|
||||
|
||||
[LibraryImport("libc")]
|
||||
public static partial int vm_map(IntPtr target_task, IntPtr* address, IntPtr size, IntPtr mask, int flags, IntPtr obj, IntPtr offset, int copy, int cur_protection, int max_protection, int inheritance);
|
||||
|
||||
[LibraryImport("libc")]
|
||||
public static partial int vm_allocate(IntPtr target_task, IntPtr* address, IntPtr size, int flags);
|
||||
|
||||
[LibraryImport("libc")]
|
||||
public static partial int vm_deallocate(IntPtr target_task, IntPtr address, IntPtr size);
|
||||
|
||||
[LibraryImport("libc")]
|
||||
public static partial int vm_remap(IntPtr target_task, IntPtr* target_address, IntPtr size, IntPtr mask, int flags, IntPtr src_task, IntPtr src_address, int copy, int* cur_protection, int* max_protection, int inheritance);
|
||||
|
||||
const int MAP_MEM_LEDGER_TAGGED = 0x002000;
|
||||
const int MAP_MEM_NAMED_CREATE = 0x020000;
|
||||
|
||||
const int VM_PROT_READ = 0x01;
|
||||
const int VM_PROT_WRITE = 0x02;
|
||||
const int VM_PROT_EXECUTE = 0x04;
|
||||
|
||||
const int VM_LEDGER_TAG_DEFAULT = 0x00000001;
|
||||
const int VM_LEDGER_FLAG_NO_FOOTPRINT = 0x00000001;
|
||||
|
||||
const int VM_INHERIT_COPY = 1;
|
||||
const int VM_INHERIT_DEFAULT = VM_INHERIT_COPY;
|
||||
|
||||
const int VM_FLAGS_FIXED = 0x0000;
|
||||
const int VM_FLAGS_ANYWHERE = 0x0001;
|
||||
const int VM_FLAGS_OVERWRITE = 0x4000;
|
||||
|
||||
const IntPtr TASK_NULL = 0;
|
||||
|
||||
public static void ReallocateBlock(IntPtr address, int size)
|
||||
{
|
||||
IntPtr selfTask = mach_task_self();
|
||||
IntPtr memorySize = (IntPtr)size;
|
||||
IntPtr memoryObjectPort = IntPtr.Zero;
|
||||
|
||||
int err = mach_make_memory_entry_64(selfTask, &memorySize, 0, MAP_MEM_NAMED_CREATE | MAP_MEM_LEDGER_TAGGED | VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE, &memoryObjectPort, 0);
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
throw new InvalidOperationException($"Make memory entry failed: {err}");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (memorySize != (IntPtr)size)
|
||||
{
|
||||
throw new InvalidOperationException($"Created with size {memorySize} instead of {size}.");
|
||||
}
|
||||
|
||||
err = mach_memory_entry_ownership(memoryObjectPort, TASK_NULL, VM_LEDGER_TAG_DEFAULT, VM_LEDGER_FLAG_NO_FOOTPRINT);
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
throw new InvalidOperationException($"Failed to set ownership: {err}");
|
||||
}
|
||||
|
||||
IntPtr mapAddress = address;
|
||||
|
||||
err = vm_map(
|
||||
selfTask,
|
||||
&mapAddress,
|
||||
memorySize,
|
||||
/*mask=*/ 0,
|
||||
/*flags=*/ VM_FLAGS_OVERWRITE,
|
||||
memoryObjectPort,
|
||||
/*offset=*/ 0,
|
||||
/*copy=*/ 0,
|
||||
VM_PROT_READ | VM_PROT_WRITE,
|
||||
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE,
|
||||
VM_INHERIT_COPY);
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
throw new InvalidOperationException($"Failed to map: {err}");
|
||||
}
|
||||
|
||||
if (address != mapAddress)
|
||||
{
|
||||
throw new InvalidOperationException($"Remap changed address");
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
//mach_port_deallocate(selfTask, memoryObjectPort);
|
||||
}
|
||||
|
||||
Console.WriteLine($"Reallocated an area... {address:x16}");
|
||||
}
|
||||
|
||||
public static void ReallocateAreaWithOwnership(IntPtr address, int size)
|
||||
{
|
||||
int mapChunkSize = 128 * 1024 * 1024;
|
||||
IntPtr endAddress = address + size;
|
||||
IntPtr blockAddress = address;
|
||||
while (blockAddress < endAddress)
|
||||
{
|
||||
int blockSize = Math.Min(mapChunkSize, (int)(endAddress - blockAddress));
|
||||
|
||||
ReallocateBlock(blockAddress, blockSize);
|
||||
|
||||
blockAddress += blockSize;
|
||||
}
|
||||
}
|
||||
|
||||
public static IntPtr AllocateSharedMemory(ulong size, bool reserve)
|
||||
{
|
||||
IntPtr address = 0;
|
||||
|
||||
int err = vm_allocate(mach_task_self(), &address, (IntPtr)size, VM_FLAGS_ANYWHERE);
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
throw new InvalidOperationException($"Failed to allocate shared memory: {err}");
|
||||
}
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
public static void DestroySharedMemory(IntPtr handle, ulong size)
|
||||
{
|
||||
vm_deallocate(mach_task_self(), handle, (IntPtr)size);
|
||||
}
|
||||
|
||||
public static IntPtr MapView(IntPtr sharedMemory, ulong srcOffset, IntPtr location, ulong size)
|
||||
{
|
||||
IntPtr taskSelf = mach_task_self();
|
||||
IntPtr srcAddress = (IntPtr)((ulong)sharedMemory + srcOffset);
|
||||
IntPtr dstAddress = location;
|
||||
|
||||
int cur_protection = 0;
|
||||
int max_protection = 0;
|
||||
|
||||
int err = vm_remap(taskSelf, &dstAddress, (IntPtr)size, 0, VM_FLAGS_OVERWRITE, taskSelf, srcAddress, 0, &cur_protection, &max_protection, VM_INHERIT_DEFAULT);
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
throw new InvalidOperationException($"Failed to allocate remap memory: {err}");
|
||||
}
|
||||
|
||||
return dstAddress;
|
||||
}
|
||||
|
||||
public static void UnmapView(IntPtr location, ulong size)
|
||||
{
|
||||
vm_deallocate(mach_task_self(), location, (IntPtr)size);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -426,7 +426,7 @@ namespace Ryujinx.Memory
|
|||
return OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134);
|
||||
}
|
||||
|
||||
return OperatingSystem.IsLinux() || OperatingSystem.IsMacOS();
|
||||
return OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace Ryujinx.Memory
|
|||
{
|
||||
return MemoryManagementWindows.Allocate((IntPtr)size);
|
||||
}
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS())
|
||||
{
|
||||
return MemoryManagementUnix.Allocate(size, forJit);
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ namespace Ryujinx.Memory
|
|||
{
|
||||
return MemoryManagementWindows.Reserve((IntPtr)size, viewCompatible);
|
||||
}
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS())
|
||||
{
|
||||
return MemoryManagementUnix.Reserve(size, forJit);
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ namespace Ryujinx.Memory
|
|||
{
|
||||
MemoryManagementWindows.Commit(address, (IntPtr)size);
|
||||
}
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS())
|
||||
{
|
||||
MemoryManagementUnix.Commit(address, size, forJit);
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ namespace Ryujinx.Memory
|
|||
{
|
||||
MemoryManagementWindows.Decommit(address, (IntPtr)size);
|
||||
}
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS())
|
||||
{
|
||||
MemoryManagementUnix.Decommit(address, size);
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ namespace Ryujinx.Memory
|
|||
{
|
||||
MemoryManagementWindows.MapView(sharedMemory, srcOffset, address, (IntPtr)size, owner);
|
||||
}
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS())
|
||||
{
|
||||
MemoryManagementUnix.MapView(sharedMemory, srcOffset, address, size);
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ namespace Ryujinx.Memory
|
|||
{
|
||||
MemoryManagementWindows.UnmapView(sharedMemory, address, (IntPtr)size, owner);
|
||||
}
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS())
|
||||
{
|
||||
MemoryManagementUnix.UnmapView(address, size);
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ namespace Ryujinx.Memory
|
|||
{
|
||||
result = MemoryManagementWindows.Reprotect(address, (IntPtr)size, permission, forView);
|
||||
}
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS())
|
||||
{
|
||||
result = MemoryManagementUnix.Reprotect(address, size, permission);
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ namespace Ryujinx.Memory
|
|||
{
|
||||
return MemoryManagementWindows.Free(address, (IntPtr)size);
|
||||
}
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS())
|
||||
{
|
||||
return MemoryManagementUnix.Free(address);
|
||||
}
|
||||
|
@ -145,7 +145,7 @@ namespace Ryujinx.Memory
|
|||
{
|
||||
return MemoryManagementWindows.CreateSharedMemory((IntPtr)size, reserve);
|
||||
}
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS())
|
||||
{
|
||||
return MemoryManagementUnix.CreateSharedMemory(size, reserve);
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ namespace Ryujinx.Memory
|
|||
{
|
||||
MemoryManagementWindows.DestroySharedMemory(handle);
|
||||
}
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS())
|
||||
{
|
||||
MemoryManagementUnix.DestroySharedMemory(handle);
|
||||
}
|
||||
|
@ -177,7 +177,7 @@ namespace Ryujinx.Memory
|
|||
{
|
||||
return MemoryManagementWindows.MapSharedMemory(handle);
|
||||
}
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS())
|
||||
{
|
||||
return MemoryManagementUnix.MapSharedMemory(handle, size);
|
||||
}
|
||||
|
@ -193,7 +193,7 @@ namespace Ryujinx.Memory
|
|||
{
|
||||
MemoryManagementWindows.UnmapSharedMemory(address);
|
||||
}
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
||||
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS())
|
||||
{
|
||||
MemoryManagementUnix.UnmapSharedMemory(address, size);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
using static Ryujinx.Memory.MemoryManagerUnixHelper;
|
||||
|
@ -8,6 +9,7 @@ namespace Ryujinx.Memory
|
|||
{
|
||||
[SupportedOSPlatform("linux")]
|
||||
[SupportedOSPlatform("macos")]
|
||||
[SupportedOSPlatform("ios")]
|
||||
static class MemoryManagementUnix
|
||||
{
|
||||
private static readonly ConcurrentDictionary<IntPtr, ulong> _allocations = new();
|
||||
|
@ -40,7 +42,7 @@ namespace Ryujinx.Memory
|
|||
flags |= MmapFlags.MAP_NORESERVE;
|
||||
}
|
||||
|
||||
if (OperatingSystem.IsMacOSVersionAtLeast(10, 14) && forJit)
|
||||
if (OperatingSystem.IsMacOS() && OperatingSystem.IsMacOSVersionAtLeast(10, 14) && forJit)
|
||||
{
|
||||
flags |= MmapFlags.MAP_JIT_DARWIN;
|
||||
|
||||
|
@ -57,6 +59,11 @@ namespace Ryujinx.Memory
|
|||
throw new SystemException(Marshal.GetLastPInvokeErrorMessage());
|
||||
}
|
||||
|
||||
if (OperatingSystem.IsIOS() && forJit)
|
||||
{
|
||||
MachJitWorkaround.ReallocateAreaWithOwnership(ptr, (int)size);
|
||||
}
|
||||
|
||||
if (!_allocations.TryAdd(ptr, size))
|
||||
{
|
||||
// This should be impossible, kernel shouldn't return an already mapped address.
|
||||
|
@ -70,7 +77,7 @@ namespace Ryujinx.Memory
|
|||
{
|
||||
MmapProts prot = MmapProts.PROT_READ | MmapProts.PROT_WRITE;
|
||||
|
||||
if (OperatingSystem.IsMacOSVersionAtLeast(10, 14) && forJit)
|
||||
if ((OperatingSystem.IsIOS() || OperatingSystem.IsMacOSVersionAtLeast(10, 14)) && forJit)
|
||||
{
|
||||
prot |= MmapProts.PROT_EXEC;
|
||||
}
|
||||
|
@ -134,11 +141,21 @@ namespace Ryujinx.Memory
|
|||
return munmap(address, size) == 0;
|
||||
}
|
||||
|
||||
private static Dictionary<IntPtr, ulong> _sharedMemorySizes = new Dictionary<nint, ulong>();
|
||||
|
||||
public unsafe static IntPtr CreateSharedMemory(ulong size, bool reserve)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (OperatingSystem.IsMacOS())
|
||||
if (OperatingSystem.IsIOS())
|
||||
{
|
||||
IntPtr baseAddress = MachJitWorkaround.AllocateSharedMemory(size, reserve);
|
||||
|
||||
_sharedMemorySizes.Add(baseAddress, size);
|
||||
|
||||
return baseAddress;
|
||||
}
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
byte[] memName = "Ryujinx-XXXXXX"u8.ToArray();
|
||||
|
||||
|
@ -185,27 +202,64 @@ namespace Ryujinx.Memory
|
|||
|
||||
public static void DestroySharedMemory(IntPtr handle)
|
||||
{
|
||||
close(handle.ToInt32());
|
||||
if (OperatingSystem.IsIOS())
|
||||
{
|
||||
if (_sharedMemorySizes.TryGetValue(handle, out ulong size))
|
||||
{
|
||||
MachJitWorkaround.DestroySharedMemory(handle, size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
close(handle.ToInt32());
|
||||
}
|
||||
}
|
||||
|
||||
public static IntPtr MapSharedMemory(IntPtr handle, ulong size)
|
||||
{
|
||||
return Mmap(IntPtr.Zero, size, MmapProts.PROT_READ | MmapProts.PROT_WRITE, MmapFlags.MAP_SHARED, handle.ToInt32(), 0);
|
||||
if (OperatingSystem.IsIOS())
|
||||
{
|
||||
// The base of the shared memory is already mapped - it's the handle.
|
||||
// Views are remapped from it.
|
||||
|
||||
return handle;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Mmap(IntPtr.Zero, size, MmapProts.PROT_READ | MmapProts.PROT_WRITE, MmapFlags.MAP_SHARED, handle.ToInt32(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static void UnmapSharedMemory(IntPtr address, ulong size)
|
||||
{
|
||||
munmap(address, size);
|
||||
if (!OperatingSystem.IsIOS())
|
||||
{
|
||||
munmap(address, size);
|
||||
}
|
||||
}
|
||||
|
||||
public static void MapView(IntPtr sharedMemory, ulong srcOffset, IntPtr location, ulong size)
|
||||
{
|
||||
Mmap(location, size, MmapProts.PROT_READ | MmapProts.PROT_WRITE, MmapFlags.MAP_FIXED | MmapFlags.MAP_SHARED, sharedMemory.ToInt32(), (long)srcOffset);
|
||||
if (OperatingSystem.IsIOS())
|
||||
{
|
||||
MachJitWorkaround.MapView(sharedMemory, srcOffset, location, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
Mmap(location, size, MmapProts.PROT_READ | MmapProts.PROT_WRITE, MmapFlags.MAP_FIXED | MmapFlags.MAP_SHARED, sharedMemory.ToInt32(), (long)srcOffset);
|
||||
}
|
||||
}
|
||||
|
||||
public static void UnmapView(IntPtr location, ulong size)
|
||||
{
|
||||
Mmap(location, size, MmapProts.PROT_NONE, MmapFlags.MAP_FIXED | MmapFlags.MAP_PRIVATE | MmapFlags.MAP_ANONYMOUS | MmapFlags.MAP_NORESERVE, -1, 0);
|
||||
if (OperatingSystem.IsIOS())
|
||||
{
|
||||
MachJitWorkaround.UnmapView(location, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
Mmap(location, size, MmapProts.PROT_NONE, MmapFlags.MAP_FIXED | MmapFlags.MAP_PRIVATE | MmapFlags.MAP_ANONYMOUS | MmapFlags.MAP_NORESERVE, -1, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace Ryujinx.Memory
|
|||
{
|
||||
[SupportedOSPlatform("linux")]
|
||||
[SupportedOSPlatform("macos")]
|
||||
[SupportedOSPlatform("ios")]
|
||||
public static partial class MemoryManagerUnixHelper
|
||||
{
|
||||
[Flags]
|
||||
|
@ -114,7 +115,7 @@ namespace Ryujinx.Memory
|
|||
{
|
||||
result |= MAP_ANONYMOUS_LINUX_GENERIC;
|
||||
}
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
else if (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS())
|
||||
{
|
||||
result |= MAP_ANONYMOUS_DARWIN;
|
||||
}
|
||||
|
@ -130,7 +131,7 @@ namespace Ryujinx.Memory
|
|||
{
|
||||
result |= MAP_NORESERVE_LINUX_GENERIC;
|
||||
}
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
else if (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS())
|
||||
{
|
||||
result |= MAP_NORESERVE_DARWIN;
|
||||
}
|
||||
|
@ -146,7 +147,7 @@ namespace Ryujinx.Memory
|
|||
{
|
||||
result |= MAP_UNLOCKED_LINUX_GENERIC;
|
||||
}
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
else if (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS())
|
||||
{
|
||||
// FIXME: Doesn't exist on Darwin
|
||||
}
|
||||
|
@ -156,7 +157,7 @@ namespace Ryujinx.Memory
|
|||
}
|
||||
}
|
||||
|
||||
if (flags.HasFlag(MmapFlags.MAP_JIT_DARWIN) && OperatingSystem.IsMacOSVersionAtLeast(10, 14))
|
||||
if (flags.HasFlag(MmapFlags.MAP_JIT_DARWIN) && (OperatingSystem.IsIOS() || OperatingSystem.IsMacOSVersionAtLeast(10, 14)))
|
||||
{
|
||||
result |= (int)MmapFlags.MAP_JIT_DARWIN;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue