Compare commits

..

3 Commits

Author SHA1 Message Date
58907e2c29 GetHashCode should not reference mutable fields (#5331) 2023-06-22 18:36:07 +02:00
649d372f7d 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
2023-06-20 17:33:54 +02:00
f9a538bb0f Ensure shader local and shared memory sizes are not zero (#5321) 2023-06-17 16:28:27 -03:00
23 changed files with 284 additions and 138 deletions

View File

@ -13,8 +13,8 @@ namespace ARMeilleure.State
// _e0 & _e1 could be marked as readonly, however they are not readonly because we modify them through the Unsafe
// APIs. This also means that one should be careful when changing the layout of this struct.
private ulong _e0;
private ulong _e1;
private readonly ulong _e0;
private readonly ulong _e1;
/// <summary>
/// Gets a new <see cref="V128"/> with all bits set to zero.

View File

@ -5,7 +5,7 @@ using System;
namespace Ryujinx.Cpu
{
class AddressSpace : IDisposable
public class AddressSpace : IDisposable
{
private const ulong PageSize = 0x1000;
@ -154,7 +154,9 @@ namespace Ryujinx.Cpu
public MemoryBlock Base { 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)
{
@ -163,17 +165,48 @@ namespace Ryujinx.Cpu
_privateTree = new IntrusiveRedBlackTree<PrivateMapping>();
_treeLock = new object();
_mappingTree.Add(new Mapping(0UL, asSize, MappingType.None));
_privateTree.Add(new PrivateMapping(0UL, asSize, default));
_mappingTree.Add(new Mapping(0UL, addressSpaceSize, MappingType.None));
_privateTree.Add(new PrivateMapping(0UL, addressSpaceSize, default));
}
_backingMemory = backingMemory;
_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;
Base = new MemoryBlock(asSize, asFlags);
Mirror = new MemoryBlock(asSize, asFlags);
ulong minAddressSpaceSize = Math.Min(asSize, 1UL << 36);
// 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)

View File

@ -38,7 +38,8 @@ namespace Ryujinx.Cpu.Jit
private readonly bool _unsafeMode;
private readonly AddressSpace _addressSpace;
private readonly ulong _addressSpaceSize;
public ulong AddressSpaceSize { get; }
private readonly PageTable<ulong> _pageTable;
@ -62,21 +63,21 @@ namespace Ryujinx.Cpu.Jit
/// <summary>
/// Creates a new instance of the host mapped memory manager.
/// </summary>
/// <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="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 MemoryManagerHostMapped(MemoryBlock backingMemory, ulong addressSpaceSize, bool unsafeMode, InvalidAccessHandler invalidAccessHandler = null)
public MemoryManagerHostMapped(AddressSpace addressSpace, bool unsafeMode, InvalidAccessHandler invalidAccessHandler)
{
_addressSpace = addressSpace;
_pageTable = new PageTable<ulong>();
_invalidAccessHandler = invalidAccessHandler;
_unsafeMode = unsafeMode;
_addressSpaceSize = addressSpaceSize;
AddressSpaceSize = addressSpace.AddressSpaceSize;
ulong asSize = PageSize;
int asBits = PageBits;
while (asSize < addressSpaceSize)
while (asSize < AddressSpaceSize)
{
asSize <<= 1;
asBits++;
@ -86,8 +87,6 @@ namespace Ryujinx.Cpu.Jit
_pageBitmap = new ulong[1 << (AddressSpaceBits - (PageBits + PageToPteShift))];
_addressSpace = new AddressSpace(backingMemory, asSize, Supports4KBPages);
Tracking = new MemoryTracking(this, (int)MemoryBlock.GetPageSize(), invalidAccessHandler);
_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>
private bool ValidateAddress(ulong va)
{
return va < _addressSpaceSize;
return va < AddressSpaceSize;
}
/// <summary>
@ -111,7 +110,7 @@ namespace Ryujinx.Cpu.Jit
private bool ValidateAddressAndSize(ulong va, ulong size)
{
ulong endVa = va + size;
return endVa >= va && endVa >= size && endVa <= _addressSpaceSize;
return endVa >= va && endVa >= size && endVa <= AddressSpaceSize;
}
/// <summary>

View File

@ -247,6 +247,17 @@ namespace Ryujinx.Graphics.Shader.Decoders
{
block.AddPushOp(op);
}
else if (op.Name == InstName.Ldl || op.Name == InstName.Stl)
{
config.SetUsedFeature(FeatureFlags.LocalMemory);
}
else if (op.Name == InstName.Atoms ||
op.Name == InstName.AtomsCas ||
op.Name == InstName.Lds ||
op.Name == InstName.Sts)
{
config.SetUsedFeature(FeatureFlags.SharedMemory);
}
block.OpCodes.Add(op);

View File

@ -27,6 +27,12 @@ namespace Ryujinx.Graphics.Shader.Instructions
public static void Atoms(EmitterContext context)
{
if (context.Config.Stage != ShaderStage.Compute)
{
context.Config.GpuAccessor.Log($"Atoms instruction is not valid on \"{context.Config.Stage}\" stage.");
return;
}
InstAtoms op = context.GetOp<InstAtoms>();
Operand offset = context.ShiftRightU32(GetSrcReg(context, op.SrcA), Const(2));
@ -114,6 +120,12 @@ namespace Ryujinx.Graphics.Shader.Instructions
public static void Lds(EmitterContext context)
{
if (context.Config.Stage != ShaderStage.Compute)
{
context.Config.GpuAccessor.Log($"Lds instruction is not valid on \"{context.Config.Stage}\" stage.");
return;
}
InstLds op = context.GetOp<InstLds>();
EmitLoad(context, StorageKind.SharedMemory, op.LsSize, GetSrcReg(context, op.SrcA), op.Dest, Imm24ToSInt(op.Imm24));
@ -144,6 +156,12 @@ namespace Ryujinx.Graphics.Shader.Instructions
public static void Sts(EmitterContext context)
{
if (context.Config.Stage != ShaderStage.Compute)
{
context.Config.GpuAccessor.Log($"Sts instruction is not valid on \"{context.Config.Stage}\" stage.");
return;
}
InstSts op = context.GetOp<InstSts>();
EmitStore(context, StorageKind.SharedMemory, op.LsSize, GetSrcReg(context, op.SrcA), op.Dest, Imm24ToSInt(op.Imm24));

View File

@ -21,6 +21,8 @@ namespace Ryujinx.Graphics.Shader.Translation
RtLayer = 1 << 5,
IaIndexing = 1 << 7,
OaIndexing = 1 << 8,
FixedFuncAttr = 1 << 9
FixedFuncAttr = 1 << 9,
LocalMemory = 1 << 10,
SharedMemory = 1 << 11
}
}

View File

@ -8,6 +8,11 @@ namespace Ryujinx.Graphics.Shader.Translation
{
class ResourceManager
{
// Those values are used if the shader as local or shared memory access,
// but for some reason the supplied size was 0.
private const int DefaultLocalMemorySize = 128;
private const int DefaultSharedMemorySize = 4096;
private static readonly string[] _stagePrefixes = new string[] { "cp", "vp", "tcp", "tep", "gp", "fp" };
private readonly IGpuAccessor _gpuAccessor;
@ -23,12 +28,12 @@ namespace Ryujinx.Graphics.Shader.Translation
private readonly HashSet<int> _usedConstantBufferBindings;
public int LocalMemoryId { get; }
public int SharedMemoryId { get; }
public int LocalMemoryId { get; private set; }
public int SharedMemoryId { get; private set; }
public ShaderProperties Properties => _properties;
public ResourceManager(ShaderStage stage, IGpuAccessor gpuAccessor, ShaderProperties properties, int localMemorySize)
public ResourceManager(ShaderStage stage, IGpuAccessor gpuAccessor, ShaderProperties properties)
{
_gpuAccessor = gpuAccessor;
_properties = properties;
@ -48,21 +53,43 @@ namespace Ryujinx.Graphics.Shader.Translation
LocalMemoryId = -1;
SharedMemoryId = -1;
}
if (localMemorySize != 0)
public void SetCurrentLocalMemory(int size, bool isUsed)
{
if (isUsed)
{
var lmem = new MemoryDefinition("local_memory", AggregateType.Array | AggregateType.U32, BitUtils.DivRoundUp(localMemorySize, sizeof(uint)));
if (size <= 0)
{
size = DefaultLocalMemorySize;
}
LocalMemoryId = properties.AddLocalMemory(lmem);
var lmem = new MemoryDefinition("local_memory", AggregateType.Array | AggregateType.U32, BitUtils.DivRoundUp(size, sizeof(uint)));
LocalMemoryId = Properties.AddLocalMemory(lmem);
}
int sharedMemorySize = stage == ShaderStage.Compute ? gpuAccessor.QueryComputeSharedMemorySize() : 0;
if (sharedMemorySize != 0)
else
{
var smem = new MemoryDefinition("shared_memory", AggregateType.Array | AggregateType.U32, BitUtils.DivRoundUp(sharedMemorySize, sizeof(uint)));
LocalMemoryId = -1;
}
}
SharedMemoryId = properties.AddSharedMemory(smem);
public void SetCurrentSharedMemory(int size, bool isUsed)
{
if (isUsed)
{
if (size <= 0)
{
size = DefaultSharedMemorySize;
}
var smem = new MemoryDefinition("shared_memory", AggregateType.Array | AggregateType.U32, BitUtils.DivRoundUp(size, sizeof(uint)));
SharedMemoryId = Properties.AddSharedMemory(smem);
}
else
{
SharedMemoryId = -1;
}
}

View File

@ -126,9 +126,10 @@ namespace Ryujinx.Graphics.Shader.Translation
public ShaderConfig(ShaderStage stage, IGpuAccessor gpuAccessor, TranslationOptions options, int localMemorySize)
{
Stage = stage;
GpuAccessor = gpuAccessor;
Options = options;
Stage = stage;
GpuAccessor = gpuAccessor;
Options = options;
LocalMemorySize = localMemorySize;
_transformFeedbackDefinitions = new Dictionary<TransformFeedbackVariable, TransformFeedbackOutput>();
@ -143,7 +144,7 @@ namespace Ryujinx.Graphics.Shader.Translation
_usedTextures = new Dictionary<TextureInfo, TextureMeta>();
_usedImages = new Dictionary<TextureInfo, TextureMeta>();
ResourceManager = new ResourceManager(stage, gpuAccessor, new ShaderProperties(), localMemorySize);
ResourceManager = new ResourceManager(stage, gpuAccessor, new ShaderProperties());
if (!gpuAccessor.QueryHostSupportsTransformFeedback() && gpuAccessor.QueryTransformFeedbackEnabled())
{
@ -192,7 +193,6 @@ namespace Ryujinx.Graphics.Shader.Translation
ThreadsPerInputPrimitive = header.ThreadsPerInputPrimitive;
OutputTopology = header.OutputTopology;
MaxOutputVertices = header.MaxOutputVertexCount;
LocalMemorySize = header.ShaderLocalMemoryLowSize + header.ShaderLocalMemoryHighSize + (header.ShaderLocalMemoryCrsSize / ThreadsPerWarp);
ImapTypes = header.ImapTypes;
OmapTargets = header.OmapTargets;
OmapSampleMask = header.OmapSampleMask;

View File

@ -149,6 +149,17 @@ namespace Ryujinx.Graphics.Shader.Translation
public ShaderProgram Translate(TranslatorContext other = null)
{
bool usesLocalMemory = _config.UsedFeatures.HasFlag(FeatureFlags.LocalMemory);
_config.ResourceManager.SetCurrentLocalMemory(_config.LocalMemorySize, usesLocalMemory);
if (_config.Stage == ShaderStage.Compute)
{
bool usesSharedMemory = _config.UsedFeatures.HasFlag(FeatureFlags.SharedMemory);
_config.ResourceManager.SetCurrentSharedMemory(GpuAccessor.QueryComputeSharedMemorySize(), usesSharedMemory);
}
FunctionCode[] code = EmitShader(_program, _config, initializeOutputs: other == null, out _);
if (other != null)
@ -157,6 +168,7 @@ namespace Ryujinx.Graphics.Shader.Translation
// We need to share the resource manager since both shaders accesses the same constant buffers.
other._config.ResourceManager = _config.ResourceManager;
other._config.ResourceManager.SetCurrentLocalMemory(other._config.LocalMemorySize, other._config.UsedFeatures.HasFlag(FeatureFlags.LocalMemory));
FunctionCode[] otherCode = EmitShader(other._program, other._config, initializeOutputs: true, out int aStart);

View File

@ -25,7 +25,15 @@ namespace Ryujinx.HLE.HOS
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)
{
@ -38,6 +46,8 @@ namespace Ryujinx.HLE.HOS
_gpuContext = gpuContext;
_cpuContext = cpuEngine.CreateCpuContext(memoryManager, for64Bit);
_memoryManager = memoryManager;
AddressSpaceSize = addressSpaceSize;
}
public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks)

View File

@ -1,4 +1,5 @@
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Cpu;
using Ryujinx.Cpu.AppleHv;
using Ryujinx.Cpu.Jit;
@ -49,7 +50,7 @@ namespace Ryujinx.HLE.HOS
{
var cpuEngine = new HvEngine(_tickSource);
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
{
@ -57,23 +58,41 @@ namespace Ryujinx.HLE.HOS
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;
}
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)
{
case MemoryManagerMode.SoftwarePageTable:
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;
case MemoryManagerMode.HostMapped:
case MemoryManagerMode.HostMappedUnsafe:
bool unsafeMode = mode == MemoryManagerMode.HostMappedUnsafe;
var memoryManagerHostMapped = new MemoryManagerHostMapped(context.Memory, addressSpaceSize, unsafeMode, invalidAccessHandler);
processContext = new ArmProcessContext<MemoryManagerHostMapped>(pid, cpuEngine, _gpu, memoryManagerHostMapped, for64Bit);
if (addressSpaceSize != addressSpace.AddressSpaceSize)
{
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;
default:

View File

@ -13,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
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;
}

View File

@ -22,6 +22,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
0x40000000
};
private const ulong RegionAlignment = 0x200000;
public const int PageSize = 0x1000;
private const int KMemoryBlockSize = 0x40;
@ -53,6 +55,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
public ulong TlsIoRegionStart { get; private set; }
public ulong TlsIoRegionEnd { get; private set; }
public ulong AslrRegionStart { get; private set; }
public ulong AslrRegionEnd { get; private set; }
private ulong _heapCapacity;
public ulong PhysicalMemoryUsage { get; private set; }
@ -61,10 +66,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
private MemoryRegion _memRegion;
private bool _aslrDisabled;
public int AddrSpaceWidth { get; private set; }
private bool _allocateFromBack;
private bool _isKernel;
private bool _aslrEnabled;
@ -78,7 +80,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
private MemoryFillValue _heapFillValue;
private MemoryFillValue _ipcFillValue;
public KPageTableBase(KernelContext context)
private ulong _reservedAddressSpaceSize;
public KPageTableBase(KernelContext context, ulong reservedAddressSpaceSize)
{
Context = context;
@ -88,6 +92,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_heapFillValue = MemoryFillValue.Zero;
_ipcFillValue = MemoryFillValue.Zero;
_reservedAddressSpaceSize = reservedAddressSpaceSize;
}
private static readonly int[] AddrSpaceSizes = new int[] { 32, 36, 32, 39 };
@ -95,7 +101,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
public Result InitializeForProcess(
AddressSpaceType addrSpaceType,
bool aslrEnabled,
bool aslrDisabled,
bool fromBack,
MemoryRegion memRegion,
ulong address,
ulong size,
@ -114,7 +120,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
Result result = CreateUserAddressSpace(
addrSpaceType,
aslrEnabled,
aslrDisabled,
fromBack,
addrSpaceBase,
addrSpaceSize,
memRegion,
@ -130,7 +136,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return result;
}
private class Region
private struct Region
{
public ulong Start;
public ulong End;
@ -141,7 +147,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
private Result CreateUserAddressSpace(
AddressSpaceType addrSpaceType,
bool aslrEnabled,
bool aslrDisabled,
bool fromBack,
ulong addrSpaceStart,
ulong addrSpaceEnd,
MemoryRegion memRegion,
@ -159,7 +165,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong codeRegionSize;
ulong stackAndTlsIoStart;
ulong stackAndTlsIoEnd;
ulong baseAddress;
switch (addrSpaceType)
{
@ -170,10 +175,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
tlsIoRegion.Size = 0;
CodeRegionStart = 0x200000;
codeRegionSize = 0x3fe00000;
AslrRegionStart = 0x200000;
AslrRegionEnd = AslrRegionStart + 0xffe00000;
stackAndTlsIoStart = 0x200000;
stackAndTlsIoEnd = 0x40000000;
baseAddress = 0x200000;
AddrSpaceWidth = 32;
break;
case AddressSpaceType.Addr36Bits:
@ -183,10 +188,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
tlsIoRegion.Size = 0;
CodeRegionStart = 0x8000000;
codeRegionSize = 0x78000000;
AslrRegionStart = 0x8000000;
AslrRegionEnd = AslrRegionStart + 0xff8000000;
stackAndTlsIoStart = 0x8000000;
stackAndTlsIoEnd = 0x80000000;
baseAddress = 0x8000000;
AddrSpaceWidth = 36;
break;
case AddressSpaceType.Addr32BitsNoMap:
@ -196,23 +201,42 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
tlsIoRegion.Size = 0;
CodeRegionStart = 0x200000;
codeRegionSize = 0x3fe00000;
AslrRegionStart = 0x200000;
AslrRegionEnd = AslrRegionStart + 0xffe00000;
stackAndTlsIoStart = 0x200000;
stackAndTlsIoEnd = 0x40000000;
baseAddress = 0x200000;
AddrSpaceWidth = 32;
break;
case AddressSpaceType.Addr39Bits:
aliasRegion.Size = 0x1000000000;
heapRegion.Size = 0x180000000;
stackRegion.Size = 0x80000000;
tlsIoRegion.Size = 0x1000000000;
CodeRegionStart = BitUtils.AlignDown<ulong>(address, 0x200000);
codeRegionSize = BitUtils.AlignUp<ulong>(endAddr, 0x200000) - CodeRegionStart;
stackAndTlsIoStart = 0;
stackAndTlsIoEnd = 0;
baseAddress = 0x8000000;
AddrSpaceWidth = 39;
if (_reservedAddressSpaceSize < addrSpaceEnd)
{
int addressSpaceWidth = (int)ulong.Log2(_reservedAddressSpaceSize);
aliasRegion.Size = 1UL << (addressSpaceWidth - 3);
heapRegion.Size = 0x180000000;
stackRegion.Size = 1UL << (addressSpaceWidth - 8);
tlsIoRegion.Size = 1UL << (addressSpaceWidth - 3);
CodeRegionStart = BitUtils.AlignDown<ulong>(address, RegionAlignment);
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;
default: throw new ArgumentException(nameof(addrSpaceType));
@ -223,11 +247,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong mapBaseAddress;
ulong mapAvailableSize;
if (CodeRegionStart - baseAddress >= addrSpaceEnd - CodeRegionEnd)
if (CodeRegionStart - AslrRegionStart >= addrSpaceEnd - CodeRegionEnd)
{
// Has more space before the start of the code region.
mapBaseAddress = baseAddress;
mapAvailableSize = CodeRegionStart - baseAddress;
mapBaseAddress = AslrRegionStart;
mapAvailableSize = CodeRegionStart - AslrRegionStart;
}
else
{
@ -254,14 +278,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
if (aslrEnabled)
{
aliasRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset >> 21) << 21;
heapRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset >> 21) << 21;
stackRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset >> 21) << 21;
tlsIoRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset >> 21) << 21;
aliasRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset / RegionAlignment) * RegionAlignment;
heapRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset / RegionAlignment) * RegionAlignment;
stackRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset / RegionAlignment) * RegionAlignment;
tlsIoRegion.AslrOffset = GetRandomValue(0, aslrMaxOffset / RegionAlignment) * RegionAlignment;
}
// 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.End = aliasRegion.Start + aliasRegion.Size;
heapRegion.Start = mapBaseAddress + heapRegion.AslrOffset;
@ -271,12 +295,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
tlsIoRegion.Start = mapBaseAddress + tlsIoRegion.AslrOffset;
tlsIoRegion.End = tlsIoRegion.Start + tlsIoRegion.Size;
SortRegion(heapRegion, aliasRegion);
SortRegion(ref aliasRegion, ref heapRegion, true);
if (stackRegion.Size != 0)
{
SortRegion(stackRegion, aliasRegion);
SortRegion(stackRegion, heapRegion);
stackRegion.Start = mapBaseAddress + stackRegion.AslrOffset;
stackRegion.End = stackRegion.Start + stackRegion.Size;
SortRegion(ref aliasRegion, ref stackRegion);
SortRegion(ref heapRegion, ref stackRegion);
}
else
{
@ -286,9 +313,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
if (tlsIoRegion.Size != 0)
{
SortRegion(tlsIoRegion, aliasRegion);
SortRegion(tlsIoRegion, heapRegion);
SortRegion(tlsIoRegion, stackRegion);
tlsIoRegion.Start = mapBaseAddress + tlsIoRegion.AslrOffset;
tlsIoRegion.End = tlsIoRegion.Start + tlsIoRegion.Size;
SortRegion(ref aliasRegion, ref tlsIoRegion);
SortRegion(ref heapRegion, ref tlsIoRegion);
if (stackRegion.Size != 0)
{
SortRegion(ref stackRegion, ref tlsIoRegion);
}
}
else
{
@ -312,11 +346,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
PhysicalMemoryUsage = 0;
_memRegion = memRegion;
_aslrDisabled = aslrDisabled;
_allocateFromBack = fromBack;
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)
{
return (ulong)GetRandomValue((long)min, (long)max);
@ -332,20 +382,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
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)
{
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 (addressTruncated < addressRounded)
{
dstFirstPagePa = GetMemoryRegionManager().AllocatePagesContiguous(Context, 1, _aslrDisabled);
dstFirstPagePa = GetMemoryRegionManager().AllocatePagesContiguous(Context, 1, _allocateFromBack);
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 (endAddrTruncated < endAddrRounded && (addressTruncated == addressRounded || addressTruncated < endAddrTruncated))
{
dstLastPagePa = GetMemoryRegionManager().AllocatePagesContiguous(Context, 1, _aslrDisabled);
dstLastPagePa = GetMemoryRegionManager().AllocatePagesContiguous(Context, 1, _allocateFromBack);
if (dstLastPagePa == 0)
{
@ -2799,38 +2835,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
public ulong GetAddrSpaceBaseAddr()
{
if (AddrSpaceWidth == 36 || AddrSpaceWidth == 39)
{
return 0x8000000;
}
else if (AddrSpaceWidth == 32)
{
return 0x200000;
}
else
{
throw new InvalidOperationException("Invalid address space width!");
}
return AslrRegionStart;
}
public ulong GetAddrSpaceSize()
{
if (AddrSpaceWidth == 36)
{
return 0xff8000000;
}
else if (AddrSpaceWidth == 39)
{
return 0x7ff8000000;
}
else if (AddrSpaceWidth == 32)
{
return 0xffe00000;
}
else
{
throw new InvalidOperationException("Invalid address space width!");
}
return AslrRegionEnd - AslrRegionStart;
}
private static ulong GetDramAddressFromPa(ulong pa)

View File

@ -8,6 +8,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{
IVirtualMemoryManager AddressSpace { get; }
ulong AddressSpaceSize { get; }
IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks);
void Execute(IExecutionContext context, ulong codeAddress);
void InvalidateCacheRegion(ulong address, ulong size);

View File

@ -1082,7 +1082,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
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)

View File

@ -8,9 +8,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{
public IVirtualMemoryManager AddressSpace { get; }
public ProcessContext(IVirtualMemoryManager asManager)
public ulong AddressSpaceSize { get; }
public ProcessContext(IVirtualMemoryManager asManager, ulong addressSpaceSize)
{
AddressSpace = asManager;
AddressSpaceSize = addressSpaceSize;
}
public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks)

View File

@ -6,7 +6,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{
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);
}
}
}

View File

@ -6,7 +6,7 @@ namespace Ryujinx.HLE.HOS.Services.Mii.Types
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x10)]
struct CreateId : IEquatable<CreateId>
{
public UInt128 Raw;
public readonly UInt128 Raw;
public bool IsNull => Raw == UInt128.Zero;
public bool IsValid => !IsNull && ((Raw >> 64) & 0xC0) == 0x80;

View File

@ -4,8 +4,8 @@ namespace Ryujinx.Tests.Unicorn
{
public struct SimdValue : IEquatable<SimdValue>
{
private ulong _e0;
private ulong _e1;
private readonly ulong _e0;
private readonly ulong _e1;
public SimdValue(ulong e0, ulong e1)
{

View File

@ -5,7 +5,7 @@ namespace Spv.Generator
{
internal struct ConstantKey : IEquatable<ConstantKey>
{
private Instruction _constant;
private readonly Instruction _constant;
public ConstantKey(Instruction constant)
{

View File

@ -5,7 +5,7 @@ namespace Spv.Generator
{
internal class DeterministicStringKey : IEquatable<DeterministicStringKey>
{
private string _value;
private readonly string _value;
public DeterministicStringKey(string value)
{

View File

@ -8,7 +8,7 @@ namespace Spv.Generator
{
public OperandType Type => OperandType.String;
private string _value;
private readonly string _value;
public LiteralString(string value)
{

View File

@ -5,7 +5,7 @@ namespace Spv.Generator
{
internal struct TypeDeclarationKey : IEquatable<TypeDeclarationKey>
{
private Instruction _typeDeclaration;
private readonly Instruction _typeDeclaration;
public TypeDeclarationKey(Instruction typeDeclaration)
{