forked from MeloNX/MeloNX
Allocate NCE patch region dynamically to avoid not having enough space
This commit is contained in:
parent
517277a11f
commit
375691b0e0
@ -1,17 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Cpu.AppleHv
|
|
||||||
{
|
|
||||||
public class DummyDiskCacheLoadState : IDiskCacheLoadState
|
|
||||||
{
|
|
||||||
#pragma warning disable CS0067 // The event is never used
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public event Action<LoadState, int, int> StateChanged;
|
|
||||||
#pragma warning restore CS0067
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public void Cancel()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -33,15 +33,12 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void PatchCodeForNce(ulong textAddress, ulong textSize, ulong patchRegionAddress, ulong patchRegionSize)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public IDiskCacheLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled)
|
public IDiskCacheLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled)
|
||||||
{
|
{
|
||||||
return new DummyDiskCacheLoadState();
|
return new DiskCacheLoadState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public void PrepareCodeRange(ulong address, ulong size)
|
public void PrepareCodeRange(ulong address, ulong size)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Cpu.Jit
|
namespace Ryujinx.Cpu
|
||||||
{
|
{
|
||||||
class DiskCacheLoadState : IDiskCacheLoadState
|
class DiskCacheLoadState : IDiskCacheLoadState
|
||||||
{
|
{
|
||||||
|
@ -38,8 +38,6 @@ namespace Ryujinx.Cpu
|
|||||||
/// <param name="size">Size of the region to be invalidated</param>
|
/// <param name="size">Size of the region to be invalidated</param>
|
||||||
void InvalidateCacheRegion(ulong address, ulong size);
|
void InvalidateCacheRegion(ulong address, ulong size);
|
||||||
|
|
||||||
void PatchCodeForNce(ulong textAddress, ulong textSize, ulong patchRegionAddress, ulong patchRegionSize);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads cached code from disk for a given application.
|
/// Loads cached code from disk for a given application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -46,11 +46,6 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
_translator.InvalidateJitCacheRegion(address, size);
|
_translator.InvalidateJitCacheRegion(address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public void PatchCodeForNce(ulong textAddress, ulong textSize, ulong patchRegionAddress, ulong patchRegionSize)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IDiskCacheLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled)
|
public IDiskCacheLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled)
|
||||||
{
|
{
|
||||||
|
81
src/Ryujinx.Cpu/Nce/NceCpuCodePatch.cs
Normal file
81
src/Ryujinx.Cpu/Nce/NceCpuCodePatch.cs
Normal file
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Native Code Execution CPU code patch.
|
||||||
|
/// </summary>
|
||||||
|
public class NceCpuCodePatch
|
||||||
|
{
|
||||||
|
private readonly List<uint> _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<PatchTarget> _patchTargets;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ulong Size => BitUtils.AlignUp((ulong)_code.Count * sizeof(uint), 0x1000UL);
|
||||||
|
|
||||||
|
public NceCpuCodePatch()
|
||||||
|
{
|
||||||
|
_code = new();
|
||||||
|
_patchTargets = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void AddCode(int textIndex, IEnumerable<uint> code)
|
||||||
|
{
|
||||||
|
int patchStartIndex = _code.Count;
|
||||||
|
_code.AddRange(code);
|
||||||
|
_patchTargets.Add(new PatchTarget(textIndex, patchStartIndex, _code.Count - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
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<uint>(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<uint>(instTextAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Size != 0)
|
||||||
|
{
|
||||||
|
memoryManager.Write(patchAddress, MemoryMarshal.Cast<uint, byte>(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -129,12 +129,6 @@ namespace Ryujinx.Cpu.Nce
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public void PatchCodeForNce(ulong textAddress, ulong textSize, ulong patchRegionAddress, ulong patchRegionSize)
|
|
||||||
{
|
|
||||||
NcePatcher.Patch(_memoryManager, textAddress, textSize, patchRegionAddress, patchRegionSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IDiskCacheLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled)
|
public IDiskCacheLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled)
|
||||||
{
|
{
|
||||||
|
@ -1,115 +1,70 @@
|
|||||||
using Ryujinx.Cpu.Nce.Arm64;
|
using Ryujinx.Cpu.Nce.Arm64;
|
||||||
using Ryujinx.Common;
|
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Memory;
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.Cpu.Nce
|
namespace Ryujinx.Cpu.Nce
|
||||||
{
|
{
|
||||||
static class NcePatcher
|
public static class NcePatcher
|
||||||
{
|
{
|
||||||
private const int ScratchBaseReg = 19;
|
private const int ScratchBaseReg = 19;
|
||||||
|
|
||||||
private const uint IntCalleeSavedRegsMask = 0x1ff80000; // X19 to X28
|
private const uint IntCalleeSavedRegsMask = 0x1ff80000; // X19 to X28
|
||||||
private const uint FpCalleeSavedRegsMask = 0xff00; // D8 to D15
|
private const uint FpCalleeSavedRegsMask = 0xff00; // D8 to D15
|
||||||
|
|
||||||
private struct Context
|
public static NceCpuCodePatch CreatePatch(ReadOnlySpan<byte> textSection)
|
||||||
{
|
{
|
||||||
public readonly ICpuMemoryManager MemoryManager;
|
NceCpuCodePatch codePatch = new();
|
||||||
public ulong PatchRegionAddress;
|
|
||||||
public ulong PatchRegionSize;
|
|
||||||
|
|
||||||
public Context(ICpuMemoryManager memoryManager, ulong patchRegionAddress, ulong patchRegionSize)
|
var textUint = MemoryMarshal.Cast<byte, uint>(textSection);
|
||||||
|
|
||||||
|
for (int i = 0; i < textUint.Length; i++)
|
||||||
{
|
{
|
||||||
MemoryManager = memoryManager;
|
uint inst = textUint[i];
|
||||||
PatchRegionAddress = patchRegionAddress;
|
ulong address = (ulong)i * sizeof(uint);
|
||||||
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<uint>(address);
|
|
||||||
|
|
||||||
if ((inst & ~(0xffffu << 5)) == 0xd4000001u) // svc #0
|
if ((inst & ~(0xffffu << 5)) == 0xd4000001u) // svc #0
|
||||||
{
|
{
|
||||||
uint svcId = (ushort)(inst >> 5);
|
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}.");
|
Logger.Debug?.Print(LogClass.Cpu, $"Patched SVC #{svcId} at 0x{address:X}.");
|
||||||
}
|
}
|
||||||
else if ((inst & ~0x1f) == 0xd53bd060) // mrs x0, tpidrro_el0
|
else if ((inst & ~0x1f) == 0xd53bd060) // mrs x0, tpidrro_el0
|
||||||
{
|
{
|
||||||
uint rd = inst & 0x1f;
|
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}.");
|
Logger.Debug?.Print(LogClass.Cpu, $"Patched MRS x{rd}, tpidrro_el0 at 0x{address:X}.");
|
||||||
}
|
}
|
||||||
else if ((inst & ~0x1f) == 0xd53bd040) // mrs x0, tpidr_el0
|
else if ((inst & ~0x1f) == 0xd53bd040) // mrs x0, tpidr_el0
|
||||||
{
|
{
|
||||||
uint rd = inst & 0x1f;
|
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}.");
|
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
|
else if ((inst & ~0x1f) == 0xd53b0020 && OperatingSystem.IsMacOS()) // mrs x0, ctr_el0
|
||||||
{
|
{
|
||||||
uint rd = inst & 0x1f;
|
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}.");
|
Logger.Debug?.Print(LogClass.Cpu, $"Patched MRS x{rd}, ctr_el0 at 0x{address:X}.");
|
||||||
}
|
}
|
||||||
else if ((inst & ~0x1f) == 0xd53be020) // mrs x0, cntpct_el0
|
else if ((inst & ~0x1f) == 0xd53be020) // mrs x0, cntpct_el0
|
||||||
{
|
{
|
||||||
uint rd = inst & 0x1f;
|
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}.");
|
Logger.Debug?.Print(LogClass.Cpu, $"Patched MRS x{rd}, cntpct_el0 at 0x{address:X}.");
|
||||||
}
|
}
|
||||||
else if ((inst & ~0x1f) == 0xd51bd040) // msr tpidr_el0, x0
|
else if ((inst & ~0x1f) == 0xd51bd040) // msr tpidr_el0, x0
|
||||||
{
|
{
|
||||||
uint rd = inst & 0x1f;
|
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}.");
|
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);
|
return codePatch;
|
||||||
if (patchRegionConsumed != 0)
|
|
||||||
{
|
|
||||||
memoryManager.Reprotect(patchRegionAddress, patchRegionConsumed, MemoryPermission.ReadAndExecute);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void PatchInstruction(ICpuMemoryManager memoryManager, ulong instructionAddress, ulong targetAddress)
|
private static uint[] WriteSvcPatch(uint svcId)
|
||||||
{
|
|
||||||
memoryManager.Write(instructionAddress, 0x14000000u | GetImm26(instructionAddress, targetAddress));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ulong WriteSvcPatch(ref Context context, ulong svcAddress, uint svcId)
|
|
||||||
{
|
{
|
||||||
Assembler asm = new();
|
Assembler asm = new();
|
||||||
|
|
||||||
@ -147,31 +102,27 @@ namespace Ryujinx.Cpu.Nce
|
|||||||
}
|
}
|
||||||
}, 0xff);
|
}, 0xff);
|
||||||
|
|
||||||
ulong targetAddress = context.GetPatchWriteAddress(asm.CodeWords + sizeof(uint));
|
asm.B(0);
|
||||||
|
|
||||||
asm.B(GetOffset(targetAddress + (ulong)asm.CodeWords * sizeof(uint), svcAddress + sizeof(uint)));
|
return asm.GetCode();
|
||||||
|
|
||||||
WriteCode(context.MemoryManager, targetAddress, asm.GetCode());
|
|
||||||
|
|
||||||
return targetAddress;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
Assembler asm = new();
|
||||||
|
|
||||||
@ -188,16 +139,12 @@ namespace Ryujinx.Cpu.Nce
|
|||||||
asm.LdrRiUn(Gpr((int)rd), ctx, NceNativeContext.GetTempStorageOffset());
|
asm.LdrRiUn(Gpr((int)rd), ctx, NceNativeContext.GetTempStorageOffset());
|
||||||
}, 1u << (int)rd);
|
}, 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)));
|
return asm.GetCode();
|
||||||
|
|
||||||
WriteCode(context.MemoryManager, targetAddress, asm.GetCode());
|
|
||||||
|
|
||||||
return targetAddress;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ulong WriteMsrTpidrEl0Patch(ref Context context, ulong msrAddress, uint rd)
|
private static uint[] WriteMsrTpidrEl0Patch(uint rd)
|
||||||
{
|
{
|
||||||
Assembler asm = new();
|
Assembler asm = new();
|
||||||
|
|
||||||
@ -213,16 +160,12 @@ namespace Ryujinx.Cpu.Nce
|
|||||||
|
|
||||||
rsr.WriteEpilogue(asm);
|
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)));
|
return asm.GetCode();
|
||||||
|
|
||||||
WriteCode(context.MemoryManager, targetAddress, asm.GetCode());
|
|
||||||
|
|
||||||
return targetAddress;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ulong WriteMrsContextRead(ref Context context, ulong mrsAddress, uint rd, int contextOffset)
|
private static uint[] WriteMrsContextRead(uint rd, int contextOffset)
|
||||||
{
|
{
|
||||||
Assembler asm = new();
|
Assembler asm = new();
|
||||||
|
|
||||||
@ -240,13 +183,9 @@ namespace Ryujinx.Cpu.Nce
|
|||||||
|
|
||||||
asm.LdrRiUn(Gpr((int)rd), Gpr((int)rd), 0);
|
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)));
|
return asm.GetCode();
|
||||||
|
|
||||||
WriteCode(context.MemoryManager, targetAddress, asm.GetCode());
|
|
||||||
|
|
||||||
return targetAddress;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteLoadContext(Assembler asm, Operand tmp0, Operand tmp1, Operand tmp2)
|
private static void WriteLoadContext(Assembler asm, Operand tmp0, Operand tmp1, Operand tmp2)
|
||||||
@ -404,7 +343,7 @@ namespace Ryujinx.Cpu.Nce
|
|||||||
rsr.WriteEpilogue(asm);
|
rsr.WriteEpilogue(asm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static uint[] GenerateThreadStartCode()
|
internal static uint[] GenerateThreadStartCode()
|
||||||
{
|
{
|
||||||
Assembler asm = new();
|
Assembler asm = new();
|
||||||
|
|
||||||
@ -434,7 +373,7 @@ namespace Ryujinx.Cpu.Nce
|
|||||||
return asm.GetCode();
|
return asm.GetCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static uint[] GenerateSuspendExceptionHandler()
|
internal static uint[] GenerateSuspendExceptionHandler()
|
||||||
{
|
{
|
||||||
Assembler asm = new();
|
Assembler asm = new();
|
||||||
|
|
||||||
@ -486,7 +425,7 @@ namespace Ryujinx.Cpu.Nce
|
|||||||
return asm.GetCode();
|
return asm.GetCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static uint[] GenerateWrapperExceptionHandler(IntPtr oldSignalHandlerSegfaultPtr, IntPtr signalHandlerPtr)
|
internal static uint[] GenerateWrapperExceptionHandler(IntPtr oldSignalHandlerSegfaultPtr, IntPtr signalHandlerPtr)
|
||||||
{
|
{
|
||||||
Assembler asm = new();
|
Assembler asm = new();
|
||||||
|
|
||||||
@ -660,13 +599,5 @@ namespace Ryujinx.Cpu.Nce
|
|||||||
{
|
{
|
||||||
return new RegisterSaveRestore((int)IntCalleeSavedRegsMask, unchecked((int)FpCalleeSavedRegsMask), OperandType.FP64, hasCall: true);
|
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]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,6 +3,7 @@ using Ryujinx.Cpu;
|
|||||||
using Ryujinx.Graphics.Gpu;
|
using Ryujinx.Graphics.Gpu;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS
|
namespace Ryujinx.HLE.HOS
|
||||||
{
|
{
|
||||||
@ -81,11 +82,6 @@ namespace Ryujinx.HLE.HOS
|
|||||||
_cpuContext.InvalidateCacheRegion(address, size);
|
_cpuContext.InvalidateCacheRegion(address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PatchCodeForNce(ulong textAddress, ulong textSize, ulong patchRegionAddress, ulong patchRegionSize)
|
|
||||||
{
|
|
||||||
_cpuContext.PatchCodeForNce(textAddress, textSize, patchRegionAddress, patchRegionSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (_memoryManager is IRefCounted rc)
|
if (_memoryManager is IRefCounted rc)
|
||||||
|
@ -44,6 +44,16 @@ namespace Ryujinx.HLE.HOS
|
|||||||
_codeSize = codeSize;
|
_codeSize = codeSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static NceCpuCodePatch CreateCodePatchForNce(KernelContext context, bool for64Bit, ReadOnlySpan<byte> 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)
|
public IProcessContext Create(KernelContext context, ulong pid, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler, bool for64Bit)
|
||||||
{
|
{
|
||||||
IArmProcessContext processContext;
|
IArmProcessContext processContext;
|
||||||
|
@ -14,6 +14,5 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||||||
IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks);
|
IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks);
|
||||||
void Execute(IExecutionContext context, ulong codeAddress);
|
void Execute(IExecutionContext context, ulong codeAddress);
|
||||||
void InvalidateCacheRegion(ulong address, ulong size);
|
void InvalidateCacheRegion(ulong address, ulong size);
|
||||||
void PatchCodeForNce(ulong textAddress, ulong textSize, ulong patchRegionAddress, ulong patchRegionSize);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,10 +31,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PatchCodeForNce(ulong textAddress, ulong textSize, ulong patchRegionAddress, ulong patchRegionSize)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ using LibHac.Tools.FsSystem;
|
|||||||
using LibHac.Tools.FsSystem.NcaUtils;
|
using LibHac.Tools.FsSystem.NcaUtils;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Cpu.Nce;
|
||||||
using Ryujinx.HLE.HOS;
|
using Ryujinx.HLE.HOS;
|
||||||
using Ryujinx.HLE.HOS.Kernel;
|
using Ryujinx.HLE.HOS.Kernel;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||||
@ -133,8 +134,6 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
return resultCode;
|
return resultCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
private const int ReservedPatchSize = 0x100000;
|
|
||||||
|
|
||||||
public static bool LoadKip(KernelContext context, KipExecutable kip)
|
public static bool LoadKip(KernelContext context, KipExecutable kip)
|
||||||
{
|
{
|
||||||
uint endOffset = kip.DataOffset + (uint)kip.Data.Length;
|
uint endOffset = kip.DataOffset + (uint)kip.Data.Length;
|
||||||
@ -200,7 +199,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Support NCE of KIPs too.
|
// TODO: Support NCE of KIPs too.
|
||||||
result = LoadIntoMemory(process, kip, codeBaseAddress, 0UL);
|
result = LoadIntoMemory(process, kip, codeBaseAddress);
|
||||||
|
|
||||||
if (result != Result.Success)
|
if (result != Result.Success)
|
||||||
{
|
{
|
||||||
@ -261,7 +260,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
_ => "",
|
_ => "",
|
||||||
}).ToUpper());
|
}).ToUpper());
|
||||||
|
|
||||||
ulong[] nsoPatch = new ulong[executables.Length];
|
NceCpuCodePatch[] nsoPatch = new NceCpuCodePatch[executables.Length];
|
||||||
ulong[] nsoBase = new ulong[executables.Length];
|
ulong[] nsoBase = new ulong[executables.Length];
|
||||||
|
|
||||||
for (int index = 0; index < executables.Length; index++)
|
for (int index = 0; index < executables.Length; index++)
|
||||||
@ -286,9 +285,15 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
|
|
||||||
nsoSize = BitUtils.AlignUp<uint>(nsoSize, KPageTableBase.PageSize);
|
nsoSize = BitUtils.AlignUp<uint>(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;
|
nsoBase[index] = codeStart + codeSize;
|
||||||
|
|
||||||
@ -391,7 +396,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
resourceLimit,
|
resourceLimit,
|
||||||
memoryRegion,
|
memoryRegion,
|
||||||
processContextFactory,
|
processContextFactory,
|
||||||
entrypointOffset: ReservedPatchSize);
|
entrypointOffset: nsoPatch[0]?.Size ?? 0UL);
|
||||||
|
|
||||||
if (result != Result.Success)
|
if (result != Result.Success)
|
||||||
{
|
{
|
||||||
@ -402,12 +407,11 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
|
|
||||||
for (int index = 0; index < executables.Length; index++)
|
for (int index = 0; index < executables.Length; index++)
|
||||||
{
|
{
|
||||||
ulong nsoPatchAddress = process.Context.ReservedSize + nsoPatch[index];
|
|
||||||
ulong nsoBaseAddress = process.Context.ReservedSize + nsoBase[index];
|
ulong nsoBaseAddress = process.Context.ReservedSize + nsoBase[index];
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.Loader, $"Loading image {index} at 0x{nsoBaseAddress:x16}...");
|
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)
|
if (result != Result.Success)
|
||||||
{
|
{
|
||||||
@ -447,7 +451,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
device.System.State.DesiredTitleLanguage);
|
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 textStart = baseAddress + image.TextOffset;
|
||||||
ulong roStart = baseAddress + image.RoOffset;
|
ulong roStart = baseAddress + image.RoOffset;
|
||||||
@ -467,7 +471,10 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
|
|
||||||
process.CpuMemory.Fill(bssStart, image.BssSize, 0);
|
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)
|
Result SetProcessMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user