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:
parent
461c24092a
commit
cf6cd71488
115 changed files with 2356 additions and 1088 deletions
11
Ryujinx.HLE/HOS/Kernel/Common/OnScopeExit.cs
Normal file
11
Ryujinx.HLE/HOS/Kernel/Common/OnScopeExit.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Common
|
||||
{
|
||||
struct OnScopeExit : IDisposable
|
||||
{
|
||||
private readonly Action _action;
|
||||
public OnScopeExit(Action action) => _action = action;
|
||||
public void Dispose() => _action();
|
||||
}
|
||||
}
|
|
@ -99,7 +99,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
copySize,
|
||||
stateMask,
|
||||
stateMask,
|
||||
MemoryPermission.ReadAndWrite,
|
||||
KMemoryPermission.ReadAndWrite,
|
||||
attributeMask,
|
||||
MemoryAttribute.None,
|
||||
desc.ServerAddress);
|
||||
|
@ -125,7 +125,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
clientEndAddr - clientEndAddrTruncated,
|
||||
stateMask,
|
||||
stateMask,
|
||||
MemoryPermission.ReadAndWrite,
|
||||
KMemoryPermission.ReadAndWrite,
|
||||
attributeMask,
|
||||
MemoryAttribute.None,
|
||||
serverEndAddrTruncated);
|
||||
|
|
|
@ -14,10 +14,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
|
||||
public bool IsLight => _parent.IsLight;
|
||||
|
||||
// TODO: Remove that, we need it for now to allow HLE
|
||||
// SM implementation to work with the new IPC system.
|
||||
public IpcService Service { get; set; }
|
||||
|
||||
public KClientPort(KernelContext context, KPort parent, int maxSessions) : base(context)
|
||||
{
|
||||
_maxSessions = maxSessions;
|
||||
|
@ -45,11 +41,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
|
||||
KSession session = new KSession(KernelContext, this);
|
||||
|
||||
if (Service != null)
|
||||
{
|
||||
session.ClientSession.Service = Service;
|
||||
}
|
||||
|
||||
KernelResult result = _parent.EnqueueIncomingSession(session.ServerSession);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
|
|
|
@ -16,10 +16,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
|
||||
public KClientPort ParentPort { get; }
|
||||
|
||||
// TODO: Remove that, we need it for now to allow HLE
|
||||
// services implementation to work with the new IPC system.
|
||||
public IpcService Service { get; set; }
|
||||
|
||||
public KClientSession(KernelContext context, KSession parent, KClientPort parentPort) : base(context)
|
||||
{
|
||||
_parent = parent;
|
||||
|
@ -84,11 +80,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
{
|
||||
_parent.DisconnectClient();
|
||||
_parent.DecrementReferenceCount();
|
||||
|
||||
if (Service is IDisposable disposableObj)
|
||||
{
|
||||
disposableObj.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -430,7 +430,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
descriptor.BufferAddress,
|
||||
MemoryState.IsPoolAllocated,
|
||||
MemoryState.IsPoolAllocated,
|
||||
MemoryPermission.Read,
|
||||
KMemoryPermission.Read,
|
||||
MemoryAttribute.Uncached,
|
||||
MemoryAttribute.None);
|
||||
|
||||
|
@ -473,9 +473,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
bool notReceiveDesc = isSendDesc || isExchangeDesc;
|
||||
bool isReceiveDesc = !notReceiveDesc;
|
||||
|
||||
MemoryPermission permission = index >= clientHeader.SendBuffersCount
|
||||
? MemoryPermission.ReadAndWrite
|
||||
: MemoryPermission.Read;
|
||||
KMemoryPermission permission = index >= clientHeader.SendBuffersCount
|
||||
? KMemoryPermission.ReadAndWrite
|
||||
: KMemoryPermission.Read;
|
||||
|
||||
uint sizeHigh4 = (descWord2 >> 24) & 0xf;
|
||||
|
||||
|
@ -559,9 +559,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
|
||||
if (serverMsg.IsCustom || clientMsg.IsCustom)
|
||||
{
|
||||
MemoryPermission permission = clientMsg.IsCustom
|
||||
? MemoryPermission.None
|
||||
: MemoryPermission.Read;
|
||||
KMemoryPermission permission = clientMsg.IsCustom
|
||||
? KMemoryPermission.None
|
||||
: KMemoryPermission.Read;
|
||||
|
||||
clientResult = clientProcess.MemoryManager.CopyDataToCurrentProcess(
|
||||
copyDst,
|
||||
|
@ -795,7 +795,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
descriptor.BufferSize,
|
||||
MemoryState.IsPoolAllocated,
|
||||
MemoryState.IsPoolAllocated,
|
||||
MemoryPermission.Read,
|
||||
KMemoryPermission.Read,
|
||||
MemoryAttribute.Uncached,
|
||||
MemoryAttribute.None,
|
||||
descriptor.BufferAddress);
|
||||
|
@ -849,9 +849,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
|
||||
if (serverMsg.IsCustom || clientMsg.IsCustom)
|
||||
{
|
||||
MemoryPermission permission = clientMsg.IsCustom
|
||||
? MemoryPermission.None
|
||||
: MemoryPermission.Read;
|
||||
KMemoryPermission permission = clientMsg.IsCustom
|
||||
? KMemoryPermission.None
|
||||
: KMemoryPermission.Read;
|
||||
|
||||
clientResult = clientProcess.MemoryManager.CopyDataFromCurrentProcess(
|
||||
copyDst,
|
||||
|
@ -898,11 +898,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
return new MessageHeader(word0, word1, word2);
|
||||
}
|
||||
|
||||
private KernelResult GetCopyObjectHandle(
|
||||
KThread srcThread,
|
||||
KProcess dstProcess,
|
||||
int srcHandle,
|
||||
out int dstHandle)
|
||||
private KernelResult GetCopyObjectHandle(KThread srcThread, KProcess dstProcess, int srcHandle, out int dstHandle)
|
||||
{
|
||||
dstHandle = 0;
|
||||
|
||||
|
@ -933,11 +929,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
}
|
||||
}
|
||||
|
||||
private KernelResult GetMoveObjectHandle(
|
||||
KProcess srcProcess,
|
||||
KProcess dstProcess,
|
||||
int srcHandle,
|
||||
out int dstHandle)
|
||||
private KernelResult GetMoveObjectHandle(KProcess srcProcess, KProcess dstProcess, int srcHandle, out int dstHandle)
|
||||
{
|
||||
dstHandle = 0;
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ using System;
|
|||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
||||
{
|
||||
class KSession : KAutoObject, IDisposable
|
||||
class KSession : KAutoObject
|
||||
{
|
||||
public KServerSession ServerSession { get; }
|
||||
public KClientSession ClientSession { get; }
|
||||
|
@ -37,19 +37,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
|
|||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && ClientSession.Service is IDisposable disposableService)
|
||||
{
|
||||
disposableService.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Destroy()
|
||||
{
|
||||
if (_hasBeenInitialized)
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
Device = device;
|
||||
Memory = memory;
|
||||
|
||||
Syscall = new Syscall(device, this);
|
||||
Syscall = new Syscall(this);
|
||||
|
||||
SyscallHandler = new SyscallHandler(this);
|
||||
|
||||
|
|
38
Ryujinx.HLE/HOS/Kernel/KernelStatic.cs
Normal file
38
Ryujinx.HLE/HOS/Kernel/KernelStatic.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
static class KernelStatic
|
||||
{
|
||||
[ThreadStatic]
|
||||
private static KernelContext Context;
|
||||
|
||||
public static void YieldUntilCompletion(Action action)
|
||||
{
|
||||
YieldUntilCompletion(Task.Factory.StartNew(action));
|
||||
}
|
||||
|
||||
public static void YieldUntilCompletion(Task task)
|
||||
{
|
||||
KThread currentThread = Context.Scheduler.GetCurrentThread();
|
||||
|
||||
Context.CriticalSection.Enter();
|
||||
|
||||
currentThread.Reschedule(ThreadSchedState.Paused);
|
||||
|
||||
task.ContinueWith((antecedent) =>
|
||||
{
|
||||
currentThread.Reschedule(ThreadSchedState.Running);
|
||||
});
|
||||
|
||||
Context.CriticalSection.Leave();
|
||||
}
|
||||
|
||||
internal static void SetKernelContext(KernelContext context)
|
||||
{
|
||||
Context = context;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,9 +8,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
public ulong PagesCount { get; private set; }
|
||||
|
||||
public MemoryState State { get; private set; }
|
||||
public MemoryPermission Permission { get; private set; }
|
||||
public KMemoryPermission Permission { get; private set; }
|
||||
public MemoryAttribute Attribute { get; private set; }
|
||||
public MemoryPermission SourcePermission { get; private set; }
|
||||
public KMemoryPermission SourcePermission { get; private set; }
|
||||
|
||||
public int IpcRefCount { get; private set; }
|
||||
public int DeviceRefCount { get; private set; }
|
||||
|
@ -19,7 +19,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
ulong baseAddress,
|
||||
ulong pagesCount,
|
||||
MemoryState state,
|
||||
MemoryPermission permission,
|
||||
KMemoryPermission permission,
|
||||
MemoryAttribute attribute,
|
||||
int ipcRefCount = 0,
|
||||
int deviceRefCount = 0)
|
||||
|
@ -33,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
DeviceRefCount = deviceRefCount;
|
||||
}
|
||||
|
||||
public void SetState(MemoryPermission permission, MemoryState state, MemoryAttribute attribute)
|
||||
public void SetState(KMemoryPermission permission, MemoryState state, MemoryAttribute attribute)
|
||||
{
|
||||
Permission = permission;
|
||||
State = state;
|
||||
|
@ -41,7 +41,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
Attribute |= attribute;
|
||||
}
|
||||
|
||||
public void SetIpcMappingPermission(MemoryPermission newPermission)
|
||||
public void SetIpcMappingPermission(KMemoryPermission newPermission)
|
||||
{
|
||||
int oldIpcRefCount = IpcRefCount++;
|
||||
|
||||
|
@ -54,8 +54,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
{
|
||||
SourcePermission = Permission;
|
||||
|
||||
Permission &= ~MemoryPermission.ReadAndWrite;
|
||||
Permission |= MemoryPermission.ReadAndWrite & newPermission;
|
||||
Permission &= ~KMemoryPermission.ReadAndWrite;
|
||||
Permission |= KMemoryPermission.ReadAndWrite & newPermission;
|
||||
}
|
||||
|
||||
Attribute |= MemoryAttribute.IpcMapped;
|
||||
|
@ -74,7 +74,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
{
|
||||
Permission = SourcePermission;
|
||||
|
||||
SourcePermission = MemoryPermission.None;
|
||||
SourcePermission = KMemoryPermission.None;
|
||||
|
||||
Attribute &= ~MemoryAttribute.IpcMapped;
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
public ulong Size { get; }
|
||||
|
||||
public MemoryState State { get; }
|
||||
public MemoryPermission Permission { get; }
|
||||
public KMemoryPermission Permission { get; }
|
||||
public MemoryAttribute Attribute { get; }
|
||||
public MemoryPermission SourcePermission { get; }
|
||||
public KMemoryPermission SourcePermission { get; }
|
||||
|
||||
public int IpcRefCount { get; }
|
||||
public int DeviceRefCount { get; }
|
||||
|
@ -17,9 +17,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
ulong address,
|
||||
ulong size,
|
||||
MemoryState state,
|
||||
MemoryPermission permission,
|
||||
KMemoryPermission permission,
|
||||
MemoryAttribute attribute,
|
||||
MemoryPermission sourcePermission,
|
||||
KMemoryPermission sourcePermission,
|
||||
int ipcRefCount,
|
||||
int deviceRefCount)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -10,15 +10,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
|
||||
private readonly long _ownerPid;
|
||||
|
||||
private readonly MemoryPermission _ownerPermission;
|
||||
private readonly MemoryPermission _userPermission;
|
||||
private readonly KMemoryPermission _ownerPermission;
|
||||
private readonly KMemoryPermission _userPermission;
|
||||
|
||||
public KSharedMemory(
|
||||
KernelContext context,
|
||||
KPageList pageList,
|
||||
long ownerPid,
|
||||
MemoryPermission ownerPermission,
|
||||
MemoryPermission userPermission) : base(context)
|
||||
KMemoryPermission ownerPermission,
|
||||
KMemoryPermission userPermission) : base(context)
|
||||
{
|
||||
_pageList = pageList;
|
||||
_ownerPid = ownerPid;
|
||||
|
@ -31,7 +31,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
ulong address,
|
||||
ulong size,
|
||||
KProcess process,
|
||||
MemoryPermission permission)
|
||||
KMemoryPermission permission)
|
||||
{
|
||||
ulong pagesCountRounded = BitUtils.DivRoundUp(size, KMemoryManager.PageSize);
|
||||
|
||||
|
@ -40,7 +40,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
return KernelResult.InvalidSize;
|
||||
}
|
||||
|
||||
MemoryPermission expectedPermission = process.Pid == _ownerPid
|
||||
KMemoryPermission expectedPermission = process.Pid == _ownerPid
|
||||
? _ownerPermission
|
||||
: _userPermission;
|
||||
|
||||
|
|
|
@ -8,12 +8,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
{
|
||||
private KProcess _creator;
|
||||
|
||||
// TODO: Remove when we no longer need to read it from the owner directly.
|
||||
public KProcess Creator => _creator;
|
||||
|
||||
private readonly KPageList _pageList;
|
||||
|
||||
public ulong Address { get; private set; }
|
||||
public ulong Size => _pageList.GetPagesCount() * KMemoryManager.PageSize;
|
||||
|
||||
public MemoryPermission Permission { get; private set; }
|
||||
public KMemoryPermission Permission { get; private set; }
|
||||
|
||||
private bool _hasBeenInitialized;
|
||||
private bool _isMapped;
|
||||
|
@ -23,7 +26,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
_pageList = new KPageList();
|
||||
}
|
||||
|
||||
public KernelResult Initialize(ulong address, ulong size, MemoryPermission permission)
|
||||
public KernelResult Initialize(ulong address, ulong size, KMemoryPermission permission)
|
||||
{
|
||||
KProcess creator = KernelContext.Scheduler.GetCurrentProcess();
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ using System;
|
|||
namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||
{
|
||||
[Flags]
|
||||
enum MemoryPermission : byte
|
||||
enum KMemoryPermission : byte
|
||||
{
|
||||
None = 0,
|
||||
Mask = 0xff,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.HOS.Diagnostics.Demangler;
|
||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||
using Ryujinx.HLE.Loaders.Elf;
|
||||
using Ryujinx.Memory;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
@ -224,7 +224,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
break;
|
||||
}
|
||||
|
||||
if (info.State == MemoryState.CodeStatic && info.Permission == MemoryPermission.ReadAndExecute)
|
||||
if (info.State == MemoryState.CodeStatic && info.Permission == KMemoryPermission.ReadAndExecute)
|
||||
{
|
||||
LoadMod0Symbols(_owner.CpuMemory, info.Address);
|
||||
}
|
||||
|
@ -235,7 +235,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
}
|
||||
}
|
||||
|
||||
private void LoadMod0Symbols(MemoryManager memory, ulong textOffset)
|
||||
private void LoadMod0Symbols(IVirtualMemoryManager memory, ulong textOffset)
|
||||
{
|
||||
ulong mod0Offset = textOffset + memory.Read<uint>(textOffset + 4);
|
||||
|
||||
|
@ -319,7 +319,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
}
|
||||
}
|
||||
|
||||
private ElfSymbol GetSymbol64(MemoryManager memory, ulong address, ulong strTblAddr)
|
||||
private ElfSymbol GetSymbol64(IVirtualMemoryManager memory, ulong address, ulong strTblAddr)
|
||||
{
|
||||
ElfSymbol64 sym = memory.Read<ElfSymbol64>(address);
|
||||
|
||||
|
@ -335,7 +335,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
return new ElfSymbol(name, sym.Info, sym.Other, sym.SectionIndex, sym.ValueAddress, sym.Size);
|
||||
}
|
||||
|
||||
private ElfSymbol GetSymbol32(MemoryManager memory, ulong address, ulong strTblAddr)
|
||||
private ElfSymbol GetSymbol32(IVirtualMemoryManager memory, ulong address, ulong strTblAddr)
|
||||
{
|
||||
ElfSymbol32 sym = memory.Read<ElfSymbol32>(address);
|
||||
|
||||
|
|
13
Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs
Normal file
13
Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
using ARMeilleure.State;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
{
|
||||
interface IProcessContext : IDisposable
|
||||
{
|
||||
IVirtualMemoryManager AddressSpace { get; }
|
||||
|
||||
void Execute(ExecutionContext context, ulong codeAddress);
|
||||
}
|
||||
}
|
10
Ryujinx.HLE/HOS/Kernel/Process/IProcessContextFactory.cs
Normal file
10
Ryujinx.HLE/HOS/Kernel/Process/IProcessContextFactory.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Memory;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
{
|
||||
interface IProcessContextFactory
|
||||
{
|
||||
IProcessContext Create(MemoryBlock backingMemory, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler);
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ using Ryujinx.HLE.Exceptions;
|
|||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
@ -15,13 +16,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
{
|
||||
class KProcess : KSynchronizationObject
|
||||
{
|
||||
public const int KernelVersionMajor = 10;
|
||||
public const int KernelVersionMinor = 4;
|
||||
public const int KernelVersionMajor = 10;
|
||||
public const int KernelVersionMinor = 4;
|
||||
public const int KernelVersionRevision = 0;
|
||||
|
||||
public const int KernelVersionPacked =
|
||||
(KernelVersionMajor << 19) |
|
||||
(KernelVersionMinor << 15) |
|
||||
(KernelVersionMajor << 19) |
|
||||
(KernelVersionMinor << 15) |
|
||||
(KernelVersionRevision << 0);
|
||||
|
||||
public KMemoryManager MemoryManager { get; private set; }
|
||||
|
@ -47,27 +48,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
public long[] RandomEntropy { get; private set; }
|
||||
|
||||
private bool _signaled;
|
||||
private bool _useSystemMemBlocks;
|
||||
|
||||
public string Name { get; private set; }
|
||||
|
||||
private int _threadCount;
|
||||
|
||||
public int MmuFlags { get; private set; }
|
||||
public ProcessCreationFlags Flags { get; private set; }
|
||||
|
||||
private MemoryRegion _memRegion;
|
||||
|
||||
public KProcessCapabilities Capabilities { get; private set; }
|
||||
|
||||
public ulong TitleId { get; private set; }
|
||||
public long Pid { get; private set; }
|
||||
public long Pid { get; private set; }
|
||||
|
||||
private long _creationTimestamp;
|
||||
private long _creationTimestamp;
|
||||
private ulong _entrypoint;
|
||||
private ThreadStart _customThreadStart;
|
||||
private ulong _imageSize;
|
||||
private ulong _mainThreadStackSize;
|
||||
private ulong _memoryUsageCapacity;
|
||||
private int _version;
|
||||
private int _version;
|
||||
|
||||
public KHandleTable HandleTable { get; private set; }
|
||||
|
||||
|
@ -77,14 +78,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
|
||||
public bool IsPaused { get; private set; }
|
||||
|
||||
public MemoryManager CpuMemory { get; private set; }
|
||||
public CpuContext CpuContext { get; private set; }
|
||||
private IProcessContextFactory _contextFactory;
|
||||
public IProcessContext Context { get; private set; }
|
||||
public IVirtualMemoryManager CpuMemory => Context.AddressSpace;
|
||||
|
||||
public HleProcessDebugger Debugger { get; private set; }
|
||||
|
||||
public KProcess(KernelContext context) : base(context)
|
||||
{
|
||||
_processLock = new object();
|
||||
_processLock = new object();
|
||||
_threadingLock = new object();
|
||||
|
||||
AddressArbiter = new KAddressArbiter(context);
|
||||
|
@ -96,6 +98,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
|
||||
RandomEntropy = new long[KScheduler.CpuCoresCount];
|
||||
|
||||
// TODO: Remove once we no longer need to initialize it externally.
|
||||
HandleTable = new KHandleTable(context);
|
||||
|
||||
_threads = new LinkedList<KThread>();
|
||||
|
||||
Debugger = new HleProcessDebugger(this);
|
||||
|
@ -103,25 +108,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
|
||||
public KernelResult InitializeKip(
|
||||
ProcessCreationInfo creationInfo,
|
||||
int[] caps,
|
||||
KPageList pageList,
|
||||
KResourceLimit resourceLimit,
|
||||
MemoryRegion memRegion)
|
||||
ReadOnlySpan<int> capabilities,
|
||||
KPageList pageList,
|
||||
KResourceLimit resourceLimit,
|
||||
MemoryRegion memRegion,
|
||||
IProcessContextFactory contextFactory)
|
||||
{
|
||||
ResourceLimit = resourceLimit;
|
||||
_memRegion = memRegion;
|
||||
_memRegion = memRegion;
|
||||
_contextFactory = contextFactory ?? new ProcessContextFactory();
|
||||
|
||||
AddressSpaceType addrSpaceType = (AddressSpaceType)((creationInfo.MmuFlags >> 1) & 7);
|
||||
AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift);
|
||||
|
||||
InitializeMemoryManager(addrSpaceType, memRegion);
|
||||
InitializeMemoryManager(creationInfo.Flags);
|
||||
|
||||
bool aslrEnabled = ((creationInfo.MmuFlags >> 5) & 1) != 0;
|
||||
bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr);
|
||||
|
||||
ulong codeAddress = creationInfo.CodeAddress;
|
||||
|
||||
ulong codeSize = (ulong)creationInfo.CodePagesCount * KMemoryManager.PageSize;
|
||||
|
||||
KMemoryBlockAllocator memoryBlockAllocator = (MmuFlags & 0x40) != 0
|
||||
KMemoryBlockAllocator memoryBlockAllocator = creationInfo.Flags.HasFlag(ProcessCreationFlags.IsApplication)
|
||||
? KernelContext.LargeMemoryBlockAllocator
|
||||
: KernelContext.SmallMemoryBlockAllocator;
|
||||
|
||||
|
@ -139,7 +146,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
return result;
|
||||
}
|
||||
|
||||
if (!ValidateCodeAddressAndSize(codeAddress, codeSize))
|
||||
if (!MemoryManager.CanContain(codeAddress, codeSize, MemoryState.CodeStatic))
|
||||
{
|
||||
return KernelResult.InvalidMemRange;
|
||||
}
|
||||
|
@ -148,14 +155,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
codeAddress,
|
||||
pageList,
|
||||
MemoryState.CodeStatic,
|
||||
MemoryPermission.None);
|
||||
KMemoryPermission.None);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result = Capabilities.InitializeForKernel(caps, MemoryManager);
|
||||
result = Capabilities.InitializeForKernel(capabilities, MemoryManager);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
|
@ -176,14 +183,17 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
|
||||
public KernelResult Initialize(
|
||||
ProcessCreationInfo creationInfo,
|
||||
int[] caps,
|
||||
KResourceLimit resourceLimit,
|
||||
MemoryRegion memRegion)
|
||||
ReadOnlySpan<int> capabilities,
|
||||
KResourceLimit resourceLimit,
|
||||
MemoryRegion memRegion,
|
||||
IProcessContextFactory contextFactory,
|
||||
ThreadStart customThreadStart = null)
|
||||
{
|
||||
ResourceLimit = resourceLimit;
|
||||
_memRegion = memRegion;
|
||||
_memRegion = memRegion;
|
||||
_contextFactory = contextFactory ?? new ProcessContextFactory();
|
||||
|
||||
ulong personalMmHeapSize = GetPersonalMmHeapSize((ulong)creationInfo.PersonalMmHeapPagesCount, memRegion);
|
||||
ulong personalMmHeapSize = GetPersonalMmHeapSize((ulong)creationInfo.SystemResourcePagesCount, memRegion);
|
||||
|
||||
ulong codePagesCount = (ulong)creationInfo.CodePagesCount;
|
||||
|
||||
|
@ -205,7 +215,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
}
|
||||
}
|
||||
|
||||
PersonalMmHeapPagesCount = (ulong)creationInfo.PersonalMmHeapPagesCount;
|
||||
PersonalMmHeapPagesCount = (ulong)creationInfo.SystemResourcePagesCount;
|
||||
|
||||
KMemoryBlockAllocator memoryBlockAllocator;
|
||||
|
||||
|
@ -215,16 +225,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
}
|
||||
else
|
||||
{
|
||||
memoryBlockAllocator = (MmuFlags & 0x40) != 0
|
||||
memoryBlockAllocator = creationInfo.Flags.HasFlag(ProcessCreationFlags.IsApplication)
|
||||
? KernelContext.LargeMemoryBlockAllocator
|
||||
: KernelContext.SmallMemoryBlockAllocator;
|
||||
}
|
||||
|
||||
AddressSpaceType addrSpaceType = (AddressSpaceType)((creationInfo.MmuFlags >> 1) & 7);
|
||||
AddressSpaceType addrSpaceType = (AddressSpaceType)((int)(creationInfo.Flags & ProcessCreationFlags.AddressSpaceMask) >> (int)ProcessCreationFlags.AddressSpaceShift);
|
||||
|
||||
InitializeMemoryManager(addrSpaceType, memRegion);
|
||||
InitializeMemoryManager(creationInfo.Flags);
|
||||
|
||||
bool aslrEnabled = ((creationInfo.MmuFlags >> 5) & 1) != 0;
|
||||
bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr);
|
||||
|
||||
ulong codeAddress = creationInfo.CodeAddress;
|
||||
|
||||
|
@ -246,7 +256,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
return result;
|
||||
}
|
||||
|
||||
if (!ValidateCodeAddressAndSize(codeAddress, codeSize))
|
||||
if (!MemoryManager.CanContain(codeAddress, codeSize, MemoryState.CodeStatic))
|
||||
{
|
||||
CleanUpForError();
|
||||
|
||||
|
@ -257,7 +267,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
codeAddress,
|
||||
codePagesCount,
|
||||
MemoryState.CodeStatic,
|
||||
MemoryPermission.None);
|
||||
KMemoryPermission.None);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
|
@ -266,7 +276,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
return result;
|
||||
}
|
||||
|
||||
result = Capabilities.InitializeForUser(caps, MemoryManager);
|
||||
result = Capabilities.InitializeForUser(capabilities, MemoryManager);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
|
@ -289,57 +299,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
CleanUpForError();
|
||||
}
|
||||
|
||||
_customThreadStart = customThreadStart;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool ValidateCodeAddressAndSize(ulong address, ulong size)
|
||||
{
|
||||
ulong codeRegionStart;
|
||||
ulong codeRegionSize;
|
||||
|
||||
switch (MemoryManager.AddrSpaceWidth)
|
||||
{
|
||||
case 32:
|
||||
codeRegionStart = 0x200000;
|
||||
codeRegionSize = 0x3fe00000;
|
||||
break;
|
||||
|
||||
case 36:
|
||||
codeRegionStart = 0x8000000;
|
||||
codeRegionSize = 0x78000000;
|
||||
break;
|
||||
|
||||
case 39:
|
||||
codeRegionStart = 0x8000000;
|
||||
codeRegionSize = 0x7ff8000000;
|
||||
break;
|
||||
|
||||
default: throw new InvalidOperationException("Invalid address space width on memory manager.");
|
||||
}
|
||||
|
||||
ulong endAddr = address + size;
|
||||
|
||||
ulong codeRegionEnd = codeRegionStart + codeRegionSize;
|
||||
|
||||
if (endAddr <= address ||
|
||||
endAddr - 1 > codeRegionEnd - 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (MemoryManager.InsideHeapRegion (address, size) ||
|
||||
MemoryManager.InsideAliasRegion(address, size))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private KernelResult ParseProcessInfo(ProcessCreationInfo creationInfo)
|
||||
{
|
||||
// Ensure that the current kernel version is equal or above to the minimum required.
|
||||
uint requiredKernelVersionMajor = (uint)Capabilities.KernelReleaseVersion >> 19;
|
||||
uint requiredKernelVersionMajor = (uint)Capabilities.KernelReleaseVersion >> 19;
|
||||
uint requiredKernelVersionMinor = ((uint)Capabilities.KernelReleaseVersion >> 15) & 0xf;
|
||||
|
||||
if (KernelContext.EnableVersionChecks)
|
||||
|
@ -377,31 +345,29 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
|
||||
_creationTimestamp = PerformanceCounter.ElapsedMilliseconds;
|
||||
|
||||
MmuFlags = creationInfo.MmuFlags;
|
||||
_version = creationInfo.Version;
|
||||
TitleId = creationInfo.TitleId;
|
||||
Flags = creationInfo.Flags;
|
||||
_version = creationInfo.Version;
|
||||
TitleId = creationInfo.TitleId;
|
||||
_entrypoint = creationInfo.CodeAddress;
|
||||
_imageSize = (ulong)creationInfo.CodePagesCount * KMemoryManager.PageSize;
|
||||
_imageSize = (ulong)creationInfo.CodePagesCount * KMemoryManager.PageSize;
|
||||
|
||||
_useSystemMemBlocks = ((MmuFlags >> 6) & 1) != 0;
|
||||
|
||||
switch ((AddressSpaceType)((MmuFlags >> 1) & 7))
|
||||
switch (Flags & ProcessCreationFlags.AddressSpaceMask)
|
||||
{
|
||||
case AddressSpaceType.Addr32Bits:
|
||||
case AddressSpaceType.Addr36Bits:
|
||||
case AddressSpaceType.Addr39Bits:
|
||||
case ProcessCreationFlags.AddressSpace32Bit:
|
||||
case ProcessCreationFlags.AddressSpace64BitDeprecated:
|
||||
case ProcessCreationFlags.AddressSpace64Bit:
|
||||
_memoryUsageCapacity = MemoryManager.HeapRegionEnd -
|
||||
MemoryManager.HeapRegionStart;
|
||||
break;
|
||||
|
||||
case AddressSpaceType.Addr32BitsNoMap:
|
||||
case ProcessCreationFlags.AddressSpace32BitWithoutAlias:
|
||||
_memoryUsageCapacity = MemoryManager.HeapRegionEnd -
|
||||
MemoryManager.HeapRegionStart +
|
||||
MemoryManager.AliasRegionEnd -
|
||||
MemoryManager.AliasRegionStart;
|
||||
break;
|
||||
|
||||
default: throw new InvalidOperationException($"Invalid MMU flags value 0x{MmuFlags:x2}.");
|
||||
default: throw new InvalidOperationException($"Invalid MMU flags value 0x{Flags:x2}.");
|
||||
}
|
||||
|
||||
GenerateRandomEntropy();
|
||||
|
@ -469,7 +435,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
}
|
||||
|
||||
ulong regionStart = MemoryManager.TlsIoRegionStart;
|
||||
ulong regionSize = MemoryManager.TlsIoRegionEnd - regionStart;
|
||||
ulong regionSize = MemoryManager.TlsIoRegionEnd - regionStart;
|
||||
|
||||
ulong regionPagesCount = regionSize / KMemoryManager.PageSize;
|
||||
|
||||
|
@ -481,7 +447,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
regionStart,
|
||||
regionPagesCount,
|
||||
MemoryState.ThreadLocal,
|
||||
MemoryPermission.ReadAndWrite,
|
||||
KMemoryPermission.ReadAndWrite,
|
||||
out ulong tlsPageVa);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
|
@ -506,7 +472,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
|
||||
KernelResult result = KernelResult.Success;
|
||||
|
||||
KTlsPageInfo pageInfo = null;
|
||||
KTlsPageInfo pageInfo;
|
||||
|
||||
if (_fullTlsPages.TryGetValue(tlsPageAddr, out pageInfo))
|
||||
{
|
||||
|
@ -594,8 +560,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
// Check if the needed size for the code and the stack will fit on the
|
||||
// memory usage capacity of this Process. Also check for possible overflow
|
||||
// on the above addition.
|
||||
if (neededSize > _memoryUsageCapacity ||
|
||||
neededSize < stackSizeRounded)
|
||||
if (neededSize > _memoryUsageCapacity || neededSize < stackSizeRounded)
|
||||
{
|
||||
threadResourceLimit?.Release(LimitableResource.Thread, 1);
|
||||
|
||||
|
@ -646,7 +611,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
ulong stackPagesCount = stackSizeRounded / KMemoryManager.PageSize;
|
||||
|
||||
ulong regionStart = MemoryManager.StackRegionStart;
|
||||
ulong regionSize = MemoryManager.StackRegionEnd - regionStart;
|
||||
ulong regionSize = MemoryManager.StackRegionEnd - regionStart;
|
||||
|
||||
ulong regionPagesCount = regionSize / KMemoryManager.PageSize;
|
||||
|
||||
|
@ -658,7 +623,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
regionStart,
|
||||
regionPagesCount,
|
||||
MemoryState.Stack,
|
||||
MemoryPermission.ReadAndWrite,
|
||||
KMemoryPermission.ReadAndWrite,
|
||||
out ulong stackBottom);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
|
@ -703,7 +668,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
stackTop,
|
||||
mainThreadPriority,
|
||||
DefaultCpuCore,
|
||||
this);
|
||||
this,
|
||||
ThreadType.User,
|
||||
_customThreadStart);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
|
@ -730,20 +697,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
|
||||
SetState(newState);
|
||||
|
||||
// TODO: We can't call KThread.Start from a non-guest thread.
|
||||
// We will need to make some changes to allow the creation of
|
||||
// dummy threads that will be used to initialize the current
|
||||
// thread on KCoreContext so that GetCurrentThread doesn't fail.
|
||||
/* Result = MainThread.Start();
|
||||
result = mainThread.Start();
|
||||
|
||||
if (Result != KernelResult.Success)
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
SetState(OldState);
|
||||
SetState(oldState);
|
||||
|
||||
CleanUpForError();
|
||||
} */
|
||||
|
||||
mainThread.Reschedule(ThreadSchedState.Running);
|
||||
}
|
||||
|
||||
if (result == KernelResult.Success)
|
||||
{
|
||||
|
@ -760,7 +721,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
{
|
||||
if (State != newState)
|
||||
{
|
||||
State = newState;
|
||||
State = newState;
|
||||
_signaled = true;
|
||||
|
||||
Signal();
|
||||
|
@ -769,23 +730,23 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
|
||||
public KernelResult InitializeThread(
|
||||
KThread thread,
|
||||
ulong entrypoint,
|
||||
ulong argsPtr,
|
||||
ulong stackTop,
|
||||
int priority,
|
||||
int cpuCore)
|
||||
ulong entrypoint,
|
||||
ulong argsPtr,
|
||||
ulong stackTop,
|
||||
int priority,
|
||||
int cpuCore)
|
||||
{
|
||||
lock (_processLock)
|
||||
{
|
||||
return thread.Initialize(entrypoint, argsPtr, stackTop, priority, cpuCore, this);
|
||||
return thread.Initialize(entrypoint, argsPtr, stackTop, priority, cpuCore, this, ThreadType.User, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void SubscribeThreadEventHandlers(ARMeilleure.State.ExecutionContext context)
|
||||
{
|
||||
context.Interrupt += InterruptHandler;
|
||||
context.Interrupt += InterruptHandler;
|
||||
context.SupervisorCall += KernelContext.SyscallHandler.SvcCall;
|
||||
context.Undefined += UndefinedInstructionHandler;
|
||||
context.Undefined += UndefinedInstructionHandler;
|
||||
}
|
||||
|
||||
private void InterruptHandler(object sender, EventArgs e)
|
||||
|
@ -910,8 +871,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
{
|
||||
if (State >= ProcessState.Started)
|
||||
{
|
||||
if (State == ProcessState.Started ||
|
||||
State == ProcessState.Crashed ||
|
||||
if (State == ProcessState.Started ||
|
||||
State == ProcessState.Crashed ||
|
||||
State == ProcessState.Attached ||
|
||||
State == ProcessState.DebugSuspended)
|
||||
{
|
||||
|
@ -1072,23 +1033,25 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
return result;
|
||||
}
|
||||
|
||||
private void InitializeMemoryManager(AddressSpaceType addrSpaceType, MemoryRegion memRegion)
|
||||
private void InitializeMemoryManager(ProcessCreationFlags flags)
|
||||
{
|
||||
int addrSpaceBits = addrSpaceType switch
|
||||
int addrSpaceBits = (flags & ProcessCreationFlags.AddressSpaceMask) switch
|
||||
{
|
||||
AddressSpaceType.Addr32Bits => 32,
|
||||
AddressSpaceType.Addr36Bits => 36,
|
||||
AddressSpaceType.Addr32BitsNoMap => 32,
|
||||
AddressSpaceType.Addr39Bits => 39,
|
||||
_ => throw new ArgumentException(nameof(addrSpaceType))
|
||||
ProcessCreationFlags.AddressSpace32Bit => 32,
|
||||
ProcessCreationFlags.AddressSpace64BitDeprecated => 36,
|
||||
ProcessCreationFlags.AddressSpace32BitWithoutAlias => 32,
|
||||
ProcessCreationFlags.AddressSpace64Bit => 39,
|
||||
_ => 39
|
||||
};
|
||||
|
||||
CpuMemory = new MemoryManager(KernelContext.Memory, 1UL << addrSpaceBits, InvalidAccessHandler);
|
||||
CpuContext = new CpuContext(CpuMemory);
|
||||
Context = _contextFactory.Create(KernelContext.Memory, 1UL << addrSpaceBits, InvalidAccessHandler);
|
||||
|
||||
// TODO: This should eventually be removed.
|
||||
// The GPU shouldn't depend on the CPU memory manager at all.
|
||||
KernelContext.Device.Gpu.SetVmm(CpuMemory);
|
||||
if (flags.HasFlag(ProcessCreationFlags.IsApplication))
|
||||
{
|
||||
KernelContext.Device.Gpu.SetVmm((MemoryManager)CpuMemory);
|
||||
}
|
||||
|
||||
MemoryManager = new KMemoryManager(KernelContext, CpuMemory);
|
||||
}
|
||||
|
@ -1109,9 +1072,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
throw new UndefinedInstructionException(e.Address, e.OpCode);
|
||||
}
|
||||
|
||||
protected override void Destroy()
|
||||
{
|
||||
CpuMemory.Dispose();
|
||||
}
|
||||
protected override void Destroy() => Context.Dispose();
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ using Ryujinx.Common;
|
|||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
{
|
||||
|
@ -24,29 +25,29 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
IrqAccessMask = new byte[0x80];
|
||||
}
|
||||
|
||||
public KernelResult InitializeForKernel(int[] caps, KMemoryManager memoryManager)
|
||||
public KernelResult InitializeForKernel(ReadOnlySpan<int> capabilities, KMemoryManager memoryManager)
|
||||
{
|
||||
AllowedCpuCoresMask = 0xf;
|
||||
AllowedThreadPriosMask = -1;
|
||||
DebuggingFlags &= ~3;
|
||||
KernelReleaseVersion = KProcess.KernelVersionPacked;
|
||||
|
||||
return Parse(caps, memoryManager);
|
||||
return Parse(capabilities, memoryManager);
|
||||
}
|
||||
|
||||
public KernelResult InitializeForUser(int[] caps, KMemoryManager memoryManager)
|
||||
public KernelResult InitializeForUser(ReadOnlySpan<int> capabilities, KMemoryManager memoryManager)
|
||||
{
|
||||
return Parse(caps, memoryManager);
|
||||
return Parse(capabilities, memoryManager);
|
||||
}
|
||||
|
||||
private KernelResult Parse(int[] caps, KMemoryManager memoryManager)
|
||||
private KernelResult Parse(ReadOnlySpan<int> capabilities, KMemoryManager memoryManager)
|
||||
{
|
||||
int mask0 = 0;
|
||||
int mask1 = 0;
|
||||
|
||||
for (int index = 0; index < caps.Length; index++)
|
||||
for (int index = 0; index < capabilities.Length; index++)
|
||||
{
|
||||
int cap = caps[index];
|
||||
int cap = capabilities[index];
|
||||
|
||||
if (((cap + 1) & ~cap) != 0x40)
|
||||
{
|
||||
|
@ -59,14 +60,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
}
|
||||
else
|
||||
{
|
||||
if ((uint)index + 1 >= caps.Length)
|
||||
if ((uint)index + 1 >= capabilities.Length)
|
||||
{
|
||||
return KernelResult.InvalidCombination;
|
||||
}
|
||||
|
||||
int prevCap = cap;
|
||||
|
||||
cap = caps[++index];
|
||||
cap = capabilities[++index];
|
||||
|
||||
if (((cap + 1) & ~cap) != 0x40)
|
||||
{
|
||||
|
@ -91,9 +92,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
return KernelResult.InvalidAddress;
|
||||
}
|
||||
|
||||
MemoryPermission perm = (prevCap >> 31) != 0
|
||||
? MemoryPermission.Read
|
||||
: MemoryPermission.ReadAndWrite;
|
||||
KMemoryPermission perm = (prevCap >> 31) != 0
|
||||
? KMemoryPermission.Read
|
||||
: KMemoryPermission.ReadAndWrite;
|
||||
|
||||
KernelResult result;
|
||||
|
||||
|
@ -216,7 +217,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
{
|
||||
long address = ((long)(uint)cap << 4) & 0xffffff000;
|
||||
|
||||
memoryManager.MapIoMemory(address, KMemoryManager.PageSize, MemoryPermission.ReadAndWrite);
|
||||
memoryManager.MapIoMemory(address, KMemoryManager.PageSize, KMemoryPermission.ReadAndWrite);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
25
Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs
Normal file
25
Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using ARMeilleure.State;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
{
|
||||
class ProcessContext : IProcessContext
|
||||
{
|
||||
public IVirtualMemoryManager AddressSpace { get; }
|
||||
|
||||
public ProcessContext(IVirtualMemoryManager asManager)
|
||||
{
|
||||
AddressSpace = asManager;
|
||||
}
|
||||
|
||||
public void Execute(ExecutionContext context, ulong codeAddress)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
13
Ryujinx.HLE/HOS/Kernel/Process/ProcessContextFactory.cs
Normal file
13
Ryujinx.HLE/HOS/Kernel/Process/ProcessContextFactory.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Memory;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
{
|
||||
class ProcessContextFactory : IProcessContextFactory
|
||||
{
|
||||
public IProcessContext Create(MemoryBlock backingMemory, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler)
|
||||
{
|
||||
return new ProcessContext(new AddressSpaceManager(backingMemory, addressSpaceSize));
|
||||
}
|
||||
}
|
||||
}
|
38
Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationFlags.cs
Normal file
38
Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationFlags.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
{
|
||||
enum ProcessCreationFlags
|
||||
{
|
||||
Is64Bit = 1 << 0,
|
||||
|
||||
AddressSpaceShift = 1,
|
||||
AddressSpace32Bit = 0 << AddressSpaceShift,
|
||||
AddressSpace64BitDeprecated = 1 << AddressSpaceShift,
|
||||
AddressSpace32BitWithoutAlias = 2 << AddressSpaceShift,
|
||||
AddressSpace64Bit = 3 << AddressSpaceShift,
|
||||
AddressSpaceMask = 7 << AddressSpaceShift,
|
||||
|
||||
EnableDebug = 1 << 4,
|
||||
EnableAslr = 1 << 5,
|
||||
IsApplication = 1 << 6,
|
||||
DeprecatedUseSecureMemory = 1 << 7,
|
||||
|
||||
PoolPartitionShift = 7,
|
||||
PoolPartitionApplication = 0 << PoolPartitionShift,
|
||||
PoolPartitionApplet = 1 << PoolPartitionShift,
|
||||
PoolPartitionSystem = 2 << PoolPartitionShift,
|
||||
PoolPartitionSystemNonSecure = 3 << PoolPartitionShift,
|
||||
PoolPartitionMask = 0xf << PoolPartitionShift,
|
||||
|
||||
OptimizeMemoryAllocation = 1 << 11,
|
||||
|
||||
All =
|
||||
Is64Bit |
|
||||
AddressSpaceMask |
|
||||
EnableDebug |
|
||||
EnableAslr |
|
||||
IsApplication |
|
||||
DeprecatedUseSecureMemory |
|
||||
PoolPartitionMask |
|
||||
OptimizeMemoryAllocation
|
||||
}
|
||||
}
|
|
@ -2,36 +2,36 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
{
|
||||
struct ProcessCreationInfo
|
||||
{
|
||||
public string Name { get; private set; }
|
||||
public string Name { get; }
|
||||
|
||||
public int Version { get; private set; }
|
||||
public ulong TitleId { get; private set; }
|
||||
public int Version { get; }
|
||||
public ulong TitleId { get; }
|
||||
|
||||
public ulong CodeAddress { get; private set; }
|
||||
public int CodePagesCount { get; private set; }
|
||||
public ulong CodeAddress { get; }
|
||||
public int CodePagesCount { get; }
|
||||
|
||||
public int MmuFlags { get; private set; }
|
||||
public int ResourceLimitHandle { get; private set; }
|
||||
public int PersonalMmHeapPagesCount { get; private set; }
|
||||
public ProcessCreationFlags Flags { get; }
|
||||
public int ResourceLimitHandle { get; }
|
||||
public int SystemResourcePagesCount { get; }
|
||||
|
||||
public ProcessCreationInfo(
|
||||
string name,
|
||||
int category,
|
||||
ulong titleId,
|
||||
ulong codeAddress,
|
||||
int codePagesCount,
|
||||
int mmuFlags,
|
||||
int resourceLimitHandle,
|
||||
int personalMmHeapPagesCount)
|
||||
int version,
|
||||
ulong titleId,
|
||||
ulong codeAddress,
|
||||
int codePagesCount,
|
||||
ProcessCreationFlags flags,
|
||||
int resourceLimitHandle,
|
||||
int systemResourcePagesCount)
|
||||
{
|
||||
Name = name;
|
||||
Version = category;
|
||||
TitleId = titleId;
|
||||
CodeAddress = codeAddress;
|
||||
CodePagesCount = codePagesCount;
|
||||
MmuFlags = mmuFlags;
|
||||
ResourceLimitHandle = resourceLimitHandle;
|
||||
PersonalMmHeapPagesCount = personalMmHeapPagesCount;
|
||||
Name = name;
|
||||
Version = version;
|
||||
TitleId = titleId;
|
||||
CodeAddress = codeAddress;
|
||||
CodePagesCount = codePagesCount;
|
||||
Flags = flags;
|
||||
ResourceLimitHandle = resourceLimitHandle;
|
||||
SystemResourcePagesCount = systemResourcePagesCount;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,21 +7,167 @@ using Ryujinx.HLE.HOS.Kernel.Ipc;
|
|||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||
{
|
||||
class Syscall
|
||||
{
|
||||
private readonly Switch _device;
|
||||
private readonly KernelContext _context;
|
||||
|
||||
public Syscall(Switch device, KernelContext context)
|
||||
public Syscall(KernelContext context)
|
||||
{
|
||||
_device = device;
|
||||
_context = context;
|
||||
}
|
||||
|
||||
// Process
|
||||
|
||||
public KernelResult GetProcessId(int handle, out long pid)
|
||||
{
|
||||
KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
|
||||
|
||||
KProcess process = currentProcess.HandleTable.GetKProcess(handle);
|
||||
|
||||
if (process == null)
|
||||
{
|
||||
KThread thread = currentProcess.HandleTable.GetKThread(handle);
|
||||
|
||||
if (thread != null)
|
||||
{
|
||||
process = thread.Owner;
|
||||
}
|
||||
|
||||
// TODO: KDebugEvent.
|
||||
}
|
||||
|
||||
pid = process?.Pid ?? 0;
|
||||
|
||||
return process != null
|
||||
? KernelResult.Success
|
||||
: KernelResult.InvalidHandle;
|
||||
}
|
||||
|
||||
public KernelResult CreateProcess(
|
||||
ProcessCreationInfo info,
|
||||
ReadOnlySpan<int> capabilities,
|
||||
out int handle,
|
||||
IProcessContextFactory contextFactory,
|
||||
ThreadStart customThreadStart = null)
|
||||
{
|
||||
handle = 0;
|
||||
|
||||
if ((info.Flags & ~ProcessCreationFlags.All) != 0)
|
||||
{
|
||||
return KernelResult.InvalidEnumValue;
|
||||
}
|
||||
|
||||
// TODO: Address space check.
|
||||
|
||||
if ((info.Flags & ProcessCreationFlags.PoolPartitionMask) > ProcessCreationFlags.PoolPartitionSystemNonSecure)
|
||||
{
|
||||
return KernelResult.InvalidEnumValue;
|
||||
}
|
||||
|
||||
if ((info.CodeAddress & 0x1fffff) != 0)
|
||||
{
|
||||
return KernelResult.InvalidAddress;
|
||||
}
|
||||
|
||||
if (info.CodePagesCount < 0 || info.SystemResourcePagesCount < 0)
|
||||
{
|
||||
return KernelResult.InvalidSize;
|
||||
}
|
||||
|
||||
if (info.Flags.HasFlag(ProcessCreationFlags.OptimizeMemoryAllocation) &&
|
||||
!info.Flags.HasFlag(ProcessCreationFlags.IsApplication))
|
||||
{
|
||||
return KernelResult.InvalidThread;
|
||||
}
|
||||
|
||||
KHandleTable handleTable = _context.Scheduler.GetCurrentProcess().HandleTable;
|
||||
|
||||
KProcess process = new KProcess(_context);
|
||||
|
||||
using var _ = new OnScopeExit(process.DecrementReferenceCount);
|
||||
|
||||
KResourceLimit resourceLimit;
|
||||
|
||||
if (info.ResourceLimitHandle != 0)
|
||||
{
|
||||
resourceLimit = handleTable.GetObject<KResourceLimit>(info.ResourceLimitHandle);
|
||||
|
||||
if (resourceLimit == null)
|
||||
{
|
||||
return KernelResult.InvalidHandle;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
resourceLimit = _context.ResourceLimit;
|
||||
}
|
||||
|
||||
MemoryRegion memRegion = (info.Flags & ProcessCreationFlags.PoolPartitionMask) switch
|
||||
{
|
||||
ProcessCreationFlags.PoolPartitionApplication => MemoryRegion.Application,
|
||||
ProcessCreationFlags.PoolPartitionApplet => MemoryRegion.Applet,
|
||||
ProcessCreationFlags.PoolPartitionSystem => MemoryRegion.Service,
|
||||
ProcessCreationFlags.PoolPartitionSystemNonSecure => MemoryRegion.NvServices,
|
||||
_ => MemoryRegion.NvServices
|
||||
};
|
||||
|
||||
KernelResult result = process.Initialize(
|
||||
info,
|
||||
capabilities,
|
||||
resourceLimit,
|
||||
memRegion,
|
||||
contextFactory,
|
||||
customThreadStart);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
_context.Processes.TryAdd(process.Pid, process);
|
||||
|
||||
return handleTable.GenerateHandle(process, out handle);
|
||||
}
|
||||
|
||||
public KernelResult StartProcess(int handle, int priority, int cpuCore, ulong mainThreadStackSize)
|
||||
{
|
||||
KProcess process = _context.Scheduler.GetCurrentProcess().HandleTable.GetObject<KProcess>(handle);
|
||||
|
||||
if (process == null)
|
||||
{
|
||||
return KernelResult.InvalidHandle;
|
||||
}
|
||||
|
||||
if ((uint)cpuCore >= KScheduler.CpuCoresCount || !process.IsCpuCoreAllowed(cpuCore))
|
||||
{
|
||||
return KernelResult.InvalidCpuCore;
|
||||
}
|
||||
|
||||
if ((uint)priority >= KScheduler.PrioritiesCount || !process.IsPriorityAllowed(priority))
|
||||
{
|
||||
return KernelResult.InvalidPriority;
|
||||
}
|
||||
|
||||
process.DefaultCpuCore = cpuCore;
|
||||
|
||||
KernelResult result = process.Start(priority, mainThreadStackSize);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
process.IncrementReferenceCount();
|
||||
|
||||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
// IPC
|
||||
|
||||
public KernelResult ConnectToNamedPort(ulong namePtr, out int handle)
|
||||
|
@ -33,6 +179,13 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return KernelResult.UserCopyFailed;
|
||||
}
|
||||
|
||||
return ConnectToNamedPort(name, out handle);
|
||||
}
|
||||
|
||||
public KernelResult ConnectToNamedPort(string name, out int handle)
|
||||
{
|
||||
handle = 0;
|
||||
|
||||
if (name.Length > 11)
|
||||
{
|
||||
return KernelResult.MaximumExceeded;
|
||||
|
@ -70,61 +223,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return result;
|
||||
}
|
||||
|
||||
public KernelResult SendSyncRequestHLE(int handle)
|
||||
{
|
||||
KProcess process = _context.Scheduler.GetCurrentProcess();
|
||||
|
||||
KClientSession clientSession = process.HandleTable.GetObject<KClientSession>(handle);
|
||||
|
||||
if (clientSession == null || clientSession.Service == null)
|
||||
{
|
||||
return SendSyncRequest(handle);
|
||||
}
|
||||
|
||||
return SendSyncRequestWithUserBufferHLE((ulong)_context.Scheduler.GetCurrentThread().Context.Tpidr, 0x100, handle);
|
||||
}
|
||||
|
||||
public KernelResult SendSyncRequestWithUserBufferHLE(ulong messagePtr, ulong messageSize, int handle)
|
||||
{
|
||||
KProcess process = _context.Scheduler.GetCurrentProcess();
|
||||
|
||||
byte[] messageData = new byte[messageSize];
|
||||
|
||||
process.CpuMemory.Read(messagePtr, messageData);
|
||||
|
||||
KClientSession clientSession = process.HandleTable.GetObject<KClientSession>(handle);
|
||||
|
||||
if (clientSession == null || clientSession.Service == null)
|
||||
{
|
||||
return SendSyncRequestWithUserBuffer(messagePtr, messageSize, handle);
|
||||
}
|
||||
|
||||
if (clientSession != null)
|
||||
{
|
||||
_context.CriticalSection.Enter();
|
||||
|
||||
KThread currentThread = _context.Scheduler.GetCurrentThread();
|
||||
|
||||
currentThread.SignaledObj = null;
|
||||
currentThread.ObjSyncResult = KernelResult.Success;
|
||||
|
||||
currentThread.Reschedule(ThreadSchedState.Paused);
|
||||
|
||||
clientSession.Service.Server.PushMessage(_device, currentThread, clientSession, messagePtr, messageSize);
|
||||
|
||||
_context.CriticalSection.Leave();
|
||||
|
||||
return currentThread.ObjSyncResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.KernelSvc, $"Invalid session handle 0x{handle:x8}!");
|
||||
|
||||
return KernelResult.InvalidHandle;
|
||||
}
|
||||
}
|
||||
|
||||
private KernelResult SendSyncRequest(int handle)
|
||||
public KernelResult SendSyncRequest(int handle)
|
||||
{
|
||||
KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
|
||||
|
||||
|
@ -407,9 +506,18 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return KernelResult.UserCopyFailed;
|
||||
}
|
||||
|
||||
KSynchronizationObject[] syncObjs = new KSynchronizationObject[handlesCount];
|
||||
return ReplyAndReceive(handles, replyTargetHandle, timeout, out handleIndex);
|
||||
}
|
||||
|
||||
for (int index = 0; index < handlesCount; index++)
|
||||
public KernelResult ReplyAndReceive(ReadOnlySpan<int> handles, int replyTargetHandle, long timeout, out int handleIndex)
|
||||
{
|
||||
handleIndex = 0;
|
||||
|
||||
KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
|
||||
|
||||
KSynchronizationObject[] syncObjs = new KSynchronizationObject[handles.Length];
|
||||
|
||||
for (int index = 0; index < handles.Length; index++)
|
||||
{
|
||||
KSynchronizationObject obj = currentProcess.HandleTable.GetObject<KSynchronizationObject>(handles[index]);
|
||||
|
||||
|
@ -601,7 +709,19 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return KernelResult.UserCopyFailed;
|
||||
}
|
||||
|
||||
if (maxSessions < 0 || name.Length > 11)
|
||||
if (name.Length > 11)
|
||||
{
|
||||
return KernelResult.MaximumExceeded;
|
||||
}
|
||||
|
||||
return ManageNamedPort(name, maxSessions, out handle);
|
||||
}
|
||||
|
||||
public KernelResult ManageNamedPort(string name, int maxSessions, out int handle)
|
||||
{
|
||||
handle = 0;
|
||||
|
||||
if (maxSessions < 0)
|
||||
{
|
||||
return KernelResult.MaximumExceeded;
|
||||
}
|
||||
|
@ -826,7 +946,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
public KernelResult MapSharedMemory(int handle, ulong address, ulong size, MemoryPermission permission)
|
||||
public KernelResult MapSharedMemory(int handle, ulong address, ulong size, KMemoryPermission permission)
|
||||
{
|
||||
if (!PageAligned(address))
|
||||
{
|
||||
|
@ -843,7 +963,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return KernelResult.InvalidMemState;
|
||||
}
|
||||
|
||||
if ((permission | MemoryPermission.Write) != MemoryPermission.ReadAndWrite)
|
||||
if ((permission | KMemoryPermission.Write) != KMemoryPermission.ReadAndWrite)
|
||||
{
|
||||
return KernelResult.InvalidPermission;
|
||||
}
|
||||
|
@ -912,7 +1032,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
currentProcess);
|
||||
}
|
||||
|
||||
public KernelResult CreateTransferMemory(ulong address, ulong size, MemoryPermission permission, out int handle)
|
||||
public KernelResult CreateTransferMemory(ulong address, ulong size, KMemoryPermission permission, out int handle)
|
||||
{
|
||||
handle = 0;
|
||||
|
||||
|
@ -931,7 +1051,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return KernelResult.InvalidMemState;
|
||||
}
|
||||
|
||||
if (permission > MemoryPermission.ReadAndWrite || permission == MemoryPermission.Write)
|
||||
if (permission > KMemoryPermission.ReadAndWrite || permission == KMemoryPermission.Write)
|
||||
{
|
||||
return KernelResult.InvalidPermission;
|
||||
}
|
||||
|
@ -1119,7 +1239,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return targetProcess.MemoryManager.UnmapProcessCodeMemory(dst, src, size);
|
||||
}
|
||||
|
||||
public KernelResult SetProcessMemoryPermission(int handle, ulong src, ulong size, MemoryPermission permission)
|
||||
public KernelResult SetProcessMemoryPermission(int handle, ulong src, ulong size, KMemoryPermission permission)
|
||||
{
|
||||
if (!PageAligned(src))
|
||||
{
|
||||
|
@ -1131,10 +1251,10 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return KernelResult.InvalidSize;
|
||||
}
|
||||
|
||||
if (permission != MemoryPermission.None &&
|
||||
permission != MemoryPermission.Read &&
|
||||
permission != MemoryPermission.ReadAndWrite &&
|
||||
permission != MemoryPermission.ReadAndExecute)
|
||||
if (permission != KMemoryPermission.None &&
|
||||
permission != KMemoryPermission.Read &&
|
||||
permission != KMemoryPermission.ReadAndWrite &&
|
||||
permission != KMemoryPermission.ReadAndExecute)
|
||||
{
|
||||
return KernelResult.InvalidPermission;
|
||||
}
|
||||
|
@ -1282,31 +1402,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return _context.Scheduler.GetCurrentThread().Context.CntpctEl0;
|
||||
}
|
||||
|
||||
public KernelResult GetProcessId(int handle, out long pid)
|
||||
{
|
||||
KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
|
||||
|
||||
KProcess process = currentProcess.HandleTable.GetKProcess(handle);
|
||||
|
||||
if (process == null)
|
||||
{
|
||||
KThread thread = currentProcess.HandleTable.GetKThread(handle);
|
||||
|
||||
if (thread != null)
|
||||
{
|
||||
process = thread.Owner;
|
||||
}
|
||||
|
||||
// TODO: KDebugEvent.
|
||||
}
|
||||
|
||||
pid = process?.Pid ?? 0;
|
||||
|
||||
return process != null
|
||||
? KernelResult.Success
|
||||
: KernelResult.InvalidHandle;
|
||||
}
|
||||
|
||||
public void Break(ulong reason)
|
||||
{
|
||||
KThread currentThread = _context.Scheduler.GetCurrentThread();
|
||||
|
@ -1997,7 +2092,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return KernelResult.InvalidThread;
|
||||
}
|
||||
|
||||
MemoryManager memory = currentProcess.CpuMemory;
|
||||
IVirtualMemoryManager memory = currentProcess.CpuMemory;
|
||||
|
||||
memory.Write(address + 0x0, thread.Context.GetX(0));
|
||||
memory.Write(address + 0x8, thread.Context.GetX(1));
|
||||
|
|
|
@ -22,12 +22,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
|
||||
public KernelResult SendSyncRequest32([R(0)] int handle)
|
||||
{
|
||||
return _syscall.SendSyncRequestHLE(handle);
|
||||
return _syscall.SendSyncRequest(handle);
|
||||
}
|
||||
|
||||
public KernelResult SendSyncRequestWithUserBuffer32([R(0)] uint messagePtr, [R(1)] uint messageSize, [R(2)] int handle)
|
||||
{
|
||||
return _syscall.SendSyncRequestWithUserBufferHLE(messagePtr, messageSize, handle);
|
||||
return _syscall.SendSyncRequestWithUserBuffer(messagePtr, messageSize, handle);
|
||||
}
|
||||
|
||||
public KernelResult CreateSession32(
|
||||
|
@ -116,7 +116,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return result;
|
||||
}
|
||||
|
||||
public KernelResult MapSharedMemory32([R(0)] int handle, [R(1)] uint address, [R(2)] uint size, [R(3)] MemoryPermission permission)
|
||||
public KernelResult MapSharedMemory32([R(0)] int handle, [R(1)] uint address, [R(2)] uint size, [R(3)] KMemoryPermission permission)
|
||||
{
|
||||
return _syscall.MapSharedMemory(handle, address, size, permission);
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
public KernelResult CreateTransferMemory32(
|
||||
[R(1)] uint address,
|
||||
[R(2)] uint size,
|
||||
[R(3)] MemoryPermission permission,
|
||||
[R(3)] KMemoryPermission permission,
|
||||
[R(1)] out int handle)
|
||||
{
|
||||
return _syscall.CreateTransferMemory(address, size, permission, out handle);
|
||||
|
@ -169,7 +169,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
[R(2)] uint srcLow,
|
||||
[R(3)] uint srcHigh,
|
||||
[R(4)] uint sizeHigh,
|
||||
[R(5)] MemoryPermission permission)
|
||||
[R(5)] KMemoryPermission permission)
|
||||
{
|
||||
ulong src = srcLow | ((ulong)srcHigh << 32);
|
||||
ulong size = sizeLow | ((ulong)sizeHigh << 32);
|
||||
|
|
|
@ -22,12 +22,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
|
||||
public KernelResult SendSyncRequest64([R(0)] int handle)
|
||||
{
|
||||
return _syscall.SendSyncRequestHLE(handle);
|
||||
return _syscall.SendSyncRequest(handle);
|
||||
}
|
||||
|
||||
public KernelResult SendSyncRequestWithUserBuffer64([R(0)] ulong messagePtr, [R(1)] ulong messageSize, [R(2)] int handle)
|
||||
{
|
||||
return _syscall.SendSyncRequestWithUserBufferHLE(messagePtr, messageSize, handle);
|
||||
return _syscall.SendSyncRequestWithUserBuffer(messagePtr, messageSize, handle);
|
||||
}
|
||||
|
||||
public KernelResult SendAsyncRequestWithUserBuffer64(
|
||||
|
@ -133,7 +133,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return _syscall.QueryMemory(infoPtr, position, out pageInfo);
|
||||
}
|
||||
|
||||
public KernelResult MapSharedMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size, [R(3)] MemoryPermission permission)
|
||||
public KernelResult MapSharedMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size, [R(3)] KMemoryPermission permission)
|
||||
{
|
||||
return _syscall.MapSharedMemory(handle, address, size, permission);
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
public KernelResult CreateTransferMemory64(
|
||||
[R(1)] ulong address,
|
||||
[R(2)] ulong size,
|
||||
[R(3)] MemoryPermission permission,
|
||||
[R(3)] KMemoryPermission permission,
|
||||
[R(1)] out int handle)
|
||||
{
|
||||
return _syscall.CreateTransferMemory(address, size, permission, out handle);
|
||||
|
@ -172,7 +172,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return _syscall.UnmapProcessCodeMemory(handle, dst, src, size);
|
||||
}
|
||||
|
||||
public KernelResult SetProcessMemoryPermission64([R(0)] int handle, [R(1)] ulong src, [R(2)] ulong size, [R(3)] MemoryPermission permission)
|
||||
public KernelResult SetProcessMemoryPermission64([R(0)] int handle, [R(1)] ulong src, [R(2)] ulong size, [R(3)] KMemoryPermission permission)
|
||||
{
|
||||
return _syscall.SetProcessMemoryPermission(handle, src, size, permission);
|
||||
}
|
||||
|
|
|
@ -229,6 +229,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
|
||||
KProcess dummyProcess = new KProcess(_context);
|
||||
|
||||
dummyProcess.HandleTable.Initialize(1024);
|
||||
|
||||
KThread dummyThread = new KThread(_context);
|
||||
|
||||
dummyThread.Initialize(0, 0, 0, 44, 0, dummyProcess, ThreadType.Dummy);
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
public ulong CondVarAddress { get; set; }
|
||||
|
||||
private ulong _entrypoint;
|
||||
private ThreadStart _customThreadStart;
|
||||
|
||||
public ulong MutexAddress { get; set; }
|
||||
|
||||
|
@ -48,12 +49,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
|
||||
public LinkedListNode<KThread>[] SiblingsPerCore { get; private set; }
|
||||
|
||||
public LinkedList<KThread> Withholder { get; set; }
|
||||
public LinkedList<KThread> Withholder { get; set; }
|
||||
public LinkedListNode<KThread> WithholderNode { get; set; }
|
||||
|
||||
public LinkedListNode<KThread> ProcessListNode { get; set; }
|
||||
|
||||
private LinkedList<KThread> _mutexWaiters;
|
||||
private LinkedList<KThread> _mutexWaiters;
|
||||
private LinkedListNode<KThread> _mutexWaiterNode;
|
||||
|
||||
public KThread MutexOwner { get; private set; }
|
||||
|
@ -65,24 +66,28 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
public KernelResult ObjSyncResult { get; set; }
|
||||
|
||||
public int DynamicPriority { get; set; }
|
||||
public int CurrentCore { get; set; }
|
||||
public int BasePriority { get; set; }
|
||||
public int PreferredCore { get; set; }
|
||||
public int CurrentCore { get; set; }
|
||||
public int BasePriority { get; set; }
|
||||
public int PreferredCore { get; set; }
|
||||
|
||||
private long _affinityMaskOverride;
|
||||
private int _preferredCoreOverride;
|
||||
private int _preferredCoreOverride;
|
||||
#pragma warning disable CS0649
|
||||
private int _affinityOverrideCount;
|
||||
private int _affinityOverrideCount;
|
||||
#pragma warning restore CS0649
|
||||
|
||||
public ThreadSchedState SchedFlags { get; private set; }
|
||||
|
||||
private int _shallBeTerminated;
|
||||
|
||||
public bool ShallBeTerminated { get => _shallBeTerminated != 0; set => _shallBeTerminated = value ? 1 : 0; }
|
||||
public bool ShallBeTerminated
|
||||
{
|
||||
get => _shallBeTerminated != 0;
|
||||
set => _shallBeTerminated = value ? 1 : 0;
|
||||
}
|
||||
|
||||
public bool SyncCancelled { get; set; }
|
||||
public bool WaitingSync { get; set; }
|
||||
public bool WaitingSync { get; set; }
|
||||
|
||||
private bool _hasExited;
|
||||
private bool _hasBeenInitialized;
|
||||
|
@ -98,7 +103,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
|
||||
public KThread(KernelContext context) : base(context)
|
||||
{
|
||||
_scheduler = KernelContext.Scheduler;
|
||||
_scheduler = KernelContext.Scheduler;
|
||||
_schedulingData = KernelContext.Scheduler.SchedulingData;
|
||||
|
||||
WaitSyncObjects = new KSynchronizationObject[MaxWaitSyncObjects];
|
||||
|
@ -110,14 +115,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
}
|
||||
|
||||
public KernelResult Initialize(
|
||||
ulong entrypoint,
|
||||
ulong argsPtr,
|
||||
ulong stackTop,
|
||||
int priority,
|
||||
int defaultCpuCore,
|
||||
KProcess owner,
|
||||
ThreadType type = ThreadType.User,
|
||||
ThreadStart customHostThreadStart = null)
|
||||
ulong entrypoint,
|
||||
ulong argsPtr,
|
||||
ulong stackTop,
|
||||
int priority,
|
||||
int defaultCpuCore,
|
||||
KProcess owner,
|
||||
ThreadType type,
|
||||
ThreadStart customThreadStart = null)
|
||||
{
|
||||
if ((uint)type > 3)
|
||||
{
|
||||
|
@ -135,11 +140,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
CurrentCore = PreferredCore;
|
||||
|
||||
DynamicPriority = priority;
|
||||
BasePriority = priority;
|
||||
BasePriority = priority;
|
||||
|
||||
ObjSyncResult = KernelResult.ThreadNotStarted;
|
||||
|
||||
_entrypoint = entrypoint;
|
||||
_customThreadStart = customThreadStart;
|
||||
|
||||
if (type == ThreadType.User)
|
||||
{
|
||||
|
@ -162,18 +168,18 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
owner.IncrementReferenceCount();
|
||||
owner.IncrementThreadCount();
|
||||
|
||||
is64Bits = (owner.MmuFlags & 1) != 0;
|
||||
is64Bits = owner.Flags.HasFlag(ProcessCreationFlags.Is64Bit);
|
||||
}
|
||||
else
|
||||
{
|
||||
is64Bits = true;
|
||||
}
|
||||
|
||||
HostThread = new Thread(customHostThreadStart ?? (() => ThreadStart(entrypoint)));
|
||||
HostThread = new Thread(ThreadStart);
|
||||
|
||||
Context = CpuContext.CreateExecutionContext();
|
||||
|
||||
bool isAarch32 = (Owner.MmuFlags & 1) == 0;
|
||||
bool isAarch32 = !Owner.Flags.HasFlag(ProcessCreationFlags.Is64Bit);
|
||||
|
||||
Context.IsAarch32 = isAarch32;
|
||||
|
||||
|
@ -189,7 +195,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
}
|
||||
|
||||
Context.CntfrqEl0 = 19200000;
|
||||
Context.Tpidr = (long)_tlsAddress;
|
||||
Context.Tpidr = (long)_tlsAddress;
|
||||
|
||||
owner.SubscribeThreadEventHandlers(Context);
|
||||
|
||||
|
@ -249,7 +255,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
{
|
||||
KThread currentThread = KernelContext.Scheduler.GetCurrentThread();
|
||||
|
||||
while (SchedFlags != ThreadSchedState.TerminationPending &&
|
||||
while (SchedFlags != ThreadSchedState.TerminationPending &&
|
||||
currentThread.SchedFlags != ThreadSchedState.TerminationPending &&
|
||||
!currentThread.ShallBeTerminated)
|
||||
{
|
||||
|
@ -351,7 +357,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
Context.RequestInterrupt();
|
||||
}
|
||||
|
||||
SignaledObj = null;
|
||||
SignaledObj = null;
|
||||
ObjSyncResult = KernelResult.ThreadTerminating;
|
||||
|
||||
ReleaseAndResume();
|
||||
|
@ -524,7 +530,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
// If the candidate was scheduled after the current thread, then it's not worth it,
|
||||
// unless the priority is higher than the current one.
|
||||
if (nextThreadOnCurrentQueue.LastScheduledTime >= thread.LastScheduledTime ||
|
||||
nextThreadOnCurrentQueue.DynamicPriority < thread.DynamicPriority)
|
||||
nextThreadOnCurrentQueue.DynamicPriority < thread.DynamicPriority)
|
||||
{
|
||||
yield return thread;
|
||||
}
|
||||
|
@ -701,7 +707,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
}
|
||||
else
|
||||
{
|
||||
SignaledObj = null;
|
||||
SignaledObj = null;
|
||||
ObjSyncResult = KernelResult.Cancelled;
|
||||
|
||||
SetNewSchedFlags(ThreadSchedState.Running);
|
||||
|
@ -734,14 +740,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
if (useOverride)
|
||||
{
|
||||
_preferredCoreOverride = newCore;
|
||||
_affinityMaskOverride = newAffinityMask;
|
||||
_affinityMaskOverride = newAffinityMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
long oldAffinityMask = AffinityMask;
|
||||
|
||||
PreferredCore = newCore;
|
||||
AffinityMask = newAffinityMask;
|
||||
AffinityMask = newAffinityMask;
|
||||
|
||||
if (oldAffinityMask != newAffinityMask)
|
||||
{
|
||||
|
@ -783,7 +789,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
|
||||
private void CombineForcePauseFlags()
|
||||
{
|
||||
ThreadSchedState oldFlags = SchedFlags;
|
||||
ThreadSchedState oldFlags = SchedFlags;
|
||||
ThreadSchedState lowNibble = SchedFlags & ThreadSchedState.LowMask;
|
||||
|
||||
SchedFlags = lowNibble | _forcePauseFlags;
|
||||
|
@ -1143,19 +1149,23 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
}
|
||||
}
|
||||
|
||||
private void ThreadStart(ulong entrypoint)
|
||||
private void ThreadStart()
|
||||
{
|
||||
Owner.CpuContext.Execute(Context, entrypoint);
|
||||
KernelStatic.SetKernelContext(KernelContext);
|
||||
|
||||
ThreadExit();
|
||||
if (_customThreadStart != null)
|
||||
{
|
||||
_customThreadStart();
|
||||
}
|
||||
else
|
||||
{
|
||||
Owner.Context.Execute(Context, _entrypoint);
|
||||
}
|
||||
|
||||
Context.Dispose();
|
||||
}
|
||||
|
||||
private void ThreadExit()
|
||||
{
|
||||
KernelContext.Scheduler.ExitThread(this);
|
||||
KernelContext.Scheduler.RemoveThread(this);
|
||||
|
||||
Context.Dispose();
|
||||
}
|
||||
|
||||
public bool IsCurrentHostThread()
|
||||
|
@ -1203,9 +1213,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
// Wake up all threads that may be waiting for a mutex being held by this thread.
|
||||
foreach (KThread thread in _mutexWaiters)
|
||||
{
|
||||
thread.MutexOwner = null;
|
||||
thread.MutexOwner = null;
|
||||
thread._preferredCoreOverride = 0;
|
||||
thread.ObjSyncResult = KernelResult.InvalidState;
|
||||
thread.ObjSyncResult = KernelResult.InvalidState;
|
||||
|
||||
thread.ReleaseAndResume();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue