[Tests] Cover backward red-zone spans, direct memory no-space results and the mount info size

This commit is contained in:
ParantezTech 2026-10-09 01:27:52 +03:00
parent ee9660d81d
commit 0666071f79
3 changed files with 104 additions and 10 deletions

View File

@ -436,6 +436,50 @@ public sealed class KernelMemoryCompatExportsTests
}
}
[Fact]
public void AvailableDirectMemorySize_FullRangeClearsOutputsAndReportsNoSpace()
{
const ulong allocationStart = 0;
const ulong allocationLength = 0x0040_0000;
var context = new CpuContext(new FakeCpuMemory(GuestMemoryBase, 0x1000), Generation.Gen5);
try
{
AllocateDirectMemory(context, allocationStart, allocationLength);
Assert.True(context.TryWriteUInt64(SpanStartOutAddress, 0xDEAD_BEEF));
Assert.True(context.TryWriteUInt64(SpanSizeOutAddress, 0xDEAD_BEEF));
context[CpuRegister.Rdi] = allocationStart;
context[CpuRegister.Rsi] = allocationStart + allocationLength;
context[CpuRegister.Rdx] = 0;
context[CpuRegister.Rcx] = SpanStartOutAddress;
context[CpuRegister.R8] = SpanSizeOutAddress;
Assert.Equal(unchecked((int)0x8002000C), KernelMemoryCompatExports.KernelAvailableDirectMemorySize(context));
Assert.True(context.TryReadUInt64(SpanStartOutAddress, out var spanStart));
Assert.True(context.TryReadUInt64(SpanSizeOutAddress, out var spanSize));
Assert.Equal(0UL, spanStart);
Assert.Equal(0UL, spanSize);
}
finally
{
ReleaseDirectMemory(context, allocationStart, allocationLength);
}
}
[Fact]
public void AvailableDirectMemorySize_EmptySearchRangeReportsNoSpace()
{
var context = new CpuContext(new FakeCpuMemory(GuestMemoryBase, 0x1000), Generation.Gen5);
context[CpuRegister.Rdi] = 0x0010_0000;
context[CpuRegister.Rsi] = 0x0010_0000;
context[CpuRegister.Rdx] = 0;
context[CpuRegister.Rcx] = SpanStartOutAddress;
context[CpuRegister.R8] = SpanSizeOutAddress;
Assert.Equal(unchecked((int)0x8002000C), KernelMemoryCompatExports.KernelAvailableDirectMemorySize(context));
}
private static void AllocateDirectMemory(CpuContext context, ulong start, ulong length, ulong outputAddress = AllocationOutAddress)
{
context[CpuRegister.Rdi] = start;

View File

@ -191,7 +191,7 @@ public sealed class GuestRedZonePatcherTests
}
[Fact]
public unsafe void LeavesShortAccessUnchangedWhenNextInstructionIsBranchTarget()
public unsafe void PatchesShortAccessBeforeBranchTargetFromThePreviousInstruction()
{
if (RuntimeInformation.ProcessArchitecture != Architecture.X64)
return;
@ -199,14 +199,45 @@ public sealed class GuestRedZonePatcherTests
var argument = OperatingSystem.IsWindows() ? (byte)0x91 : (byte)0x97;
byte[] function =
[
0x48, 0xB8, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, // mov rax, value
0x48, 0x89, 0x44, 0x24, 0xF8, // mov [rsp-8], rax
0x48, 0x8D, argument, 0x00, 0x20, 0x00, 0x00, // lea rdx, [arg+0x2000]
0xB8, 0xFE, 0xFF, 0xFF, 0xFF, // mov eax, 0xFFFFFFFE
0x21, 0x02, // and [rdx], eax
0x48, 0x8B, 0x44, 0x24, 0xF8, // target: mov rax, [rsp-8]
0xC3, // ret
0xEB, 0xF8, // jmp target
0x48, 0xB8, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11,
0x48, 0x89, 0x44, 0x24, 0xF8,
0x48, 0x8D, argument, 0x00, 0x20, 0x00, 0x00,
0xB8, 0xFE, 0xFF, 0xFF, 0xFF,
0x21, 0x02,
0x48, 0x8B, 0x44, 0x24, 0xF8,
0xC3,
0xEB, 0xF8,
];
using var image = PatchedImage.Create(function, [(0x2000, 7u)]);
if (OperatingSystem.IsWindows() || OperatingSystem.IsMacOS())
{
Assert.Equal(1, image.Result.PatchedSites);
Assert.Equal(0xE9, image.ReadByte(22));
}
Assert.Equal(0x1122_3344_5566_7788UL, ((delegate* unmanaged<ulong, ulong>)image.Base)(image.Base));
Assert.Equal(6u, image.ReadUInt32(0x2000));
}
[Fact]
public unsafe void LeavesShortAccessBeforeBranchTargetUnchangedWhenAnIndirectBranchIsUnresolved()
{
if (RuntimeInformation.ProcessArchitecture != Architecture.X64)
return;
var argument = OperatingSystem.IsWindows() ? (byte)0x91 : (byte)0x97;
byte[] function =
[
0x48, 0xB8, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11,
0x48, 0x89, 0x44, 0x24, 0xF8,
0x48, 0x8D, argument, 0x00, 0x20, 0x00, 0x00,
0xB8, 0xFE, 0xFF, 0xFF, 0xFF,
0x21, 0x02,
0x48, 0x8B, 0x44, 0x24, 0xF8,
0xC3,
0xEB, 0xF8,
0xFF, 0xE0,
];
using var image = PatchedImage.Create(function, [(0x2000, 7u)]);
@ -215,7 +246,7 @@ public sealed class GuestRedZonePatcherTests
{
Assert.Equal(1, image.Result.RedZoneFunctions);
Assert.Equal(1, image.Result.UnrelocatableSites);
Assert.Equal(1, image.Result.BranchTargetRefusals);
Assert.Equal(1, image.Result.IndirectBranchRefusals);
}
for (var index = 0; index < function.Length; index++)

View File

@ -247,6 +247,25 @@ public sealed class SaveDataExportsTests : IDisposable
Assert.Equal(16382UL, freeBlocks);
}
[Fact]
public void GetMountInfo_WritesOnlyTheGuestStructure()
{
Assert.Equal(0, Mount());
WriteAscii(MountPointStr, MountPoint);
Span<byte> sentinel = stackalloc byte[0x10];
sentinel.Fill(0xCD);
Assert.True(_memory.TryWrite(MountInfo + 0x30, sentinel));
Assert.Equal(
0,
SaveDataExports.SaveDataGetMountInfo(
Reg(rdi: MountPointStr, rsi: MountInfo)));
Span<byte> after = stackalloc byte[0x10];
Assert.True(_memory.TryRead(MountInfo + 0x30, after));
Assert.True(after.SequenceEqual(sentinel));
}
[Fact]
public void DirNameSearch_ReportsBlockCapacityAndRemainingBlocks()
{