Improve kernel IPC implementation (#550)

* Implement some IPC related kernel SVCs properly

* Fix BLZ decompression when the segment also has a uncompressed chunck

* Set default cpu core on process start from ProgramLoader, remove debug message

* Load process capabilities properly on KIPs

* Fix a copy/paste error in UnmapPhysicalMemory64

* Implement smarter switching between old and new IPC system to support the old HLE services implementation without the manual switch

* Implement RegisterService on sm and AcceptSession (partial)

* Misc fixes and improvements on new IPC methods

* Move IPC related SVCs into a separate file, and logging on RegisterService (sm)

* Some small fixes related to receive list buffers and error cases

* Load NSOs using the correct pool partition

* Fix corner case on GetMaskFromMinMax where range is 64, doesn't happen in pratice however

* Fix send static buffer copy

* Session release, implement closing requests on client disconnect

* Implement ConnectToPort SVC

* KLightSession init
This commit is contained in:
gdkchan 2019-01-18 20:26:39 -02:00 committed by GitHub
parent 3731d0ce84
commit 22bacc6188
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
51 changed files with 4310 additions and 840 deletions

View file

@ -2,14 +2,11 @@ using ChocolArm64.Memory;
using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel.Common;
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.HLE.HOS.Services;
using System.Threading;
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
@ -82,7 +79,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
private KernelResult CloseHandle(int handle)
{
object obj = _process.HandleTable.GetObject<object>(handle);
KAutoObject obj = _process.HandleTable.GetObject<KAutoObject>(handle);
_process.HandleTable.CloseHandle(handle);
@ -144,88 +141,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return _system.Scheduler.GetCurrentThread().Context.ThreadState.CntpctEl0;
}
public KernelResult ConnectToNamedPort64(ulong namePtr, out int handle)
{
return ConnectToNamedPort(namePtr, out handle);
}
private KernelResult ConnectToNamedPort(ulong namePtr, out int handle)
{
string name = MemoryHelper.ReadAsciiString(_memory, (long)namePtr, 8);
//TODO: Validate that app has perms to access the service, and that the service
//actually exists, return error codes otherwise.
KSession session = new KSession(ServiceFactory.MakeService(_system, name), name);
return _process.HandleTable.GenerateHandle(session, out handle);
}
public KernelResult SendSyncRequest64(int handle)
{
return SendSyncRequest((ulong)_system.Scheduler.GetCurrentThread().Context.ThreadState.Tpidr, 0x100, handle);
}
public KernelResult SendSyncRequestWithUserBuffer64(ulong messagePtr, ulong size, int handle)
{
return SendSyncRequest(messagePtr, size, handle);
}
private KernelResult SendSyncRequest(ulong messagePtr, ulong size, int handle)
{
byte[] messageData = _memory.ReadBytes((long)messagePtr, (long)size);
KSession session = _process.HandleTable.GetObject<KSession>(handle);
if (session != null)
{
_system.CriticalSection.Enter();
KThread currentThread = _system.Scheduler.GetCurrentThread();
currentThread.SignaledObj = null;
currentThread.ObjSyncResult = KernelResult.Success;
currentThread.Reschedule(ThreadSchedState.Paused);
IpcMessage message = new IpcMessage(messageData, (long)messagePtr);
ThreadPool.QueueUserWorkItem(ProcessIpcRequest, new HleIpcMessage(
currentThread,
session,
message,
(long)messagePtr));
_system.ThreadCounter.AddCount();
_system.CriticalSection.Leave();
return currentThread.ObjSyncResult;
}
else
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid session handle 0x{handle:x8}!");
return KernelResult.InvalidHandle;
}
}
private void ProcessIpcRequest(object state)
{
HleIpcMessage ipcMessage = (HleIpcMessage)state;
ipcMessage.Thread.ObjSyncResult = IpcHandler.IpcCall(
_device,
_process,
_memory,
ipcMessage.Session,
ipcMessage.Message,
ipcMessage.MessagePtr);
_system.ThreadCounter.Signal();
ipcMessage.Thread.Reschedule(ThreadSchedState.Running);
}
public KernelResult GetProcessId64(int handle, out long pid)
{
return GetProcessId(handle, out pid);
@ -664,99 +579,5 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.Success;
}
public KernelResult CreatePort64(
int maxSessions,
bool isLight,
ulong namePtr,
out int serverPortHandle,
out int clientPortHandle)
{
return CreatePort(maxSessions, isLight, namePtr, out serverPortHandle, out clientPortHandle);
}
private KernelResult CreatePort(
int maxSessions,
bool isLight,
ulong namePtr,
out int serverPortHandle,
out int clientPortHandle)
{
serverPortHandle = clientPortHandle = 0;
if (maxSessions < 1)
{
return KernelResult.MaximumExceeded;
}
KPort port = new KPort(_system);
port.Initialize(maxSessions, isLight, (long)namePtr);
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KernelResult result = currentProcess.HandleTable.GenerateHandle(port.ClientPort, out clientPortHandle);
if (result != KernelResult.Success)
{
return result;
}
result = currentProcess.HandleTable.GenerateHandle(port.ServerPort, out serverPortHandle);
if (result != KernelResult.Success)
{
currentProcess.HandleTable.CloseHandle(clientPortHandle);
}
return result;
}
public KernelResult ManageNamedPort64(ulong namePtr, int maxSessions, out int handle)
{
return ManageNamedPort(namePtr, maxSessions, out handle);
}
private KernelResult ManageNamedPort(ulong namePtr, int maxSessions, out int handle)
{
handle = 0;
if (!KernelTransfer.UserToKernelString(_system, namePtr, 12, out string name))
{
return KernelResult.UserCopyFailed;
}
if (maxSessions < 0 || name.Length > 11)
{
return KernelResult.MaximumExceeded;
}
if (maxSessions == 0)
{
return KClientPort.RemoveName(_system, name);
}
KPort port = new KPort(_system);
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KernelResult result = currentProcess.HandleTable.GenerateHandle(port.ServerPort, out handle);
if (result != KernelResult.Success)
{
return result;
}
port.Initialize(maxSessions, false, 0);
result = port.SetName(name);
if (result != KernelResult.Success)
{
currentProcess.HandleTable.CloseHandle(handle);
}
return result;
}
}
}