diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2020-07-17 01:19:07 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-07-17 14:19:07 +1000 |
| commit | 9f6b24edfddf871320290463437b3f3cb7e29006 (patch) | |
| tree | 4b8b45db5fe931ac37f843778c58a2d676fe3fba /Ryujinx.HLE/HOS/Kernel/SupervisorCall | |
| parent | 46f8cef6a9e4a305803f1356446e25ce54909130 (diff) | |
Improve kernel IPC related syscalls (#1379)
* Implement session count decrement when the handle is closed
* Remove unused field
* Implement SendSyncRequestWithUserBuffer, SendAsyncRequestWithUserBuffer and ReplyAndReceiveWithUserBuffer syscalls
* Nits
* Fix swapped copy dst/src
* Add missing pointer buffer descriptor write on reply
* Fix IPC unaligned buffer copy and restoring client attributes on reply
* Oops
* Fix SetIpcMappingPermission
* Fix unaligned copy bugs
* Free memory used for temporary IPC buffers
Diffstat (limited to 'Ryujinx.HLE/HOS/Kernel/SupervisorCall')
| -rw-r--r-- | Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs | 262 | ||||
| -rw-r--r-- | Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs | 6 | ||||
| -rw-r--r-- | Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs | 34 | ||||
| -rw-r--r-- | Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallTable.cs | 114 |
4 files changed, 335 insertions, 81 deletions
diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs index a0a15fcf..fba22fc1 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs @@ -1,5 +1,4 @@ -using ARMeilleure.Memory; -using Ryujinx.Common; +using Ryujinx.Common; using Ryujinx.Common.Logging; using Ryujinx.Cpu; using Ryujinx.HLE.Exceptions; @@ -96,16 +95,25 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } - public KernelResult SendSyncRequest(int handle) + public KernelResult SendSyncRequestHLE(int handle) { - return SendSyncRequestWithUserBuffer((ulong)_context.Scheduler.GetCurrentThread().Context.Tpidr, 0x100, handle); + KProcess process = _context.Scheduler.GetCurrentProcess(); + + KClientSession clientSession = process.HandleTable.GetObject<KClientSession>(handle); + + if (clientSession == null || clientSession.Service == null) + { + return SendSyncRequest(handle); + } + + return SendSyncRequestWithUserBufferHLE((ulong)_context.Scheduler.GetCurrentThread().Context.Tpidr, 0x100, handle); } - public KernelResult SendSyncRequestWithUserBuffer(ulong messagePtr, ulong size, int handle) + public KernelResult SendSyncRequestWithUserBufferHLE(ulong messagePtr, ulong messageSize, int handle) { KProcess process = _context.Scheduler.GetCurrentProcess(); - byte[] messageData = new byte[size]; + byte[] messageData = new byte[messageSize]; process.CpuMemory.Read(messagePtr, messageData); @@ -113,7 +121,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall if (clientSession == null || clientSession.Service == null) { - return SendSyncRequest_(handle); + return SendSyncRequestWithUserBuffer(messagePtr, messageSize, handle); } if (clientSession != null) @@ -168,7 +176,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall ipcMessage.Thread.Reschedule(ThreadSchedState.Running); } - private KernelResult SendSyncRequest_(int handle) + private KernelResult SendSyncRequest(int handle) { KProcess currentProcess = _context.Scheduler.GetCurrentProcess(); @@ -182,6 +190,123 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return session.SendSyncRequest(); } + public KernelResult SendSyncRequestWithUserBuffer(ulong messagePtr, ulong messageSize, int handle) + { + if (!PageAligned(messagePtr)) + { + return KernelResult.InvalidAddress; + } + + if (!PageAligned(messageSize) || messageSize == 0) + { + return KernelResult.InvalidSize; + } + + if (messagePtr + messageSize <= messagePtr) + { + return KernelResult.InvalidMemState; + } + + KProcess currentProcess = _context.Scheduler.GetCurrentProcess(); + + KernelResult result = currentProcess.MemoryManager.BorrowIpcBuffer(messagePtr, messageSize); + + if (result != KernelResult.Success) + { + return result; + } + + KClientSession session = currentProcess.HandleTable.GetObject<KClientSession>(handle); + + if (session == null) + { + result = KernelResult.InvalidHandle; + } + else + { + result = session.SendSyncRequest(messagePtr, messageSize); + } + + KernelResult result2 = currentProcess.MemoryManager.UnborrowIpcBuffer(messagePtr, messageSize); + + if (result == KernelResult.Success) + { + result = result2; + } + + return result; + } + + public KernelResult SendAsyncRequestWithUserBuffer(ulong messagePtr, ulong messageSize, int handle, out int doneEventHandle) + { + doneEventHandle = 0; + + if (!PageAligned(messagePtr)) + { + return KernelResult.InvalidAddress; + } + + if (!PageAligned(messageSize) || messageSize == 0) + { + return KernelResult.InvalidSize; + } + + if (messagePtr + messageSize <= messagePtr) + { + return KernelResult.InvalidMemState; + } + + KProcess currentProcess = _context.Scheduler.GetCurrentProcess(); + + KernelResult result = currentProcess.MemoryManager.BorrowIpcBuffer(messagePtr, messageSize); + + if (result != KernelResult.Success) + { + return result; + } + + KResourceLimit resourceLimit = currentProcess.ResourceLimit; + + if (resourceLimit != null && !resourceLimit.Reserve(LimitableResource.Event, 1)) + { + currentProcess.MemoryManager.UnborrowIpcBuffer(messagePtr, messageSize); + + return KernelResult.ResLimitExceeded; + } + + KClientSession session = currentProcess.HandleTable.GetObject<KClientSession>(handle); + + if (session == null) + { + result = KernelResult.InvalidHandle; + } + else + { + KEvent doneEvent = new KEvent(_context); + + result = currentProcess.HandleTable.GenerateHandle(doneEvent.ReadableEvent, out doneEventHandle); + + if (result == KernelResult.Success) + { + result = session.SendAsyncRequest(doneEvent.WritableEvent, messagePtr, messageSize); + + if (result != KernelResult.Success) + { + currentProcess.HandleTable.CloseHandle(doneEventHandle); + } + } + } + + if (result != KernelResult.Success) + { + resourceLimit?.Release(LimitableResource.Event, 1); + + currentProcess.MemoryManager.UnborrowIpcBuffer(messagePtr, messageSize); + } + + return result; + } + public KernelResult CreateSession( bool isLight, ulong namePtr, @@ -348,7 +473,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall syncObjs[index] = obj; } - KernelResult result; + KernelResult result = KernelResult.Success; if (replyTargetHandle != 0) { @@ -356,32 +481,131 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall if (replyTarget == null) { - return KernelResult.InvalidHandle; + result = KernelResult.InvalidHandle; } + else + { + result = replyTarget.Reply(); + } + } - result = replyTarget.Reply(); + if (result == KernelResult.Success) + { + while ((result = _context.Synchronization.WaitFor(syncObjs, timeout, out handleIndex)) == KernelResult.Success) + { + KServerSession session = currentProcess.HandleTable.GetObject<KServerSession>(handles[handleIndex]); - if (result != KernelResult.Success) + if (session == null) + { + break; + } + + if ((result = session.Receive()) != KernelResult.NotFound) + { + break; + } + } + } + + return result; + } + + public KernelResult ReplyAndReceiveWithUserBuffer( + ulong handlesPtr, + ulong messagePtr, + ulong messageSize, + int handlesCount, + int replyTargetHandle, + long timeout, + out int handleIndex) + { + handleIndex = 0; + + if ((uint)handlesCount > 0x40) + { + return KernelResult.MaximumExceeded; + } + + KProcess currentProcess = _context.Scheduler.GetCurrentProcess(); + + ulong copySize = (ulong)((long)handlesCount * 4); + + if (!currentProcess.MemoryManager.InsideAddrSpace(handlesPtr, copySize)) + { + return KernelResult.UserCopyFailed; + } + + if (handlesPtr + copySize < handlesPtr) + { + return KernelResult.UserCopyFailed; + } + + KernelResult result = currentProcess.MemoryManager.BorrowIpcBuffer(messagePtr, messageSize); + + if (result != KernelResult.Success) + { + return result; + } + + int[] handles = new int[handlesCount]; + + if (!KernelTransfer.UserToKernelInt32Array(_context, handlesPtr, handles)) + { + currentProcess.MemoryManager.UnborrowIpcBuffer(messagePtr, messageSize); + + return KernelResult.UserCopyFailed; + } + + KSynchronizationObject[] syncObjs = new KSynchronizationObject[handlesCount]; + + for (int index = 0; index < handlesCount; index++) + { + KSynchronizationObject obj = currentProcess.HandleTable.GetObject<KSynchronizationObject>(handles[index]); + + if (obj == null) { - return result; + currentProcess.MemoryManager.UnborrowIpcBuffer(messagePtr, messageSize); + + return KernelResult.InvalidHandle; } + + syncObjs[index] = obj; } - while ((result = _context.Synchronization.WaitFor(syncObjs, timeout, out handleIndex)) == KernelResult.Success) + if (replyTargetHandle != 0) { - KServerSession session = currentProcess.HandleTable.GetObject<KServerSession>(handles[handleIndex]); + KServerSession replyTarget = currentProcess.HandleTable.GetObject<KServerSession>(replyTargetHandle); - if (session == null) + if (replyTarget == null) { - break; + result = KernelResult.InvalidHandle; + } + else + { + result = replyTarget.Reply(messagePtr, messageSize); } + } - if ((result = session.Receive()) != KernelResult.NotFound) + if (result == KernelResult.Success) + { + while ((result = _context.Synchronization.WaitFor(syncObjs, timeout, out handleIndex)) == KernelResult.Success) { - break; + KServerSession session = currentProcess.HandleTable.GetObject<KServerSession>(handles[handleIndex]); + + if (session == null) + { + break; + } + + if ((result = session.Receive(messagePtr, messageSize)) != KernelResult.NotFound) + { + break; + } } } + currentProcess.MemoryManager.UnborrowIpcBuffer(messagePtr, messageSize); + return result; } diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs index d7cbcbf5..224af6d8 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.SendSyncRequest(handle); + return _syscall.SendSyncRequestHLE(handle); } - public KernelResult SendSyncRequestWithUserBuffer32([R(0)] uint messagePtr, [R(1)] uint size, [R(2)] int handle) + public KernelResult SendSyncRequestWithUserBuffer32([R(0)] uint messagePtr, [R(1)] uint messageSize, [R(2)] int handle) { - return _syscall.SendSyncRequestWithUserBuffer(messagePtr, size, handle); + return _syscall.SendSyncRequestWithUserBufferHLE(messagePtr, messageSize, handle); } public KernelResult CreateSession32( diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs index 5dfcdcba..47f78a25 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs @@ -22,12 +22,21 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall public KernelResult SendSyncRequest64([R(0)] int handle) { - return _syscall.SendSyncRequest(handle); + return _syscall.SendSyncRequestHLE(handle); } - public KernelResult SendSyncRequestWithUserBuffer64([R(0)] ulong messagePtr, [R(1)] ulong size, [R(2)] int handle) + public KernelResult SendSyncRequestWithUserBuffer64([R(0)] ulong messagePtr, [R(1)] ulong messageSize, [R(2)] int handle) { - return _syscall.SendSyncRequestWithUserBuffer(messagePtr, size, handle); + return _syscall.SendSyncRequestWithUserBufferHLE(messagePtr, messageSize, handle); + } + + public KernelResult SendAsyncRequestWithUserBuffer64( + [R(1)] ulong messagePtr, + [R(2)] ulong messageSize, + [R(3)] int handle, + [R(1)] out int doneEventHandle) + { + return _syscall.SendAsyncRequestWithUserBuffer(messagePtr, messageSize, handle, out doneEventHandle); } public KernelResult CreateSession64( @@ -54,6 +63,25 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return _syscall.ReplyAndReceive(handlesPtr, handlesCount, replyTargetHandle, timeout, out handleIndex); } + public KernelResult ReplyAndReceiveWithUserBuffer64( + [R(1)] ulong messagePtr, + [R(2)] ulong messageSize, + [R(3)] ulong handlesPtr, + [R(4)] int handlesCount, + [R(5)] int replyTargetHandle, + [R(6)] long timeout, + [R(1)] out int handleIndex) + { + return _syscall.ReplyAndReceiveWithUserBuffer( + handlesPtr, + messagePtr, + messageSize, + handlesCount, + replyTargetHandle, + timeout, + out handleIndex); + } + public KernelResult CreatePort64( [R(2)] int maxSessions, [R(3)] bool isLight, diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallTable.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallTable.cs index 043a54af..dcfd9347 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallTable.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallTable.cs @@ -24,62 +24,64 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall Dictionary<int, string> svcFuncs64 = new Dictionary<int, string> { - { 0x01, nameof(Syscall64.SetHeapSize64) }, - { 0x03, nameof(Syscall64.SetMemoryAttribute64) }, - { 0x04, nameof(Syscall64.MapMemory64) }, - { 0x05, nameof(Syscall64.UnmapMemory64) }, - { 0x06, nameof(Syscall64.QueryMemory64) }, - { 0x07, nameof(Syscall64.ExitProcess64) }, - { 0x08, nameof(Syscall64.CreateThread64) }, - { 0x09, nameof(Syscall64.StartThread64) }, - { 0x0a, nameof(Syscall64.ExitThread64) }, - { 0x0b, nameof(Syscall64.SleepThread64) }, - { 0x0c, nameof(Syscall64.GetThreadPriority64) }, - { 0x0d, nameof(Syscall64.SetThreadPriority64) }, - { 0x0e, nameof(Syscall64.GetThreadCoreMask64) }, - { 0x0f, nameof(Syscall64.SetThreadCoreMask64) }, - { 0x10, nameof(Syscall64.GetCurrentProcessorNumber64) }, - { 0x11, nameof(Syscall64.SignalEvent64) }, - { 0x12, nameof(Syscall64.ClearEvent64) }, - { 0x13, nameof(Syscall64.MapSharedMemory64) }, - { 0x14, nameof(Syscall64.UnmapSharedMemory64) }, - { 0x15, nameof(Syscall64.CreateTransferMemory64) }, - { 0x16, nameof(Syscall64.CloseHandle64) }, - { 0x17, nameof(Syscall64.ResetSignal64) }, - { 0x18, nameof(Syscall64.WaitSynchronization64) }, - { 0x19, nameof(Syscall64.CancelSynchronization64) }, - { 0x1a, nameof(Syscall64.ArbitrateLock64) }, - { 0x1b, nameof(Syscall64.ArbitrateUnlock64) }, - { 0x1c, nameof(Syscall64.WaitProcessWideKeyAtomic64) }, - { 0x1d, nameof(Syscall64.SignalProcessWideKey64) }, - { 0x1e, nameof(Syscall64.GetSystemTick64) }, - { 0x1f, nameof(Syscall64.ConnectToNamedPort64) }, - { 0x21, nameof(Syscall64.SendSyncRequest64) }, - { 0x22, nameof(Syscall64.SendSyncRequestWithUserBuffer64) }, - { 0x24, nameof(Syscall64.GetProcessId64) }, - { 0x25, nameof(Syscall64.GetThreadId64) }, - { 0x26, nameof(Syscall64.Break64) }, - { 0x27, nameof(Syscall64.OutputDebugString64) }, - { 0x29, nameof(Syscall64.GetInfo64) }, - { 0x2c, nameof(Syscall64.MapPhysicalMemory64) }, - { 0x2d, nameof(Syscall64.UnmapPhysicalMemory64) }, - { 0x32, nameof(Syscall64.SetThreadActivity64) }, - { 0x33, nameof(Syscall64.GetThreadContext364) }, - { 0x34, nameof(Syscall64.WaitForAddress64) }, - { 0x35, nameof(Syscall64.SignalToAddress64) }, - { 0x40, nameof(Syscall64.CreateSession64) }, - { 0x41, nameof(Syscall64.AcceptSession64) }, - { 0x43, nameof(Syscall64.ReplyAndReceive64) }, - { 0x45, nameof(Syscall64.CreateEvent64) }, - { 0x65, nameof(Syscall64.GetProcessList64) }, - { 0x6f, nameof(Syscall64.GetSystemInfo64) }, - { 0x70, nameof(Syscall64.CreatePort64) }, - { 0x71, nameof(Syscall64.ManageNamedPort64) }, - { 0x72, nameof(Syscall64.ConnectToPort64) }, - { 0x73, nameof(Syscall64.SetProcessMemoryPermission64) }, - { 0x77, nameof(Syscall64.MapProcessCodeMemory64) }, - { 0x78, nameof(Syscall64.UnmapProcessCodeMemory64) }, - { 0x7B, nameof(Syscall64.TerminateProcess64) } + { 0x01, nameof(Syscall64.SetHeapSize64) }, + { 0x03, nameof(Syscall64.SetMemoryAttribute64) }, + { 0x04, nameof(Syscall64.MapMemory64) }, + { 0x05, nameof(Syscall64.UnmapMemory64) }, + { 0x06, nameof(Syscall64.QueryMemory64) }, + { 0x07, nameof(Syscall64.ExitProcess64) }, + { 0x08, nameof(Syscall64.CreateThread64) }, + { 0x09, nameof(Syscall64.StartThread64) }, + { 0x0a, nameof(Syscall64.ExitThread64) }, + { 0x0b, nameof(Syscall64.SleepThread64) }, + { 0x0c, nameof(Syscall64.GetThreadPriority64) }, + { 0x0d, nameof(Syscall64.SetThreadPriority64) }, + { 0x0e, nameof(Syscall64.GetThreadCoreMask64) }, + { 0x0f, nameof(Syscall64.SetThreadCoreMask64) }, + { 0x10, nameof(Syscall64.GetCurrentProcessorNumber64) }, + { 0x11, nameof(Syscall64.SignalEvent64) }, + { 0x12, nameof(Syscall64.ClearEvent64) }, + { 0x13, nameof(Syscall64.MapSharedMemory64) }, + { 0x14, nameof(Syscall64.UnmapSharedMemory64) }, + { 0x15, nameof(Syscall64.CreateTransferMemory64) }, + { 0x16, nameof(Syscall64.CloseHandle64) }, + { 0x17, nameof(Syscall64.ResetSignal64) }, + { 0x18, nameof(Syscall64.WaitSynchronization64) }, + { 0x19, nameof(Syscall64.CancelSynchronization64) }, + { 0x1a, nameof(Syscall64.ArbitrateLock64) }, + { 0x1b, nameof(Syscall64.ArbitrateUnlock64) }, + { 0x1c, nameof(Syscall64.WaitProcessWideKeyAtomic64) }, + { 0x1d, nameof(Syscall64.SignalProcessWideKey64) }, + { 0x1e, nameof(Syscall64.GetSystemTick64) }, + { 0x1f, nameof(Syscall64.ConnectToNamedPort64) }, + { 0x21, nameof(Syscall64.SendSyncRequest64) }, + { 0x22, nameof(Syscall64.SendSyncRequestWithUserBuffer64) }, + { 0x23, nameof(Syscall64.SendAsyncRequestWithUserBuffer64) }, + { 0x24, nameof(Syscall64.GetProcessId64) }, + { 0x25, nameof(Syscall64.GetThreadId64) }, + { 0x26, nameof(Syscall64.Break64) }, + { 0x27, nameof(Syscall64.OutputDebugString64) }, + { 0x29, nameof(Syscall64.GetInfo64) }, + { 0x2c, nameof(Syscall64.MapPhysicalMemory64) }, + { 0x2d, nameof(Syscall64.UnmapPhysicalMemory64) }, + { 0x32, nameof(Syscall64.SetThreadActivity64) }, + { 0x33, nameof(Syscall64.GetThreadContext364) }, + { 0x34, nameof(Syscall64.WaitForAddress64) }, + { 0x35, nameof(Syscall64.SignalToAddress64) }, + { 0x40, nameof(Syscall64.CreateSession64) }, + { 0x41, nameof(Syscall64.AcceptSession64) }, + { 0x43, nameof(Syscall64.ReplyAndReceive64) }, + { 0x44, nameof(Syscall64.ReplyAndReceiveWithUserBuffer64) }, + { 0x45, nameof(Syscall64.CreateEvent64) }, + { 0x65, nameof(Syscall64.GetProcessList64) }, + { 0x6f, nameof(Syscall64.GetSystemInfo64) }, + { 0x70, nameof(Syscall64.CreatePort64) }, + { 0x71, nameof(Syscall64.ManageNamedPort64) }, + { 0x72, nameof(Syscall64.ConnectToPort64) }, + { 0x73, nameof(Syscall64.SetProcessMemoryPermission64) }, + { 0x77, nameof(Syscall64.MapProcessCodeMemory64) }, + { 0x78, nameof(Syscall64.UnmapProcessCodeMemory64) }, + { 0x7B, nameof(Syscall64.TerminateProcess64) } }; foreach (KeyValuePair<int, string> value in svcFuncs64) |
