forked from MeloNX/MeloNX
81 lines
2.9 KiB
C#
81 lines
2.9 KiB
C#
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;
|
|
}
|
|
}
|
|
} |