82 lines
2.9 KiB
C#
82 lines
2.9 KiB
C#
// Copyright (C) 2026 SharpEmu Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
using SharpEmu.HLE.Host;
|
|
using SharpEmu.HLE.Host.Posix;
|
|
using SharpEmu.HLE.Host.Windows;
|
|
using Xunit;
|
|
|
|
namespace SharpEmu.Libs.Tests.Memory.HostViews;
|
|
|
|
internal static class HostViewTestSupport
|
|
{
|
|
public const ulong Segment = 0x4000;
|
|
public const ulong BackingSize = 1UL << 20;
|
|
public const ulong Marker = 0x5348_5250_5649_4557;
|
|
|
|
public static bool Supported => OperatingSystem.IsWindows() || OperatingSystem.IsLinux() || OperatingSystem.IsMacOS();
|
|
|
|
public static IHostMemory PlatformMemory => OperatingSystem.IsWindows() ? new WindowsHostMemory() : new PosixHostMemory();
|
|
|
|
public static ulong HoleSize(IHostViewMemory views) => AlignUp(4 * Segment, views.Granularity);
|
|
|
|
// Keep search tests below the guest address limit and outside reserved graphics memory.
|
|
public static ulong ProbeGuestAddress(IHostViewMemory views, ulong size)
|
|
{
|
|
size = AlignUp(size, views.Granularity);
|
|
var step = AlignUp(Math.Max(size, 0x1000000UL), views.Granularity);
|
|
for (var candidate = 0x70_0000_0000UL; candidate < 0x71_0000_0000UL; candidate += step)
|
|
{
|
|
if (views.ReserveHole(candidate, size) != candidate) continue;
|
|
Assert.True(views.FreeHole(candidate, size));
|
|
return candidate;
|
|
}
|
|
Assert.Fail("No free guest test range was found.");
|
|
return 0;
|
|
}
|
|
|
|
public static ulong AlignUp(ulong value, ulong alignment) => (value + alignment - 1) / alignment * alignment;
|
|
|
|
// Reserves then frees a probe so the address is free and granularity-aligned.
|
|
public static ulong ProbeFreeAddress(IHostViewMemory views, ulong size)
|
|
{
|
|
var memory = PlatformMemory;
|
|
for (var attempt = 0; attempt < 8; attempt++)
|
|
{
|
|
var probe = memory.Reserve(0, size, HostPageProtection.ReadWrite);
|
|
Assert.NotEqual(0UL, probe);
|
|
Assert.True(memory.Free(probe));
|
|
if (probe % views.Granularity == 0)
|
|
{
|
|
return probe;
|
|
}
|
|
}
|
|
|
|
Assert.Fail("no aligned free address after 8 attempts");
|
|
return 0;
|
|
}
|
|
|
|
// No fixed replacement may run unless ReserveHole returned this exact address.
|
|
public static ulong ReserveFreeHole(IHostViewMemory views, ulong size)
|
|
{
|
|
for (var attempt = 0; attempt < 8; attempt++)
|
|
{
|
|
var probe = ProbeFreeAddress(views, size);
|
|
if (views.ReserveHole(probe, size) == probe)
|
|
{
|
|
return probe;
|
|
}
|
|
}
|
|
|
|
Assert.Fail("no free hole could be reserved after 8 attempts");
|
|
return 0;
|
|
}
|
|
|
|
public static HostBackingObject CreateBacking(IHostViewMemory views)
|
|
{
|
|
Assert.True(views.TryCreateBacking(BackingSize, out var backing, out var failure));
|
|
Assert.Equal(HostViewFailure.None, failure);
|
|
return backing!;
|
|
}
|
|
}
|