IPC refactor part 2: Use ReplyAndReceive on HLE services and remove special handling from kernel (#1458)

* IPC refactor part 2: Use ReplyAndReceive on HLE services and remove special handling from kernel

* Fix for applet transfer memory + some nits

* Keep handles if possible to avoid server handle table exhaustion

* Fix IPC ZeroFill bug

* am: Correctly implement CreateManagedDisplayLayer and implement CreateManagedDisplaySeparableLayer

CreateManagedDisplaySeparableLayer is requires since 10.x+ when appletResourceUserId != 0

* Make it exit properly

* Make ServiceNotImplementedException show the full message again

* Allow yielding execution to avoid starving other threads

* Only wait if active

* Merge IVirtualMemoryManager and IAddressSpaceManager

* Fix Ro loading data from the wrong process

Co-authored-by: Thog <me@thog.eu>
This commit is contained in:
gdkchan 2020-12-01 20:23:43 -03:00 committed by GitHub
parent 461c24092a
commit cf6cd71488
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
115 changed files with 2356 additions and 1088 deletions

View file

@ -1,9 +1,10 @@
using Ryujinx.Common;
using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.Memory;
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace Ryujinx.HLE.HOS.Kernel.Memory
{
@ -27,11 +28,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
// needs to be split in 2, plus one block that will be the new one inserted.
private const int MaxBlocksNeededForInsertion = 2;
private LinkedList<KMemoryBlock> _blocks;
private readonly LinkedList<KMemoryBlock> _blocks;
private MemoryManager _cpuMemory;
private readonly IVirtualMemoryManager _cpuMemory;
private KernelContext _context;
private readonly KernelContext _context;
public ulong AddrSpaceStart { get; private set; }
public ulong AddrSpaceEnd { get; private set; }
@ -73,7 +74,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
private MersenneTwister _randomNumberGenerator;
public KMemoryManager(KernelContext context, MemoryManager cpuMemory)
public KMemoryManager(KernelContext context, IVirtualMemoryManager cpuMemory)
{
_context = context;
_cpuMemory = cpuMemory;
@ -352,7 +353,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
addrSpaceStart,
addrSpacePagesCount,
MemoryState.Unmapped,
MemoryPermission.None,
KMemoryPermission.None,
MemoryAttribute.None));
return KernelResult.Success;
@ -362,13 +363,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong address,
KPageList pageList,
MemoryState state,
MemoryPermission permission)
KMemoryPermission permission)
{
ulong pagesCount = pageList.GetPagesCount();
ulong size = pagesCount * PageSize;
if (!ValidateRegionForState(address, size, state))
if (!CanContain(address, size, state))
{
return KernelResult.InvalidMemState;
}
@ -437,8 +438,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.Mask,
stateExpected,
MemoryPermission.None,
MemoryPermission.None,
KMemoryPermission.None,
KMemoryPermission.None,
MemoryAttribute.Mask,
MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped,
@ -467,13 +468,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
public KernelResult MapNormalMemory(long address, long size, MemoryPermission permission)
public KernelResult MapNormalMemory(long address, long size, KMemoryPermission permission)
{
// TODO.
return KernelResult.Success;
}
public KernelResult MapIoMemory(long address, long size, MemoryPermission permission)
public KernelResult MapIoMemory(long address, long size, KMemoryPermission permission)
{
// TODO.
return KernelResult.Success;
@ -487,7 +488,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong regionStart,
ulong regionPagesCount,
MemoryState state,
MemoryPermission permission,
KMemoryPermission permission,
out ulong address)
{
address = 0;
@ -496,7 +497,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong regionEndAddr = regionStart + regionSize;
if (!ValidateRegionForState(regionStart, regionSize, state))
if (!CanContain(regionStart, regionSize, state))
{
return KernelResult.InvalidMemState;
}
@ -547,11 +548,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong address,
ulong pagesCount,
MemoryState state,
MemoryPermission permission)
KMemoryPermission permission)
{
ulong size = pagesCount * PageSize;
if (!ValidateRegionForState(address, size, state))
if (!CanContain(address, size, state))
{
return KernelResult.InvalidMemState;
}
@ -596,13 +597,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.Mask,
MemoryState.Heap,
MemoryPermission.Mask,
MemoryPermission.ReadAndWrite,
KMemoryPermission.Mask,
KMemoryPermission.ReadAndWrite,
MemoryAttribute.Mask,
MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped,
out MemoryState state,
out MemoryPermission permission,
out KMemoryPermission permission,
out _);
success &= IsUnmapped(dst, size);
@ -618,14 +619,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
AddVaRangeToPageList(pageList, src, pagesCount);
KernelResult result = MmuChangePermission(src, pagesCount, MemoryPermission.None);
KernelResult result = MmuChangePermission(src, pagesCount, KMemoryPermission.None);
if (result != KernelResult.Success)
{
return result;
}
result = MapPages(dst, pageList, MemoryPermission.None);
result = MapPages(dst, pageList, KMemoryPermission.None);
if (result != KernelResult.Success)
{
@ -634,7 +635,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return result;
}
InsertBlock(src, pagesCount, state, MemoryPermission.None, MemoryAttribute.Borrowed);
InsertBlock(src, pagesCount, state, KMemoryPermission.None, MemoryAttribute.Borrowed);
InsertBlock(dst, pagesCount, MemoryState.ModCodeStatic);
return KernelResult.Success;
@ -657,8 +658,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.Mask,
MemoryState.Heap,
MemoryPermission.None,
MemoryPermission.None,
KMemoryPermission.None,
KMemoryPermission.None,
MemoryAttribute.Mask,
MemoryAttribute.Borrowed,
MemoryAttribute.IpcAndDeviceMapped,
@ -671,8 +672,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
PageSize,
MemoryState.UnmapProcessCodeMemoryAllowed,
MemoryState.UnmapProcessCodeMemoryAllowed,
MemoryPermission.None,
MemoryPermission.None,
KMemoryPermission.None,
KMemoryPermission.None,
MemoryAttribute.Mask,
MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped,
@ -685,8 +686,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.Mask,
state,
MemoryPermission.None,
MemoryPermission.None,
KMemoryPermission.None,
KMemoryPermission.None,
MemoryAttribute.Mask,
MemoryAttribute.None);
@ -707,7 +708,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
InsertBlock(dst, pagesCount, MemoryState.Unmapped);
InsertBlock(src, pagesCount, MemoryState.Heap, MemoryPermission.ReadAndWrite);
InsertBlock(src, pagesCount, MemoryState.Heap, KMemoryPermission.ReadAndWrite);
return KernelResult.Success;
}
@ -788,7 +789,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
_currentHeapAddr,
pagesCount,
pageList,
MemoryPermission.ReadAndWrite,
KMemoryPermission.ReadAndWrite,
MemoryOperation.MapVa);
if (result != KernelResult.Success)
@ -798,7 +799,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return result;
}
InsertBlock(_currentHeapAddr, pagesCount, MemoryState.Heap, MemoryPermission.ReadAndWrite);
InsertBlock(_currentHeapAddr, pagesCount, MemoryState.Heap, KMemoryPermission.ReadAndWrite);
}
else
{
@ -816,8 +817,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
sizeDelta,
MemoryState.Mask,
MemoryState.Heap,
MemoryPermission.Mask,
MemoryPermission.ReadAndWrite,
KMemoryPermission.Mask,
KMemoryPermission.ReadAndWrite,
MemoryAttribute.Mask,
MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped,
@ -886,13 +887,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.AttributeChangeAllowed,
MemoryState.AttributeChangeAllowed,
MemoryPermission.None,
MemoryPermission.None,
KMemoryPermission.None,
KMemoryPermission.None,
MemoryAttribute.BorrowedAndIpcMapped,
MemoryAttribute.None,
MemoryAttribute.DeviceMappedAndUncached,
out MemoryState state,
out MemoryPermission permission,
out KMemoryPermission permission,
out MemoryAttribute attribute))
{
if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
@ -932,9 +933,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
AddrSpaceEnd,
~AddrSpaceEnd + 1,
MemoryState.Reserved,
MemoryPermission.None,
KMemoryPermission.None,
MemoryAttribute.None,
MemoryPermission.None,
KMemoryPermission.None,
0,
0);
}
@ -951,8 +952,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.MapAllowed,
MemoryState.MapAllowed,
MemoryPermission.Mask,
MemoryPermission.ReadAndWrite,
KMemoryPermission.Mask,
KMemoryPermission.ReadAndWrite,
MemoryAttribute.Mask,
MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped,
@ -975,18 +976,18 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
AddVaRangeToPageList(pageList, src, pagesCount);
KernelResult result = MmuChangePermission(src, pagesCount, MemoryPermission.None);
KernelResult result = MmuChangePermission(src, pagesCount, KMemoryPermission.None);
if (result != KernelResult.Success)
{
return result;
}
result = MapPages(dst, pageList, MemoryPermission.ReadAndWrite);
result = MapPages(dst, pageList, KMemoryPermission.ReadAndWrite);
if (result != KernelResult.Success)
{
if (MmuChangePermission(src, pagesCount, MemoryPermission.ReadAndWrite) != KernelResult.Success)
if (MmuChangePermission(src, pagesCount, KMemoryPermission.ReadAndWrite) != KernelResult.Success)
{
throw new InvalidOperationException("Unexpected failure reverting memory permission.");
}
@ -994,8 +995,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return result;
}
InsertBlock(src, pagesCount, srcState, MemoryPermission.None, MemoryAttribute.Borrowed);
InsertBlock(dst, pagesCount, MemoryState.Stack, MemoryPermission.ReadAndWrite);
InsertBlock(src, pagesCount, srcState, KMemoryPermission.None, MemoryAttribute.Borrowed);
InsertBlock(dst, pagesCount, MemoryState.Stack, KMemoryPermission.ReadAndWrite);
return KernelResult.Success;
}
@ -1017,8 +1018,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.Mask,
stateExpected,
MemoryPermission.None,
MemoryPermission.None,
KMemoryPermission.None,
KMemoryPermission.None,
MemoryAttribute.Mask,
MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped,
@ -1058,8 +1059,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.MapAllowed,
MemoryState.MapAllowed,
MemoryPermission.Mask,
MemoryPermission.None,
KMemoryPermission.Mask,
KMemoryPermission.None,
MemoryAttribute.Mask,
MemoryAttribute.Borrowed,
MemoryAttribute.IpcAndDeviceMapped,
@ -1072,13 +1073,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.Mask,
MemoryState.Stack,
MemoryPermission.None,
MemoryPermission.None,
KMemoryPermission.None,
KMemoryPermission.None,
MemoryAttribute.Mask,
MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped,
out _,
out MemoryPermission dstPermission,
out KMemoryPermission dstPermission,
out _);
if (success)
@ -1108,7 +1109,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return result;
}
result = MmuChangePermission(src, pagesCount, MemoryPermission.ReadAndWrite);
result = MmuChangePermission(src, pagesCount, KMemoryPermission.ReadAndWrite);
if (result != KernelResult.Success)
{
@ -1117,7 +1118,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return result;
}
InsertBlock(src, pagesCount, srcState, MemoryPermission.ReadAndWrite);
InsertBlock(src, pagesCount, srcState, KMemoryPermission.ReadAndWrite);
InsertBlock(dst, pagesCount, MemoryState.Unmapped);
return KernelResult.Success;
@ -1129,7 +1130,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
public KernelResult SetProcessMemoryPermission(ulong address, ulong size, MemoryPermission permission)
public KernelResult SetProcessMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
{
lock (_blocks)
{
@ -1138,20 +1139,20 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.ProcessPermissionChangeAllowed,
MemoryState.ProcessPermissionChangeAllowed,
MemoryPermission.None,
MemoryPermission.None,
KMemoryPermission.None,
KMemoryPermission.None,
MemoryAttribute.Mask,
MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped,
out MemoryState oldState,
out MemoryPermission oldPermission,
out KMemoryPermission oldPermission,
out _))
{
MemoryState newState = oldState;
// If writing into the code region is allowed, then we need
// to change it to mutable.
if ((permission & MemoryPermission.Write) != 0)
if ((permission & KMemoryPermission.Write) != 0)
{
if (oldState == MemoryState.CodeStatic)
{
@ -1176,7 +1177,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong pagesCount = size / PageSize;
MemoryOperation operation = (permission & MemoryPermission.Execute) != 0
MemoryOperation operation = (permission & KMemoryPermission.Execute) != 0
? MemoryOperation.ChangePermsAndAttributes
: MemoryOperation.ChangePermRw;
@ -1270,10 +1271,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
address,
pagesCount,
MemoryState.Unmapped,
MemoryPermission.None,
KMemoryPermission.None,
MemoryAttribute.None,
MemoryState.Heap,
MemoryPermission.ReadAndWrite,
KMemoryPermission.ReadAndWrite,
MemoryAttribute.None);
}
@ -1410,7 +1411,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
pagesCount,
srcPa,
true,
MemoryPermission.ReadAndWrite,
KMemoryPermission.ReadAndWrite,
MemoryOperation.MapPa);
dstVa += pagesCount * PageSize;
@ -1428,7 +1429,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong src,
MemoryState stateMask,
MemoryState stateExpected,
MemoryPermission permission,
KMemoryPermission permission,
MemoryAttribute attributeMask,
MemoryAttribute attributeExpected)
{
@ -1450,7 +1451,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong size,
MemoryState stateMask,
MemoryState stateExpected,
MemoryPermission permission,
KMemoryPermission permission,
MemoryAttribute attributeMask,
MemoryAttribute attributeExpected,
ulong src)
@ -1474,7 +1475,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong serverAddress,
MemoryState stateMask,
MemoryState stateExpected,
MemoryPermission permission,
KMemoryPermission permission,
MemoryAttribute attributeMask,
MemoryAttribute attributeExpected,
bool toServer)
@ -1529,7 +1530,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong size,
ulong src,
KMemoryManager sourceMemMgr,
MemoryPermission permission,
KMemoryPermission permission,
MemoryState state,
bool copyData,
out ulong dst)
@ -1568,7 +1569,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
private KernelResult GetPagesForMappingIntoAnotherProcess(
ulong address,
ulong size,
MemoryPermission permission,
KMemoryPermission permission,
MemoryState state,
bool copyData,
bool aslrDisabled,
@ -1600,9 +1601,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
default: return KernelResult.InvalidCombination;
}
MemoryPermission permissionMask = permission == MemoryPermission.ReadAndWrite
? MemoryPermission.None
: MemoryPermission.Read;
KMemoryPermission permissionMask = permission == KMemoryPermission.ReadAndWrite
? KMemoryPermission.None
: KMemoryPermission.Read;
MemoryAttribute attributeMask = MemoryAttribute.Borrowed | MemoryAttribute.Uncached;
@ -1634,7 +1635,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
foreach (KMemoryInfo info in IterateOverRange(addressRounded, endAddrVisited))
{
if ((info.Permission & MemoryPermission.ReadAndWrite) != permissionMask && info.IpcRefCount == 0)
if ((info.Permission & KMemoryPermission.ReadAndWrite) != permissionMask && info.IpcRefCount == 0)
{
ulong blockAddress = GetAddrInRange(info, addressRounded);
ulong blockSize = GetSizeInRange(info, addressRounded, endAddrVisited);
@ -1661,7 +1662,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
if (addressRounded < endAddrTruncated)
{
foreach (KMemoryInfo info in IterateOverRange(addressTruncated, endAddrRounded))
foreach (KMemoryInfo info in IterateOverRange(addressRounded, endAddrTruncated))
{
// Check if the block state matches what we expect.
if ((info.State & stateMask) != stateMask ||
@ -1678,7 +1679,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong blockPagesCount = blockSize / PageSize;
if ((info.Permission & MemoryPermission.ReadAndWrite) != permissionMask && info.IpcRefCount == 0)
if ((info.Permission & KMemoryPermission.ReadAndWrite) != permissionMask && info.IpcRefCount == 0)
{
result = DoMmuOperation(
blockAddress,
@ -1784,7 +1785,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
{
ulong unusedSizeBefore = address - addressTruncated;
_context.Memory.ZeroFill(dstFirstPagePa, unusedSizeBefore);
_context.Memory.ZeroFill(GetDramAddressFromPa(dstFirstPagePa), unusedSizeBefore);
ulong copySize = addressRounded <= endAddr ? addressRounded - address : size;
@ -1803,7 +1804,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
if (unusedSizeAfter != 0)
{
_context.Memory.ZeroFill(firstPageFillAddress, unusedSizeAfter);
_context.Memory.ZeroFill(GetDramAddressFromPa(firstPageFillAddress), unusedSizeAfter);
}
if (pages.AddRange(dstFirstPagePa, 1) != KernelResult.Success)
@ -1865,7 +1866,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
unusedSizeAfter = PageSize;
}
_context.Memory.ZeroFill(lastPageFillAddr, unusedSizeAfter);
_context.Memory.ZeroFill(GetDramAddressFromPa(lastPageFillAddr), unusedSizeAfter);
if (pages.AddRange(dstLastPagePa, 1) != KernelResult.Success)
{
@ -1897,7 +1898,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
private KernelResult MapPagesFromAnotherProcess(
ulong size,
ulong address,
MemoryPermission permission,
KMemoryPermission permission,
MemoryState state,
KPageList pageList,
out ulong dst)
@ -1975,8 +1976,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.Mask,
state,
MemoryPermission.Read,
MemoryPermission.Read,
KMemoryPermission.Read,
KMemoryPermission.Read,
MemoryAttribute.Mask,
MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped,
@ -1996,14 +1997,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong pagesCount = (endAddrRounded - addressTruncated) / PageSize;
KernelResult result = DoMmuOperation(
addressTruncated,
pagesCount,
0,
false,
MemoryPermission.None,
MemoryOperation.Unmap);
// Free pages we had to create on-demand, if any of the buffer was not page aligned.
// Real kernel has page ref counting, so this is done as part of the unmap operation.
if (addressTruncated != addressRounded)
@ -2016,6 +2009,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
FreeSinglePage(_memRegion, ConvertVaToPa(endAddrTruncated));
}
KernelResult result = DoMmuOperation(
addressTruncated,
pagesCount,
0,
false,
KMemoryPermission.None,
MemoryOperation.Unmap);
if (result == KernelResult.Success)
{
InsertBlock(addressTruncated, pagesCount, MemoryState.Unmapped);
@ -2037,7 +2038,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong addressRounded = BitUtils.AlignUp (address, PageSize);
ulong endAddrTruncated = BitUtils.AlignDown(endAddr, PageSize);
ulong pagesCount = (endAddrTruncated - addressRounded) / PageSize;
ulong pagesCount = addressRounded < endAddrTruncated ? (endAddrTruncated - addressRounded) / PageSize : 0;
if (pagesCount == 0)
{
return KernelResult.Success;
}
MemoryState stateMask;
@ -2111,23 +2117,23 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.IpcBufferAllowed,
MemoryState.IpcBufferAllowed,
MemoryPermission.Mask,
MemoryPermission.ReadAndWrite,
KMemoryPermission.Mask,
KMemoryPermission.ReadAndWrite,
MemoryAttribute.Mask,
MemoryAttribute.None,
MemoryPermission.None,
KMemoryPermission.None,
MemoryAttribute.Borrowed);
}
public KernelResult BorrowTransferMemory(KPageList pageList, ulong address, ulong size, MemoryPermission permission)
public KernelResult BorrowTransferMemory(KPageList pageList, ulong address, ulong size, KMemoryPermission permission)
{
return SetAttributesAndChangePermission(
address,
size,
MemoryState.TransferMemoryAllowed,
MemoryState.TransferMemoryAllowed,
MemoryPermission.Mask,
MemoryPermission.ReadAndWrite,
KMemoryPermission.Mask,
KMemoryPermission.ReadAndWrite,
MemoryAttribute.Mask,
MemoryAttribute.None,
permission,
@ -2140,11 +2146,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong size,
MemoryState stateMask,
MemoryState stateExpected,
MemoryPermission permissionMask,
MemoryPermission permissionExpected,
KMemoryPermission permissionMask,
KMemoryPermission permissionExpected,
MemoryAttribute attributeMask,
MemoryAttribute attributeExpected,
MemoryPermission newPermission,
KMemoryPermission newPermission,
MemoryAttribute attributeSetMask,
KPageList pageList = null)
{
@ -2166,7 +2172,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
attributeExpected,
MemoryAttribute.IpcAndDeviceMapped,
out MemoryState oldState,
out MemoryPermission oldPermission,
out KMemoryPermission oldPermission,
out MemoryAttribute oldAttribute))
{
ulong pagesCount = size / PageSize;
@ -2181,7 +2187,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return KernelResult.OutOfResource;
}
if (newPermission == MemoryPermission.None)
if (newPermission == KMemoryPermission.None)
{
newPermission = oldPermission;
}
@ -2222,11 +2228,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.IpcBufferAllowed,
MemoryState.IpcBufferAllowed,
MemoryPermission.None,
MemoryPermission.None,
KMemoryPermission.None,
KMemoryPermission.None,
MemoryAttribute.Mask,
MemoryAttribute.Borrowed,
MemoryPermission.ReadAndWrite,
KMemoryPermission.ReadAndWrite,
MemoryAttribute.Borrowed);
}
@ -2237,11 +2243,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.TransferMemoryAllowed,
MemoryState.TransferMemoryAllowed,
MemoryPermission.None,
MemoryPermission.None,
KMemoryPermission.None,
KMemoryPermission.None,
MemoryAttribute.Mask,
MemoryAttribute.Borrowed,
MemoryPermission.ReadAndWrite,
KMemoryPermission.ReadAndWrite,
MemoryAttribute.Borrowed,
pageList);
}
@ -2251,11 +2257,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong size,
MemoryState stateMask,
MemoryState stateExpected,
MemoryPermission permissionMask,
MemoryPermission permissionExpected,
KMemoryPermission permissionMask,
KMemoryPermission permissionExpected,
MemoryAttribute attributeMask,
MemoryAttribute attributeExpected,
MemoryPermission newPermission,
KMemoryPermission newPermission,
MemoryAttribute attributeClearMask,
KPageList pageList = null)
{
@ -2277,7 +2283,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
attributeExpected,
MemoryAttribute.IpcAndDeviceMapped,
out MemoryState oldState,
out MemoryPermission oldPermission,
out KMemoryPermission oldPermission,
out MemoryAttribute oldAttribute))
{
ulong pagesCount = size / PageSize;
@ -2299,7 +2305,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return KernelResult.OutOfResource;
}
if (newPermission == MemoryPermission.None)
if (newPermission == KMemoryPermission.None)
{
newPermission = oldPermission;
}
@ -2385,8 +2391,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
size,
MemoryState.Mask,
MemoryState.Unmapped,
MemoryPermission.Mask,
MemoryPermission.None,
KMemoryPermission.Mask,
KMemoryPermission.None,
MemoryAttribute.Mask,
MemoryAttribute.None,
MemoryAttribute.IpcAndDeviceMapped,
@ -2400,13 +2406,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong size,
MemoryState stateMask,
MemoryState stateExpected,
MemoryPermission permissionMask,
MemoryPermission permissionExpected,
KMemoryPermission permissionMask,
KMemoryPermission permissionExpected,
MemoryAttribute attributeMask,
MemoryAttribute attributeExpected,
MemoryAttribute attributeIgnoreMask,
out MemoryState outState,
out MemoryPermission outPermission,
out KMemoryPermission outPermission,
out MemoryAttribute outAttribute)
{
ulong endAddr = address + size;
@ -2416,7 +2422,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
KMemoryInfo info = node.Value.GetInfo();
MemoryState firstState = info.State;
MemoryPermission firstPermission = info.Permission;
KMemoryPermission firstPermission = info.Permission;
MemoryAttribute firstAttribute = info.Attribute;
do
@ -2432,7 +2438,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
(firstPermission & permissionMask) != permissionExpected)
{
outState = MemoryState.Unmapped;
outPermission = MemoryPermission.None;
outPermission = KMemoryPermission.None;
outAttribute = MemoryAttribute.None;
return false;
@ -2452,8 +2458,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong size,
MemoryState stateMask,
MemoryState stateExpected,
MemoryPermission permissionMask,
MemoryPermission permissionExpected,
KMemoryPermission permissionMask,
KMemoryPermission permissionExpected,
MemoryAttribute attributeMask,
MemoryAttribute attributeExpected)
{
@ -2490,10 +2496,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong baseAddress,
ulong pagesCount,
MemoryState oldState,
MemoryPermission oldPermission,
KMemoryPermission oldPermission,
MemoryAttribute oldAttribute,
MemoryState newState,
MemoryPermission newPermission,
KMemoryPermission newPermission,
MemoryAttribute newAttribute)
{
// Insert new block on the list only on areas where the state
@ -2553,13 +2559,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
_blockAllocator.Count += _blocks.Count - oldCount;
ValidateInternalState();
}
private void InsertBlock(
ulong baseAddress,
ulong pagesCount,
MemoryState state,
MemoryPermission permission = MemoryPermission.None,
KMemoryPermission permission = KMemoryPermission.None,
MemoryAttribute attribute = MemoryAttribute.None)
{
// Inserts new block at the list, replacing and splitting
@ -2605,25 +2613,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
_blockAllocator.Count += _blocks.Count - oldCount;
ValidateInternalState();
}
private static void SetIpcMappingPermissions(KMemoryBlock block, MemoryPermission permission)
private static void SetIpcMappingPermissions(KMemoryBlock block, KMemoryPermission permission)
{
block.SetIpcMappingPermission(permission);
}
private static void RestoreIpcMappingPermissions(KMemoryBlock block, MemoryPermission permission)
private static void RestoreIpcMappingPermissions(KMemoryBlock block, KMemoryPermission permission)
{
block.RestoreIpcMappingPermission();
}
private delegate void BlockMutator(KMemoryBlock block, MemoryPermission newPerm);
private delegate void BlockMutator(KMemoryBlock block, KMemoryPermission newPerm);
private void InsertBlock(
ulong baseAddress,
ulong pagesCount,
BlockMutator blockMutate,
MemoryPermission permission = MemoryPermission.None)
KMemoryPermission permission = KMemoryPermission.None)
{
// Inserts new block at the list, replacing and splitting
// existing blocks as needed, then calling the callback
@ -2671,6 +2681,31 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
_blockAllocator.Count += _blocks.Count - oldCount;
ValidateInternalState();
}
[Conditional("DEBUG")]
private void ValidateInternalState()
{
ulong expectedAddress = 0;
LinkedListNode<KMemoryBlock> node = _blocks.First;
while (node != null)
{
LinkedListNode<KMemoryBlock> newNode = node;
KMemoryBlock currBlock = node.Value;
Debug.Assert(currBlock.BaseAddress == expectedAddress);
expectedAddress = currBlock.BaseAddress + currBlock.PagesCount * PageSize;
node = newNode.Next;
}
Debug.Assert(expectedAddress == AddrSpaceEnd);
}
private LinkedListNode<KMemoryBlock> MergeEqualStateNeighbors(LinkedListNode<KMemoryBlock> node)
@ -2876,13 +2911,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
return null;
}
private bool ValidateRegionForState(ulong address, ulong size, MemoryState state)
public bool CanContain(ulong address, ulong size, MemoryState state)
{
ulong endAddr = address + size;
ulong regionBaseAddr = GetBaseAddrForState(state);
ulong regionEndAddr = regionBaseAddr + GetSizeForState(state);
ulong regionBaseAddr = GetBaseAddress(state);
ulong regionEndAddr = regionBaseAddr + GetSize(state);
bool InsideRegion()
{
@ -2891,17 +2925,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
endAddr - 1 <= regionEndAddr - 1;
}
bool OutsideHeapRegion()
{
return endAddr <= HeapRegionStart ||
address >= HeapRegionEnd;
}
bool OutsideMapRegion()
{
return endAddr <= AliasRegionStart ||
address >= AliasRegionEnd;
}
bool OutsideHeapRegion() => endAddr <= HeapRegionStart || address >= HeapRegionEnd;
bool OutsideAliasRegion() => endAddr <= AliasRegionStart || address >= AliasRegionEnd;
switch (state)
{
@ -2919,10 +2944,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
case MemoryState.ProcessMemory:
case MemoryState.CodeReadOnly:
case MemoryState.CodeWritable:
return InsideRegion() && OutsideHeapRegion() && OutsideMapRegion();
return InsideRegion() && OutsideHeapRegion() && OutsideAliasRegion();
case MemoryState.Heap:
return InsideRegion() && OutsideMapRegion();
return InsideRegion() && OutsideAliasRegion();
case MemoryState.IpcBuffer0:
case MemoryState.IpcBuffer1:
@ -2936,7 +2961,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
throw new ArgumentException($"Invalid state value \"{state}\".");
}
private ulong GetBaseAddrForState(MemoryState state)
private ulong GetBaseAddress(MemoryState state)
{
switch (state)
{
@ -2975,7 +3000,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
throw new ArgumentException($"Invalid state value \"{state}\".");
}
private ulong GetSizeForState(MemoryState state)
private ulong GetSize(MemoryState state)
{
switch (state)
{
@ -3050,7 +3075,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
}
}
private KernelResult MapPages(ulong address, KPageList pageList, MemoryPermission permission)
private KernelResult MapPages(ulong address, KPageList pageList, KMemoryPermission permission)
{
ulong currAddr = address;
@ -3090,11 +3115,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
pagesCount,
0,
false,
MemoryPermission.None,
KMemoryPermission.None,
MemoryOperation.Unmap);
}
private KernelResult MmuChangePermission(ulong address, ulong pagesCount, MemoryPermission permission)
private KernelResult MmuChangePermission(ulong address, ulong pagesCount, KMemoryPermission permission)
{
return DoMmuOperation(
address,
@ -3110,7 +3135,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong pagesCount,
ulong srcPa,
bool map,
MemoryPermission permission,
KMemoryPermission permission,
MemoryOperation operation)
{
if (map != (operation == MemoryOperation.MapPa))
@ -3171,7 +3196,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
ulong address,
ulong pagesCount,
KPageList pageList,
MemoryPermission permission,
KMemoryPermission permission,
MemoryOperation operation)
{
if (operation != MemoryOperation.MapVa)