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
|
@ -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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue