forked from MeloNX/MeloNX
Remove address space mirror and tweak address space layout when host has small adress space
This commit is contained in:
parent
bbe460cecd
commit
c57f6a7fe3
@ -5,6 +5,8 @@ namespace Ryujinx.Cpu
|
|||||||
{
|
{
|
||||||
public class AddressSpace : IDisposable
|
public class AddressSpace : IDisposable
|
||||||
{
|
{
|
||||||
|
private const MemoryAllocationFlags AsFlags = MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible;
|
||||||
|
|
||||||
private readonly MemoryBlock _backingMemory;
|
private readonly MemoryBlock _backingMemory;
|
||||||
|
|
||||||
public MemoryBlock Base { get; }
|
public MemoryBlock Base { get; }
|
||||||
@ -25,28 +27,42 @@ namespace Ryujinx.Cpu
|
|||||||
{
|
{
|
||||||
addressSpace = null;
|
addressSpace = null;
|
||||||
|
|
||||||
const MemoryAllocationFlags AsFlags = MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible;
|
MemoryBlock baseMemory = null;
|
||||||
|
MemoryBlock mirrorMemory = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
baseMemory = new MemoryBlock(asSize, AsFlags);
|
||||||
|
mirrorMemory = new MemoryBlock(asSize, AsFlags);
|
||||||
|
addressSpace = new AddressSpace(backingMemory, baseMemory, mirrorMemory, asSize);
|
||||||
|
}
|
||||||
|
catch (SystemException)
|
||||||
|
{
|
||||||
|
baseMemory?.Dispose();
|
||||||
|
mirrorMemory?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
return addressSpace != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryCreateWithoutMirror(ulong asSize, out MemoryBlock addressSpace)
|
||||||
|
{
|
||||||
|
addressSpace = null;
|
||||||
|
|
||||||
ulong minAddressSpaceSize = Math.Min(asSize, 1UL << 36);
|
ulong minAddressSpaceSize = Math.Min(asSize, 1UL << 36);
|
||||||
|
|
||||||
// Attempt to create the address space with expected size or try to reduce it until it succeed.
|
// Attempt to create the address space with expected size or try to reduce it until it succeed.
|
||||||
for (ulong addressSpaceSize = asSize; addressSpaceSize >= minAddressSpaceSize; addressSpaceSize >>= 1)
|
for (ulong addressSpaceSize = asSize; addressSpaceSize >= minAddressSpaceSize; addressSpaceSize -= 0x100000000UL)
|
||||||
{
|
{
|
||||||
MemoryBlock baseMemory = null;
|
|
||||||
MemoryBlock mirrorMemory = null;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
baseMemory = new MemoryBlock(addressSpaceSize, AsFlags);
|
MemoryBlock baseMemory = new MemoryBlock(addressSpaceSize, AsFlags);
|
||||||
mirrorMemory = new MemoryBlock(addressSpaceSize, AsFlags);
|
addressSpace = baseMemory;
|
||||||
addressSpace = new AddressSpace(backingMemory, baseMemory, mirrorMemory, addressSpaceSize);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
catch (SystemException)
|
catch (SystemException)
|
||||||
{
|
{
|
||||||
baseMemory?.Dispose();
|
|
||||||
mirrorMemory?.Dispose();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
330
src/Ryujinx.Cpu/Jit/MemoryManagerHostNoMirror.cs
Normal file
330
src/Ryujinx.Cpu/Jit/MemoryManagerHostNoMirror.cs
Normal file
@ -0,0 +1,330 @@
|
|||||||
|
using ARMeilleure.Memory;
|
||||||
|
using Ryujinx.Memory;
|
||||||
|
using Ryujinx.Memory.Range;
|
||||||
|
using Ryujinx.Memory.Tracking;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Ryujinx.Cpu.Jit
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a CPU memory manager which maps guest virtual memory directly onto a host virtual region.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class MemoryManagerHostNoMirror : VirtualMemoryManagerRefCountedBase, ICpuMemoryManager, IVirtualMemoryManagerTracked, IWritableBlock
|
||||||
|
{
|
||||||
|
private readonly InvalidAccessHandler _invalidAccessHandler;
|
||||||
|
private readonly bool _unsafeMode;
|
||||||
|
|
||||||
|
private readonly MemoryBlock _addressSpace;
|
||||||
|
private readonly MemoryBlock _backingMemory;
|
||||||
|
private readonly PageTable<ulong> _pageTable;
|
||||||
|
|
||||||
|
public int AddressSpaceBits { get; }
|
||||||
|
protected override ulong AddressSpaceSize { get; }
|
||||||
|
|
||||||
|
private readonly MemoryEhMeilleure _memoryEh;
|
||||||
|
|
||||||
|
private readonly ManagedPageFlags _pages;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool UsesPrivateAllocations => false;
|
||||||
|
|
||||||
|
public IntPtr PageTablePointer => _addressSpace.Pointer;
|
||||||
|
|
||||||
|
public MemoryManagerType Type => _unsafeMode ? MemoryManagerType.HostMappedUnsafe : MemoryManagerType.HostMapped;
|
||||||
|
|
||||||
|
public MemoryTracking Tracking { get; }
|
||||||
|
|
||||||
|
public event Action<ulong, ulong> UnmapEvent;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the host mapped memory manager.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="addressSpace">Address space instance to use</param>
|
||||||
|
/// <param name="unsafeMode">True if unmanaged access should not be masked (unsafe), false otherwise.</param>
|
||||||
|
/// <param name="invalidAccessHandler">Optional function to handle invalid memory accesses</param>
|
||||||
|
public MemoryManagerHostNoMirror(
|
||||||
|
MemoryBlock addressSpace,
|
||||||
|
MemoryBlock backingMemory,
|
||||||
|
bool unsafeMode,
|
||||||
|
InvalidAccessHandler invalidAccessHandler)
|
||||||
|
{
|
||||||
|
_addressSpace = addressSpace;
|
||||||
|
_backingMemory = backingMemory;
|
||||||
|
_pageTable = new PageTable<ulong>();
|
||||||
|
_invalidAccessHandler = invalidAccessHandler;
|
||||||
|
_unsafeMode = unsafeMode;
|
||||||
|
AddressSpaceSize = addressSpace.Size;
|
||||||
|
|
||||||
|
ulong asSize = PageSize;
|
||||||
|
int asBits = PageBits;
|
||||||
|
|
||||||
|
while (asSize < addressSpace.Size)
|
||||||
|
{
|
||||||
|
asSize <<= 1;
|
||||||
|
asBits++;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddressSpaceBits = asBits;
|
||||||
|
|
||||||
|
_pages = new ManagedPageFlags(asBits);
|
||||||
|
|
||||||
|
Tracking = new MemoryTracking(this, (int)MemoryBlock.GetPageSize(), invalidAccessHandler);
|
||||||
|
_memoryEh = new MemoryEhMeilleure(addressSpace, null, Tracking);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ensures the combination of virtual address and size is part of the addressable space and fully mapped.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="va">Virtual address of the range</param>
|
||||||
|
/// <param name="size">Size of the range in bytes</param>
|
||||||
|
private void AssertMapped(ulong va, ulong size)
|
||||||
|
{
|
||||||
|
if (!ValidateAddressAndSize(va, size) || !_pages.IsRangeMapped(va, size))
|
||||||
|
{
|
||||||
|
throw new InvalidMemoryRegionException($"Not mapped: va=0x{va:X16}, size=0x{size:X16}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void Map(ulong va, ulong pa, ulong size, MemoryMapFlags flags)
|
||||||
|
{
|
||||||
|
AssertValidAddressAndSize(va, size);
|
||||||
|
|
||||||
|
_addressSpace.MapView(_backingMemory, pa, va, size);
|
||||||
|
_pages.AddMapping(va, size);
|
||||||
|
PtMap(va, pa, size);
|
||||||
|
|
||||||
|
Tracking.Map(va, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PtMap(ulong va, ulong pa, ulong size)
|
||||||
|
{
|
||||||
|
while (size != 0)
|
||||||
|
{
|
||||||
|
_pageTable.Map(va, pa);
|
||||||
|
|
||||||
|
va += PageSize;
|
||||||
|
pa += PageSize;
|
||||||
|
size -= PageSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void Unmap(ulong va, ulong size)
|
||||||
|
{
|
||||||
|
AssertValidAddressAndSize(va, size);
|
||||||
|
|
||||||
|
UnmapEvent?.Invoke(va, size);
|
||||||
|
Tracking.Unmap(va, size);
|
||||||
|
|
||||||
|
_pages.RemoveMapping(va, size);
|
||||||
|
PtUnmap(va, size);
|
||||||
|
_addressSpace.UnmapView(_backingMemory, va, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PtUnmap(ulong va, ulong size)
|
||||||
|
{
|
||||||
|
while (size != 0)
|
||||||
|
{
|
||||||
|
_pageTable.Unmap(va);
|
||||||
|
|
||||||
|
va += PageSize;
|
||||||
|
size -= PageSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void Reprotect(ulong va, ulong size, MemoryPermission permission)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ref T GetRef<T>(ulong va) where T : unmanaged
|
||||||
|
{
|
||||||
|
if (!IsContiguous(va, Unsafe.SizeOf<T>()))
|
||||||
|
{
|
||||||
|
ThrowMemoryNotContiguous();
|
||||||
|
}
|
||||||
|
|
||||||
|
SignalMemoryTracking(va, (ulong)Unsafe.SizeOf<T>(), true);
|
||||||
|
|
||||||
|
return ref _backingMemory.GetRef<T>(GetPhysicalAddressChecked(va));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override bool IsMapped(ulong va)
|
||||||
|
{
|
||||||
|
return ValidateAddress(va) && _pages.IsMapped(va);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool IsRangeMapped(ulong va, ulong size)
|
||||||
|
{
|
||||||
|
AssertValidAddressAndSize(va, size);
|
||||||
|
|
||||||
|
return _pages.IsRangeMapped(va, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public IEnumerable<HostMemoryRange> GetHostRegions(ulong va, ulong size)
|
||||||
|
{
|
||||||
|
if (size == 0)
|
||||||
|
{
|
||||||
|
return Enumerable.Empty<HostMemoryRange>();
|
||||||
|
}
|
||||||
|
|
||||||
|
var guestRegions = GetPhysicalRegionsImpl(va, size);
|
||||||
|
if (guestRegions == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var regions = new HostMemoryRange[guestRegions.Count];
|
||||||
|
|
||||||
|
for (int i = 0; i < regions.Length; i++)
|
||||||
|
{
|
||||||
|
var guestRegion = guestRegions[i];
|
||||||
|
IntPtr pointer = _backingMemory.GetPointer(guestRegion.Address, guestRegion.Size);
|
||||||
|
regions[i] = new HostMemoryRange((nuint)(ulong)pointer, guestRegion.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return regions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public IEnumerable<MemoryRange> GetPhysicalRegions(ulong va, ulong size)
|
||||||
|
{
|
||||||
|
if (size == 0)
|
||||||
|
{
|
||||||
|
return Enumerable.Empty<MemoryRange>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetPhysicalRegionsImpl(va, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<MemoryRange> GetPhysicalRegionsImpl(ulong va, ulong size)
|
||||||
|
{
|
||||||
|
if (!ValidateAddress(va) || !ValidateAddressAndSize(va, size))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pages = GetPagesCount(va, (uint)size, out va);
|
||||||
|
|
||||||
|
var regions = new List<MemoryRange>();
|
||||||
|
|
||||||
|
ulong regionStart = GetPhysicalAddressInternal(va);
|
||||||
|
ulong regionSize = PageSize;
|
||||||
|
|
||||||
|
for (int page = 0; page < pages - 1; page++)
|
||||||
|
{
|
||||||
|
if (!ValidateAddress(va + PageSize))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ulong newPa = GetPhysicalAddressInternal(va + PageSize);
|
||||||
|
|
||||||
|
if (GetPhysicalAddressInternal(va) + PageSize != newPa)
|
||||||
|
{
|
||||||
|
regions.Add(new MemoryRange(regionStart, regionSize));
|
||||||
|
regionStart = newPa;
|
||||||
|
regionSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
va += PageSize;
|
||||||
|
regionSize += PageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
regions.Add(new MemoryRange(regionStart, regionSize));
|
||||||
|
|
||||||
|
return regions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ulong GetPhysicalAddressChecked(ulong va)
|
||||||
|
{
|
||||||
|
if (!IsMapped(va))
|
||||||
|
{
|
||||||
|
ThrowInvalidMemoryRegionException($"Not mapped: va=0x{va:X16}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetPhysicalAddressInternal(va);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ulong GetPhysicalAddressInternal(ulong va)
|
||||||
|
{
|
||||||
|
return _pageTable.Read(va) + (va & PageMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
/// <remarks>
|
||||||
|
/// This function also validates that the given range is both valid and mapped, and will throw if it is not.
|
||||||
|
/// </remarks>
|
||||||
|
public override void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null)
|
||||||
|
{
|
||||||
|
AssertValidAddressAndSize(va, size);
|
||||||
|
|
||||||
|
if (precise)
|
||||||
|
{
|
||||||
|
Tracking.VirtualMemoryEvent(va, size, write, precise: true, exemptId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_pages.SignalMemoryTracking(Tracking, va, size, write, exemptId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void TrackingReprotect(ulong va, ulong size, MemoryPermission protection, bool guest)
|
||||||
|
{
|
||||||
|
if (guest)
|
||||||
|
{
|
||||||
|
_addressSpace.Reprotect(va, size, protection, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_pages.TrackingReprotect(va, size, protection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public RegionHandle BeginTracking(ulong address, ulong size, int id, RegionFlags flags)
|
||||||
|
{
|
||||||
|
return Tracking.BeginTracking(address, size, id, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public MultiRegionHandle BeginGranularTracking(ulong address, ulong size, IEnumerable<IRegionHandle> handles, ulong granularity, int id, RegionFlags flags)
|
||||||
|
{
|
||||||
|
return Tracking.BeginGranularTracking(address, size, handles, granularity, id, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public SmartMultiRegionHandle BeginSmartGranularTracking(ulong address, ulong size, ulong granularity, int id)
|
||||||
|
{
|
||||||
|
return Tracking.BeginSmartGranularTracking(address, size, granularity, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disposes of resources used by the memory manager.
|
||||||
|
/// </summary>
|
||||||
|
protected override void Destroy()
|
||||||
|
{
|
||||||
|
_addressSpace.Dispose();
|
||||||
|
_memoryEh.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Memory<byte> GetPhysicalAddressMemory(nuint pa, int size)
|
||||||
|
=> _backingMemory.GetMemory(pa, size);
|
||||||
|
|
||||||
|
protected override Span<byte> GetPhysicalAddressSpan(nuint pa, int size)
|
||||||
|
=> _backingMemory.GetSpan(pa, size);
|
||||||
|
|
||||||
|
protected override nuint TranslateVirtualAddressChecked(ulong va)
|
||||||
|
=> (nuint)GetPhysicalAddressChecked(va);
|
||||||
|
|
||||||
|
protected override nuint TranslateVirtualAddressUnchecked(ulong va)
|
||||||
|
=> (nuint)GetPhysicalAddressInternal(va);
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,6 @@ using Ryujinx.Memory;
|
|||||||
using Ryujinx.Memory.Range;
|
using Ryujinx.Memory.Range;
|
||||||
using Ryujinx.Memory.Tracking;
|
using Ryujinx.Memory.Tracking;
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
@ -15,10 +14,7 @@ namespace Ryujinx.Cpu.Nce
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class MemoryManagerNative : VirtualMemoryManagerRefCountedBase, ICpuMemoryManager, IVirtualMemoryManagerTracked, IWritableBlock
|
public sealed class MemoryManagerNative : VirtualMemoryManagerRefCountedBase, ICpuMemoryManager, IVirtualMemoryManagerTracked, IWritableBlock
|
||||||
{
|
{
|
||||||
private readonly InvalidAccessHandler _invalidAccessHandler;
|
|
||||||
|
|
||||||
private readonly MemoryBlock _addressSpace;
|
private readonly MemoryBlock _addressSpace;
|
||||||
private readonly MemoryBlock _addressSpaceMirror;
|
|
||||||
|
|
||||||
private readonly MemoryBlock _backingMemory;
|
private readonly MemoryBlock _backingMemory;
|
||||||
private readonly PageTable<ulong> _pageTable;
|
private readonly PageTable<ulong> _pageTable;
|
||||||
@ -30,8 +26,6 @@ namespace Ryujinx.Cpu.Nce
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool UsesPrivateAllocations => false;
|
public bool UsesPrivateAllocations => false;
|
||||||
|
|
||||||
public int AddressSpaceBits { get; }
|
|
||||||
|
|
||||||
public IntPtr PageTablePointer => IntPtr.Zero;
|
public IntPtr PageTablePointer => IntPtr.Zero;
|
||||||
|
|
||||||
public ulong ReservedSize => (ulong)_addressSpace.Pointer.ToInt64();
|
public ulong ReservedSize => (ulong)_addressSpace.Pointer.ToInt64();
|
||||||
@ -42,24 +36,25 @@ namespace Ryujinx.Cpu.Nce
|
|||||||
|
|
||||||
public event Action<ulong, ulong> UnmapEvent;
|
public event Action<ulong, ulong> UnmapEvent;
|
||||||
|
|
||||||
|
public int AddressSpaceBits { get; }
|
||||||
protected override ulong AddressSpaceSize { get; }
|
protected override ulong AddressSpaceSize { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the host mapped memory manager.
|
/// Creates a new instance of the host mapped memory manager.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="addressSpace">Address space instance to use</param>
|
/// <param name="addressSpace">Address space memory block</param>
|
||||||
/// <param name="backingMemory">Physical backing memory where virtual memory will be mapped to</param>
|
/// <param name="backingMemory">Physical backing memory where virtual memory will be mapped to</param>
|
||||||
/// <param name="addressSpaceSize">Size of the address space</param>
|
/// <param name="addressSpaceSize">Size of the address space</param>
|
||||||
/// <param name="invalidAccessHandler">Optional function to handle invalid memory accesses</param>
|
/// <param name="invalidAccessHandler">Optional function to handle invalid memory accesses</param>
|
||||||
public MemoryManagerNative(
|
public MemoryManagerNative(
|
||||||
AddressSpace addressSpace,
|
MemoryBlock addressSpace,
|
||||||
MemoryBlock backingMemory,
|
MemoryBlock backingMemory,
|
||||||
ulong addressSpaceSize,
|
ulong addressSpaceSize,
|
||||||
InvalidAccessHandler invalidAccessHandler = null)
|
InvalidAccessHandler invalidAccessHandler = null)
|
||||||
{
|
{
|
||||||
_backingMemory = backingMemory;
|
_backingMemory = backingMemory;
|
||||||
_pageTable = new PageTable<ulong>();
|
_pageTable = new PageTable<ulong>();
|
||||||
_invalidAccessHandler = invalidAccessHandler;
|
AddressSpaceSize = addressSpaceSize;
|
||||||
|
|
||||||
ulong asSize = PageSize;
|
ulong asSize = PageSize;
|
||||||
int asBits = PageBits;
|
int asBits = PageBits;
|
||||||
@ -71,43 +66,39 @@ namespace Ryujinx.Cpu.Nce
|
|||||||
}
|
}
|
||||||
|
|
||||||
AddressSpaceBits = asBits;
|
AddressSpaceBits = asBits;
|
||||||
AddressSpaceSize = addressSpace.AddressSpaceSize;
|
|
||||||
|
|
||||||
_pages = new ManagedPageFlags(AddressSpaceBits);
|
_pages = new ManagedPageFlags(asBits);
|
||||||
|
|
||||||
_addressSpace = addressSpace.Base;
|
_addressSpace = addressSpace;
|
||||||
_addressSpaceMirror = addressSpace.Mirror;
|
|
||||||
|
|
||||||
Tracking = new MemoryTracking(this, PageSize, invalidAccessHandler);
|
Tracking = new MemoryTracking(this, PageSize, invalidAccessHandler);
|
||||||
_memoryEh = new MemoryEhMeilleure(asSize, Tracking);
|
_memoryEh = new MemoryEhMeilleure(asSize, Tracking);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Ensures the combination of virtual address and size is part of the addressable space and fully mapped.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="va">Virtual address of the range</param>
|
|
||||||
/// <param name="size">Size of the range in bytes</param>
|
|
||||||
private void AssertMapped(ulong va, ulong size)
|
|
||||||
{
|
|
||||||
if (!ValidateAddressAndSize(va, size) || !_pages.IsRangeMapped(va, size))
|
|
||||||
{
|
|
||||||
throw new InvalidMemoryRegionException($"Not mapped: va=0x{va:X16}, size=0x{size:X16}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Map(ulong va, ulong pa, ulong size, MemoryMapFlags flags)
|
public void Map(ulong va, ulong pa, ulong size, MemoryMapFlags flags)
|
||||||
{
|
{
|
||||||
AssertValidAddressAndSize(va, size);
|
AssertValidAddressAndSize(va, size);
|
||||||
|
|
||||||
_addressSpace.MapView(_backingMemory, pa, AddressToOffset(va), size);
|
_addressSpace.MapView(_backingMemory, pa, AddressToOffset(va), size);
|
||||||
_addressSpaceMirror.MapView(_backingMemory, pa, AddressToOffset(va), size);
|
|
||||||
_pages.AddMapping(va, size);
|
_pages.AddMapping(va, size);
|
||||||
PtMap(va, pa, size);
|
PtMap(va, pa, size);
|
||||||
|
|
||||||
Tracking.Map(va, size);
|
Tracking.Map(va, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void PtMap(ulong va, ulong pa, ulong size)
|
||||||
|
{
|
||||||
|
while (size != 0)
|
||||||
|
{
|
||||||
|
_pageTable.Map(va, pa);
|
||||||
|
|
||||||
|
va += PageSize;
|
||||||
|
pa += PageSize;
|
||||||
|
size -= PageSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Unmap(ulong va, ulong size)
|
public void Unmap(ulong va, ulong size)
|
||||||
{
|
{
|
||||||
@ -119,19 +110,6 @@ namespace Ryujinx.Cpu.Nce
|
|||||||
_pages.RemoveMapping(va, size);
|
_pages.RemoveMapping(va, size);
|
||||||
PtUnmap(va, size);
|
PtUnmap(va, size);
|
||||||
_addressSpace.UnmapView(_backingMemory, AddressToOffset(va), size);
|
_addressSpace.UnmapView(_backingMemory, AddressToOffset(va), size);
|
||||||
_addressSpaceMirror.UnmapView(_backingMemory, AddressToOffset(va), size);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PtMap(ulong va, ulong pa, ulong size)
|
|
||||||
{
|
|
||||||
while (size != 0)
|
|
||||||
{
|
|
||||||
_pageTable.Map(va, pa);
|
|
||||||
|
|
||||||
va += PageSize;
|
|
||||||
pa += PageSize;
|
|
||||||
size -= PageSize;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PtUnmap(ulong va, ulong size)
|
private void PtUnmap(ulong va, ulong size)
|
||||||
@ -151,193 +129,16 @@ namespace Ryujinx.Cpu.Nce
|
|||||||
_addressSpace.Reprotect(AddressToOffset(va), size, permission);
|
_addressSpace.Reprotect(AddressToOffset(va), size, permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override T Read<T>(ulong va)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
AssertMapped(va, (ulong)Unsafe.SizeOf<T>());
|
|
||||||
|
|
||||||
return _addressSpaceMirror.Read<T>(AddressToOffset(va));
|
|
||||||
}
|
|
||||||
catch (InvalidMemoryRegionException)
|
|
||||||
{
|
|
||||||
if (_invalidAccessHandler == null || !_invalidAccessHandler(va))
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override T ReadTracked<T>(ulong va)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
SignalMemoryTracking(va, (ulong)Unsafe.SizeOf<T>(), false);
|
|
||||||
|
|
||||||
return Read<T>(va);
|
|
||||||
}
|
|
||||||
catch (InvalidMemoryRegionException)
|
|
||||||
{
|
|
||||||
if (_invalidAccessHandler == null || !_invalidAccessHandler(va))
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Read(ulong va, Span<byte> data)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
AssertMapped(va, (ulong)data.Length);
|
|
||||||
|
|
||||||
_addressSpaceMirror.Read(AddressToOffset(va), data);
|
|
||||||
}
|
|
||||||
catch (InvalidMemoryRegionException)
|
|
||||||
{
|
|
||||||
if (_invalidAccessHandler == null || !_invalidAccessHandler(va))
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override void Write<T>(ulong va, T value)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
SignalMemoryTracking(va, (ulong)Unsafe.SizeOf<T>(), write: true);
|
|
||||||
|
|
||||||
_addressSpaceMirror.Write(AddressToOffset(va), value);
|
|
||||||
}
|
|
||||||
catch (InvalidMemoryRegionException)
|
|
||||||
{
|
|
||||||
if (_invalidAccessHandler == null || !_invalidAccessHandler(va))
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Write(ulong va, ReadOnlySpan<byte> data)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
SignalMemoryTracking(va, (ulong)data.Length, write: true);
|
|
||||||
|
|
||||||
_addressSpaceMirror.Write(AddressToOffset(va), data);
|
|
||||||
}
|
|
||||||
catch (InvalidMemoryRegionException)
|
|
||||||
{
|
|
||||||
if (_invalidAccessHandler == null || !_invalidAccessHandler(va))
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteUntracked(ulong va, ReadOnlySpan<byte> data)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
AssertMapped(va, (ulong)data.Length);
|
|
||||||
|
|
||||||
_addressSpaceMirror.Write(AddressToOffset(va), data);
|
|
||||||
}
|
|
||||||
catch (InvalidMemoryRegionException)
|
|
||||||
{
|
|
||||||
if (_invalidAccessHandler == null || !_invalidAccessHandler(va))
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
SignalMemoryTracking(va, (ulong)data.Length, false);
|
|
||||||
|
|
||||||
Span<byte> target = _addressSpaceMirror.GetSpan(AddressToOffset(va), data.Length);
|
|
||||||
bool changed = !data.SequenceEqual(target);
|
|
||||||
|
|
||||||
if (changed)
|
|
||||||
{
|
|
||||||
data.CopyTo(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
return changed;
|
|
||||||
}
|
|
||||||
catch (InvalidMemoryRegionException)
|
|
||||||
{
|
|
||||||
if (_invalidAccessHandler == null || !_invalidAccessHandler(va))
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override ReadOnlySequence<byte> GetReadOnlySequence(ulong va, int size, bool tracked = false)
|
|
||||||
{
|
|
||||||
if (tracked)
|
|
||||||
{
|
|
||||||
SignalMemoryTracking(va, (ulong)size, write: false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AssertMapped(va, (ulong)size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ReadOnlySequence<byte>(_addressSpaceMirror.GetMemory(va, size));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
|
|
||||||
{
|
|
||||||
if (tracked)
|
|
||||||
{
|
|
||||||
SignalMemoryTracking(va, (ulong)size, write: false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AssertMapped(va, (ulong)size);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size == 0)
|
|
||||||
{
|
|
||||||
return ReadOnlySpan<byte>.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _addressSpaceMirror.GetSpan(AddressToOffset(va), size);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override WritableRegion GetWritableRegion(ulong va, int size, bool tracked = false)
|
|
||||||
{
|
|
||||||
if (tracked)
|
|
||||||
{
|
|
||||||
SignalMemoryTracking(va, (ulong)size, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AssertMapped(va, (ulong)size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _addressSpaceMirror.GetWritableRegion(AddressToOffset(va), size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public ref T GetRef<T>(ulong va) where T : unmanaged
|
public ref T GetRef<T>(ulong va) where T : unmanaged
|
||||||
{
|
{
|
||||||
|
if (!IsContiguous(va, Unsafe.SizeOf<T>()))
|
||||||
|
{
|
||||||
|
ThrowMemoryNotContiguous();
|
||||||
|
}
|
||||||
|
|
||||||
SignalMemoryTracking(va, (ulong)Unsafe.SizeOf<T>(), true);
|
SignalMemoryTracking(va, (ulong)Unsafe.SizeOf<T>(), true);
|
||||||
|
|
||||||
return ref _addressSpaceMirror.GetRef<T>(AddressToOffset(va));
|
return ref _backingMemory.GetRef<T>(GetPhysicalAddressChecked(va));
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@ -357,19 +158,52 @@ namespace Ryujinx.Cpu.Nce
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IEnumerable<HostMemoryRange> GetHostRegions(ulong va, ulong size)
|
public IEnumerable<HostMemoryRange> GetHostRegions(ulong va, ulong size)
|
||||||
{
|
{
|
||||||
AssertValidAddressAndSize(va, size);
|
if (size == 0)
|
||||||
|
{
|
||||||
|
return Enumerable.Empty<HostMemoryRange>();
|
||||||
|
}
|
||||||
|
|
||||||
return Enumerable.Repeat(new HostMemoryRange((nuint)(ulong)_addressSpaceMirror.GetPointer(AddressToOffset(va), size), size), 1);
|
var guestRegions = GetPhysicalRegionsImpl(va, size);
|
||||||
|
if (guestRegions == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var regions = new HostMemoryRange[guestRegions.Count];
|
||||||
|
|
||||||
|
for (int i = 0; i < regions.Length; i++)
|
||||||
|
{
|
||||||
|
var guestRegion = guestRegions[i];
|
||||||
|
IntPtr pointer = _backingMemory.GetPointer(guestRegion.Address, guestRegion.Size);
|
||||||
|
regions[i] = new HostMemoryRange((nuint)(ulong)pointer, guestRegion.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return regions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IEnumerable<MemoryRange> GetPhysicalRegions(ulong va, ulong size)
|
public IEnumerable<MemoryRange> GetPhysicalRegions(ulong va, ulong size)
|
||||||
{
|
{
|
||||||
|
if (size == 0)
|
||||||
|
{
|
||||||
|
return Enumerable.Empty<MemoryRange>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetPhysicalRegionsImpl(va, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<MemoryRange> GetPhysicalRegionsImpl(ulong va, ulong size)
|
||||||
|
{
|
||||||
|
if (!ValidateAddress(va) || !ValidateAddressAndSize(va, size))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
int pages = GetPagesCount(va, (uint)size, out va);
|
int pages = GetPagesCount(va, (uint)size, out va);
|
||||||
|
|
||||||
var regions = new List<MemoryRange>();
|
var regions = new List<MemoryRange>();
|
||||||
|
|
||||||
ulong regionStart = GetPhysicalAddressChecked(va);
|
ulong regionStart = GetPhysicalAddressInternal(va);
|
||||||
ulong regionSize = PageSize;
|
ulong regionSize = PageSize;
|
||||||
|
|
||||||
for (int page = 0; page < pages - 1; page++)
|
for (int page = 0; page < pages - 1; page++)
|
||||||
@ -379,9 +213,9 @@ namespace Ryujinx.Cpu.Nce
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong newPa = GetPhysicalAddressChecked(va + PageSize);
|
ulong newPa = GetPhysicalAddressInternal(va + PageSize);
|
||||||
|
|
||||||
if (GetPhysicalAddressChecked(va) + PageSize != newPa)
|
if (GetPhysicalAddressInternal(va) + PageSize != newPa)
|
||||||
{
|
{
|
||||||
regions.Add(new MemoryRange(regionStart, regionSize));
|
regions.Add(new MemoryRange(regionStart, regionSize));
|
||||||
regionStart = newPa;
|
regionStart = newPa;
|
||||||
@ -476,15 +310,14 @@ namespace Ryujinx.Cpu.Nce
|
|||||||
protected override void Destroy()
|
protected override void Destroy()
|
||||||
{
|
{
|
||||||
_addressSpace.Dispose();
|
_addressSpace.Dispose();
|
||||||
_addressSpaceMirror.Dispose();
|
|
||||||
_memoryEh.Dispose();
|
_memoryEh.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Memory<byte> GetPhysicalAddressMemory(nuint pa, int size)
|
protected override Memory<byte> GetPhysicalAddressMemory(nuint pa, int size)
|
||||||
=> _addressSpaceMirror.GetMemory(pa, size);
|
=> _backingMemory.GetMemory(pa, size);
|
||||||
|
|
||||||
protected override Span<byte> GetPhysicalAddressSpan(nuint pa, int size)
|
protected override Span<byte> GetPhysicalAddressSpan(nuint pa, int size)
|
||||||
=> _addressSpaceMirror.GetSpan(pa, size);
|
=> _backingMemory.GetSpan(pa, size);
|
||||||
|
|
||||||
protected override nuint TranslateVirtualAddressChecked(ulong va)
|
protected override nuint TranslateVirtualAddressChecked(ulong va)
|
||||||
=> (nuint)GetPhysicalAddressChecked(va);
|
=> (nuint)GetPhysicalAddressChecked(va);
|
||||||
|
@ -1603,42 +1603,36 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
DynamicState.ReplayIfDirty(Gd, CommandBuffer);
|
DynamicState.ReplayIfDirty(Gd, CommandBuffer);
|
||||||
|
|
||||||
// Setting graphics state with a compute pipeline bound crashes the Adreno driver.
|
if (_needsIndexBufferRebind && _indexBufferPattern == null)
|
||||||
if (pbp == PipelineBindPoint.Graphics)
|
|
||||||
{
|
{
|
||||||
DynamicState.ReplayIfDirty(Gd.Api, CommandBuffer);
|
_indexBuffer.BindIndexBuffer(Gd, Cbs);
|
||||||
|
_needsIndexBufferRebind = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (_needsIndexBufferRebind && _indexBufferPattern == null)
|
if (_needsTransformFeedbackBuffersRebind)
|
||||||
|
{
|
||||||
|
PauseTransformFeedbackInternal();
|
||||||
|
|
||||||
|
for (int i = 0; i < Constants.MaxTransformFeedbackBuffers; i++)
|
||||||
{
|
{
|
||||||
_indexBuffer.BindIndexBuffer(Gd, Cbs);
|
_transformFeedbackBuffers[i].BindTransformFeedbackBuffer(Gd, Cbs, (uint)i);
|
||||||
_needsIndexBufferRebind = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_needsTransformFeedbackBuffersRebind)
|
_needsTransformFeedbackBuffersRebind = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_vertexBuffersDirty != 0)
|
||||||
|
{
|
||||||
|
while (_vertexBuffersDirty != 0)
|
||||||
{
|
{
|
||||||
PauseTransformFeedbackInternal();
|
int i = BitOperations.TrailingZeroCount(_vertexBuffersDirty);
|
||||||
|
|
||||||
for (int i = 0; i < Constants.MaxTransformFeedbackBuffers; i++)
|
_vertexBuffers[i].BindVertexBuffer(Gd, Cbs, (uint)i, ref _newState, _vertexBufferUpdater);
|
||||||
{
|
|
||||||
_transformFeedbackBuffers[i].BindTransformFeedbackBuffer(Gd, Cbs, (uint)i);
|
|
||||||
}
|
|
||||||
|
|
||||||
_needsTransformFeedbackBuffersRebind = false;
|
_vertexBuffersDirty &= ~(1UL << i);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_vertexBuffersDirty != 0)
|
_vertexBufferUpdater.Commit(Cbs);
|
||||||
{
|
|
||||||
while (_vertexBuffersDirty != 0)
|
|
||||||
{
|
|
||||||
int i = BitOperations.TrailingZeroCount(_vertexBuffersDirty);
|
|
||||||
|
|
||||||
_vertexBuffers[i].BindVertexBuffer(Gd, Cbs, (uint)i, ref _newState, _vertexBufferUpdater);
|
|
||||||
|
|
||||||
_vertexBuffersDirty &= ~(1UL << i);
|
|
||||||
}
|
|
||||||
|
|
||||||
_vertexBufferUpdater.Commit(Cbs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_bindingBarriersDirty)
|
if (_bindingBarriersDirty)
|
||||||
|
@ -57,7 +57,6 @@ namespace Ryujinx.HLE.HOS
|
|||||||
public IProcessContext Create(KernelContext context, ulong pid, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler, bool for64Bit)
|
public IProcessContext Create(KernelContext context, ulong pid, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler, bool for64Bit)
|
||||||
{
|
{
|
||||||
IArmProcessContext processContext;
|
IArmProcessContext processContext;
|
||||||
AddressSpace addressSpace = null;
|
|
||||||
|
|
||||||
bool isArm64Host = RuntimeInformation.ProcessArchitecture == Architecture.Arm64;
|
bool isArm64Host = RuntimeInformation.ProcessArchitecture == Architecture.Arm64;
|
||||||
|
|
||||||
@ -71,16 +70,16 @@ namespace Ryujinx.HLE.HOS
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!AddressSpace.TryCreate(context.Memory, addressSpaceSize, out addressSpace))
|
if (!AddressSpace.TryCreateWithoutMirror(addressSpaceSize, out var addressSpace))
|
||||||
{
|
{
|
||||||
throw new Exception("Address space creation failed");
|
throw new Exception("Address space creation failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.Cpu, $"NCE Base AS Address: 0x{addressSpace.Base.Pointer.ToInt64():X} Size: 0x{addressSpace.AddressSpaceSize:X}");
|
Logger.Info?.Print(LogClass.Cpu, $"NCE Base AS Address: 0x{addressSpace.Pointer.ToInt64():X} Size: 0x{addressSpace.Size:X}");
|
||||||
|
|
||||||
var cpuEngine = new NceEngine(_tickSource);
|
var cpuEngine = new NceEngine(_tickSource);
|
||||||
var memoryManager = new MemoryManagerNative(addressSpace, context.Memory, addressSpaceSize, invalidAccessHandler);
|
var memoryManager = new MemoryManagerNative(addressSpace, context.Memory, addressSpaceSize, invalidAccessHandler);
|
||||||
processContext = new ArmProcessContext<MemoryManagerNative>(pid, cpuEngine, _gpu, memoryManager, addressSpace.AddressSpaceSize, for64Bit, memoryManager.ReservedSize);
|
processContext = new ArmProcessContext<MemoryManagerNative>(pid, cpuEngine, _gpu, memoryManager, addressSpace.Size, for64Bit, memoryManager.ReservedSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -98,10 +97,14 @@ namespace Ryujinx.HLE.HOS
|
|||||||
? new LightningJitEngine(_tickSource)
|
? new LightningJitEngine(_tickSource)
|
||||||
: new JitEngine(_tickSource);
|
: new JitEngine(_tickSource);
|
||||||
|
|
||||||
|
AddressSpace addressSpace = null;
|
||||||
|
MemoryBlock asNoMirror = null;
|
||||||
|
|
||||||
// We want to use host tracked mode if the host page size is > 4KB.
|
// We want to use host tracked mode if the host page size is > 4KB.
|
||||||
if ((mode == MemoryManagerMode.HostMapped || mode == MemoryManagerMode.HostMappedUnsafe) && MemoryBlock.GetPageSize() <= 0x1000)
|
if ((mode == MemoryManagerMode.HostMapped || mode == MemoryManagerMode.HostMappedUnsafe) && MemoryBlock.GetPageSize() <= 0x1000)
|
||||||
{
|
{
|
||||||
if (!AddressSpace.TryCreate(context.Memory, addressSpaceSize, out addressSpace))
|
if (!AddressSpace.TryCreate(context.Memory, addressSpaceSize, out addressSpace) &&
|
||||||
|
!AddressSpace.TryCreateWithoutMirror(addressSpaceSize, out asNoMirror))
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.Cpu, "Address space creation failed, falling back to software page table");
|
Logger.Warning?.Print(LogClass.Cpu, "Address space creation failed, falling back to software page table");
|
||||||
|
|
||||||
@ -112,13 +115,15 @@ namespace Ryujinx.HLE.HOS
|
|||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
case MemoryManagerMode.SoftwarePageTable:
|
case MemoryManagerMode.SoftwarePageTable:
|
||||||
var memoryManager = new MemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler);
|
{
|
||||||
processContext = new ArmProcessContext<MemoryManager>(pid, cpuEngine, _gpu, memoryManager, addressSpaceSize, for64Bit);
|
var mm = new MemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler);
|
||||||
|
processContext = new ArmProcessContext<MemoryManager>(pid, cpuEngine, _gpu, mm, addressSpaceSize, for64Bit);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MemoryManagerMode.HostMapped:
|
case MemoryManagerMode.HostMapped:
|
||||||
case MemoryManagerMode.HostMappedUnsafe:
|
case MemoryManagerMode.HostMappedUnsafe:
|
||||||
if (addressSpace == null)
|
if (addressSpace == null && asNoMirror == null)
|
||||||
{
|
{
|
||||||
var memoryManagerHostTracked = new MemoryManagerHostTracked(context.Memory, addressSpaceSize, mode == MemoryManagerMode.HostMappedUnsafe, invalidAccessHandler);
|
var memoryManagerHostTracked = new MemoryManagerHostTracked(context.Memory, addressSpaceSize, mode == MemoryManagerMode.HostMappedUnsafe, invalidAccessHandler);
|
||||||
processContext = new ArmProcessContext<MemoryManagerHostTracked>(pid, cpuEngine, _gpu, memoryManagerHostTracked, addressSpaceSize, for64Bit);
|
processContext = new ArmProcessContext<MemoryManagerHostTracked>(pid, cpuEngine, _gpu, memoryManagerHostTracked, addressSpaceSize, for64Bit);
|
||||||
@ -130,14 +135,29 @@ namespace Ryujinx.HLE.HOS
|
|||||||
Logger.Warning?.Print(LogClass.Emulation, $"Allocated address space (0x{addressSpace.AddressSpaceSize:X}) is smaller than guest application requirements (0x{addressSpaceSize:X})");
|
Logger.Warning?.Print(LogClass.Emulation, $"Allocated address space (0x{addressSpace.AddressSpaceSize:X}) is smaller than guest application requirements (0x{addressSpaceSize:X})");
|
||||||
}
|
}
|
||||||
|
|
||||||
var memoryManagerHostMapped = new MemoryManagerHostMapped(addressSpace, mode == MemoryManagerMode.HostMappedUnsafe, invalidAccessHandler);
|
bool unsafeMode = mode == MemoryManagerMode.HostMappedUnsafe;
|
||||||
processContext = new ArmProcessContext<MemoryManagerHostMapped>(pid, cpuEngine, _gpu, memoryManagerHostMapped, addressSpace.AddressSpaceSize, for64Bit);
|
|
||||||
|
if (addressSpace != null)
|
||||||
|
{
|
||||||
|
var mm = new MemoryManagerHostMapped(addressSpace, unsafeMode, invalidAccessHandler);
|
||||||
|
processContext = new ArmProcessContext<MemoryManagerHostMapped>(pid, cpuEngine, _gpu, mm, addressSpace.AddressSpaceSize, for64Bit);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var mm = new MemoryManagerHostNoMirror(asNoMirror, context.Memory, unsafeMode, invalidAccessHandler);
|
||||||
|
processContext = new ArmProcessContext<MemoryManagerHostNoMirror>(pid, cpuEngine, _gpu, mm, asNoMirror.Size, for64Bit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new InvalidOperationException($"{nameof(mode)} contains an invalid value: {mode}");
|
throw new InvalidOperationException($"{nameof(mode)} contains an invalid value: {mode}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (addressSpaceSize != processContext.AddressSpaceSize)
|
||||||
|
{
|
||||||
|
Logger.Warning?.Print(LogClass.Emulation, $"Allocated address space (0x{processContext.AddressSpaceSize:X}) is smaller than guest application requirements (0x{addressSpaceSize:X})");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DiskCacheLoadState = processContext.Initialize(_titleIdText, _displayVersion, _diskCacheEnabled, _codeAddress, _codeSize);
|
DiskCacheLoadState = processContext.Initialize(_titleIdText, _displayVersion, _diskCacheEnabled, _codeAddress, _codeSize);
|
||||||
|
@ -221,11 +221,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ProcessCreationFlags.AddressSpace64Bit:
|
case ProcessCreationFlags.AddressSpace64Bit:
|
||||||
|
ulong reservedAddressSpaceSize = _reservedAddressSpaceSize;
|
||||||
if (_reservedAddressSpaceSize < addrSpaceEnd)
|
if (_reservedAddressSpaceSize < addrSpaceEnd)
|
||||||
{
|
{
|
||||||
int addressSpaceWidth = (int)ulong.Log2(_reservedAddressSpaceSize);
|
int addressSpaceWidth = (int)ulong.Log2(reservedAddressSpaceSize);
|
||||||
|
|
||||||
aliasRegion.Size = 1UL << (addressSpaceWidth - 3);
|
aliasRegion.Size = reservedAddressSpaceSize >= 0x1800000000 ? 0x1000000000 : 1UL << (addressSpaceWidth - 3);
|
||||||
heapRegion.Size = 0x180000000;
|
heapRegion.Size = 0x180000000;
|
||||||
stackRegion.Size = 1UL << (addressSpaceWidth - 8);
|
stackRegion.Size = 1UL << (addressSpaceWidth - 8);
|
||||||
tlsIoRegion.Size = 1UL << (addressSpaceWidth - 3);
|
tlsIoRegion.Size = 1UL << (addressSpaceWidth - 3);
|
||||||
@ -234,7 +235,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||||||
stackAndTlsIoStart = 0;
|
stackAndTlsIoStart = 0;
|
||||||
stackAndTlsIoEnd = 0;
|
stackAndTlsIoEnd = 0;
|
||||||
AslrRegionStart = Math.Max(reservedSize, 0x8000000);
|
AslrRegionStart = Math.Max(reservedSize, 0x8000000);
|
||||||
addrSpaceEnd = reservedSize + (1UL << addressSpaceWidth);
|
addrSpaceEnd = reservedSize + reservedAddressSpaceSize;
|
||||||
AslrRegionEnd = addrSpaceEnd;
|
AslrRegionEnd = addrSpaceEnd;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using LibHac.Account;
|
using LibHac.Account;
|
||||||
using LibHac.Common;
|
using LibHac.Common;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
using LibHac.Fs.Fsa;
|
using LibHac.Fs.Fsa;
|
||||||
@ -252,7 +252,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
ulong argsStart = 0;
|
ulong argsStart = 0;
|
||||||
uint argsSize = 0;
|
uint argsSize = 0;
|
||||||
ulong codeStart = ((meta.Flags & 1) != 0 ? 0x8000000UL : 0x200000UL) + CodeStartOffset;
|
ulong codeStart = ((meta.Flags & 1) != 0 ? 0x8000000UL : 0x200000UL) + CodeStartOffset;
|
||||||
uint codeSize = 0;
|
ulong codeSize = 0;
|
||||||
|
|
||||||
var buildIds = executables.Select(e => (e switch
|
var buildIds = executables.Select(e => (e switch
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user