Fix Memory Crash

This commit is contained in:
Stossy11 2024-12-23 20:27:58 +11:00
parent 0968360e08
commit ace6616067
2 changed files with 52 additions and 72 deletions

View File

@ -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);
} }
} }
} }