From 375691b0e0b5e750caaf01b5cf85813634146bd8 Mon Sep 17 00:00:00 2001 From: Gabriel A Date: Sun, 9 Jul 2023 21:28:09 -0300 Subject: [PATCH] Allocate NCE patch region dynamically to avoid not having enough space --- .../AppleHv/DummyDiskCacheLoadState.cs | 17 --- src/Ryujinx.Cpu/AppleHv/HvCpuContext.cs | 7 +- src/Ryujinx.Cpu/DiskCacheLoadState.cs | 2 +- src/Ryujinx.Cpu/ICpuContext.cs | 2 - src/Ryujinx.Cpu/Jit/JitCpuContext.cs | 5 - src/Ryujinx.Cpu/Nce/NceCpuCodePatch.cs | 81 ++++++++++ src/Ryujinx.Cpu/Nce/NceCpuContext.cs | 6 - src/Ryujinx.Cpu/Nce/NcePatcher.cs | 143 +++++------------- src/Ryujinx.HLE/HOS/ArmProcessContext.cs | 6 +- .../HOS/ArmProcessContextFactory.cs | 10 ++ .../HOS/Kernel/Process/IProcessContext.cs | 1 - .../HOS/Kernel/Process/ProcessContext.cs | 4 - .../Loaders/Processes/ProcessLoaderHelper.cs | 29 ++-- 13 files changed, 150 insertions(+), 163 deletions(-) delete mode 100644 src/Ryujinx.Cpu/AppleHv/DummyDiskCacheLoadState.cs create mode 100644 src/Ryujinx.Cpu/Nce/NceCpuCodePatch.cs diff --git a/src/Ryujinx.Cpu/AppleHv/DummyDiskCacheLoadState.cs b/src/Ryujinx.Cpu/AppleHv/DummyDiskCacheLoadState.cs deleted file mode 100644 index 8e775f094..000000000 --- a/src/Ryujinx.Cpu/AppleHv/DummyDiskCacheLoadState.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace Ryujinx.Cpu.AppleHv -{ - public class DummyDiskCacheLoadState : IDiskCacheLoadState - { -#pragma warning disable CS0067 // The event is never used - /// - public event Action StateChanged; -#pragma warning restore CS0067 - - /// - public void Cancel() - { - } - } -} diff --git a/src/Ryujinx.Cpu/AppleHv/HvCpuContext.cs b/src/Ryujinx.Cpu/AppleHv/HvCpuContext.cs index 7c8067189..94b1f6f4c 100644 --- a/src/Ryujinx.Cpu/AppleHv/HvCpuContext.cs +++ b/src/Ryujinx.Cpu/AppleHv/HvCpuContext.cs @@ -33,15 +33,12 @@ namespace Ryujinx.Cpu.AppleHv } /// - public void PatchCodeForNce(ulong textAddress, ulong textSize, ulong patchRegionAddress, ulong patchRegionSize) - { - } - public IDiskCacheLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled) { - return new DummyDiskCacheLoadState(); + return new DiskCacheLoadState(); } + /// public void PrepareCodeRange(ulong address, ulong size) { } diff --git a/src/Ryujinx.Cpu/DiskCacheLoadState.cs b/src/Ryujinx.Cpu/DiskCacheLoadState.cs index 930bd95a1..5882b9a5b 100644 --- a/src/Ryujinx.Cpu/DiskCacheLoadState.cs +++ b/src/Ryujinx.Cpu/DiskCacheLoadState.cs @@ -1,6 +1,6 @@ using System; -namespace Ryujinx.Cpu.Jit +namespace Ryujinx.Cpu { class DiskCacheLoadState : IDiskCacheLoadState { diff --git a/src/Ryujinx.Cpu/ICpuContext.cs b/src/Ryujinx.Cpu/ICpuContext.cs index 011f6ed28..edcebdfc4 100644 --- a/src/Ryujinx.Cpu/ICpuContext.cs +++ b/src/Ryujinx.Cpu/ICpuContext.cs @@ -38,8 +38,6 @@ namespace Ryujinx.Cpu /// Size of the region to be invalidated void InvalidateCacheRegion(ulong address, ulong size); - void PatchCodeForNce(ulong textAddress, ulong textSize, ulong patchRegionAddress, ulong patchRegionSize); - /// /// Loads cached code from disk for a given application. /// diff --git a/src/Ryujinx.Cpu/Jit/JitCpuContext.cs b/src/Ryujinx.Cpu/Jit/JitCpuContext.cs index 0adb6af74..dce0490a4 100644 --- a/src/Ryujinx.Cpu/Jit/JitCpuContext.cs +++ b/src/Ryujinx.Cpu/Jit/JitCpuContext.cs @@ -46,11 +46,6 @@ namespace Ryujinx.Cpu.Jit _translator.InvalidateJitCacheRegion(address, size); } - /// - public void PatchCodeForNce(ulong textAddress, ulong textSize, ulong patchRegionAddress, ulong patchRegionSize) - { - } - /// public IDiskCacheLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled) { diff --git a/src/Ryujinx.Cpu/Nce/NceCpuCodePatch.cs b/src/Ryujinx.Cpu/Nce/NceCpuCodePatch.cs new file mode 100644 index 000000000..bb1f65109 --- /dev/null +++ b/src/Ryujinx.Cpu/Nce/NceCpuCodePatch.cs @@ -0,0 +1,81 @@ +using Ryujinx.Common; +using Ryujinx.Memory; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace Ryujinx.Cpu.Nce +{ + /// + /// Native Code Execution CPU code patch. + /// + public class NceCpuCodePatch + { + private readonly List _code; + + private readonly struct PatchTarget + { + public readonly int TextIndex; + public readonly int PatchStartIndex; + public readonly int PatchBranchIndex; + + public PatchTarget(int textIndex, int patchStartIndex, int patchBranchIndex) + { + TextIndex = textIndex; + PatchStartIndex = patchStartIndex; + PatchBranchIndex = patchBranchIndex; + } + } + + private readonly List _patchTargets; + + /// + public ulong Size => BitUtils.AlignUp((ulong)_code.Count * sizeof(uint), 0x1000UL); + + public NceCpuCodePatch() + { + _code = new(); + _patchTargets = new(); + } + + internal void AddCode(int textIndex, IEnumerable code) + { + int patchStartIndex = _code.Count; + _code.AddRange(code); + _patchTargets.Add(new PatchTarget(textIndex, patchStartIndex, _code.Count - 1)); + } + + /// + public void Write(IVirtualMemoryManager memoryManager, ulong patchAddress, ulong textAddress) + { + uint[] code = _code.ToArray(); + + foreach (var patchTarget in _patchTargets) + { + ulong instPatchStartAddress = patchAddress + (ulong)patchTarget.PatchStartIndex * sizeof(uint); + ulong instPatchBranchAddress = patchAddress + (ulong)patchTarget.PatchBranchIndex * sizeof(uint); + ulong instTextAddress = textAddress + (ulong)patchTarget.TextIndex * sizeof(uint); + + uint prevInst = memoryManager.Read(instTextAddress); + + code[patchTarget.PatchBranchIndex] |= EncodeSImm26_2(checked((int)((long)instTextAddress - (long)instPatchBranchAddress + sizeof(uint)))); + memoryManager.Write(instTextAddress, 0x14000000u | EncodeSImm26_2(checked((int)((long)instPatchStartAddress - (long)instTextAddress)))); + + uint newInst = memoryManager.Read(instTextAddress); + } + + if (Size != 0) + { + memoryManager.Write(patchAddress, MemoryMarshal.Cast(code)); + memoryManager.Reprotect(patchAddress, Size, MemoryPermission.ReadAndExecute); + } + } + + private static uint EncodeSImm26_2(int value) + { + uint imm = (uint)(value >> 2) & 0x3ffffff; + Debug.Assert(((int)imm << 6) >> 4 == value, $"Failed to encode constant 0x{value:X}."); + return imm; + } + } +} \ No newline at end of file diff --git a/src/Ryujinx.Cpu/Nce/NceCpuContext.cs b/src/Ryujinx.Cpu/Nce/NceCpuContext.cs index ca2fcc8bb..7eeed1bc8 100644 --- a/src/Ryujinx.Cpu/Nce/NceCpuContext.cs +++ b/src/Ryujinx.Cpu/Nce/NceCpuContext.cs @@ -129,12 +129,6 @@ namespace Ryujinx.Cpu.Nce { } - /// - public void PatchCodeForNce(ulong textAddress, ulong textSize, ulong patchRegionAddress, ulong patchRegionSize) - { - NcePatcher.Patch(_memoryManager, textAddress, textSize, patchRegionAddress, patchRegionSize); - } - /// public IDiskCacheLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled) { diff --git a/src/Ryujinx.Cpu/Nce/NcePatcher.cs b/src/Ryujinx.Cpu/Nce/NcePatcher.cs index 4c8973063..04a1c16c7 100644 --- a/src/Ryujinx.Cpu/Nce/NcePatcher.cs +++ b/src/Ryujinx.Cpu/Nce/NcePatcher.cs @@ -1,115 +1,70 @@ using Ryujinx.Cpu.Nce.Arm64; -using Ryujinx.Common; using Ryujinx.Common.Logging; -using Ryujinx.Memory; using System; +using System.Runtime.InteropServices; namespace Ryujinx.Cpu.Nce { - static class NcePatcher + public static class NcePatcher { private const int ScratchBaseReg = 19; private const uint IntCalleeSavedRegsMask = 0x1ff80000; // X19 to X28 private const uint FpCalleeSavedRegsMask = 0xff00; // D8 to D15 - private struct Context + public static NceCpuCodePatch CreatePatch(ReadOnlySpan textSection) { - public readonly ICpuMemoryManager MemoryManager; - public ulong PatchRegionAddress; - public ulong PatchRegionSize; + NceCpuCodePatch codePatch = new(); - public Context(ICpuMemoryManager memoryManager, ulong patchRegionAddress, ulong patchRegionSize) + var textUint = MemoryMarshal.Cast(textSection); + + for (int i = 0; i < textUint.Length; i++) { - MemoryManager = memoryManager; - PatchRegionAddress = patchRegionAddress; - PatchRegionSize = patchRegionSize; - } - - public ulong GetPatchWriteAddress(int length) - { - ulong byteLength = (ulong)length * 4; - - if (PatchRegionSize < byteLength) - { - throw new Exception("No enough space for patch."); - } - - ulong address = PatchRegionAddress; - PatchRegionAddress += byteLength; - PatchRegionSize -= byteLength; - - return address; - } - } - - public static void Patch( - ICpuMemoryManager memoryManager, - ulong textAddress, - ulong textSize, - ulong patchRegionAddress, - ulong patchRegionSize) - { - Context context = new Context(memoryManager, patchRegionAddress, patchRegionSize); - - ulong address = textAddress; - while (address < textAddress + textSize) - { - uint inst = memoryManager.Read(address); + uint inst = textUint[i]; + ulong address = (ulong)i * sizeof(uint); if ((inst & ~(0xffffu << 5)) == 0xd4000001u) // svc #0 { uint svcId = (ushort)(inst >> 5); - PatchInstruction(memoryManager, address, WriteSvcPatch(ref context, address, svcId)); + codePatch.AddCode(i, WriteSvcPatch(svcId)); Logger.Debug?.Print(LogClass.Cpu, $"Patched SVC #{svcId} at 0x{address:X}."); } else if ((inst & ~0x1f) == 0xd53bd060) // mrs x0, tpidrro_el0 { uint rd = inst & 0x1f; - PatchInstruction(memoryManager, address, WriteMrsTpidrroEl0Patch(ref context, address, rd)); + codePatch.AddCode(i, WriteMrsTpidrroEl0Patch(rd)); Logger.Debug?.Print(LogClass.Cpu, $"Patched MRS x{rd}, tpidrro_el0 at 0x{address:X}."); } else if ((inst & ~0x1f) == 0xd53bd040) // mrs x0, tpidr_el0 { uint rd = inst & 0x1f; - PatchInstruction(memoryManager, address, WriteMrsTpidrEl0Patch(ref context, address, rd)); + codePatch.AddCode(i, WriteMrsTpidrEl0Patch(rd)); Logger.Debug?.Print(LogClass.Cpu, $"Patched MRS x{rd}, tpidr_el0 at 0x{address:X}."); } else if ((inst & ~0x1f) == 0xd53b0020 && OperatingSystem.IsMacOS()) // mrs x0, ctr_el0 { uint rd = inst & 0x1f; - PatchInstruction(memoryManager, address, WriteMrsCtrEl0Patch(ref context, address, rd)); + codePatch.AddCode(i, WriteMrsCtrEl0Patch(rd)); Logger.Debug?.Print(LogClass.Cpu, $"Patched MRS x{rd}, ctr_el0 at 0x{address:X}."); } else if ((inst & ~0x1f) == 0xd53be020) // mrs x0, cntpct_el0 { uint rd = inst & 0x1f; - PatchInstruction(memoryManager, address, WriteMrsCntpctEl0Patch(ref context, address, rd)); + codePatch.AddCode(i, WriteMrsCntpctEl0Patch(rd)); Logger.Debug?.Print(LogClass.Cpu, $"Patched MRS x{rd}, cntpct_el0 at 0x{address:X}."); } else if ((inst & ~0x1f) == 0xd51bd040) // msr tpidr_el0, x0 { uint rd = inst & 0x1f; - PatchInstruction(memoryManager, address, WriteMsrTpidrEl0Patch(ref context, address, rd)); + codePatch.AddCode(i, WriteMsrTpidrEl0Patch(rd)); Logger.Debug?.Print(LogClass.Cpu, $"Patched MSR tpidr_el0, x{rd} at 0x{address:X}."); } - - address += 4; } - ulong patchRegionConsumed = BitUtils.AlignUp(context.PatchRegionAddress - patchRegionAddress, 0x1000UL); - if (patchRegionConsumed != 0) - { - memoryManager.Reprotect(patchRegionAddress, patchRegionConsumed, MemoryPermission.ReadAndExecute); - } + return codePatch; } - private static void PatchInstruction(ICpuMemoryManager memoryManager, ulong instructionAddress, ulong targetAddress) - { - memoryManager.Write(instructionAddress, 0x14000000u | GetImm26(instructionAddress, targetAddress)); - } - - private static ulong WriteSvcPatch(ref Context context, ulong svcAddress, uint svcId) + private static uint[] WriteSvcPatch(uint svcId) { Assembler asm = new(); @@ -147,31 +102,27 @@ namespace Ryujinx.Cpu.Nce } }, 0xff); - ulong targetAddress = context.GetPatchWriteAddress(asm.CodeWords + sizeof(uint)); + asm.B(0); - asm.B(GetOffset(targetAddress + (ulong)asm.CodeWords * sizeof(uint), svcAddress + sizeof(uint))); - - WriteCode(context.MemoryManager, targetAddress, asm.GetCode()); - - return targetAddress; + return asm.GetCode(); } - private static ulong WriteMrsTpidrroEl0Patch(ref Context context, ulong mrsAddress, uint rd) + private static uint[] WriteMrsTpidrroEl0Patch(uint rd) { - return WriteMrsContextRead(ref context, mrsAddress, rd, NceNativeContext.GetTpidrroEl0Offset()); + return WriteMrsContextRead(rd, NceNativeContext.GetTpidrroEl0Offset()); } - private static ulong WriteMrsTpidrEl0Patch(ref Context context, ulong mrsAddress, uint rd) + private static uint[] WriteMrsTpidrEl0Patch(uint rd) { - return WriteMrsContextRead(ref context, mrsAddress, rd, NceNativeContext.GetTpidrEl0Offset()); + return WriteMrsContextRead(rd, NceNativeContext.GetTpidrEl0Offset()); } - private static ulong WriteMrsCtrEl0Patch(ref Context context, ulong mrsAddress, uint rd) + private static uint[] WriteMrsCtrEl0Patch(uint rd) { - return WriteMrsContextRead(ref context, mrsAddress, rd, NceNativeContext.GetCtrEl0Offset()); + return WriteMrsContextRead(rd, NceNativeContext.GetCtrEl0Offset()); } - private static ulong WriteMrsCntpctEl0Patch(ref Context context, ulong mrsAddress, uint rd) + private static uint[] WriteMrsCntpctEl0Patch(uint rd) { Assembler asm = new(); @@ -188,16 +139,12 @@ namespace Ryujinx.Cpu.Nce asm.LdrRiUn(Gpr((int)rd), ctx, NceNativeContext.GetTempStorageOffset()); }, 1u << (int)rd); - ulong targetAddress = context.GetPatchWriteAddress(asm.CodeWords + sizeof(uint)); + asm.B(0); - asm.B(GetOffset(targetAddress + (ulong)asm.CodeWords * sizeof(uint), mrsAddress + sizeof(uint))); - - WriteCode(context.MemoryManager, targetAddress, asm.GetCode()); - - return targetAddress; + return asm.GetCode(); } - private static ulong WriteMsrTpidrEl0Patch(ref Context context, ulong msrAddress, uint rd) + private static uint[] WriteMsrTpidrEl0Patch(uint rd) { Assembler asm = new(); @@ -213,16 +160,12 @@ namespace Ryujinx.Cpu.Nce rsr.WriteEpilogue(asm); - ulong targetAddress = context.GetPatchWriteAddress(asm.CodeWords + sizeof(uint)); + asm.B(0); - asm.B(GetOffset(targetAddress + (ulong)asm.CodeWords * sizeof(uint), msrAddress + sizeof(uint))); - - WriteCode(context.MemoryManager, targetAddress, asm.GetCode()); - - return targetAddress; + return asm.GetCode(); } - private static ulong WriteMrsContextRead(ref Context context, ulong mrsAddress, uint rd, int contextOffset) + private static uint[] WriteMrsContextRead(uint rd, int contextOffset) { Assembler asm = new(); @@ -240,13 +183,9 @@ namespace Ryujinx.Cpu.Nce asm.LdrRiUn(Gpr((int)rd), Gpr((int)rd), 0); - ulong targetAddress = context.GetPatchWriteAddress(asm.CodeWords + sizeof(uint)); + asm.B(0); - asm.B(GetOffset(targetAddress + (ulong)asm.CodeWords * sizeof(uint), mrsAddress + sizeof(uint))); - - WriteCode(context.MemoryManager, targetAddress, asm.GetCode()); - - return targetAddress; + return asm.GetCode(); } private static void WriteLoadContext(Assembler asm, Operand tmp0, Operand tmp1, Operand tmp2) @@ -404,7 +343,7 @@ namespace Ryujinx.Cpu.Nce rsr.WriteEpilogue(asm); } - public static uint[] GenerateThreadStartCode() + internal static uint[] GenerateThreadStartCode() { Assembler asm = new(); @@ -434,7 +373,7 @@ namespace Ryujinx.Cpu.Nce return asm.GetCode(); } - public static uint[] GenerateSuspendExceptionHandler() + internal static uint[] GenerateSuspendExceptionHandler() { Assembler asm = new(); @@ -486,7 +425,7 @@ namespace Ryujinx.Cpu.Nce return asm.GetCode(); } - public static uint[] GenerateWrapperExceptionHandler(IntPtr oldSignalHandlerSegfaultPtr, IntPtr signalHandlerPtr) + internal static uint[] GenerateWrapperExceptionHandler(IntPtr oldSignalHandlerSegfaultPtr, IntPtr signalHandlerPtr) { Assembler asm = new(); @@ -660,13 +599,5 @@ namespace Ryujinx.Cpu.Nce { return new RegisterSaveRestore((int)IntCalleeSavedRegsMask, unchecked((int)FpCalleeSavedRegsMask), OperandType.FP64, hasCall: true); } - - private static void WriteCode(ICpuMemoryManager memoryManager, ulong address, uint[] code) - { - for (int i = 0; i < code.Length; i++) - { - memoryManager.Write(address + (ulong)i * sizeof(uint), code[i]); - } - } } } \ No newline at end of file diff --git a/src/Ryujinx.HLE/HOS/ArmProcessContext.cs b/src/Ryujinx.HLE/HOS/ArmProcessContext.cs index 1735fcaa4..5219e50ad 100644 --- a/src/Ryujinx.HLE/HOS/ArmProcessContext.cs +++ b/src/Ryujinx.HLE/HOS/ArmProcessContext.cs @@ -3,6 +3,7 @@ using Ryujinx.Cpu; using Ryujinx.Graphics.Gpu; using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.Memory; +using System; namespace Ryujinx.HLE.HOS { @@ -81,11 +82,6 @@ namespace Ryujinx.HLE.HOS _cpuContext.InvalidateCacheRegion(address, size); } - public void PatchCodeForNce(ulong textAddress, ulong textSize, ulong patchRegionAddress, ulong patchRegionSize) - { - _cpuContext.PatchCodeForNce(textAddress, textSize, patchRegionAddress, patchRegionSize); - } - public void Dispose() { if (_memoryManager is IRefCounted rc) diff --git a/src/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs b/src/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs index fc137f0b5..41e6bad19 100644 --- a/src/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs +++ b/src/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs @@ -44,6 +44,16 @@ namespace Ryujinx.HLE.HOS _codeSize = codeSize; } + public static NceCpuCodePatch CreateCodePatchForNce(KernelContext context, bool for64Bit, ReadOnlySpan textSection) + { + if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64 && for64Bit && context.Device.Configuration.UseHypervisor && !OperatingSystem.IsMacOS()) + { + return NcePatcher.CreatePatch(textSection); + } + + return null; + } + public IProcessContext Create(KernelContext context, ulong pid, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler, bool for64Bit) { IArmProcessContext processContext; diff --git a/src/Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs b/src/Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs index 9918c5d73..42e6b6416 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs @@ -14,6 +14,5 @@ namespace Ryujinx.HLE.HOS.Kernel.Process IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks); void Execute(IExecutionContext context, ulong codeAddress); void InvalidateCacheRegion(ulong address, ulong size); - void PatchCodeForNce(ulong textAddress, ulong textSize, ulong patchRegionAddress, ulong patchRegionSize); } } diff --git a/src/Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs b/src/Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs index d91cef4fa..6107487d8 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs @@ -31,10 +31,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process { } - public void PatchCodeForNce(ulong textAddress, ulong textSize, ulong patchRegionAddress, ulong patchRegionSize) - { - } - public void Dispose() { } diff --git a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoaderHelper.cs b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoaderHelper.cs index 8a53a2c82..3f17822c8 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoaderHelper.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoaderHelper.cs @@ -11,6 +11,7 @@ using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Common; using Ryujinx.Common.Logging; +using Ryujinx.Cpu.Nce; using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Common; @@ -133,8 +134,6 @@ namespace Ryujinx.HLE.Loaders.Processes return resultCode; } - private const int ReservedPatchSize = 0x100000; - public static bool LoadKip(KernelContext context, KipExecutable kip) { uint endOffset = kip.DataOffset + (uint)kip.Data.Length; @@ -200,7 +199,7 @@ namespace Ryujinx.HLE.Loaders.Processes } // TODO: Support NCE of KIPs too. - result = LoadIntoMemory(process, kip, codeBaseAddress, 0UL); + result = LoadIntoMemory(process, kip, codeBaseAddress); if (result != Result.Success) { @@ -261,7 +260,7 @@ namespace Ryujinx.HLE.Loaders.Processes _ => "", }).ToUpper()); - ulong[] nsoPatch = new ulong[executables.Length]; + NceCpuCodePatch[] nsoPatch = new NceCpuCodePatch[executables.Length]; ulong[] nsoBase = new ulong[executables.Length]; for (int index = 0; index < executables.Length; index++) @@ -286,9 +285,15 @@ namespace Ryujinx.HLE.Loaders.Processes nsoSize = BitUtils.AlignUp(nsoSize, KPageTableBase.PageSize); - nsoPatch[index] = codeStart + codeSize; + bool for64Bit = ((ProcessCreationFlags)meta.Flags).HasFlag(ProcessCreationFlags.Is64Bit); - codeSize += ReservedPatchSize; + NceCpuCodePatch codePatch = ArmProcessContextFactory.CreateCodePatchForNce(context, for64Bit, nso.Text); + nsoPatch[index] = codePatch; + + if (codePatch != null) + { + codeSize += codePatch.Size; + } nsoBase[index] = codeStart + codeSize; @@ -391,7 +396,7 @@ namespace Ryujinx.HLE.Loaders.Processes resourceLimit, memoryRegion, processContextFactory, - entrypointOffset: ReservedPatchSize); + entrypointOffset: nsoPatch[0]?.Size ?? 0UL); if (result != Result.Success) { @@ -402,12 +407,11 @@ namespace Ryujinx.HLE.Loaders.Processes for (int index = 0; index < executables.Length; index++) { - ulong nsoPatchAddress = process.Context.ReservedSize + nsoPatch[index]; ulong nsoBaseAddress = process.Context.ReservedSize + nsoBase[index]; Logger.Info?.Print(LogClass.Loader, $"Loading image {index} at 0x{nsoBaseAddress:x16}..."); - result = LoadIntoMemory(process, executables[index], nsoBaseAddress, nsoPatchAddress); + result = LoadIntoMemory(process, executables[index], nsoBaseAddress, nsoPatch[index]); if (result != Result.Success) { @@ -447,7 +451,7 @@ namespace Ryujinx.HLE.Loaders.Processes device.System.State.DesiredTitleLanguage); } - private static Result LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress, ulong patchAddress) + private static Result LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress, NceCpuCodePatch codePatch = null) { ulong textStart = baseAddress + image.TextOffset; ulong roStart = baseAddress + image.RoOffset; @@ -467,7 +471,10 @@ namespace Ryujinx.HLE.Loaders.Processes process.CpuMemory.Fill(bssStart, image.BssSize, 0); - process.Context.PatchCodeForNce(textStart, (ulong)image.Text.Length, patchAddress, ReservedPatchSize); + if (codePatch != null) + { + codePatch.Write(process.CpuMemory, baseAddress - codePatch.Size, textStart); + } Result SetProcessMemoryPermission(ulong address, ulong size, KMemoryPermission permission) {