forked from Mirror/Ryujinx
misc: Implement address space size workarounds (#5191)
* misc: Implement address space size workarounds This adds code to support userland with less than 39 bits of address space available by testing reserving multiple sizes and reducing guess address space when needed. This is required for ARM64 support when the kernel is configured to use 63..39 bits for kernel space.(meaning only 38 bits is available to userland) * Address comments * Fix 32 bits address space support and address more comments
This commit is contained in:
parent
f9a538bb0f
commit
649d372f7d
10 changed files with 187 additions and 111 deletions
|
@ -5,7 +5,7 @@ using System;
|
||||||
|
|
||||||
namespace Ryujinx.Cpu
|
namespace Ryujinx.Cpu
|
||||||
{
|
{
|
||||||
class AddressSpace : IDisposable
|
public class AddressSpace : IDisposable
|
||||||
{
|
{
|
||||||
private const ulong PageSize = 0x1000;
|
private const ulong PageSize = 0x1000;
|
||||||
|
|
||||||
|
@ -154,7 +154,9 @@ namespace Ryujinx.Cpu
|
||||||
public MemoryBlock Base { get; }
|
public MemoryBlock Base { get; }
|
||||||
public MemoryBlock Mirror { get; }
|
public MemoryBlock Mirror { get; }
|
||||||
|
|
||||||
public AddressSpace(MemoryBlock backingMemory, ulong asSize, bool supports4KBPages)
|
public ulong AddressSpaceSize { get; }
|
||||||
|
|
||||||
|
public AddressSpace(MemoryBlock backingMemory, MemoryBlock baseMemory, MemoryBlock mirrorMemory, ulong addressSpaceSize, bool supports4KBPages)
|
||||||
{
|
{
|
||||||
if (!supports4KBPages)
|
if (!supports4KBPages)
|
||||||
{
|
{
|
||||||
|
@ -163,17 +165,48 @@ namespace Ryujinx.Cpu
|
||||||
_privateTree = new IntrusiveRedBlackTree<PrivateMapping>();
|
_privateTree = new IntrusiveRedBlackTree<PrivateMapping>();
|
||||||
_treeLock = new object();
|
_treeLock = new object();
|
||||||
|
|
||||||
_mappingTree.Add(new Mapping(0UL, asSize, MappingType.None));
|
_mappingTree.Add(new Mapping(0UL, addressSpaceSize, MappingType.None));
|
||||||
_privateTree.Add(new PrivateMapping(0UL, asSize, default));
|
_privateTree.Add(new PrivateMapping(0UL, addressSpaceSize, default));
|
||||||
}
|
}
|
||||||
|
|
||||||
_backingMemory = backingMemory;
|
_backingMemory = backingMemory;
|
||||||
_supports4KBPages = supports4KBPages;
|
_supports4KBPages = supports4KBPages;
|
||||||
|
|
||||||
|
Base = baseMemory;
|
||||||
|
Mirror = mirrorMemory;
|
||||||
|
AddressSpaceSize = addressSpaceSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryCreate(MemoryBlock backingMemory, ulong asSize, bool supports4KBPages, out AddressSpace addressSpace)
|
||||||
|
{
|
||||||
|
addressSpace = null;
|
||||||
|
|
||||||
MemoryAllocationFlags asFlags = MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible;
|
MemoryAllocationFlags asFlags = MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible;
|
||||||
|
|
||||||
Base = new MemoryBlock(asSize, asFlags);
|
ulong minAddressSpaceSize = Math.Min(asSize, 1UL << 36);
|
||||||
Mirror = new MemoryBlock(asSize, asFlags);
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
MemoryBlock baseMemory = null;
|
||||||
|
MemoryBlock mirrorMemory = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
baseMemory = new MemoryBlock(addressSpaceSize, asFlags);
|
||||||
|
mirrorMemory = new MemoryBlock(addressSpaceSize, asFlags);
|
||||||
|
addressSpace = new AddressSpace(backingMemory, baseMemory, mirrorMemory, addressSpaceSize, supports4KBPages);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (OutOfMemoryException)
|
||||||
|
{
|
||||||
|
baseMemory?.Dispose();
|
||||||
|
mirrorMemory?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return addressSpace != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Map(ulong va, ulong pa, ulong size, MemoryMapFlags flags)
|
public void Map(ulong va, ulong pa, ulong size, MemoryMapFlags flags)
|
||||||
|
|
|
@ -38,7 +38,8 @@ namespace Ryujinx.Cpu.Jit
|
||||||
private readonly bool _unsafeMode;
|
private readonly bool _unsafeMode;
|
||||||
|
|
||||||
private readonly AddressSpace _addressSpace;
|
private readonly AddressSpace _addressSpace;
|
||||||
private readonly ulong _addressSpaceSize;
|
|
||||||
|
public ulong AddressSpaceSize { get; }
|
||||||
|
|
||||||
private readonly PageTable<ulong> _pageTable;
|
private readonly PageTable<ulong> _pageTable;
|
||||||
|
|
||||||
|
@ -62,21 +63,21 @@ namespace Ryujinx.Cpu.Jit
|
||||||
/// <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="backingMemory">Physical backing memory where virtual memory will be mapped to</param>
|
/// <param name="addressSpace">Address space instance to use</param>
|
||||||
/// <param name="addressSpaceSize">Size of the address space</param>
|
|
||||||
/// <param name="unsafeMode">True if unmanaged access should not be masked (unsafe), false otherwise.</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>
|
/// <param name="invalidAccessHandler">Optional function to handle invalid memory accesses</param>
|
||||||
public MemoryManagerHostMapped(MemoryBlock backingMemory, ulong addressSpaceSize, bool unsafeMode, InvalidAccessHandler invalidAccessHandler = null)
|
public MemoryManagerHostMapped(AddressSpace addressSpace, bool unsafeMode, InvalidAccessHandler invalidAccessHandler)
|
||||||
{
|
{
|
||||||
|
_addressSpace = addressSpace;
|
||||||
_pageTable = new PageTable<ulong>();
|
_pageTable = new PageTable<ulong>();
|
||||||
_invalidAccessHandler = invalidAccessHandler;
|
_invalidAccessHandler = invalidAccessHandler;
|
||||||
_unsafeMode = unsafeMode;
|
_unsafeMode = unsafeMode;
|
||||||
_addressSpaceSize = addressSpaceSize;
|
AddressSpaceSize = addressSpace.AddressSpaceSize;
|
||||||
|
|
||||||
ulong asSize = PageSize;
|
ulong asSize = PageSize;
|
||||||
int asBits = PageBits;
|
int asBits = PageBits;
|
||||||
|
|
||||||
while (asSize < addressSpaceSize)
|
while (asSize < AddressSpaceSize)
|
||||||
{
|
{
|
||||||
asSize <<= 1;
|
asSize <<= 1;
|
||||||
asBits++;
|
asBits++;
|
||||||
|
@ -86,8 +87,6 @@ namespace Ryujinx.Cpu.Jit
|
||||||
|
|
||||||
_pageBitmap = new ulong[1 << (AddressSpaceBits - (PageBits + PageToPteShift))];
|
_pageBitmap = new ulong[1 << (AddressSpaceBits - (PageBits + PageToPteShift))];
|
||||||
|
|
||||||
_addressSpace = new AddressSpace(backingMemory, asSize, Supports4KBPages);
|
|
||||||
|
|
||||||
Tracking = new MemoryTracking(this, (int)MemoryBlock.GetPageSize(), invalidAccessHandler);
|
Tracking = new MemoryTracking(this, (int)MemoryBlock.GetPageSize(), invalidAccessHandler);
|
||||||
_memoryEh = new MemoryEhMeilleure(_addressSpace.Base, _addressSpace.Mirror, Tracking);
|
_memoryEh = new MemoryEhMeilleure(_addressSpace.Base, _addressSpace.Mirror, Tracking);
|
||||||
}
|
}
|
||||||
|
@ -99,7 +98,7 @@ namespace Ryujinx.Cpu.Jit
|
||||||
/// <returns>True if the virtual address is part of the addressable space</returns>
|
/// <returns>True if the virtual address is part of the addressable space</returns>
|
||||||
private bool ValidateAddress(ulong va)
|
private bool ValidateAddress(ulong va)
|
||||||
{
|
{
|
||||||
return va < _addressSpaceSize;
|
return va < AddressSpaceSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -111,7 +110,7 @@ namespace Ryujinx.Cpu.Jit
|
||||||
private bool ValidateAddressAndSize(ulong va, ulong size)
|
private bool ValidateAddressAndSize(ulong va, ulong size)
|
||||||
{
|
{
|
||||||
ulong endVa = va + size;
|
ulong endVa = va + size;
|
||||||
return endVa >= va && endVa >= size && endVa <= _addressSpaceSize;
|
return endVa >= va && endVa >= size && endVa <= AddressSpaceSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -25,7 +25,15 @@ namespace Ryujinx.HLE.HOS
|
||||||
|
|
||||||
public IVirtualMemoryManager AddressSpace => _memoryManager;
|
public IVirtualMemoryManager AddressSpace => _memoryManager;
|
||||||
|
|
||||||
public ArmProcessContext(ulong pid, ICpuEngine cpuEngine, GpuContext gpuContext, T memoryManager, bool for64Bit)
|
public ulong AddressSpaceSize { get; }
|
||||||
|
|
||||||
|
public ArmProcessContext(
|
||||||
|
ulong pid,
|
||||||
|
ICpuEngine cpuEngine,
|
||||||
|
GpuContext gpuContext,
|
||||||
|
T memoryManager,
|
||||||
|
ulong addressSpaceSize,
|
||||||
|
bool for64Bit)
|
||||||
{
|
{
|
||||||
if (memoryManager is IRefCounted rc)
|
if (memoryManager is IRefCounted rc)
|
||||||
{
|
{
|
||||||
|
@ -38,6 +46,8 @@ namespace Ryujinx.HLE.HOS
|
||||||
_gpuContext = gpuContext;
|
_gpuContext = gpuContext;
|
||||||
_cpuContext = cpuEngine.CreateCpuContext(memoryManager, for64Bit);
|
_cpuContext = cpuEngine.CreateCpuContext(memoryManager, for64Bit);
|
||||||
_memoryManager = memoryManager;
|
_memoryManager = memoryManager;
|
||||||
|
|
||||||
|
AddressSpaceSize = addressSpaceSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks)
|
public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Cpu;
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.Cpu.AppleHv;
|
using Ryujinx.Cpu.AppleHv;
|
||||||
using Ryujinx.Cpu.Jit;
|
using Ryujinx.Cpu.Jit;
|
||||||
|
@ -49,7 +50,7 @@ namespace Ryujinx.HLE.HOS
|
||||||
{
|
{
|
||||||
var cpuEngine = new HvEngine(_tickSource);
|
var cpuEngine = new HvEngine(_tickSource);
|
||||||
var memoryManager = new HvMemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler);
|
var memoryManager = new HvMemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler);
|
||||||
processContext = new ArmProcessContext<HvMemoryManager>(pid, cpuEngine, _gpu, memoryManager, for64Bit);
|
processContext = new ArmProcessContext<HvMemoryManager>(pid, cpuEngine, _gpu, memoryManager, addressSpaceSize, for64Bit);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -57,23 +58,41 @@ namespace Ryujinx.HLE.HOS
|
||||||
|
|
||||||
if (!MemoryBlock.SupportsFlags(MemoryAllocationFlags.ViewCompatible))
|
if (!MemoryBlock.SupportsFlags(MemoryAllocationFlags.ViewCompatible))
|
||||||
{
|
{
|
||||||
|
Logger.Warning?.Print(LogClass.Cpu, "Host system doesn't support views, falling back to software page table");
|
||||||
|
|
||||||
mode = MemoryManagerMode.SoftwarePageTable;
|
mode = MemoryManagerMode.SoftwarePageTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
var cpuEngine = new JitEngine(_tickSource);
|
var cpuEngine = new JitEngine(_tickSource);
|
||||||
|
|
||||||
|
AddressSpace addressSpace = null;
|
||||||
|
|
||||||
|
if (mode == MemoryManagerMode.HostMapped || mode == MemoryManagerMode.HostMappedUnsafe)
|
||||||
|
{
|
||||||
|
if (!AddressSpace.TryCreate(context.Memory, addressSpaceSize, MemoryBlock.GetPageSize() == MemoryManagerHostMapped.PageSize, out addressSpace))
|
||||||
|
{
|
||||||
|
Logger.Warning?.Print(LogClass.Cpu, "Address space creation failed, falling back to software page table");
|
||||||
|
|
||||||
|
mode = MemoryManagerMode.SoftwarePageTable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
case MemoryManagerMode.SoftwarePageTable:
|
case MemoryManagerMode.SoftwarePageTable:
|
||||||
var memoryManager = new MemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler);
|
var memoryManager = new MemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler);
|
||||||
processContext = new ArmProcessContext<MemoryManager>(pid, cpuEngine, _gpu, memoryManager, for64Bit);
|
processContext = new ArmProcessContext<MemoryManager>(pid, cpuEngine, _gpu, memoryManager, addressSpaceSize, for64Bit);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MemoryManagerMode.HostMapped:
|
case MemoryManagerMode.HostMapped:
|
||||||
case MemoryManagerMode.HostMappedUnsafe:
|
case MemoryManagerMode.HostMappedUnsafe:
|
||||||
bool unsafeMode = mode == MemoryManagerMode.HostMappedUnsafe;
|
if (addressSpaceSize != addressSpace.AddressSpaceSize)
|
||||||
var memoryManagerHostMapped = new MemoryManagerHostMapped(context.Memory, addressSpaceSize, unsafeMode, invalidAccessHandler);
|
{
|
||||||
processContext = new ArmProcessContext<MemoryManagerHostMapped>(pid, cpuEngine, _gpu, memoryManagerHostMapped, for64Bit);
|
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);
|
||||||
|
processContext = new ArmProcessContext<MemoryManagerHostMapped>(pid, cpuEngine, _gpu, memoryManagerHostMapped, addressSpace.AddressSpaceSize, for64Bit);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
|
|
||||||
protected override bool Supports4KBPages => _cpuMemory.Supports4KBPages;
|
protected override bool Supports4KBPages => _cpuMemory.Supports4KBPages;
|
||||||
|
|
||||||
public KPageTable(KernelContext context, IVirtualMemoryManager cpuMemory) : base(context)
|
public KPageTable(KernelContext context, IVirtualMemoryManager cpuMemory, ulong reservedAddressSpaceSize) : base(context, reservedAddressSpaceSize)
|
||||||
{
|
{
|
||||||
_cpuMemory = cpuMemory;
|
_cpuMemory = cpuMemory;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
0x40000000
|
0x40000000
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private const ulong RegionAlignment = 0x200000;
|
||||||
|
|
||||||
public const int PageSize = 0x1000;
|
public const int PageSize = 0x1000;
|
||||||
|
|
||||||
private const int KMemoryBlockSize = 0x40;
|
private const int KMemoryBlockSize = 0x40;
|
||||||
|
@ -53,6 +55,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
public ulong TlsIoRegionStart { get; private set; }
|
public ulong TlsIoRegionStart { get; private set; }
|
||||||
public ulong TlsIoRegionEnd { get; private set; }
|
public ulong TlsIoRegionEnd { get; private set; }
|
||||||
|
|
||||||
|
public ulong AslrRegionStart { get; private set; }
|
||||||
|
public ulong AslrRegionEnd { get; private set; }
|
||||||
|
|
||||||
private ulong _heapCapacity;
|
private ulong _heapCapacity;
|
||||||
|
|
||||||
public ulong PhysicalMemoryUsage { get; private set; }
|
public ulong PhysicalMemoryUsage { get; private set; }
|
||||||
|
@ -61,10 +66,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
|
|
||||||
private MemoryRegion _memRegion;
|
private MemoryRegion _memRegion;
|
||||||
|
|
||||||
private bool _aslrDisabled;
|
private bool _allocateFromBack;
|
||||||
|
|
||||||
public int AddrSpaceWidth { get; private set; }
|
|
||||||
|
|
||||||
private bool _isKernel;
|
private bool _isKernel;
|
||||||
|
|
||||||
private bool _aslrEnabled;
|
private bool _aslrEnabled;
|
||||||
|
@ -78,7 +80,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
private MemoryFillValue _heapFillValue;
|
private MemoryFillValue _heapFillValue;
|
||||||
private MemoryFillValue _ipcFillValue;
|
private MemoryFillValue _ipcFillValue;
|
||||||
|
|
||||||
public KPageTableBase(KernelContext context)
|
private ulong _reservedAddressSpaceSize;
|
||||||
|
|
||||||
|
public KPageTableBase(KernelContext context, ulong reservedAddressSpaceSize)
|
||||||
{
|
{
|
||||||
Context = context;
|
Context = context;
|
||||||
|
|
||||||
|
@ -88,6 +92,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
|
|
||||||
_heapFillValue = MemoryFillValue.Zero;
|
_heapFillValue = MemoryFillValue.Zero;
|
||||||
_ipcFillValue = MemoryFillValue.Zero;
|
_ipcFillValue = MemoryFillValue.Zero;
|
||||||
|
|
||||||
|
_reservedAddressSpaceSize = reservedAddressSpaceSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly int[] AddrSpaceSizes = new int[] { 32, 36, 32, 39 };
|
private static readonly int[] AddrSpaceSizes = new int[] { 32, 36, 32, 39 };
|
||||||
|
@ -95,7 +101,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
public Result InitializeForProcess(
|
public Result InitializeForProcess(
|
||||||
AddressSpaceType addrSpaceType,
|
AddressSpaceType addrSpaceType,
|
||||||
bool aslrEnabled,
|
bool aslrEnabled,
|
||||||
bool aslrDisabled,
|
bool fromBack,
|
||||||
MemoryRegion memRegion,
|
MemoryRegion memRegion,
|
||||||
ulong address,
|
ulong address,
|
||||||
ulong size,
|
ulong size,
|
||||||
|
@ -114,7 +120,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
Result result = CreateUserAddressSpace(
|
Result result = CreateUserAddressSpace(
|
||||||
addrSpaceType,
|
addrSpaceType,
|
||||||
aslrEnabled,
|
aslrEnabled,
|
||||||
aslrDisabled,
|
fromBack,
|
||||||
addrSpaceBase,
|
addrSpaceBase,
|
||||||
addrSpaceSize,
|
addrSpaceSize,
|
||||||
memRegion,
|
memRegion,
|
||||||
|
@ -130,7 +136,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Region
|
private struct Region
|
||||||
{
|
{
|
||||||
public ulong Start;
|
public ulong Start;
|
||||||
public ulong End;
|
public ulong End;
|
||||||
|
@ -141,7 +147,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
private Result CreateUserAddressSpace(
|
private Result CreateUserAddressSpace(
|
||||||
AddressSpaceType addrSpaceType,
|
AddressSpaceType addrSpaceType,
|
||||||
bool aslrEnabled,
|
bool aslrEnabled,
|
||||||
bool aslrDisabled,
|
bool fromBack,
|
||||||
ulong addrSpaceStart,
|
ulong addrSpaceStart,
|
||||||
ulong addrSpaceEnd,
|
ulong addrSpaceEnd,
|
||||||
MemoryRegion memRegion,
|
MemoryRegion memRegion,
|
||||||
|
@ -159,7 +165,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
ulong codeRegionSize;
|
ulong codeRegionSize;
|
||||||
ulong stackAndTlsIoStart;
|
ulong stackAndTlsIoStart;
|
||||||
ulong stackAndTlsIoEnd;
|
ulong stackAndTlsIoEnd;
|
||||||
ulong baseAddress;
|
|
||||||
|
|
||||||
switch (addrSpaceType)
|
switch (addrSpaceType)
|
||||||
{
|
{
|
||||||
|
@ -170,10 +175,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
tlsIoRegion.Size = 0;
|
tlsIoRegion.Size = 0;
|
||||||
CodeRegionStart = 0x200000;
|
CodeRegionStart = 0x200000;
|
||||||
codeRegionSize = 0x3fe00000;
|
codeRegionSize = 0x3fe00000;
|
||||||
|
AslrRegionStart = 0x200000;
|
||||||
|
AslrRegionEnd = AslrRegionStart + 0xffe00000;
|
||||||
stackAndTlsIoStart = 0x200000;
|
stackAndTlsIoStart = 0x200000;
|
||||||
stackAndTlsIoEnd = 0x40000000;
|
stackAndTlsIoEnd = 0x40000000;
|
||||||
baseAddress = 0x200000;
|
|
||||||
AddrSpaceWidth = 32;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AddressSpaceType.Addr36Bits:
|
case AddressSpaceType.Addr36Bits:
|
||||||
|
@ -183,10 +188,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
tlsIoRegion.Size = 0;
|
tlsIoRegion.Size = 0;
|
||||||
CodeRegionStart = 0x8000000;
|
CodeRegionStart = 0x8000000;
|
||||||
codeRegionSize = 0x78000000;
|
codeRegionSize = 0x78000000;
|
||||||
|
AslrRegionStart = 0x8000000;
|
||||||
|
AslrRegionEnd = AslrRegionStart + 0xff8000000;
|
||||||
stackAndTlsIoStart = 0x8000000;
|
stackAndTlsIoStart = 0x8000000;
|
||||||
stackAndTlsIoEnd = 0x80000000;
|
stackAndTlsIoEnd = 0x80000000;
|
||||||
baseAddress = 0x8000000;
|
|
||||||
AddrSpaceWidth = 36;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AddressSpaceType.Addr32BitsNoMap:
|
case AddressSpaceType.Addr32BitsNoMap:
|
||||||
|
@ -196,23 +201,42 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
tlsIoRegion.Size = 0;
|
tlsIoRegion.Size = 0;
|
||||||
CodeRegionStart = 0x200000;
|
CodeRegionStart = 0x200000;
|
||||||
codeRegionSize = 0x3fe00000;
|
codeRegionSize = 0x3fe00000;
|
||||||
|
AslrRegionStart = 0x200000;
|
||||||
|
AslrRegionEnd = AslrRegionStart + 0xffe00000;
|
||||||
stackAndTlsIoStart = 0x200000;
|
stackAndTlsIoStart = 0x200000;
|
||||||
stackAndTlsIoEnd = 0x40000000;
|
stackAndTlsIoEnd = 0x40000000;
|
||||||
baseAddress = 0x200000;
|
|
||||||
AddrSpaceWidth = 32;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AddressSpaceType.Addr39Bits:
|
case AddressSpaceType.Addr39Bits:
|
||||||
aliasRegion.Size = 0x1000000000;
|
if (_reservedAddressSpaceSize < addrSpaceEnd)
|
||||||
heapRegion.Size = 0x180000000;
|
{
|
||||||
stackRegion.Size = 0x80000000;
|
int addressSpaceWidth = (int)ulong.Log2(_reservedAddressSpaceSize);
|
||||||
tlsIoRegion.Size = 0x1000000000;
|
|
||||||
CodeRegionStart = BitUtils.AlignDown<ulong>(address, 0x200000);
|
aliasRegion.Size = 1UL << (addressSpaceWidth - 3);
|
||||||
codeRegionSize = BitUtils.AlignUp<ulong>(endAddr, 0x200000) - CodeRegionStart;
|
heapRegion.Size = 0x180000000;
|
||||||
stackAndTlsIoStart = 0;
|
stackRegion.Size = 1UL << (addressSpaceWidth - 8);
|
||||||
stackAndTlsIoEnd = 0;
|
tlsIoRegion.Size = 1UL << (addressSpaceWidth - 3);
|
||||||
baseAddress = 0x8000000;
|
CodeRegionStart = BitUtils.AlignDown<ulong>(address, RegionAlignment);
|
||||||
AddrSpaceWidth = 39;
|
codeRegionSize = BitUtils.AlignUp<ulong>(endAddr, RegionAlignment) - CodeRegionStart;
|
||||||
|
stackAndTlsIoStart = 0;
|
||||||
|
stackAndTlsIoEnd = 0;
|
||||||
|
AslrRegionStart = 0x8000000;
|
||||||
|
addrSpaceEnd = 1UL << addressSpaceWidth;
|
||||||
|
AslrRegionEnd = addrSpaceEnd;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
aliasRegion.Size = 0x1000000000;
|
||||||
|
heapRegion.Size = 0x180000000;
|
||||||
|
stackRegion.Size = 0x80000000;
|
||||||
|
tlsIoRegion.Size = 0x1000000000;
|
||||||
|
CodeRegionStart = BitUtils.AlignDown(address, RegionAlignment);
|
||||||
|
codeRegionSize = BitUtils.AlignUp(endAddr, RegionAlignment) - CodeRegionStart;
|
||||||
|
AslrRegionStart = 0x8000000;
|
||||||
|
AslrRegionEnd = AslrRegionStart + 0x7ff8000000;
|
||||||
|
stackAndTlsIoStart = 0;
|
||||||
|
stackAndTlsIoEnd = 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: throw new ArgumentException(nameof(addrSpaceType));
|
default: throw new ArgumentException(nameof(addrSpaceType));
|
||||||
|
@ -223,11 +247,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
ulong mapBaseAddress;
|
ulong mapBaseAddress;
|
||||||
ulong mapAvailableSize;
|
ulong mapAvailableSize;
|
||||||
|
|
||||||
if (CodeRegionStart - baseAddress >= addrSpaceEnd - CodeRegionEnd)
|
if (CodeRegionStart - AslrRegionStart >= addrSpaceEnd - CodeRegionEnd)
|
||||||
{
|
{
|
||||||
// Has more space before the start of the code region.
|
// Has more space before the start of the code region.
|
||||||
mapBaseAddress = baseAddress;
|
mapBaseAddress = AslrRegionStart;
|
||||||
mapAvailableSize = CodeRegionStart - baseAddress;
|
mapAvailableSize = CodeRegionStart - AslrRegionStart;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -254,14 +278,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
|
|
||||||
if (aslrEnabled)
|
if (aslrEnabled)
|
||||||
{
|
{
|
||||||
aliasRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset >> 21) << 21;
|
aliasRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset / RegionAlignment) * RegionAlignment;
|
||||||
heapRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset >> 21) << 21;
|
heapRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset / RegionAlignment) * RegionAlignment;
|
||||||
stackRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset >> 21) << 21;
|
stackRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset / RegionAlignment) * RegionAlignment;
|
||||||
tlsIoRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset >> 21) << 21;
|
tlsIoRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset / RegionAlignment) * RegionAlignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Regions are sorted based on ASLR offset.
|
// Regions are sorted based on ASLR offset.
|
||||||
// When ASLR is disabled, the order is Map, Heap, NewMap and TlsIo.
|
// When ASLR is disabled, the order is Alias, Heap, Stack and TlsIo.
|
||||||
aliasRegion.Start = mapBaseAddress + aliasRegion.AslrOffset;
|
aliasRegion.Start = mapBaseAddress + aliasRegion.AslrOffset;
|
||||||
aliasRegion.End = aliasRegion.Start + aliasRegion.Size;
|
aliasRegion.End = aliasRegion.Start + aliasRegion.Size;
|
||||||
heapRegion.Start = mapBaseAddress + heapRegion.AslrOffset;
|
heapRegion.Start = mapBaseAddress + heapRegion.AslrOffset;
|
||||||
|
@ -271,12 +295,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
tlsIoRegion.Start = mapBaseAddress + tlsIoRegion.AslrOffset;
|
tlsIoRegion.Start = mapBaseAddress + tlsIoRegion.AslrOffset;
|
||||||
tlsIoRegion.End = tlsIoRegion.Start + tlsIoRegion.Size;
|
tlsIoRegion.End = tlsIoRegion.Start + tlsIoRegion.Size;
|
||||||
|
|
||||||
SortRegion(heapRegion, aliasRegion);
|
SortRegion(ref aliasRegion, ref heapRegion, true);
|
||||||
|
|
||||||
if (stackRegion.Size != 0)
|
if (stackRegion.Size != 0)
|
||||||
{
|
{
|
||||||
SortRegion(stackRegion, aliasRegion);
|
stackRegion.Start = mapBaseAddress + stackRegion.AslrOffset;
|
||||||
SortRegion(stackRegion, heapRegion);
|
stackRegion.End = stackRegion.Start + stackRegion.Size;
|
||||||
|
|
||||||
|
SortRegion(ref aliasRegion, ref stackRegion);
|
||||||
|
SortRegion(ref heapRegion, ref stackRegion);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -286,9 +313,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
|
|
||||||
if (tlsIoRegion.Size != 0)
|
if (tlsIoRegion.Size != 0)
|
||||||
{
|
{
|
||||||
SortRegion(tlsIoRegion, aliasRegion);
|
tlsIoRegion.Start = mapBaseAddress + tlsIoRegion.AslrOffset;
|
||||||
SortRegion(tlsIoRegion, heapRegion);
|
tlsIoRegion.End = tlsIoRegion.Start + tlsIoRegion.Size;
|
||||||
SortRegion(tlsIoRegion, stackRegion);
|
|
||||||
|
SortRegion(ref aliasRegion, ref tlsIoRegion);
|
||||||
|
SortRegion(ref heapRegion, ref tlsIoRegion);
|
||||||
|
|
||||||
|
if (stackRegion.Size != 0)
|
||||||
|
{
|
||||||
|
SortRegion(ref stackRegion, ref tlsIoRegion);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -312,11 +346,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
PhysicalMemoryUsage = 0;
|
PhysicalMemoryUsage = 0;
|
||||||
|
|
||||||
_memRegion = memRegion;
|
_memRegion = memRegion;
|
||||||
_aslrDisabled = aslrDisabled;
|
_allocateFromBack = fromBack;
|
||||||
|
|
||||||
return _blockManager.Initialize(addrSpaceStart, addrSpaceEnd, slabManager);
|
return _blockManager.Initialize(addrSpaceStart, addrSpaceEnd, slabManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void SortRegion(ref Region lhs, ref Region rhs, bool checkForEquality = false)
|
||||||
|
{
|
||||||
|
bool res = checkForEquality ? lhs.AslrOffset <= rhs.AslrOffset : lhs.AslrOffset < rhs.AslrOffset;
|
||||||
|
|
||||||
|
if (res)
|
||||||
|
{
|
||||||
|
rhs.Start += lhs.Size;
|
||||||
|
rhs.End += lhs.Size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lhs.Start += rhs.Size;
|
||||||
|
lhs.End += rhs.Size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private ulong GetRandomValue(ulong min, ulong max)
|
private ulong GetRandomValue(ulong min, ulong max)
|
||||||
{
|
{
|
||||||
return (ulong)GetRandomValue((long)min, (long)max);
|
return (ulong)GetRandomValue((long)min, (long)max);
|
||||||
|
@ -332,20 +382,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
return _randomNumberGenerator.GenRandomNumber(min, max);
|
return _randomNumberGenerator.GenRandomNumber(min, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SortRegion(Region lhs, Region rhs)
|
|
||||||
{
|
|
||||||
if (lhs.AslrOffset < rhs.AslrOffset)
|
|
||||||
{
|
|
||||||
rhs.Start += lhs.Size;
|
|
||||||
rhs.End += lhs.Size;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
lhs.Start += rhs.Size;
|
|
||||||
lhs.End += rhs.Size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result MapPages(ulong address, KPageList pageList, MemoryState state, KMemoryPermission permission)
|
public Result MapPages(ulong address, KPageList pageList, MemoryState state, KMemoryPermission permission)
|
||||||
{
|
{
|
||||||
ulong pagesCount = pageList.GetPagesCount();
|
ulong pagesCount = pageList.GetPagesCount();
|
||||||
|
@ -1827,7 +1863,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
// If not, allocate a new page and copy the unaligned chunck.
|
// If not, allocate a new page and copy the unaligned chunck.
|
||||||
if (addressTruncated < addressRounded)
|
if (addressTruncated < addressRounded)
|
||||||
{
|
{
|
||||||
dstFirstPagePa = GetMemoryRegionManager().AllocatePagesContiguous(Context, 1, _aslrDisabled);
|
dstFirstPagePa = GetMemoryRegionManager().AllocatePagesContiguous(Context, 1, _allocateFromBack);
|
||||||
|
|
||||||
if (dstFirstPagePa == 0)
|
if (dstFirstPagePa == 0)
|
||||||
{
|
{
|
||||||
|
@ -1841,7 +1877,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
// If not, allocate a new page and copy the unaligned chunck.
|
// If not, allocate a new page and copy the unaligned chunck.
|
||||||
if (endAddrTruncated < endAddrRounded && (addressTruncated == addressRounded || addressTruncated < endAddrTruncated))
|
if (endAddrTruncated < endAddrRounded && (addressTruncated == addressRounded || addressTruncated < endAddrTruncated))
|
||||||
{
|
{
|
||||||
dstLastPagePa = GetMemoryRegionManager().AllocatePagesContiguous(Context, 1, _aslrDisabled);
|
dstLastPagePa = GetMemoryRegionManager().AllocatePagesContiguous(Context, 1, _allocateFromBack);
|
||||||
|
|
||||||
if (dstLastPagePa == 0)
|
if (dstLastPagePa == 0)
|
||||||
{
|
{
|
||||||
|
@ -2799,38 +2835,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
|
|
||||||
public ulong GetAddrSpaceBaseAddr()
|
public ulong GetAddrSpaceBaseAddr()
|
||||||
{
|
{
|
||||||
if (AddrSpaceWidth == 36 || AddrSpaceWidth == 39)
|
return AslrRegionStart;
|
||||||
{
|
|
||||||
return 0x8000000;
|
|
||||||
}
|
|
||||||
else if (AddrSpaceWidth == 32)
|
|
||||||
{
|
|
||||||
return 0x200000;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Invalid address space width!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ulong GetAddrSpaceSize()
|
public ulong GetAddrSpaceSize()
|
||||||
{
|
{
|
||||||
if (AddrSpaceWidth == 36)
|
return AslrRegionEnd - AslrRegionStart;
|
||||||
{
|
|
||||||
return 0xff8000000;
|
|
||||||
}
|
|
||||||
else if (AddrSpaceWidth == 39)
|
|
||||||
{
|
|
||||||
return 0x7ff8000000;
|
|
||||||
}
|
|
||||||
else if (AddrSpaceWidth == 32)
|
|
||||||
{
|
|
||||||
return 0xffe00000;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Invalid address space width!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ulong GetDramAddressFromPa(ulong pa)
|
private static ulong GetDramAddressFromPa(ulong pa)
|
||||||
|
|
|
@ -8,6 +8,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
{
|
{
|
||||||
IVirtualMemoryManager AddressSpace { get; }
|
IVirtualMemoryManager AddressSpace { get; }
|
||||||
|
|
||||||
|
ulong AddressSpaceSize { get; }
|
||||||
|
|
||||||
IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks);
|
IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks);
|
||||||
void Execute(IExecutionContext context, ulong codeAddress);
|
void Execute(IExecutionContext context, ulong codeAddress);
|
||||||
void InvalidateCacheRegion(ulong address, ulong size);
|
void InvalidateCacheRegion(ulong address, ulong size);
|
||||||
|
|
|
@ -1082,7 +1082,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
|
|
||||||
Context = _contextFactory.Create(KernelContext, Pid, 1UL << addrSpaceBits, InvalidAccessHandler, for64Bit);
|
Context = _contextFactory.Create(KernelContext, Pid, 1UL << addrSpaceBits, InvalidAccessHandler, for64Bit);
|
||||||
|
|
||||||
MemoryManager = new KPageTable(KernelContext, CpuMemory);
|
MemoryManager = new KPageTable(KernelContext, CpuMemory, Context.AddressSpaceSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool InvalidAccessHandler(ulong va)
|
private bool InvalidAccessHandler(ulong va)
|
||||||
|
|
|
@ -8,9 +8,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
{
|
{
|
||||||
public IVirtualMemoryManager AddressSpace { get; }
|
public IVirtualMemoryManager AddressSpace { get; }
|
||||||
|
|
||||||
public ProcessContext(IVirtualMemoryManager asManager)
|
public ulong AddressSpaceSize { get; }
|
||||||
|
|
||||||
|
public ProcessContext(IVirtualMemoryManager asManager, ulong addressSpaceSize)
|
||||||
{
|
{
|
||||||
AddressSpace = asManager;
|
AddressSpace = asManager;
|
||||||
|
AddressSpaceSize = addressSpaceSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks)
|
public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks)
|
||||||
|
|
|
@ -6,7 +6,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
{
|
{
|
||||||
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)
|
||||||
{
|
{
|
||||||
return new ProcessContext(new AddressSpaceManager(context.Memory, addressSpaceSize));
|
return new ProcessContext(new AddressSpaceManager(context.Memory, addressSpaceSize), addressSpaceSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue