aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Kernel
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.HLE/HOS/Kernel')
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Common/OnScopeExit.cs11
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs4
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Ipc/KClientPort.cs9
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs9
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs34
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Ipc/KSession.cs15
-rw-r--r--Ryujinx.HLE/HOS/Kernel/KernelContext.cs2
-rw-r--r--Ryujinx.HLE/HOS/Kernel/KernelStatic.cs38
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Memory/KMemoryBlock.cs16
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Memory/KMemoryInfo.cs8
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Memory/KMemoryManager.cs327
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs12
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Memory/KTransferMemory.cs7
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Memory/MemoryPermission.cs2
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs10
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs13
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/IProcessContextFactory.cs10
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs234
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs27
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs25
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/ProcessContextFactory.cs13
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationFlags.cs38
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationInfo.cs46
-rw-r--r--Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs273
-rw-r--r--Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs10
-rw-r--r--Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs10
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs2
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs90
28 files changed, 750 insertions, 545 deletions
diff --git a/Ryujinx.HLE/HOS/Kernel/Common/OnScopeExit.cs b/Ryujinx.HLE/HOS/Kernel/Common/OnScopeExit.cs
new file mode 100644
index 00000000..098d83d1
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Kernel/Common/OnScopeExit.cs
@@ -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();
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs b/Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs
index 0986adf7..fbd32845 100644
--- a/Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Ipc/KBufferDescriptorTable.cs
@@ -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);
diff --git a/Ryujinx.HLE/HOS/Kernel/Ipc/KClientPort.cs b/Ryujinx.HLE/HOS/Kernel/Ipc/KClientPort.cs
index 8d6669cf..c3b7d1dd 100644
--- a/Ryujinx.HLE/HOS/Kernel/Ipc/KClientPort.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Ipc/KClientPort.cs
@@ -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)
diff --git a/Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs b/Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs
index 2c2d9644..d535bf82 100644
--- a/Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Ipc/KClientSession.cs
@@ -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();
- }
}
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs b/Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs
index 48669832..e9c6127f 100644
--- a/Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Ipc/KServerSession.cs
@@ -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;
diff --git a/Ryujinx.HLE/HOS/Kernel/Ipc/KSession.cs b/Ryujinx.HLE/HOS/Kernel/Ipc/KSession.cs
index 4b5886a9..d614857c 100644
--- a/Ryujinx.HLE/HOS/Kernel/Ipc/KSession.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Ipc/KSession.cs
@@ -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)
diff --git a/Ryujinx.HLE/HOS/Kernel/KernelContext.cs b/Ryujinx.HLE/HOS/Kernel/KernelContext.cs
index a2d8bc47..d19c43ee 100644
--- a/Ryujinx.HLE/HOS/Kernel/KernelContext.cs
+++ b/Ryujinx.HLE/HOS/Kernel/KernelContext.cs
@@ -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);
diff --git a/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs b/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs
new file mode 100644
index 00000000..c7deadae
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs
@@ -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;
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryBlock.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryBlock.cs
index 04e14e1b..b93b68d9 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryBlock.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryBlock.cs
@@ -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;
}
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryInfo.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryInfo.cs
index 21e9e494..af070ac2 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryInfo.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryInfo.cs
@@ -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)
{
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryManager.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryManager.cs
index 43e7ad69..63ac8583 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryManager.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KMemoryManager.cs
@@ -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)
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs
index 65134f0d..ca0e3421 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KSharedMemory.cs
@@ -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;
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/KTransferMemory.cs b/Ryujinx.HLE/HOS/Kernel/Memory/KTransferMemory.cs
index d3e6208e..96349452 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/KTransferMemory.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/KTransferMemory.cs
@@ -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();
diff --git a/Ryujinx.HLE/HOS/Kernel/Memory/MemoryPermission.cs b/Ryujinx.HLE/HOS/Kernel/Memory/MemoryPermission.cs
index 0ad90abd..8bfd8d94 100644
--- a/Ryujinx.HLE/HOS/Kernel/Memory/MemoryPermission.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Memory/MemoryPermission.cs
@@ -3,7 +3,7 @@ using System;
namespace Ryujinx.HLE.HOS.Kernel.Memory
{
[Flags]
- enum MemoryPermission : byte
+ enum KMemoryPermission : byte
{
None = 0,
Mask = 0xff,
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs b/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs
index 376badfb..5ad33154 100644
--- a/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs
@@ -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);
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs b/Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs
new file mode 100644
index 00000000..758ac6b1
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs
@@ -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);
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/IProcessContextFactory.cs b/Ryujinx.HLE/HOS/Kernel/Process/IProcessContextFactory.cs
new file mode 100644
index 00000000..c438b570
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Kernel/Process/IProcessContextFactory.cs
@@ -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);
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
index d02e25a3..8e914f19 100644
--- a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
@@ -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();
}
- 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;
- }
+ _customThreadStart = customThreadStart;
- return true;
+ return result;
}
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;
-
- _useSystemMemBlocks = ((MmuFlags >> 6) & 1) != 0;
+ _imageSize = (ulong)creationInfo.CodePagesCount * KMemoryManager.PageSize;
- 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();
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs b/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs
index 2396aea8..e1cdb30f 100644
--- a/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Process/KProcessCapabilities.cs
@@ -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;
}
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs b/Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs
new file mode 100644
index 00000000..54997cb7
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs
@@ -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()
+ {
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/ProcessContextFactory.cs b/Ryujinx.HLE/HOS/Kernel/Process/ProcessContextFactory.cs
new file mode 100644
index 00000000..03db62fa
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Kernel/Process/ProcessContextFactory.cs
@@ -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));
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationFlags.cs b/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationFlags.cs
new file mode 100644
index 00000000..a34481e5
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationFlags.cs
@@ -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
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationInfo.cs b/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationInfo.cs
index a5820865..26c23b3b 100644
--- a/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationInfo.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Process/ProcessCreationInfo.cs
@@ -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;
}
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
index c1e7026b..5e32ca58 100644
--- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
+++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs
@@ -7,124 +7,223 @@ 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;
}
- // IPC
+ // Process
- public KernelResult ConnectToNamedPort(ulong namePtr, out int handle)
+ 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 (!KernelTransfer.UserToKernelString(_context, namePtr, 12, out string name))
+ if ((info.Flags & ~ProcessCreationFlags.All) != 0)
{
- return KernelResult.UserCopyFailed;
+ return KernelResult.InvalidEnumValue;
}
- if (name.Length > 11)
+ // TODO: Address space check.
+
+ if ((info.Flags & ProcessCreationFlags.PoolPartitionMask) > ProcessCreationFlags.PoolPartitionSystemNonSecure)
{
- return KernelResult.MaximumExceeded;
+ return KernelResult.InvalidEnumValue;
}
- KAutoObject autoObj = KAutoObject.FindNamedObject(_context, name);
+ if ((info.CodeAddress & 0x1fffff) != 0)
+ {
+ return KernelResult.InvalidAddress;
+ }
- if (!(autoObj is KClientPort clientPort))
+ if (info.CodePagesCount < 0 || info.SystemResourcePagesCount < 0)
{
- return KernelResult.NotFound;
+ return KernelResult.InvalidSize;
}
- KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
+ if (info.Flags.HasFlag(ProcessCreationFlags.OptimizeMemoryAllocation) &&
+ !info.Flags.HasFlag(ProcessCreationFlags.IsApplication))
+ {
+ return KernelResult.InvalidThread;
+ }
- KernelResult result = currentProcess.HandleTable.ReserveHandle(out handle);
+ KHandleTable handleTable = _context.Scheduler.GetCurrentProcess().HandleTable;
- if (result != KernelResult.Success)
+ KProcess process = new KProcess(_context);
+
+ using var _ = new OnScopeExit(process.DecrementReferenceCount);
+
+ KResourceLimit resourceLimit;
+
+ if (info.ResourceLimitHandle != 0)
{
- return result;
+ resourceLimit = handleTable.GetObject<KResourceLimit>(info.ResourceLimitHandle);
+
+ if (resourceLimit == null)
+ {
+ return KernelResult.InvalidHandle;
+ }
+ }
+ else
+ {
+ resourceLimit = _context.ResourceLimit;
}
- result = clientPort.Connect(out KClientSession clientSession);
+ 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)
{
- currentProcess.HandleTable.CancelHandleReservation(handle);
-
return result;
}
- currentProcess.HandleTable.SetReservedHandleObj(handle, clientSession);
-
- clientSession.DecrementReferenceCount();
+ _context.Processes.TryAdd(process.Pid, process);
- return result;
+ return handleTable.GenerateHandle(process, out handle);
}
- public KernelResult SendSyncRequestHLE(int handle)
+ public KernelResult StartProcess(int handle, int priority, int cpuCore, ulong mainThreadStackSize)
{
- KProcess process = _context.Scheduler.GetCurrentProcess();
+ KProcess process = _context.Scheduler.GetCurrentProcess().HandleTable.GetObject<KProcess>(handle);
- KClientSession clientSession = process.HandleTable.GetObject<KClientSession>(handle);
+ if (process == null)
+ {
+ return KernelResult.InvalidHandle;
+ }
- if (clientSession == null || clientSession.Service == null)
+ if ((uint)cpuCore >= KScheduler.CpuCoresCount || !process.IsCpuCoreAllowed(cpuCore))
{
- return SendSyncRequest(handle);
+ 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;
}
- return SendSyncRequestWithUserBufferHLE((ulong)_context.Scheduler.GetCurrentThread().Context.Tpidr, 0x100, handle);
+ process.IncrementReferenceCount();
+
+ return KernelResult.Success;
}
- public KernelResult SendSyncRequestWithUserBufferHLE(ulong messagePtr, ulong messageSize, int handle)
+ // IPC
+
+ public KernelResult ConnectToNamedPort(ulong namePtr, out int handle)
{
- KProcess process = _context.Scheduler.GetCurrentProcess();
+ handle = 0;
- byte[] messageData = new byte[messageSize];
+ if (!KernelTransfer.UserToKernelString(_context, namePtr, 12, out string name))
+ {
+ return KernelResult.UserCopyFailed;
+ }
- process.CpuMemory.Read(messagePtr, messageData);
+ return ConnectToNamedPort(name, out handle);
+ }
- KClientSession clientSession = process.HandleTable.GetObject<KClientSession>(handle);
+ public KernelResult ConnectToNamedPort(string name, out int handle)
+ {
+ handle = 0;
- if (clientSession == null || clientSession.Service == null)
+ if (name.Length > 11)
{
- return SendSyncRequestWithUserBuffer(messagePtr, messageSize, handle);
+ return KernelResult.MaximumExceeded;
}
- if (clientSession != null)
- {
- _context.CriticalSection.Enter();
+ KAutoObject autoObj = KAutoObject.FindNamedObject(_context, name);
- KThread currentThread = _context.Scheduler.GetCurrentThread();
+ if (!(autoObj is KClientPort clientPort))
+ {
+ return KernelResult.NotFound;
+ }
- currentThread.SignaledObj = null;
- currentThread.ObjSyncResult = KernelResult.Success;
+ KProcess currentProcess = _context.Scheduler.GetCurrentProcess();
- currentThread.Reschedule(ThreadSchedState.Paused);
+ KernelResult result = currentProcess.HandleTable.ReserveHandle(out handle);
- clientSession.Service.Server.PushMessage(_device, currentThread, clientSession, messagePtr, messageSize);
+ if (result != KernelResult.Success)
+ {
+ return result;
+ }
- _context.CriticalSection.Leave();
+ result = clientPort.Connect(out KClientSession clientSession);
- return currentThread.ObjSyncResult;
- }
- else
+ if (result != KernelResult.Success)
{
- Logger.Warning?.Print(LogClass.KernelSvc, $"Invalid session handle 0x{handle:x8}!");
+ currentProcess.HandleTable.CancelHandleReservation(handle);
- return KernelResult.InvalidHandle;
+ return result;
}
+
+ currentProcess.HandleTable.SetReservedHandleObj(handle, clientSession);
+
+ clientSession.DecrementReferenceCount();
+
+ return result;
}
- 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));
diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs
index 224af6d8..b57175a3 100644
--- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs
+++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs
@@ -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);
diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs
index 47f78a25..07ca4aae 100644
--- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs
+++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs
@@ -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);
}
diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs
index 84995513..c6da361d 100644
--- a/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Threading/KScheduler.cs
@@ -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);
diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
index 27ff3883..f523cb9c 100644
--- a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
@@ -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();
-
- Context.Dispose();
- }
+ if (_customThreadStart != null)
+ {
+ _customThreadStart();
+ }
+ else
+ {
+ Owner.Context.Execute(Context, _entrypoint);
+ }
- 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();
}