forked from MeloNX/MeloNX
Fix Memory Crash
This commit is contained in:
parent
0968360e08
commit
ace6616067
Binary file not shown.
@ -7,7 +7,6 @@ namespace Ryujinx.Memory
|
|||||||
[SupportedOSPlatform("ios")]
|
[SupportedOSPlatform("ios")]
|
||||||
static unsafe partial class MachJitWorkaround
|
static unsafe partial class MachJitWorkaround
|
||||||
{
|
{
|
||||||
// Previous imports remain the same
|
|
||||||
[LibraryImport("libc")]
|
[LibraryImport("libc")]
|
||||||
public static partial int mach_task_self();
|
public static partial int mach_task_self();
|
||||||
|
|
||||||
@ -47,16 +46,26 @@ namespace Ryujinx.Memory
|
|||||||
|
|
||||||
private const IntPtr TASK_NULL = 0;
|
private const IntPtr TASK_NULL = 0;
|
||||||
private static readonly IntPtr _selfTask;
|
private static readonly IntPtr _selfTask;
|
||||||
|
private static readonly int DEFAULT_CHUNK_SIZE = 16 * 1024 * 1024;
|
||||||
// Updated to iOS 16KB page size
|
|
||||||
private const int PAGE_SIZE = 16 * 1024;
|
|
||||||
private const ulong PAGE_MASK = ~((ulong)PAGE_SIZE - 1);
|
|
||||||
|
|
||||||
static MachJitWorkaround()
|
static MachJitWorkaround()
|
||||||
{
|
{
|
||||||
_selfTask = mach_task_self();
|
_selfTask = mach_task_self();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int CalculateOptimalChunkSize(int totalSize)
|
||||||
|
{
|
||||||
|
// Dynamically calculate chunk size based on total allocation size
|
||||||
|
// For smaller allocations, use smaller chunks to avoid waste
|
||||||
|
if (totalSize <= DEFAULT_CHUNK_SIZE)
|
||||||
|
{
|
||||||
|
return totalSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
int chunkCount = Math.Max(4, totalSize / DEFAULT_CHUNK_SIZE);
|
||||||
|
return (totalSize + chunkCount - 1) / chunkCount;
|
||||||
|
}
|
||||||
|
|
||||||
private static void HandleMachError(int error, string operation)
|
private static void HandleMachError(int error, string operation)
|
||||||
{
|
{
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
@ -67,30 +76,29 @@ namespace Ryujinx.Memory
|
|||||||
|
|
||||||
private static IntPtr ReallocateBlock(IntPtr address, int size)
|
private static IntPtr ReallocateBlock(IntPtr address, int size)
|
||||||
{
|
{
|
||||||
// Ensure size is page-aligned
|
IntPtr memorySize = (IntPtr)size;
|
||||||
int alignedSize = (int)((((ulong)size + PAGE_SIZE - 1) & PAGE_MASK));
|
|
||||||
|
|
||||||
// Deallocate existing mapping
|
|
||||||
vm_deallocate(_selfTask, address, (IntPtr)alignedSize);
|
|
||||||
|
|
||||||
IntPtr memorySize = (IntPtr)alignedSize;
|
|
||||||
IntPtr memoryObjectPort = IntPtr.Zero;
|
IntPtr memoryObjectPort = IntPtr.Zero;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Create minimal permission memory entry initially
|
// Create memory entry
|
||||||
HandleMachError(
|
HandleMachError(
|
||||||
mach_make_memory_entry_64(
|
mach_make_memory_entry_64(
|
||||||
_selfTask,
|
_selfTask,
|
||||||
&memorySize,
|
&memorySize,
|
||||||
IntPtr.Zero,
|
IntPtr.Zero,
|
||||||
Flags.MAP_MEM_NAMED_CREATE | Flags.MAP_MEM_LEDGER_TAGGED |
|
Flags.MAP_MEM_NAMED_CREATE | Flags.MAP_MEM_LEDGER_TAGGED |
|
||||||
Flags.VM_PROT_READ | Flags.VM_PROT_WRITE, // Don't request execute initially
|
Flags.VM_PROT_READ | Flags.VM_PROT_WRITE | Flags.VM_PROT_EXECUTE,
|
||||||
&memoryObjectPort,
|
&memoryObjectPort,
|
||||||
IntPtr.Zero),
|
IntPtr.Zero),
|
||||||
"make_memory_entry_64");
|
"make_memory_entry_64");
|
||||||
|
|
||||||
// Set no-footprint flag to minimize memory usage
|
if (memorySize != (IntPtr)size)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Memory allocation size mismatch. Requested: {size}, Allocated: {(long)memorySize}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set ownership
|
||||||
HandleMachError(
|
HandleMachError(
|
||||||
mach_memory_entry_ownership(
|
mach_memory_entry_ownership(
|
||||||
memoryObjectPort,
|
memoryObjectPort,
|
||||||
@ -101,21 +109,21 @@ namespace Ryujinx.Memory
|
|||||||
|
|
||||||
IntPtr mapAddress = address;
|
IntPtr mapAddress = address;
|
||||||
|
|
||||||
// Map with minimal initial permissions
|
// Map memory
|
||||||
int result = vm_map(
|
HandleMachError(
|
||||||
_selfTask,
|
vm_map(
|
||||||
&mapAddress,
|
_selfTask,
|
||||||
memorySize,
|
&mapAddress,
|
||||||
IntPtr.Zero,
|
memorySize,
|
||||||
Flags.VM_FLAGS_OVERWRITE,
|
IntPtr.Zero,
|
||||||
memoryObjectPort,
|
Flags.VM_FLAGS_OVERWRITE,
|
||||||
IntPtr.Zero,
|
memoryObjectPort,
|
||||||
0,
|
IntPtr.Zero,
|
||||||
Flags.VM_PROT_READ | Flags.VM_PROT_WRITE,
|
0,
|
||||||
Flags.VM_PROT_READ | Flags.VM_PROT_WRITE | Flags.VM_PROT_EXECUTE, // Allow execute as max protection
|
Flags.VM_PROT_READ | Flags.VM_PROT_WRITE,
|
||||||
Flags.VM_INHERIT_COPY);
|
Flags.VM_PROT_READ | Flags.VM_PROT_WRITE | Flags.VM_PROT_EXECUTE,
|
||||||
|
Flags.VM_INHERIT_COPY),
|
||||||
HandleMachError(result, "vm_map");
|
"vm_map");
|
||||||
|
|
||||||
if (address != mapAddress)
|
if (address != mapAddress)
|
||||||
{
|
{
|
||||||
@ -126,9 +134,9 @@ namespace Ryujinx.Memory
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
// Proper cleanup of memory object port
|
||||||
if (memoryObjectPort != IntPtr.Zero)
|
if (memoryObjectPort != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
// Implement proper cleanup if needed
|
|
||||||
// mach_port_deallocate(_selfTask, memoryObjectPort);
|
// mach_port_deallocate(_selfTask, memoryObjectPort);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -136,44 +144,24 @@ namespace Ryujinx.Memory
|
|||||||
|
|
||||||
public static void ReallocateAreaWithOwnership(IntPtr address, int size)
|
public static void ReallocateAreaWithOwnership(IntPtr address, int size)
|
||||||
{
|
{
|
||||||
if (size <= 0)
|
int chunkSize = CalculateOptimalChunkSize(size);
|
||||||
{
|
IntPtr currentAddress = address;
|
||||||
throw new ArgumentException("Size must be positive", nameof(size));
|
IntPtr endAddress = address + size;
|
||||||
}
|
|
||||||
|
|
||||||
// Align size to 16KB page boundary
|
while (currentAddress < endAddress)
|
||||||
int alignedSize = (int)((((ulong)size + PAGE_SIZE - 1) & PAGE_MASK));
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
ReallocateBlock(address, alignedSize);
|
int blockSize = Math.Min(chunkSize, (int)(endAddress - currentAddress));
|
||||||
}
|
ReallocateBlock(currentAddress, blockSize);
|
||||||
catch (InvalidOperationException)
|
currentAddress += blockSize;
|
||||||
{
|
|
||||||
// If first attempt fails, try with explicit deallocation and retry
|
|
||||||
vm_deallocate(_selfTask, address, (IntPtr)alignedSize);
|
|
||||||
ReallocateBlock(address, alignedSize);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IntPtr AllocateSharedMemory(ulong size, bool reserve)
|
public static IntPtr AllocateSharedMemory(ulong size, bool reserve)
|
||||||
{
|
{
|
||||||
if (size == 0)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Size must be positive", nameof(size));
|
|
||||||
}
|
|
||||||
|
|
||||||
ulong alignedSize = (size + (ulong)PAGE_SIZE - 1) & PAGE_MASK;
|
|
||||||
|
|
||||||
IntPtr address = IntPtr.Zero;
|
IntPtr address = IntPtr.Zero;
|
||||||
HandleMachError(
|
HandleMachError(
|
||||||
vm_allocate(
|
vm_allocate(_selfTask, &address, (IntPtr)size, Flags.VM_FLAGS_ANYWHERE),
|
||||||
_selfTask,
|
|
||||||
&address,
|
|
||||||
(IntPtr)alignedSize,
|
|
||||||
Flags.VM_FLAGS_ANYWHERE),
|
|
||||||
"vm_allocate");
|
"vm_allocate");
|
||||||
|
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,8 +169,7 @@ namespace Ryujinx.Memory
|
|||||||
{
|
{
|
||||||
if (handle != IntPtr.Zero && size > 0)
|
if (handle != IntPtr.Zero && size > 0)
|
||||||
{
|
{
|
||||||
ulong alignedSize = (size + (ulong)PAGE_SIZE - 1) & PAGE_MASK;
|
vm_deallocate(_selfTask, handle, (IntPtr)size);
|
||||||
vm_deallocate(_selfTask, handle, (IntPtr)alignedSize);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,24 +180,18 @@ namespace Ryujinx.Memory
|
|||||||
throw new ArgumentException("Invalid mapping parameters");
|
throw new ArgumentException("Invalid mapping parameters");
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong alignedOffset = srcOffset & PAGE_MASK;
|
IntPtr srcAddress = (IntPtr)((ulong)sharedMemory + srcOffset);
|
||||||
ulong alignedSize = (size + (ulong)PAGE_SIZE - 1) & PAGE_MASK;
|
|
||||||
|
|
||||||
IntPtr srcAddress = (IntPtr)((ulong)sharedMemory + alignedOffset);
|
|
||||||
IntPtr dstAddress = location;
|
IntPtr dstAddress = location;
|
||||||
int curProtection = 0;
|
int curProtection = 0;
|
||||||
int maxProtection = 0;
|
int maxProtection = 0;
|
||||||
|
|
||||||
// Deallocate existing mapping
|
|
||||||
vm_deallocate(_selfTask, location, (IntPtr)alignedSize);
|
|
||||||
|
|
||||||
HandleMachError(
|
HandleMachError(
|
||||||
vm_remap(
|
vm_remap(
|
||||||
_selfTask,
|
_selfTask,
|
||||||
&dstAddress,
|
&dstAddress,
|
||||||
(IntPtr)alignedSize,
|
(IntPtr)size,
|
||||||
IntPtr.Zero,
|
IntPtr.Zero,
|
||||||
Flags.VM_FLAGS_FIXED,
|
Flags.VM_FLAGS_OVERWRITE,
|
||||||
_selfTask,
|
_selfTask,
|
||||||
srcAddress,
|
srcAddress,
|
||||||
0,
|
0,
|
||||||
@ -226,8 +207,7 @@ namespace Ryujinx.Memory
|
|||||||
{
|
{
|
||||||
if (location != IntPtr.Zero && size > 0)
|
if (location != IntPtr.Zero && size > 0)
|
||||||
{
|
{
|
||||||
ulong alignedSize = (size + (ulong)PAGE_SIZE - 1) & PAGE_MASK;
|
vm_deallocate(_selfTask, location, (IntPtr)size);
|
||||||
vm_deallocate(_selfTask, location, (IntPtr)alignedSize);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user