diff options
| author | TSR Berry <20988865+TSRBerry@users.noreply.github.com> | 2023-04-08 01:22:00 +0200 |
|---|---|---|
| committer | Mary <thog@protonmail.com> | 2023-04-27 23:51:14 +0200 |
| commit | cee712105850ac3385cd0091a923438167433f9f (patch) | |
| tree | 4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /Ryujinx.HLE/HOS/Services/ServerBase.cs | |
| parent | cd124bda587ef09668a971fa1cac1c3f0cfc9f21 (diff) | |
Move solution and projects to src
Diffstat (limited to 'Ryujinx.HLE/HOS/Services/ServerBase.cs')
| -rw-r--r-- | Ryujinx.HLE/HOS/Services/ServerBase.cs | 423 |
1 files changed, 0 insertions, 423 deletions
diff --git a/Ryujinx.HLE/HOS/Services/ServerBase.cs b/Ryujinx.HLE/HOS/Services/ServerBase.cs deleted file mode 100644 index b994679a..00000000 --- a/Ryujinx.HLE/HOS/Services/ServerBase.cs +++ /dev/null @@ -1,423 +0,0 @@ -using Ryujinx.Common; -using Ryujinx.Common.Memory; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel; -using Ryujinx.HLE.HOS.Kernel.Ipc; -using Ryujinx.HLE.HOS.Kernel.Process; -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.Horizon.Common; -using System; -using System.Buffers; -using System.Buffers.Binary; -using System.Collections.Generic; -using System.IO; -using System.Threading; - -namespace Ryujinx.HLE.HOS.Services -{ - class ServerBase : IDisposable - { - // Must be the maximum value used by services (highest one know is the one used by nvservices = 0x8000). - // Having a size that is too low will cause failures as data copy will fail if the receiving buffer is - // not large enough. - private const int PointerBufferSize = 0x8000; - - private readonly static uint[] DefaultCapabilities = new uint[] - { - 0x030363F7, - 0x1FFFFFCF, - 0x207FFFEF, - 0x47E0060F, - 0x0048BFFF, - 0x01007FFF - }; - - private readonly object _handleLock = new(); - - private readonly KernelContext _context; - private KProcess _selfProcess; - - private readonly List<int> _sessionHandles = new List<int>(); - private readonly List<int> _portHandles = new List<int>(); - private readonly Dictionary<int, IpcService> _sessions = new Dictionary<int, IpcService>(); - private readonly Dictionary<int, Func<IpcService>> _ports = new Dictionary<int, Func<IpcService>>(); - - private readonly MemoryStream _requestDataStream; - private readonly BinaryReader _requestDataReader; - - private readonly MemoryStream _responseDataStream; - private readonly BinaryWriter _responseDataWriter; - - public ManualResetEvent InitDone { get; } - public string Name { get; } - public Func<IpcService> SmObjectFactory { get; } - - public ServerBase(KernelContext context, string name, Func<IpcService> smObjectFactory = null) - { - _context = context; - - _requestDataStream = MemoryStreamManager.Shared.GetStream(); - _requestDataReader = new BinaryReader(_requestDataStream); - - _responseDataStream = MemoryStreamManager.Shared.GetStream(); - _responseDataWriter = new BinaryWriter(_responseDataStream); - - InitDone = new ManualResetEvent(false); - Name = name; - SmObjectFactory = smObjectFactory; - - const ProcessCreationFlags flags = - ProcessCreationFlags.EnableAslr | - ProcessCreationFlags.AddressSpace64Bit | - ProcessCreationFlags.Is64Bit | - ProcessCreationFlags.PoolPartitionSystem; - - ProcessCreationInfo creationInfo = new ProcessCreationInfo("Service", 1, 0, 0x8000000, 1, flags, 0, 0); - - KernelStatic.StartInitialProcess(context, creationInfo, DefaultCapabilities, 44, Main); - } - - private void AddPort(int serverPortHandle, Func<IpcService> objectFactory) - { - lock (_handleLock) - { - _portHandles.Add(serverPortHandle); - } - _ports.Add(serverPortHandle, objectFactory); - } - - public void AddSessionObj(KServerSession serverSession, IpcService obj) - { - // Ensure that the sever loop is running. - InitDone.WaitOne(); - - _selfProcess.HandleTable.GenerateHandle(serverSession, out int serverSessionHandle); - AddSessionObj(serverSessionHandle, obj); - } - - public void AddSessionObj(int serverSessionHandle, IpcService obj) - { - lock (_handleLock) - { - _sessionHandles.Add(serverSessionHandle); - } - _sessions.Add(serverSessionHandle, obj); - } - - private void Main() - { - ServerLoop(); - } - - private void ServerLoop() - { - _selfProcess = KernelStatic.GetCurrentProcess(); - - if (SmObjectFactory != null) - { - _context.Syscall.ManageNamedPort(out int serverPortHandle, "sm:", 50); - - AddPort(serverPortHandle, SmObjectFactory); - } - - InitDone.Set(); - - KThread thread = KernelStatic.GetCurrentThread(); - ulong messagePtr = thread.TlsAddress; - _context.Syscall.SetHeapSize(out ulong heapAddr, 0x200000); - - _selfProcess.CpuMemory.Write(messagePtr + 0x0, 0); - _selfProcess.CpuMemory.Write(messagePtr + 0x4, 2 << 10); - _selfProcess.CpuMemory.Write(messagePtr + 0x8, heapAddr | ((ulong)PointerBufferSize << 48)); - - int replyTargetHandle = 0; - - while (true) - { - int handleCount; - int portHandleCount; - int[] handles; - - lock (_handleLock) - { - portHandleCount = _portHandles.Count; - handleCount = portHandleCount + _sessionHandles.Count; - - handles = ArrayPool<int>.Shared.Rent(handleCount); - - _portHandles.CopyTo(handles, 0); - _sessionHandles.CopyTo(handles, portHandleCount); - } - - // We still need a timeout here to allow the service to pick up and listen new sessions... - var rc = _context.Syscall.ReplyAndReceive(out int signaledIndex, handles.AsSpan(0, handleCount), replyTargetHandle, 1000000L); - - thread.HandlePostSyscall(); - - if (!thread.Context.Running) - { - break; - } - - replyTargetHandle = 0; - - if (rc == Result.Success && signaledIndex >= portHandleCount) - { - // We got a IPC request, process it, pass to the appropriate service if needed. - int signaledHandle = handles[signaledIndex]; - - if (Process(signaledHandle, heapAddr)) - { - replyTargetHandle = signaledHandle; - } - } - else - { - if (rc == Result.Success) - { - // We got a new connection, accept the session to allow servicing future requests. - if (_context.Syscall.AcceptSession(out int serverSessionHandle, handles[signaledIndex]) == Result.Success) - { - IpcService obj = _ports[handles[signaledIndex]].Invoke(); - - AddSessionObj(serverSessionHandle, obj); - } - } - - _selfProcess.CpuMemory.Write(messagePtr + 0x0, 0); - _selfProcess.CpuMemory.Write(messagePtr + 0x4, 2 << 10); - _selfProcess.CpuMemory.Write(messagePtr + 0x8, heapAddr | ((ulong)PointerBufferSize << 48)); - } - - ArrayPool<int>.Shared.Return(handles); - } - - Dispose(); - } - - private bool Process(int serverSessionHandle, ulong recvListAddr) - { - KProcess process = KernelStatic.GetCurrentProcess(); - KThread thread = KernelStatic.GetCurrentThread(); - ulong messagePtr = thread.TlsAddress; - - IpcMessage request = ReadRequest(process, messagePtr); - - IpcMessage response = new IpcMessage(); - - ulong tempAddr = recvListAddr; - int sizesOffset = request.RawData.Length - ((request.RecvListBuff.Count * 2 + 3) & ~3); - - bool noReceive = true; - - for (int i = 0; i < request.ReceiveBuff.Count; i++) - { - noReceive &= (request.ReceiveBuff[i].Position == 0); - } - - if (noReceive) - { - response.PtrBuff.EnsureCapacity(request.RecvListBuff.Count); - - for (int i = 0; i < request.RecvListBuff.Count; i++) - { - ulong size = (ulong)BinaryPrimitives.ReadInt16LittleEndian(request.RawData.AsSpan(sizesOffset + i * 2, 2)); - - response.PtrBuff.Add(new IpcPtrBuffDesc(tempAddr, (uint)i, size)); - - request.RecvListBuff[i] = new IpcRecvListBuffDesc(tempAddr, size); - - tempAddr += size; - } - } - - bool shouldReply = true; - bool isTipcCommunication = false; - - _requestDataStream.SetLength(0); - _requestDataStream.Write(request.RawData); - _requestDataStream.Position = 0; - - if (request.Type == IpcMessageType.CmifRequest || - request.Type == IpcMessageType.CmifRequestWithContext) - { - response.Type = IpcMessageType.CmifResponse; - - _responseDataStream.SetLength(0); - - ServiceCtx context = new ServiceCtx( - _context.Device, - process, - process.CpuMemory, - thread, - request, - response, - _requestDataReader, - _responseDataWriter); - - _sessions[serverSessionHandle].CallCmifMethod(context); - - response.RawData = _responseDataStream.ToArray(); - } - else if (request.Type == IpcMessageType.CmifControl || - request.Type == IpcMessageType.CmifControlWithContext) - { - uint magic = (uint)_requestDataReader.ReadUInt64(); - uint cmdId = (uint)_requestDataReader.ReadUInt64(); - - switch (cmdId) - { - case 0: - FillHipcResponse(response, 0, _sessions[serverSessionHandle].ConvertToDomain()); - break; - - case 3: - FillHipcResponse(response, 0, PointerBufferSize); - break; - - // TODO: Whats the difference between IpcDuplicateSession/Ex? - case 2: - case 4: - int unknown = _requestDataReader.ReadInt32(); - - _context.Syscall.CreateSession(out int dupServerSessionHandle, out int dupClientSessionHandle, false, 0); - - AddSessionObj(dupServerSessionHandle, _sessions[serverSessionHandle]); - - response.HandleDesc = IpcHandleDesc.MakeMove(dupClientSessionHandle); - - FillHipcResponse(response, 0); - - break; - - default: throw new NotImplementedException(cmdId.ToString()); - } - } - else if (request.Type == IpcMessageType.CmifCloseSession || request.Type == IpcMessageType.TipcCloseSession) - { - _context.Syscall.CloseHandle(serverSessionHandle); - lock (_handleLock) - { - _sessionHandles.Remove(serverSessionHandle); - } - IpcService service = _sessions[serverSessionHandle]; - (service as IDisposable)?.Dispose(); - _sessions.Remove(serverSessionHandle); - shouldReply = false; - } - // If the type is past 0xF, we are using TIPC - else if (request.Type > IpcMessageType.TipcCloseSession) - { - isTipcCommunication = true; - - // Response type is always the same as request on TIPC. - response.Type = request.Type; - - _responseDataStream.SetLength(0); - - ServiceCtx context = new ServiceCtx( - _context.Device, - process, - process.CpuMemory, - thread, - request, - response, - _requestDataReader, - _responseDataWriter); - - _sessions[serverSessionHandle].CallTipcMethod(context); - - response.RawData = _responseDataStream.ToArray(); - - using var responseStream = response.GetStreamTipc(); - process.CpuMemory.Write(messagePtr, responseStream.GetReadOnlySequence()); - } - else - { - throw new NotImplementedException(request.Type.ToString()); - } - - if (!isTipcCommunication) - { - using var responseStream = response.GetStream((long)messagePtr, recvListAddr | ((ulong)PointerBufferSize << 48)); - process.CpuMemory.Write(messagePtr, responseStream.GetReadOnlySequence()); - } - - return shouldReply; - } - - private static IpcMessage ReadRequest(KProcess process, ulong messagePtr) - { - const int messageSize = 0x100; - - byte[] reqData = ArrayPool<byte>.Shared.Rent(messageSize); - - Span<byte> reqDataSpan = reqData.AsSpan(0, messageSize); - reqDataSpan.Clear(); - - process.CpuMemory.Read(messagePtr, reqDataSpan); - - IpcMessage request = new IpcMessage(reqDataSpan, (long)messagePtr); - - ArrayPool<byte>.Shared.Return(reqData); - - return request; - } - - private void FillHipcResponse(IpcMessage response, long result) - { - FillHipcResponse(response, result, ReadOnlySpan<byte>.Empty); - } - - private void FillHipcResponse(IpcMessage response, long result, int value) - { - Span<byte> span = stackalloc byte[sizeof(int)]; - BinaryPrimitives.WriteInt32LittleEndian(span, value); - FillHipcResponse(response, result, span); - } - - private void FillHipcResponse(IpcMessage response, long result, ReadOnlySpan<byte> data) - { - response.Type = IpcMessageType.CmifResponse; - - _responseDataStream.SetLength(0); - - _responseDataStream.Write(IpcMagic.Sfco); - _responseDataStream.Write(result); - - _responseDataStream.Write(data); - - response.RawData = _responseDataStream.ToArray(); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - foreach (IpcService service in _sessions.Values) - { - if (service is IDisposable disposableObj) - { - disposableObj.Dispose(); - } - - service.DestroyAtExit(); - } - - _sessions.Clear(); - - _requestDataReader.Dispose(); - _requestDataStream.Dispose(); - _responseDataWriter.Dispose(); - _responseDataStream.Dispose(); - - InitDone.Dispose(); - } - } - - public void Dispose() - { - Dispose(true); - } - } -} |
