[Tests] Cover random devices, POSIX open, UDS initialization, pad class data and exception contexts
Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>
This commit is contained in:
parent
757567bd15
commit
cde859c5e5
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright (C) 2026 SharpEmu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
using System.Buffers.Binary;
|
||||
using SharpEmu.Core.Cpu.Native;
|
||||
using SharpEmu.HLE;
|
||||
using Xunit;
|
||||
|
||||
namespace SharpEmu.Libs.Tests.Cpu;
|
||||
|
||||
public sealed class GuestExceptionContextLayoutTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public void ExceptionContext_UsesBareMcontextAndSonyStackAlias(bool saved)
|
||||
{
|
||||
const ulong address = 0x1_0000_0100;
|
||||
var memory = new FakeCpuMemory(0x1_0000_0000, 0x1000);
|
||||
var context = new CpuContext(memory, Generation.Gen5)
|
||||
{
|
||||
Rip = 0x101000,
|
||||
Rflags = 0x246,
|
||||
FsBase = 0x303000,
|
||||
GsBase = 0x404000,
|
||||
};
|
||||
context[CpuRegister.Rdi] = 0x11;
|
||||
context[CpuRegister.Rbx] = 0x22;
|
||||
context[CpuRegister.Rsp] = 0x202000;
|
||||
var continuation = saved ? new GuestCpuContinuation
|
||||
{
|
||||
Rip = 0x505000,
|
||||
Rsp = 0x606000,
|
||||
Rflags = 0x203,
|
||||
Rdi = 0x33,
|
||||
Rbx = 0x44,
|
||||
FsBase = 0x707000,
|
||||
GsBase = 0x808000,
|
||||
} : default;
|
||||
|
||||
Assert.True(DirectExecutionBackend.TryWriteGuestExceptionContext(context, address, continuation, 0x500));
|
||||
var bytes = new byte[0x500];
|
||||
Assert.True(memory.TryRead(address, bytes));
|
||||
|
||||
Assert.Equal(saved ? continuation.Rdi : context[CpuRegister.Rdi], Read64(0x08));
|
||||
Assert.Equal(saved ? continuation.Rbx : context[CpuRegister.Rbx], Read64(0x40));
|
||||
Assert.Equal(saved ? continuation.Rip : context.Rip, Read64(0xA0));
|
||||
Assert.Equal(saved ? continuation.Rflags : context.Rflags, Read64(0xB0));
|
||||
Assert.Equal(saved ? continuation.Rsp : context[CpuRegister.Rsp], Read64(0xB8));
|
||||
Assert.Equal(Read64(0xB8), Read64(0xF8));
|
||||
Assert.Equal(0x480UL, Read64(0xC8));
|
||||
Assert.Equal(saved ? continuation.FsBase : context.FsBase, Read64(0x440));
|
||||
Assert.Equal(saved ? continuation.GsBase : context.GsBase, Read64(0x448));
|
||||
|
||||
ulong Read64(int offset) => BinaryPrimitives.ReadUInt64LittleEndian(bytes.AsSpan(offset, sizeof(ulong)));
|
||||
}
|
||||
}
|
||||
|
|
@ -197,6 +197,59 @@ public sealed class KernelMemoryCompatExportsTests
|
|||
Assert.Equal(ulong.MaxValue, context[CpuRegister.Rax]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UnderscoreOpen_MissingFileUsesPosixFailureAbi()
|
||||
{
|
||||
var memory = new FakeCpuMemory(GuestMemoryBase, 0x1000);
|
||||
var context = new CpuContext(memory, Generation.Gen5) { FsBase = GuestMemoryBase + 0x800 };
|
||||
memory.WriteCString(GuestMemoryBase + 0x100, "/__sharpemu_test_missing__/resource_level_high.bin");
|
||||
context[CpuRegister.Rdi] = GuestMemoryBase + 0x100;
|
||||
|
||||
Assert.Equal(-1, KernelMemoryCompatExports.KernelOpenUnderscore(context));
|
||||
Assert.Equal(ulong.MaxValue, context[CpuRegister.Rax]);
|
||||
Assert.True(context.TryReadUInt32(context.FsBase + 0x40, out var errno));
|
||||
Assert.Equal(2u, errno);
|
||||
Assert.Equal((int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND, KernelExports.KernelOpen(context));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("/dev/random")]
|
||||
[InlineData("/dev/urandom")]
|
||||
public void PosixRandomDevice_OpenReadFstatAndClose(string path)
|
||||
{
|
||||
var memory = new FakeCpuMemory(GuestMemoryBase, 0x1000);
|
||||
var context = new CpuContext(memory, Generation.Gen5);
|
||||
memory.WriteCString(GuestMemoryBase + 0x100, path);
|
||||
context[CpuRegister.Rdi] = GuestMemoryBase + 0x100;
|
||||
|
||||
Assert.Equal(0, KernelMemoryCompatExports.KernelOpenUnderscore(context));
|
||||
var fd = context[CpuRegister.Rax];
|
||||
Assert.True(fd >= 3);
|
||||
try
|
||||
{
|
||||
context[CpuRegister.Rdi] = fd;
|
||||
context[CpuRegister.Rsi] = GuestMemoryBase + 0x200;
|
||||
context[CpuRegister.Rdx] = 32;
|
||||
Assert.Equal(0, KernelMemoryCompatExports.PosixRead(context));
|
||||
Assert.Equal(32UL, context[CpuRegister.Rax]);
|
||||
var randomBytes = new byte[32];
|
||||
Assert.True(memory.TryRead(GuestMemoryBase + 0x200, randomBytes));
|
||||
Assert.Contains(randomBytes, value => value != 0);
|
||||
|
||||
context[CpuRegister.Rsi] = GuestMemoryBase + 0x400;
|
||||
Assert.Equal(0, KernelMemoryCompatExports.PosixFstat(context));
|
||||
}
|
||||
finally
|
||||
{
|
||||
context[CpuRegister.Rdi] = fd;
|
||||
Assert.Equal(0, KernelMemoryCompatExports.PosixClose(context));
|
||||
}
|
||||
|
||||
context[CpuRegister.Rsi] = GuestMemoryBase + 0x200;
|
||||
context[CpuRegister.Rdx] = 1;
|
||||
Assert.Equal(-1, KernelMemoryCompatExports.PosixRead(context));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PosixOpen_MissingFileReturnsMinusOne()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -27,6 +27,29 @@ public sealed class NpUniversalDataSystemExportsTests : IDisposable
|
|||
|
||||
public void Dispose() => NpUniversalDataSystemState.ResetForTests();
|
||||
|
||||
[Fact]
|
||||
public void ContextBootstrap_PreservesHandlesAcrossExplicitInitialization()
|
||||
{
|
||||
var context = CreateContext(userId: 7, serviceLabel: 3, options: 0x11);
|
||||
var serviceHandle = CreateServiceHandle();
|
||||
var before = NpUniversalDataSystemState.GetMemoryStat();
|
||||
Assert.True(before.CurrentInUseSize > 0);
|
||||
|
||||
Initialize(poolSize: 0x20_0000);
|
||||
Initialize(poolSize: 0x40_0000);
|
||||
|
||||
SetRegisters((ulong)(uint)context, (ulong)(uint)serviceHandle, 0x22);
|
||||
AssertSuccess(NpUniversalDataSystemExports.NpUniversalDataSystemRegisterContext(_context));
|
||||
var after = NpUniversalDataSystemState.GetMemoryStat();
|
||||
Assert.Equal(0x40_0000UL, after.PoolSize);
|
||||
Assert.True(after.CurrentInUseSize >= before.CurrentInUseSize);
|
||||
Assert.True(after.MaximumInUseSize >= before.MaximumInUseSize);
|
||||
|
||||
AssertSuccess(NpUniversalDataSystemExports.NpUniversalDataSystemTerminate(_context));
|
||||
SetRegisters((ulong)(uint)context, (ulong)(uint)serviceHandle, 0x22);
|
||||
Assert.Equal(ErrorInvalidArgument, NpUniversalDataSystemExports.NpUniversalDataSystemRegisterContext(_context));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FullLifecycle_PreservesAttachedChildAfterItsHandleIsDestroyed()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,6 +23,49 @@ public sealed class PadExportsTests : IDisposable
|
|||
|
||||
public void Dispose() => PadExports.ResetOpenedPadForTests();
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0)]
|
||||
[InlineData(4, 4)]
|
||||
[InlineData(15, 12)]
|
||||
public void DeviceClassParseData_BoundsThePayloadAndPreservesAdjacentMemory(int length, int copied)
|
||||
{
|
||||
var padData = new byte[0x78];
|
||||
padData[0x4C] = 1;
|
||||
padData[0x6B] = (byte)length;
|
||||
for (var index = 0; index < 12; index++)
|
||||
{
|
||||
padData[0x6C + index] = (byte)(index + 1);
|
||||
}
|
||||
Assert.True(_memory.TryWrite(Base + 0x100, padData));
|
||||
Assert.True(_memory.TryWrite(Base + 0x200, Enumerable.Repeat((byte)0xA5, 32).ToArray()));
|
||||
_ctx[CpuRegister.Rdi] = 0;
|
||||
_ctx[CpuRegister.Rsi] = Base + 0x100;
|
||||
_ctx[CpuRegister.Rdx] = Base + 0x200;
|
||||
|
||||
Assert.Equal(0, PadExports.PadDeviceClassParseData(_ctx));
|
||||
var output = new byte[32];
|
||||
Assert.True(_memory.TryRead(Base + 0x200, output));
|
||||
Assert.Equal(copied == 0 ? 0 : -1, BitConverter.ToInt32(output));
|
||||
Assert.Equal(1, output[4]);
|
||||
Assert.Equal(copied, output[8]);
|
||||
Assert.Equal(padData.AsSpan(0x6C, copied).ToArray(), output.AsSpan(12, copied).ToArray());
|
||||
Assert.All(output[24..], value => Assert.Equal(0xA5, value));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DeviceClassGetExtendedInformation_LeavesAdjacentMemoryIntact()
|
||||
{
|
||||
const ulong address = Base + 0x100;
|
||||
Assert.True(_memory.TryWrite(address, Enumerable.Repeat((byte)0xA5, 32).ToArray()));
|
||||
_ctx[CpuRegister.Rdi] = 0;
|
||||
_ctx[CpuRegister.Rsi] = address;
|
||||
Assert.Equal(0, PadExports.PadDeviceClassGetExtendedInformation(_ctx));
|
||||
var output = new byte[32];
|
||||
Assert.True(_memory.TryRead(address, output));
|
||||
Assert.All(output[..0x14], value => Assert.Equal(0, value));
|
||||
Assert.All(output[0x14..], value => Assert.Equal(0xA5, value));
|
||||
}
|
||||
|
||||
[NativeX64Theory]
|
||||
[InlineData(0, 0)]
|
||||
[InlineData(1, 0)]
|
||||
|
|
|
|||
Loading…
Reference in New Issue