diff --git a/src/SharpEmu.Core/Cpu/Native/DirectExecutionBackend.Imports.cs b/src/SharpEmu.Core/Cpu/Native/DirectExecutionBackend.Imports.cs index a84e1a6..5aae604 100644 --- a/src/SharpEmu.Core/Cpu/Native/DirectExecutionBackend.Imports.cs +++ b/src/SharpEmu.Core/Cpu/Native/DirectExecutionBackend.Imports.cs @@ -231,9 +231,6 @@ public sealed partial class DirectExecutionBackend ProbeReturnRip(num7, num); Console.Error.Flush(); } - ProbeReturnRip(0x0000000800EA020Eul, 999001); - ProbeReturnRip(0x0000000800EA0213ul, 999002); - ProbeReturnRip(0x0000000800EA040Aul, 999003); try { OrbisGen2Result orbisGen2Result; @@ -426,7 +423,20 @@ public sealed partial class DirectExecutionBackend return false; } int num2 = CountDistinctImportLoopValuesFromTail(_importLoopReturnRips, sampleCount, 3); - return num2 <= 2; + if (num2 > 2) + { + return false; + } + int num3 = Math.Min(_importLoopSignatureCount, Math.Max(sampleCount * 8, ImportLoopWideDiversityWindow)); + if (num3 <= sampleCount) + { + return true; + } + if (CountDistinctImportLoopValuesFromTail(_importLoopNidHashes, num3, 3) > 2) + { + return false; + } + return CountDistinctImportLoopValuesFromTail(_importLoopReturnRips, num3, 3) <= 2; } private int CountDistinctImportLoopValuesFromTail(ulong[] source, int sampleCount, int stopAfter) diff --git a/src/SharpEmu.Core/Cpu/Native/DirectExecutionBackend.cs b/src/SharpEmu.Core/Cpu/Native/DirectExecutionBackend.cs index d3ff65c..1d308a4 100644 --- a/src/SharpEmu.Core/Cpu/Native/DirectExecutionBackend.cs +++ b/src/SharpEmu.Core/Cpu/Native/DirectExecutionBackend.cs @@ -13,6 +13,10 @@ namespace SharpEmu.Core.Cpu.Native; public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, IDisposable { + private const int ImportLoopHistoryLength = 2048; + + private const int ImportLoopWideDiversityWindow = 768; + private readonly struct ImportStubEntry { public ulong Address { get; } @@ -89,7 +93,7 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I private const uint PAGE_EXECUTE_READ = 32u; - private const int TlsHandlerRegionSize = 4096; + private const int TlsHandlerRegionSize = 16384; private const ulong TlsModuleAllocStart = 140726751354880uL; @@ -179,11 +183,11 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I private ulong _entryReturnSentinelRip; - private readonly ulong[] _importLoopSignatures = new ulong[192]; + private readonly ulong[] _importLoopSignatures = new ulong[ImportLoopHistoryLength]; - private readonly ulong[] _importLoopNidHashes = new ulong[192]; + private readonly ulong[] _importLoopNidHashes = new ulong[ImportLoopHistoryLength]; - private readonly ulong[] _importLoopReturnRips = new ulong[192]; + private readonly ulong[] _importLoopReturnRips = new ulong[ImportLoopHistoryLength]; private int _importLoopSignatureCount; @@ -601,14 +605,6 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I { return exportName switch { - "_init_env" or - "atexit" or - "strlen" or - "strnlen" or - "strcmp" or - "strncmp" or - "strcpy" or - "strncpy" or "memcpy" or "memmove" or "memset" or diff --git a/src/SharpEmu.Core/Memory/PhysicalVirtualMemory.cs b/src/SharpEmu.Core/Memory/PhysicalVirtualMemory.cs index ee18cae..802515f 100644 --- a/src/SharpEmu.Core/Memory/PhysicalVirtualMemory.cs +++ b/src/SharpEmu.Core/Memory/PhysicalVirtualMemory.cs @@ -40,6 +40,9 @@ public sealed unsafe class PhysicalVirtualMemory : IVirtualMemory, IDisposable [return: MarshalAs(UnmanagedType.Bool)] private static extern bool VirtualProtect(void* lpAddress, nuint dwSize, uint flNewProtect, out uint lpflOldProtect); + [DllImport("kernel32.dll")] + private static extern nuint VirtualQuery(void* lpAddress, out MemoryBasicInformation64 lpBuffer, nuint dwLength); + [DllImport("kernel32.dll")] private static extern void FlushInstructionCache(void* hProcess, void* lpBaseAddress, nuint dwSize); @@ -351,6 +354,11 @@ public sealed unsafe class PhysicalVirtualMemory : IVirtualMemory, IDisposable return true; } + if (!EnsureRangeCommitted((ulong)srcPtr, (ulong)destination.Length, region)) + { + return false; + } + if (!TryTemporarilyProtectForRead((ulong)srcPtr, (ulong)destination.Length, region, out var touchedPages)) { return false; @@ -389,6 +397,11 @@ public sealed unsafe class PhysicalVirtualMemory : IVirtualMemory, IDisposable return true; } + if (!EnsureRangeCommitted((ulong)destPtr, (ulong)source.Length, region)) + { + return false; + } + if (!VirtualProtect(destPtr, (nuint)source.Length, PAGE_EXECUTE_READWRITE, out var oldProtect)) { return false; @@ -494,6 +507,48 @@ public sealed unsafe class PhysicalVirtualMemory : IVirtualMemory, IDisposable return protection is PAGE_EXECUTE or PAGE_EXECUTE_READ or PAGE_EXECUTE_READWRITE or PAGE_EXECUTE_WRITECOPY; } + private static uint GetCommitProtection(MemoryRegion region) + { + return region.IsExecutable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; + } + + private static unsafe bool EnsureRangeCommitted(ulong address, ulong size, MemoryRegion region) + { + if (size == 0 || !region.IsReservedOnly) + { + return true; + } + + var startPage = AlignDown(address, PageSize); + var endPage = AlignUp(address + size, PageSize); + var commitProtection = GetCommitProtection(region); + + for (var pageAddress = startPage; pageAddress < endPage; pageAddress += PageSize) + { + if (VirtualQuery((void*)pageAddress, out var info, (nuint)sizeof(MemoryBasicInformation64)) == 0) + { + return false; + } + + if (info.State == MEM_COMMIT) + { + continue; + } + + if (info.State != MEM_RESERVE) + { + return false; + } + + if (VirtualAlloc((void*)pageAddress, (nuint)PageSize, MEM_COMMIT, commitProtection) == null) + { + return false; + } + } + + return true; + } + private bool TryTemporarilyProtectForRead( ulong address, ulong size, @@ -558,4 +613,17 @@ public sealed unsafe class PhysicalVirtualMemory : IVirtualMemory, IDisposable public bool IsReservedOnly { get; set; } public uint Protection { get; set; } } + + private struct MemoryBasicInformation64 + { + public ulong BaseAddress; + public ulong AllocationBase; + public uint AllocationProtect; + public uint Alignment1; + public ulong RegionSize; + public uint State; + public uint Protect; + public uint Type; + public uint Alignment2; + } } diff --git a/src/SharpEmu.Libs/Kernel/KernelPthreadCompatExports.cs b/src/SharpEmu.Libs/Kernel/KernelPthreadCompatExports.cs index 98fd63c..318a2f7 100644 --- a/src/SharpEmu.Libs/Kernel/KernelPthreadCompatExports.cs +++ b/src/SharpEmu.Libs/Kernel/KernelPthreadCompatExports.cs @@ -258,14 +258,14 @@ public static class KernelPthreadCompatExports ExportName = "scePthreadCondSignal", Target = Generation.Gen4 | Generation.Gen5, LibraryName = "libKernel")] - public static int PthreadCondSignal(CpuContext ctx) => PthreadCondSignalCore(ctx[CpuRegister.Rdi], broadcast: false); + public static int PthreadCondSignal(CpuContext ctx) => PthreadCondSignalCore(ctx, ctx[CpuRegister.Rdi], broadcast: false); [SysAbiExport( Nid = "JGgj7Uvrl+A", ExportName = "scePthreadCondBroadcast", Target = Generation.Gen4 | Generation.Gen5, LibraryName = "libKernel")] - public static int PthreadCondBroadcast(CpuContext ctx) => PthreadCondSignalCore(ctx[CpuRegister.Rdi], broadcast: true); + public static int PthreadCondBroadcast(CpuContext ctx) => PthreadCondSignalCore(ctx, ctx[CpuRegister.Rdi], broadcast: true); [SysAbiExport( Nid = "Op8TBGY5KHg", @@ -279,7 +279,7 @@ public static class KernelPthreadCompatExports ExportName = "pthread_cond_broadcast", Target = Generation.Gen4 | Generation.Gen5, LibraryName = "libKernel")] - public static int PosixPthreadCondBroadcast(CpuContext ctx) => PthreadCondSignalCore(ctx[CpuRegister.Rdi], broadcast: true); + public static int PosixPthreadCondBroadcast(CpuContext ctx) => PthreadCondSignalCore(ctx, ctx[CpuRegister.Rdi], broadcast: true); [SysAbiExport( Nid = "m5-2bsNfv7s", @@ -901,14 +901,14 @@ public static class KernelPthreadCompatExports return waitResult; } - private static int PthreadCondSignalCore(ulong condAddress, bool broadcast) + private static int PthreadCondSignalCore(CpuContext ctx, ulong condAddress, bool broadcast) { if (condAddress == 0) { return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT; } - if (!TryResolveCondState(null, condAddress, createIfZero: false, out _, out var state)) + if (!TryResolveCondState(ctx, condAddress, createIfZero: true, out _, out var state)) { return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND; }