diff options
Diffstat (limited to 'src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs')
-rw-r--r-- | src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs | 180 |
1 files changed, 95 insertions, 85 deletions
diff --git a/src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs b/src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs index 614eb527..6746a0a7 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Memory/KPageTableBase.cs @@ -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) |