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

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

* Fix for applet transfer memory + some nits

* Keep handles if possible to avoid server handle table exhaustion

* Fix IPC ZeroFill bug

* am: Correctly implement CreateManagedDisplayLayer and implement CreateManagedDisplaySeparableLayer

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

* Make it exit properly

* Make ServiceNotImplementedException show the full message again

* Allow yielding execution to avoid starving other threads

* Only wait if active

* Merge IVirtualMemoryManager and IAddressSpaceManager

* Fix Ro loading data from the wrong process

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

View file

@ -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();
}
}

View file

@ -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);

View file

@ -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)

View file

@ -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();
}
}
}
}

View file

@ -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;

View file

@ -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)

View file

@ -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);

View 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;
}
}
}

View file

@ -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;
}

View file

@ -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)
{

View file

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

View file

@ -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;

View file

@ -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();

View file

@ -3,7 +3,7 @@ using System;
namespace Ryujinx.HLE.HOS.Kernel.Memory
{
[Flags]
enum MemoryPermission : byte
enum KMemoryPermission : byte
{
None = 0,
Mask = 0xff,

View file

@ -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);

View 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);
}
}

View 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);
}
}

View file

@ -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();
}
}

View file

@ -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;
}

View 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()
{
}
}
}

View 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));
}
}
}

View 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
}
}

View file

@ -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;
}
}
}

View file

@ -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));

View file

@ -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);

View file

@ -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);
}

View file

@ -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);

View file

@ -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();
}