mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-22 19:06:15 +08:00
[Kernel] Return largest available direct-memory span (#334)
This commit is contained in:
@@ -2459,7 +2459,20 @@ public static partial class KernelMemoryCompatExports
|
|||||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryFindAvailableDirectMemorySpanLocked(searchStart, searchEnd, alignment, out var candidate, out var rangeAvailable))
|
bool foundSpan;
|
||||||
|
ulong candidate;
|
||||||
|
ulong rangeAvailable;
|
||||||
|
lock (_memoryGate)
|
||||||
|
{
|
||||||
|
foundSpan = TryFindAvailableDirectMemorySpanLocked(
|
||||||
|
searchStart,
|
||||||
|
searchEnd,
|
||||||
|
alignment,
|
||||||
|
out candidate,
|
||||||
|
out rangeAvailable);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundSpan)
|
||||||
{
|
{
|
||||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
|
||||||
}
|
}
|
||||||
@@ -5909,9 +5922,12 @@ public static partial class KernelMemoryCompatExports
|
|||||||
var gapEnd = Math.Min(allocation.Start, effectiveEnd);
|
var gapEnd = Math.Min(allocation.Start, effectiveEnd);
|
||||||
if (candidate < gapEnd)
|
if (candidate < gapEnd)
|
||||||
{
|
{
|
||||||
spanStart = candidate;
|
var candidateLength = gapEnd - candidate;
|
||||||
spanLength = gapEnd - candidate;
|
if (candidateLength > spanLength)
|
||||||
return true;
|
{
|
||||||
|
spanStart = candidate;
|
||||||
|
spanLength = candidateLength;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allocation.Start >= effectiveEnd)
|
if (allocation.Start >= effectiveEnd)
|
||||||
@@ -5922,12 +5938,20 @@ public static partial class KernelMemoryCompatExports
|
|||||||
candidate = AlignUp(Math.Max(candidate, allocationEnd), alignment);
|
candidate = AlignUp(Math.Max(candidate, allocationEnd), alignment);
|
||||||
if (candidate >= effectiveEnd)
|
if (candidate >= effectiveEnd)
|
||||||
{
|
{
|
||||||
return false;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (candidate < effectiveEnd)
|
||||||
|
{
|
||||||
|
var candidateLength = effectiveEnd - candidate;
|
||||||
|
if (candidateLength > spanLength)
|
||||||
|
{
|
||||||
|
spanStart = candidate;
|
||||||
|
spanLength = candidateLength;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spanStart = candidate;
|
|
||||||
spanLength = effectiveEnd - candidate;
|
|
||||||
return spanLength != 0;
|
return spanLength != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,20 @@ using Xunit;
|
|||||||
|
|
||||||
namespace SharpEmu.Libs.Tests.Kernel;
|
namespace SharpEmu.Libs.Tests.Kernel;
|
||||||
|
|
||||||
|
[CollectionDefinition(KernelMemoryCompatStateCollection.Name, DisableParallelization = true)]
|
||||||
|
public sealed class KernelMemoryCompatStateCollection
|
||||||
|
{
|
||||||
|
public const string Name = "KernelMemoryCompatState";
|
||||||
|
}
|
||||||
|
|
||||||
|
[Collection(KernelMemoryCompatStateCollection.Name)]
|
||||||
public sealed class KernelMemoryCompatExportsTests
|
public sealed class KernelMemoryCompatExportsTests
|
||||||
{
|
{
|
||||||
|
private const ulong GuestMemoryBase = 0x1_0000_0000;
|
||||||
|
private const ulong AllocationOutAddress = GuestMemoryBase + 0x100;
|
||||||
|
private const ulong SpanStartOutAddress = GuestMemoryBase + 0x108;
|
||||||
|
private const ulong SpanSizeOutAddress = GuestMemoryBase + 0x110;
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void PosixStat_MissingFileReturnsMinusOne()
|
public void PosixStat_MissingFileReturnsMinusOne()
|
||||||
{
|
{
|
||||||
@@ -63,4 +75,93 @@ public sealed class KernelMemoryCompatExportsTests
|
|||||||
CultureInfo.CurrentCulture = previousCulture;
|
CultureInfo.CurrentCulture = previousCulture;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AvailableDirectMemorySize_FragmentedRangeReturnsLargestAlignedSpan()
|
||||||
|
{
|
||||||
|
const ulong firstAllocationStart = 0x0020_0000;
|
||||||
|
const ulong firstAllocationLength = 0x0020_0000;
|
||||||
|
const ulong secondAllocationStart = 0x00C0_0000;
|
||||||
|
const ulong secondAllocationLength = 0x0040_0000;
|
||||||
|
var context = new CpuContext(new FakeCpuMemory(GuestMemoryBase, 0x1000), Generation.Gen5);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AllocateDirectMemory(context, firstAllocationStart, firstAllocationLength);
|
||||||
|
AllocateDirectMemory(context, secondAllocationStart, secondAllocationLength);
|
||||||
|
|
||||||
|
QueryAvailableDirectMemory(context, 0, 0x0100_0000, 0x4000);
|
||||||
|
|
||||||
|
Assert.True(context.TryReadUInt64(SpanStartOutAddress, out var spanStart));
|
||||||
|
Assert.True(context.TryReadUInt64(SpanSizeOutAddress, out var spanSize));
|
||||||
|
Assert.Equal(0x0040_0000UL, spanStart);
|
||||||
|
Assert.Equal(0x0080_0000UL, spanSize);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ReleaseDirectMemory(context, firstAllocationStart, firstAllocationLength);
|
||||||
|
ReleaseDirectMemory(context, secondAllocationStart, secondAllocationLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AvailableDirectMemorySize_AppliesAlignmentBeforeComparingSpans()
|
||||||
|
{
|
||||||
|
const ulong allocationStart = 0x0070_0000;
|
||||||
|
const ulong allocationLength = 0x0010_0000;
|
||||||
|
var context = new CpuContext(new FakeCpuMemory(GuestMemoryBase, 0x1000), Generation.Gen5);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AllocateDirectMemory(context, allocationStart, allocationLength);
|
||||||
|
|
||||||
|
QueryAvailableDirectMemory(context, 0x0010_0000, 0x00C0_0000, 0x0040_0000);
|
||||||
|
|
||||||
|
Assert.True(context.TryReadUInt64(SpanStartOutAddress, out var spanStart));
|
||||||
|
Assert.True(context.TryReadUInt64(SpanSizeOutAddress, out var spanSize));
|
||||||
|
Assert.Equal(0x0080_0000UL, spanStart);
|
||||||
|
Assert.Equal(0x0040_0000UL, spanSize);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ReleaseDirectMemory(context, allocationStart, allocationLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AllocateDirectMemory(CpuContext context, ulong start, ulong length)
|
||||||
|
{
|
||||||
|
context[CpuRegister.Rdi] = start;
|
||||||
|
context[CpuRegister.Rsi] = start + length;
|
||||||
|
context[CpuRegister.Rdx] = length;
|
||||||
|
context[CpuRegister.Rcx] = 0x4000;
|
||||||
|
context[CpuRegister.R8] = 0;
|
||||||
|
context[CpuRegister.R9] = AllocationOutAddress;
|
||||||
|
|
||||||
|
Assert.Equal(0, KernelMemoryCompatExports.KernelAllocateDirectMemory(context));
|
||||||
|
Assert.True(context.TryReadUInt64(AllocationOutAddress, out var allocatedAddress));
|
||||||
|
Assert.Equal(start, allocatedAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void QueryAvailableDirectMemory(
|
||||||
|
CpuContext context,
|
||||||
|
ulong searchStart,
|
||||||
|
ulong searchEnd,
|
||||||
|
ulong alignment)
|
||||||
|
{
|
||||||
|
context[CpuRegister.Rdi] = searchStart;
|
||||||
|
context[CpuRegister.Rsi] = searchEnd;
|
||||||
|
context[CpuRegister.Rdx] = alignment;
|
||||||
|
context[CpuRegister.Rcx] = SpanStartOutAddress;
|
||||||
|
context[CpuRegister.R8] = SpanSizeOutAddress;
|
||||||
|
|
||||||
|
Assert.Equal(0, KernelMemoryCompatExports.KernelAvailableDirectMemorySize(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ReleaseDirectMemory(CpuContext context, ulong start, ulong length)
|
||||||
|
{
|
||||||
|
context[CpuRegister.Rdi] = start;
|
||||||
|
context[CpuRegister.Rsi] = length;
|
||||||
|
|
||||||
|
Assert.Equal(0, KernelMemoryCompatExports.KernelReleaseDirectMemory(context));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user