Move solution and projects to src

This commit is contained in:
TSR Berry 2023-04-08 01:22:00 +02:00 committed by Mary
parent cd124bda58
commit cee7121058
3466 changed files with 55 additions and 55 deletions

View file

@ -0,0 +1,10 @@
namespace Ryujinx.HLE.HOS.Kernel.Ipc
{
enum ChannelState
{
NotInitialized,
Open,
ClientDisconnected,
ServerDisconnected
}
}

View file

@ -0,0 +1,20 @@
using Ryujinx.HLE.HOS.Kernel.Memory;
namespace Ryujinx.HLE.HOS.Kernel.Ipc
{
class KBufferDescriptor
{
public ulong ClientAddress { get; }
public ulong ServerAddress { get; }
public ulong Size { get; }
public MemoryState State { get; }
public KBufferDescriptor(ulong src, ulong dst, ulong size, MemoryState state)
{
ClientAddress = src;
ServerAddress = dst;
Size = size;
State = state;
}
}
}

View file

@ -0,0 +1,217 @@
using Ryujinx.Common;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.Horizon.Common;
using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Kernel.Ipc
{
class KBufferDescriptorTable
{
private const int MaxInternalBuffersCount = 8;
private List<KBufferDescriptor> _sendBufferDescriptors;
private List<KBufferDescriptor> _receiveBufferDescriptors;
private List<KBufferDescriptor> _exchangeBufferDescriptors;
public KBufferDescriptorTable()
{
_sendBufferDescriptors = new List<KBufferDescriptor>(MaxInternalBuffersCount);
_receiveBufferDescriptors = new List<KBufferDescriptor>(MaxInternalBuffersCount);
_exchangeBufferDescriptors = new List<KBufferDescriptor>(MaxInternalBuffersCount);
}
public Result AddSendBuffer(ulong src, ulong dst, ulong size, MemoryState state)
{
return Add(_sendBufferDescriptors, src, dst, size, state);
}
public Result AddReceiveBuffer(ulong src, ulong dst, ulong size, MemoryState state)
{
return Add(_receiveBufferDescriptors, src, dst, size, state);
}
public Result AddExchangeBuffer(ulong src, ulong dst, ulong size, MemoryState state)
{
return Add(_exchangeBufferDescriptors, src, dst, size, state);
}
private Result Add(List<KBufferDescriptor> list, ulong src, ulong dst, ulong size, MemoryState state)
{
if (list.Count < MaxInternalBuffersCount)
{
list.Add(new KBufferDescriptor(src, dst, size, state));
return Result.Success;
}
return KernelResult.OutOfMemory;
}
public Result CopyBuffersToClient(KPageTableBase memoryManager)
{
Result result = CopyToClient(memoryManager, _receiveBufferDescriptors);
if (result != Result.Success)
{
return result;
}
return CopyToClient(memoryManager, _exchangeBufferDescriptors);
}
private Result CopyToClient(KPageTableBase memoryManager, List<KBufferDescriptor> list)
{
foreach (KBufferDescriptor desc in list)
{
MemoryState stateMask;
switch (desc.State)
{
case MemoryState.IpcBuffer0: stateMask = MemoryState.IpcSendAllowedType0; break;
case MemoryState.IpcBuffer1: stateMask = MemoryState.IpcSendAllowedType1; break;
case MemoryState.IpcBuffer3: stateMask = MemoryState.IpcSendAllowedType3; break;
default: return KernelResult.InvalidCombination;
}
MemoryAttribute attributeMask = MemoryAttribute.Borrowed | MemoryAttribute.Uncached;
if (desc.State == MemoryState.IpcBuffer0)
{
attributeMask |= MemoryAttribute.DeviceMapped;
}
ulong clientAddrTruncated = BitUtils.AlignDown<ulong>(desc.ClientAddress, KPageTableBase.PageSize);
ulong clientAddrRounded = BitUtils.AlignUp<ulong>(desc.ClientAddress, KPageTableBase.PageSize);
// Check if address is not aligned, in this case we need to perform 2 copies.
if (clientAddrTruncated != clientAddrRounded)
{
ulong copySize = clientAddrRounded - desc.ClientAddress;
if (copySize > desc.Size)
{
copySize = desc.Size;
}
Result result = memoryManager.CopyDataFromCurrentProcess(
desc.ClientAddress,
copySize,
stateMask,
stateMask,
KMemoryPermission.ReadAndWrite,
attributeMask,
MemoryAttribute.None,
desc.ServerAddress);
if (result != Result.Success)
{
return result;
}
}
ulong clientEndAddr = desc.ClientAddress + desc.Size;
ulong serverEndAddr = desc.ServerAddress + desc.Size;
ulong clientEndAddrTruncated = BitUtils.AlignDown<ulong>(clientEndAddr, (ulong)KPageTableBase.PageSize);
ulong clientEndAddrRounded = BitUtils.AlignUp<ulong>(clientEndAddr, KPageTableBase.PageSize);
ulong serverEndAddrTruncated = BitUtils.AlignDown<ulong>(serverEndAddr, (ulong)KPageTableBase.PageSize);
if (clientEndAddrTruncated < clientEndAddrRounded &&
(clientAddrTruncated == clientAddrRounded || clientAddrTruncated < clientEndAddrTruncated))
{
Result result = memoryManager.CopyDataFromCurrentProcess(
clientEndAddrTruncated,
clientEndAddr - clientEndAddrTruncated,
stateMask,
stateMask,
KMemoryPermission.ReadAndWrite,
attributeMask,
MemoryAttribute.None,
serverEndAddrTruncated);
if (result != Result.Success)
{
return result;
}
}
}
return Result.Success;
}
public Result UnmapServerBuffers(KPageTableBase memoryManager)
{
Result result = UnmapServer(memoryManager, _sendBufferDescriptors);
if (result != Result.Success)
{
return result;
}
result = UnmapServer(memoryManager, _receiveBufferDescriptors);
if (result != Result.Success)
{
return result;
}
return UnmapServer(memoryManager, _exchangeBufferDescriptors);
}
private Result UnmapServer(KPageTableBase memoryManager, List<KBufferDescriptor> list)
{
foreach (KBufferDescriptor descriptor in list)
{
Result result = memoryManager.UnmapNoAttributeIfStateEquals(
descriptor.ServerAddress,
descriptor.Size,
descriptor.State);
if (result != Result.Success)
{
return result;
}
}
return Result.Success;
}
public Result RestoreClientBuffers(KPageTableBase memoryManager)
{
Result result = RestoreClient(memoryManager, _sendBufferDescriptors);
if (result != Result.Success)
{
return result;
}
result = RestoreClient(memoryManager, _receiveBufferDescriptors);
if (result != Result.Success)
{
return result;
}
return RestoreClient(memoryManager, _exchangeBufferDescriptors);
}
private Result RestoreClient(KPageTableBase memoryManager, List<KBufferDescriptor> list)
{
foreach (KBufferDescriptor descriptor in list)
{
Result result = memoryManager.UnmapIpcRestorePermission(
descriptor.ClientAddress,
descriptor.Size,
descriptor.State);
if (result != Result.Success)
{
return result;
}
}
return Result.Success;
}
}
}

View file

@ -0,0 +1,144 @@
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.Horizon.Common;
using System.Threading;
namespace Ryujinx.HLE.HOS.Kernel.Ipc
{
class KClientPort : KSynchronizationObject
{
private int _sessionsCount;
private readonly int _maxSessions;
private readonly KPort _parent;
public bool IsLight => _parent.IsLight;
public KClientPort(KernelContext context, KPort parent, int maxSessions) : base(context)
{
_maxSessions = maxSessions;
_parent = parent;
}
public Result Connect(out KClientSession clientSession)
{
clientSession = null;
KProcess currentProcess = KernelStatic.GetCurrentProcess();
if (currentProcess.ResourceLimit != null &&
!currentProcess.ResourceLimit.Reserve(LimitableResource.Session, 1))
{
return KernelResult.ResLimitExceeded;
}
if (!IncrementSessionsCount())
{
currentProcess.ResourceLimit?.Release(LimitableResource.Session, 1);
return KernelResult.SessionCountExceeded;
}
KSession session = new KSession(KernelContext, this);
Result result = _parent.EnqueueIncomingSession(session.ServerSession);
if (result != Result.Success)
{
session.ClientSession.DecrementReferenceCount();
session.ServerSession.DecrementReferenceCount();
return result;
}
clientSession = session.ClientSession;
return result;
}
public Result ConnectLight(out KLightClientSession clientSession)
{
clientSession = null;
KProcess currentProcess = KernelStatic.GetCurrentProcess();
if (currentProcess.ResourceLimit != null &&
!currentProcess.ResourceLimit.Reserve(LimitableResource.Session, 1))
{
return KernelResult.ResLimitExceeded;
}
if (!IncrementSessionsCount())
{
currentProcess.ResourceLimit?.Release(LimitableResource.Session, 1);
return KernelResult.SessionCountExceeded;
}
KLightSession session = new KLightSession(KernelContext);
Result result = _parent.EnqueueIncomingLightSession(session.ServerSession);
if (result != Result.Success)
{
session.ClientSession.DecrementReferenceCount();
session.ServerSession.DecrementReferenceCount();
return result;
}
clientSession = session.ClientSession;
return result;
}
private bool IncrementSessionsCount()
{
while (true)
{
int currentCount = _sessionsCount;
if (currentCount < _maxSessions)
{
if (Interlocked.CompareExchange(ref _sessionsCount, currentCount + 1, currentCount) == currentCount)
{
return true;
}
}
else
{
return false;
}
}
}
public void Disconnect()
{
KernelContext.CriticalSection.Enter();
SignalIfMaximumReached(Interlocked.Decrement(ref _sessionsCount));
KernelContext.CriticalSection.Leave();
}
private void SignalIfMaximumReached(int value)
{
if (value == _maxSessions)
{
Signal();
}
}
public new static Result RemoveName(KernelContext context, string name)
{
KAutoObject foundObj = FindNamedObject(context, name);
if (!(foundObj is KClientPort))
{
return KernelResult.NotFound;
}
return KAutoObject.RemoveName(context, name);
}
}
}

View file

@ -0,0 +1,84 @@
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.Horizon.Common;
namespace Ryujinx.HLE.HOS.Kernel.Ipc
{
class KClientSession : KSynchronizationObject
{
public KProcess CreatorProcess { get; }
private KSession _parent;
public ChannelState State { get; set; }
public KClientPort ParentPort { get; }
public KClientSession(KernelContext context, KSession parent, KClientPort parentPort) : base(context)
{
_parent = parent;
ParentPort = parentPort;
parentPort?.IncrementReferenceCount();
State = ChannelState.Open;
CreatorProcess = KernelStatic.GetCurrentProcess();
CreatorProcess.IncrementReferenceCount();
}
public Result SendSyncRequest(ulong customCmdBuffAddr = 0, ulong customCmdBuffSize = 0)
{
KThread currentThread = KernelStatic.GetCurrentThread();
KSessionRequest request = new KSessionRequest(currentThread, customCmdBuffAddr, customCmdBuffSize);
KernelContext.CriticalSection.Enter();
currentThread.SignaledObj = null;
currentThread.ObjSyncResult = Result.Success;
Result result = _parent.ServerSession.EnqueueRequest(request);
KernelContext.CriticalSection.Leave();
if (result == Result.Success)
{
result = currentThread.ObjSyncResult;
}
return result;
}
public Result SendAsyncRequest(KWritableEvent asyncEvent, ulong customCmdBuffAddr = 0, ulong customCmdBuffSize = 0)
{
KThread currentThread = KernelStatic.GetCurrentThread();
KSessionRequest request = new KSessionRequest(currentThread, customCmdBuffAddr, customCmdBuffSize, asyncEvent);
KernelContext.CriticalSection.Enter();
Result result = _parent.ServerSession.EnqueueRequest(request);
KernelContext.CriticalSection.Leave();
return result;
}
public void DisconnectFromPort()
{
if (ParentPort != null)
{
ParentPort.Disconnect();
ParentPort.DecrementReferenceCount();
}
}
protected override void Destroy()
{
_parent.DisconnectClient();
_parent.DecrementReferenceCount();
}
}
}

View file

@ -0,0 +1,14 @@
using Ryujinx.HLE.HOS.Kernel.Common;
namespace Ryujinx.HLE.HOS.Kernel.Ipc
{
class KLightClientSession : KAutoObject
{
private readonly KLightSession _parent;
public KLightClientSession(KernelContext context, KLightSession parent) : base(context)
{
_parent = parent;
}
}
}

View file

@ -0,0 +1,14 @@
using Ryujinx.HLE.HOS.Kernel.Common;
namespace Ryujinx.HLE.HOS.Kernel.Ipc
{
class KLightServerSession : KAutoObject
{
private readonly KLightSession _parent;
public KLightServerSession(KernelContext context, KLightSession parent) : base(context)
{
_parent = parent;
}
}
}

View file

@ -0,0 +1,16 @@
using Ryujinx.HLE.HOS.Kernel.Common;
namespace Ryujinx.HLE.HOS.Kernel.Ipc
{
class KLightSession : KAutoObject
{
public KLightServerSession ServerSession { get; }
public KLightClientSession ClientSession { get; }
public KLightSession(KernelContext context) : base(context)
{
ServerSession = new KLightServerSession(context, this);
ClientSession = new KLightClientSession(context, this);
}
}
}

View file

@ -0,0 +1,72 @@
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.Horizon.Common;
namespace Ryujinx.HLE.HOS.Kernel.Ipc
{
class KPort : KAutoObject
{
public KServerPort ServerPort { get; }
public KClientPort ClientPort { get; }
private string _name;
private ChannelState _state;
public bool IsLight { get; private set; }
public KPort(KernelContext context, int maxSessions, bool isLight, string name) : base(context)
{
ServerPort = new KServerPort(context, this);
ClientPort = new KClientPort(context, this, maxSessions);
IsLight = isLight;
_name = name;
_state = ChannelState.Open;
}
public Result EnqueueIncomingSession(KServerSession session)
{
Result result;
KernelContext.CriticalSection.Enter();
if (_state == ChannelState.Open)
{
ServerPort.EnqueueIncomingSession(session);
result = Result.Success;
}
else
{
result = KernelResult.PortClosed;
}
KernelContext.CriticalSection.Leave();
return result;
}
public Result EnqueueIncomingLightSession(KLightServerSession session)
{
Result result;
KernelContext.CriticalSection.Enter();
if (_state == ChannelState.Open)
{
ServerPort.EnqueueIncomingLightSession(session);
result = Result.Success;
}
else
{
result = KernelResult.PortClosed;
}
KernelContext.CriticalSection.Leave();
return result;
}
}
}

View file

@ -0,0 +1,87 @@
using Ryujinx.HLE.HOS.Kernel.Common;
using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Kernel.Ipc
{
class KServerPort : KSynchronizationObject
{
private readonly LinkedList<KServerSession> _incomingConnections;
private readonly LinkedList<KLightServerSession> _lightIncomingConnections;
private readonly KPort _parent;
public bool IsLight => _parent.IsLight;
public KServerPort(KernelContext context, KPort parent) : base(context)
{
_parent = parent;
_incomingConnections = new LinkedList<KServerSession>();
_lightIncomingConnections = new LinkedList<KLightServerSession>();
}
public void EnqueueIncomingSession(KServerSession session)
{
AcceptIncomingConnection(_incomingConnections, session);
}
public void EnqueueIncomingLightSession(KLightServerSession session)
{
AcceptIncomingConnection(_lightIncomingConnections, session);
}
private void AcceptIncomingConnection<T>(LinkedList<T> list, T session)
{
KernelContext.CriticalSection.Enter();
list.AddLast(session);
if (list.Count == 1)
{
Signal();
}
KernelContext.CriticalSection.Leave();
}
public KServerSession AcceptIncomingConnection()
{
return AcceptIncomingConnection(_incomingConnections);
}
public KLightServerSession AcceptIncomingLightConnection()
{
return AcceptIncomingConnection(_lightIncomingConnections);
}
private T AcceptIncomingConnection<T>(LinkedList<T> list)
{
T session = default;
KernelContext.CriticalSection.Enter();
if (list.Count != 0)
{
session = list.First.Value;
list.RemoveFirst();
}
KernelContext.CriticalSection.Leave();
return session;
}
public override bool IsSignaled()
{
if (_parent.IsLight)
{
return _lightIncomingConnections.Count != 0;
}
else
{
return _incomingConnections.Count != 0;
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,54 @@
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Process;
namespace Ryujinx.HLE.HOS.Kernel.Ipc
{
class KSession : KAutoObject
{
public KServerSession ServerSession { get; }
public KClientSession ClientSession { get; }
private bool _hasBeenInitialized;
public KSession(KernelContext context, KClientPort parentPort = null) : base(context)
{
IncrementReferenceCount();
ServerSession = new KServerSession(context, this);
ClientSession = new KClientSession(context, this, parentPort);
_hasBeenInitialized = true;
}
public void DisconnectClient()
{
if (ClientSession.State == ChannelState.Open)
{
ClientSession.State = ChannelState.ClientDisconnected;
ServerSession.CancelAllRequestsClientDisconnected();
}
}
public void DisconnectServer()
{
if (ClientSession.State == ChannelState.Open)
{
ClientSession.State = ChannelState.ServerDisconnected;
}
}
protected override void Destroy()
{
if (_hasBeenInitialized)
{
ClientSession.DisconnectFromPort();
KProcess creatorProcess = ClientSession.CreatorProcess;
creatorProcess.ResourceLimit?.Release(LimitableResource.Session, 1);
creatorProcess.DecrementReferenceCount();
}
}
}
}

View file

@ -0,0 +1,33 @@
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading;
namespace Ryujinx.HLE.HOS.Kernel.Ipc
{
class KSessionRequest
{
public KBufferDescriptorTable BufferDescriptorTable { get; }
public KThread ClientThread { get; }
public KProcess ServerProcess { get; set; }
public KWritableEvent AsyncEvent { get; }
public ulong CustomCmdBuffAddr { get; }
public ulong CustomCmdBuffSize { get; }
public KSessionRequest(
KThread clientThread,
ulong customCmdBuffAddr,
ulong customCmdBuffSize,
KWritableEvent asyncEvent = null)
{
ClientThread = clientThread;
CustomCmdBuffAddr = customCmdBuffAddr;
CustomCmdBuffSize = customCmdBuffSize;
AsyncEvent = asyncEvent;
BufferDescriptorTable = new KBufferDescriptorTable();
}
}
}