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)
{