sharpemu/tests/SharpEmu.Libs.Tests/Agc/AgcIndirectPatchTests.cs

132 lines
5.0 KiB
C#

// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using System.Buffers.Binary;
using SharpEmu.HLE;
using SharpEmu.Libs.Agc;
using Xunit;
namespace SharpEmu.Libs.Tests.Agc;
public sealed class AgcIndirectPatchTests
{
private const ulong BaseAddress = 0x2_2000_0000;
private const ulong CommandAddress = BaseAddress + 0x100;
private const uint SetContextRegIndirectHeader = 0xC003_9F00u;
[Fact]
public void SetCxRegisterCount_ReplacesCountAndPreservesOtherFields()
{
var memory = new FakeCpuMemory(BaseAddress, 0x1000);
var ctx = new CpuContext(memory, Generation.Gen5);
WriteUInt32(memory, CommandAddress, SetContextRegIndirectHeader);
WriteUInt64(memory, CommandAddress + 4, 0x5566_7788_99AA_BBCC);
WriteUInt32(memory, CommandAddress + 12, 0x8000_0000u);
WriteUInt32(memory, CommandAddress + 16, 0xCAFE_0003u);
ctx[CpuRegister.Rdi] = CommandAddress;
ctx[CpuRegister.Rsi] = 0x4C;
var result = AgcExports.SetCxRegIndirectPatchSetNumRegisters(ctx);
Assert.Equal((int)OrbisGen2Result.ORBIS_GEN2_OK, result);
Assert.Equal(0UL, ctx[CpuRegister.Rax]);
Assert.Equal(SetContextRegIndirectHeader, ReadUInt32(memory, CommandAddress));
Assert.Equal(0x5566_7788_99AA_BBCCUL, ReadUInt64(memory, CommandAddress + 4));
Assert.Equal(0x8000_0000u, ReadUInt32(memory, CommandAddress + 12));
Assert.Equal(0xCAFE_004Cu, ReadUInt32(memory, CommandAddress + 16));
}
[Fact]
public void SetCxRegisterCount_AllowsZeroAndAddRegistersUsesNewCount()
{
var memory = new FakeCpuMemory(BaseAddress, 0x1000);
var ctx = new CpuContext(memory, Generation.Gen5);
WriteUInt32(memory, CommandAddress, SetContextRegIndirectHeader);
WriteUInt32(memory, CommandAddress + 16, 9);
ctx[CpuRegister.Rdi] = CommandAddress;
ctx[CpuRegister.Rsi] = 0;
Assert.Equal(
(int)OrbisGen2Result.ORBIS_GEN2_OK,
AgcExports.SetCxRegIndirectPatchSetNumRegisters(ctx));
Assert.Equal(0u, ReadUInt32(memory, CommandAddress + 16));
ctx[CpuRegister.Rsi] = 7;
Assert.Equal(
(int)OrbisGen2Result.ORBIS_GEN2_OK,
AgcExports.SetCxRegIndirectPatchAddRegisters(ctx));
Assert.Equal(7u, ReadUInt32(memory, CommandAddress + 16));
}
[Fact]
public void SetCxAddress_PatchesNativeAddressAndPreservesLowControlBits()
{
var memory = new FakeCpuMemory(BaseAddress, 0x1000);
var ctx = new CpuContext(memory, Generation.Gen5);
WriteUInt32(memory, CommandAddress, SetContextRegIndirectHeader);
WriteUInt32(memory, CommandAddress + 4, 3u);
WriteUInt32(memory, CommandAddress + 8, 0u);
ctx[CpuRegister.Rdi] = CommandAddress;
ctx[CpuRegister.Rsi] = 0x0000_0002_3456_789CUL;
var result = AgcExports.SetCxRegIndirectPatchSetAddress(ctx);
Assert.Equal((int)OrbisGen2Result.ORBIS_GEN2_OK, result);
Assert.Equal(0x0000_0002_3456_789FUL, ReadUInt64(memory, CommandAddress + 4));
}
[Fact]
public void SetCxRegisterCount_RejectsNullCommandAddress()
{
var memory = new FakeCpuMemory(BaseAddress, 0x1000);
var ctx = new CpuContext(memory, Generation.Gen5);
ctx[CpuRegister.Rdi] = 0;
ctx[CpuRegister.Rsi] = 4;
Assert.Equal(
(int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT,
AgcExports.SetCxRegIndirectPatchSetNumRegisters(ctx));
}
[Fact]
public void SetCxRegisterCount_ReturnsMemoryFaultForInvalidGuestMemory()
{
var memory = new FakeCpuMemory(BaseAddress, 0x1000);
var ctx = new CpuContext(memory, Generation.Gen5);
ctx[CpuRegister.Rdi] = BaseAddress + 0x1000;
ctx[CpuRegister.Rsi] = 4;
Assert.Equal(
(int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT,
AgcExports.SetCxRegIndirectPatchSetNumRegisters(ctx));
}
private static uint ReadUInt32(FakeCpuMemory memory, ulong address)
{
Span<byte> buffer = stackalloc byte[sizeof(uint)];
Assert.True(memory.TryRead(address, buffer));
return BinaryPrimitives.ReadUInt32LittleEndian(buffer);
}
private static ulong ReadUInt64(FakeCpuMemory memory, ulong address)
{
Span<byte> buffer = stackalloc byte[sizeof(ulong)];
Assert.True(memory.TryRead(address, buffer));
return BinaryPrimitives.ReadUInt64LittleEndian(buffer);
}
private static void WriteUInt32(FakeCpuMemory memory, ulong address, uint value)
{
Span<byte> buffer = stackalloc byte[sizeof(uint)];
BinaryPrimitives.WriteUInt32LittleEndian(buffer, value);
Assert.True(memory.TryWrite(address, buffer));
}
private static void WriteUInt64(FakeCpuMemory memory, ulong address, ulong value)
{
Span<byte> buffer = stackalloc byte[sizeof(ulong)];
BinaryPrimitives.WriteUInt64LittleEndian(buffer, value);
Assert.True(memory.TryWrite(address, buffer));
}
}