diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/InvalidSvcException.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/InvalidSvcException.cs deleted file mode 100644 index f2e28bb7b..000000000 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/InvalidSvcException.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall -{ - class InvalidSvcException : Exception - { - public InvalidSvcException(string message) : base(message) { } - } -} diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/PointerSizedAttribute.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/PointerSizedAttribute.cs new file mode 100644 index 000000000..154164fb5 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/PointerSizedAttribute.cs @@ -0,0 +1,9 @@ +using System; + +namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall +{ + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] + class PointerSizedAttribute : Attribute + { + } +} diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/RAttribute.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/RAttribute.cs deleted file mode 100644 index c1d9eeed0..000000000 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/RAttribute.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall -{ - [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)] - public class RAttribute : Attribute - { - public readonly int Index; - - public RAttribute(int index) - { - Index = index; - } - } -} diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcAttribute.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcAttribute.cs new file mode 100644 index 000000000..b8839d1d3 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcAttribute.cs @@ -0,0 +1,15 @@ +using System; + +namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + class SvcAttribute : Attribute + { + public int Id { get; } + + public SvcAttribute(int id) + { + Id = id; + } + } +} diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcImplAttribute.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcImplAttribute.cs new file mode 100644 index 000000000..a32d851f6 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcImplAttribute.cs @@ -0,0 +1,9 @@ +using System; + +namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + class SvcImplAttribute : Attribute + { + } +} diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs index 571699d99..179c7d4b2 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs @@ -12,6 +12,7 @@ using System.Threading; namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall { + [SvcImpl] class Syscall { private readonly KernelContext _context; @@ -23,6 +24,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall // Process + [Svc(0x24)] public KernelResult GetProcessId(out ulong pid, int handle) { KProcess currentProcess = KernelStatic.GetCurrentProcess(); @@ -167,9 +169,18 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.Success; } + [Svc(0x5f)] + public KernelResult FlushProcessDataCache(int processHandle, ulong address, ulong size) + { + // FIXME: This needs to be implemented as ARMv7 doesn't have any way to do cache maintenance operations on EL0. + // As we don't support (and don't actually need) to flush the cache, this is stubbed. + return KernelResult.Success; + } + // IPC - public KernelResult ConnectToNamedPort(out int handle, ulong namePtr) + [Svc(0x1f)] + public KernelResult ConnectToNamedPort(out int handle, [PointerSized] ulong namePtr) { handle = 0; @@ -222,6 +233,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } + [Svc(0x21)] public KernelResult SendSyncRequest(int handle) { KProcess currentProcess = KernelStatic.GetCurrentProcess(); @@ -236,7 +248,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return session.SendSyncRequest(); } - public KernelResult SendSyncRequestWithUserBuffer(ulong messagePtr, ulong messageSize, int handle) + [Svc(0x22)] + public KernelResult SendSyncRequestWithUserBuffer( + [PointerSized] ulong messagePtr, + [PointerSized] ulong messageSize, + int handle) { if (!PageAligned(messagePtr)) { @@ -283,7 +299,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } - public KernelResult SendAsyncRequestWithUserBuffer(out int doneEventHandle, ulong messagePtr, ulong messageSize, int handle) + [Svc(0x23)] + public KernelResult SendAsyncRequestWithUserBuffer( + out int doneEventHandle, + [PointerSized] ulong messagePtr, + [PointerSized] ulong messageSize, + int handle) { doneEventHandle = 0; @@ -353,11 +374,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } + [Svc(0x40)] public KernelResult CreateSession( out int serverSessionHandle, out int clientSessionHandle, bool isLight, - ulong namePtr) + [PointerSized] ulong namePtr) { serverSessionHandle = 0; clientSessionHandle = 0; @@ -419,6 +441,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } + [Svc(0x41)] public KernelResult AcceptSession(out int sessionHandle, int portHandle) { sessionHandle = 0; @@ -470,9 +493,10 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } + [Svc(0x43)] public KernelResult ReplyAndReceive( out int handleIndex, - ulong handlesPtr, + [PointerSized] ulong handlesPtr, int handlesCount, int replyTargetHandle, long timeout) @@ -575,11 +599,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } + [Svc(0x44)] public KernelResult ReplyAndReceiveWithUserBuffer( out int handleIndex, - ulong handlesPtr, - ulong messagePtr, - ulong messageSize, + [PointerSized] ulong messagePtr, + [PointerSized] ulong messageSize, + [PointerSized] ulong handlesPtr, int handlesCount, int replyTargetHandle, long timeout) @@ -679,12 +704,13 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } + [Svc(0x70)] public KernelResult CreatePort( out int serverPortHandle, out int clientPortHandle, int maxSessions, bool isLight, - ulong namePtr) + [PointerSized] ulong namePtr) { serverPortHandle = clientPortHandle = 0; @@ -714,7 +740,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } - public KernelResult ManageNamedPort(out int handle, ulong namePtr, int maxSessions) + [Svc(0x71)] + public KernelResult ManageNamedPort(out int handle, [PointerSized] ulong namePtr, int maxSessions) { handle = 0; @@ -766,6 +793,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } + [Svc(0x72)] public KernelResult ConnectToPort(out int clientSessionHandle, int clientPortHandle) { clientSessionHandle = 0; @@ -819,7 +847,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall // Memory - public KernelResult SetHeapSize(out ulong address, ulong size) + [Svc(1)] + public KernelResult SetHeapSize([PointerSized] out ulong address, [PointerSized] ulong size) { if ((size & 0xfffffffe001fffff) != 0) { @@ -833,7 +862,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return process.MemoryManager.SetHeapSize(size, out address); } - public KernelResult SetMemoryPermission(ulong address, ulong size, KMemoryPermission permission) + [Svc(2)] + public KernelResult SetMemoryPermission([PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission) { if (!PageAligned(address)) { @@ -865,9 +895,10 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return currentProcess.MemoryManager.SetMemoryPermission(address, size, permission); } + [Svc(3)] public KernelResult SetMemoryAttribute( - ulong address, - ulong size, + [PointerSized] ulong address, + [PointerSized] ulong size, MemoryAttribute attributeMask, MemoryAttribute attributeValue) { @@ -905,7 +936,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } - public KernelResult MapMemory(ulong dst, ulong src, ulong size) + [Svc(4)] + public KernelResult MapMemory([PointerSized] ulong dst, [PointerSized] ulong src, [PointerSized] ulong size) { if (!PageAligned(src | dst)) { @@ -941,7 +973,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return process.MemoryManager.Map(dst, src, size); } - public KernelResult UnmapMemory(ulong dst, ulong src, ulong size) + [Svc(5)] + public KernelResult UnmapMemory([PointerSized] ulong dst, [PointerSized] ulong src, [PointerSized] ulong size) { if (!PageAligned(src | dst)) { @@ -977,7 +1010,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return process.MemoryManager.Unmap(dst, src, size); } - public KernelResult QueryMemory(ulong infoPtr, out ulong pageInfo, ulong address) + [Svc(6)] + public KernelResult QueryMemory([PointerSized] ulong infoPtr, [PointerSized] out ulong pageInfo, [PointerSized] ulong address) { KernelResult result = QueryMemory(out MemoryInfo info, out pageInfo, address); @@ -1011,7 +1045,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.Success; } - public KernelResult MapSharedMemory(int handle, ulong address, ulong size, KMemoryPermission permission) + [Svc(0x13)] + public KernelResult MapSharedMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission) { if (!PageAligned(address)) { @@ -1057,7 +1092,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall permission); } - public KernelResult UnmapSharedMemory(int handle, ulong address, ulong size) + [Svc(0x14)] + public KernelResult UnmapSharedMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size) { if (!PageAligned(address)) { @@ -1097,7 +1133,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall currentProcess); } - public KernelResult CreateTransferMemory(out int handle, ulong address, ulong size, KMemoryPermission permission) + [Svc(0x15)] + public KernelResult CreateTransferMemory(out int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission) { handle = 0; @@ -1160,7 +1197,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } - public KernelResult MapTransferMemory(int handle, ulong address, ulong size, KMemoryPermission permission) + [Svc(0x51)] + public KernelResult MapTransferMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission) { if (!PageAligned(address)) { @@ -1206,7 +1244,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall permission); } - public KernelResult UnmapTransferMemory(int handle, ulong address, ulong size) + [Svc(0x52)] + public KernelResult UnmapTransferMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size) { if (!PageAligned(address)) { @@ -1246,7 +1285,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall currentProcess); } - public KernelResult MapPhysicalMemory(ulong address, ulong size) + [Svc(0x2c)] + public KernelResult MapPhysicalMemory([PointerSized] ulong address, [PointerSized] ulong size) { if (!PageAligned(address)) { @@ -1281,7 +1321,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return process.MemoryManager.MapPhysicalMemory(address, size); } - public KernelResult UnmapPhysicalMemory(ulong address, ulong size) + [Svc(0x2d)] + public KernelResult UnmapPhysicalMemory([PointerSized] ulong address, [PointerSized] ulong size) { if (!PageAligned(address)) { @@ -1316,7 +1357,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return process.MemoryManager.UnmapPhysicalMemory(address, size); } - public KernelResult CreateCodeMemory(ulong address, ulong size, out int handle) + [Svc(0x4b)] + public KernelResult CreateCodeMemory(out int handle, [PointerSized] ulong address, [PointerSized] ulong size) { handle = 0; @@ -1356,7 +1398,13 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return currentProcess.HandleTable.GenerateHandle(codeMemory, out handle); } - public KernelResult ControlCodeMemory(int handle, CodeMemoryOperation op, ulong address, ulong size, KMemoryPermission permission) + [Svc(0x4c)] + public KernelResult ControlCodeMemory( + int handle, + CodeMemoryOperation op, + ulong address, + ulong size, + KMemoryPermission permission) { KProcess currentProcess = KernelStatic.GetCurrentProcess(); @@ -1428,7 +1476,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } } - public KernelResult SetProcessMemoryPermission(int handle, ulong src, ulong size, KMemoryPermission permission) + [Svc(0x73)] + public KernelResult SetProcessMemoryPermission( + int handle, + [PointerSized] ulong src, + [PointerSized] ulong size, + KMemoryPermission permission) { if (!PageAligned(src)) { @@ -1465,7 +1518,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return targetProcess.MemoryManager.SetProcessMemoryPermission(src, size, permission); } - public KernelResult MapProcessMemory(ulong dst, int handle, ulong src, ulong size) + [Svc(0x74)] + public KernelResult MapProcessMemory( + [PointerSized] ulong dst, + int handle, + ulong src, + [PointerSized] ulong size) { if (!PageAligned(src) || !PageAligned(dst)) { @@ -1517,7 +1575,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return dstProcess.MemoryManager.MapPages(dst, pageList, MemoryState.ProcessMemory, KMemoryPermission.ReadAndWrite); } - public KernelResult UnmapProcessMemory(ulong dst, int handle, ulong src, ulong size) + [Svc(0x75)] + public KernelResult UnmapProcessMemory( + [PointerSized] ulong dst, + int handle, + ulong src, + [PointerSized] ulong size) { if (!PageAligned(src) || !PageAligned(dst)) { @@ -1558,6 +1621,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.Success; } + [Svc(0x77)] public KernelResult MapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size) { if (!PageAligned(dst) || !PageAligned(src)) @@ -1595,6 +1659,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return targetProcess.MemoryManager.MapProcessCodeMemory(dst, src, size); } + [Svc(0x78)] public KernelResult UnmapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size) { if (!PageAligned(dst) || !PageAligned(src)) @@ -1639,6 +1704,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall // System + [Svc(0x7b)] public KernelResult TerminateProcess(int handle) { KProcess process = KernelStatic.GetCurrentProcess(); @@ -1668,11 +1734,13 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } + [Svc(7)] public void ExitProcess() { KernelStatic.GetCurrentProcess().TerminateCurrentProcess(); } + [Svc(0x11)] public KernelResult SignalEvent(int handle) { KProcess process = KernelStatic.GetCurrentProcess(); @@ -1695,6 +1763,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } + [Svc(0x12)] public KernelResult ClearEvent(int handle) { KernelResult result; @@ -1717,6 +1786,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } + [Svc(0x16)] public KernelResult CloseHandle(int handle) { KProcess currentProcess = KernelStatic.GetCurrentProcess(); @@ -1724,6 +1794,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return currentProcess.HandleTable.CloseHandle(handle) ? KernelResult.Success : KernelResult.InvalidHandle; } + [Svc(0x17)] public KernelResult ResetSignal(int handle) { KProcess currentProcess = KernelStatic.GetCurrentProcess(); @@ -1753,11 +1824,13 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } + [Svc(0x1e)] public ulong GetSystemTick() { return _context.TickSource.Counter; } + [Svc(0x26)] public void Break(ulong reason) { KThread currentThread = KernelStatic.GetCurrentThread(); @@ -1784,7 +1857,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } } - public void OutputDebugString(ulong strPtr, ulong size) + [Svc(0x27)] + public void OutputDebugString([PointerSized] ulong strPtr, [PointerSized] ulong size) { KProcess process = KernelStatic.GetCurrentProcess(); @@ -1793,6 +1867,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall Logger.Warning?.Print(LogClass.KernelSvc, str); } + [Svc(0x29)] public KernelResult GetInfo(out ulong value, InfoType id, int handle, long subId) { value = 0; @@ -2038,6 +2113,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.Success; } + [Svc(0x45)] public KernelResult CreateEvent(out int wEventHandle, out int rEventHandle) { KEvent Event = new KEvent(_context); @@ -2063,7 +2139,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } - public KernelResult GetProcessList(out int count, ulong address, int maxCount) + [Svc(0x65)] + public KernelResult GetProcessList(out int count, [PointerSized] ulong address, int maxCount) { count = 0; @@ -2112,6 +2189,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.Success; } + [Svc(0x6f)] public KernelResult GetSystemInfo(out long value, uint id, int handle, long subId) { value = 0; @@ -2168,6 +2246,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.Success; } + [Svc(0x30)] public KernelResult GetResourceLimitLimitValue(out long limitValue, int handle, LimitableResource resource) { limitValue = 0; @@ -2189,6 +2268,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.Success; } + [Svc(0x31)] public KernelResult GetResourceLimitCurrentValue(out long limitValue, int handle, LimitableResource resource) { limitValue = 0; @@ -2210,6 +2290,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.Success; } + [Svc(0x37)] public KernelResult GetResourceLimitPeakValue(out long peak, int handle, LimitableResource resource) { peak = 0; @@ -2231,6 +2312,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.Success; } + [Svc(0x7d)] public KernelResult CreateResourceLimit(out int handle) { KResourceLimit limit = new KResourceLimit(_context); @@ -2240,6 +2322,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return process.HandleTable.GenerateHandle(limit, out handle); } + [Svc(0x7e)] public KernelResult SetResourceLimitLimitValue(int handle, LimitableResource resource, long limitValue) { if (resource >= LimitableResource.Count) @@ -2259,11 +2342,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall // Thread + [Svc(8)] public KernelResult CreateThread( out int handle, - ulong entrypoint, - ulong argsPtr, - ulong stackTop, + [PointerSized] ulong entrypoint, + [PointerSized] ulong argsPtr, + [PointerSized] ulong stackTop, int priority, int cpuCore) { @@ -2320,6 +2404,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } + [Svc(9)] public KernelResult StartThread(int handle) { KProcess process = KernelStatic.GetCurrentProcess(); @@ -2347,6 +2432,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } } + [Svc(0xa)] public void ExitThread() { KThread currentThread = KernelStatic.GetCurrentThread(); @@ -2354,6 +2440,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall currentThread.Exit(); } + [Svc(0xb)] public void SleepThread(long timeout) { if (timeout < 1) @@ -2371,6 +2458,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } } + [Svc(0xc)] public KernelResult GetThreadPriority(out int priority, int handle) { KProcess process = KernelStatic.GetCurrentProcess(); @@ -2391,6 +2479,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } } + [Svc(0xd)] public KernelResult SetThreadPriority(int handle, int priority) { // TODO: NPDM check. @@ -2409,6 +2498,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.Success; } + [Svc(0xe)] public KernelResult GetThreadCoreMask(out int preferredCore, out ulong affinityMask, int handle) { KProcess process = KernelStatic.GetCurrentProcess(); @@ -2431,6 +2521,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } } + [Svc(0xf)] public KernelResult SetThreadCoreMask(int handle, int preferredCore, ulong affinityMask) { KProcess currentProcess = KernelStatic.GetCurrentProcess(); @@ -2479,11 +2570,13 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return thread.SetCoreAndAffinityMask(preferredCore, affinityMask); } + [Svc(0x10)] public int GetCurrentProcessorNumber() { return KernelStatic.GetCurrentThread().CurrentCore; } + [Svc(0x25)] public KernelResult GetThreadId(out ulong threadUid, int handle) { KProcess process = KernelStatic.GetCurrentProcess(); @@ -2504,6 +2597,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } } + [Svc(0x32)] public KernelResult SetThreadActivity(int handle, bool pause) { KProcess process = KernelStatic.GetCurrentProcess(); @@ -2528,7 +2622,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return thread.SetActivity(pause); } - public KernelResult GetThreadContext3(ulong address, int handle) + [Svc(0x33)] + public KernelResult GetThreadContext3([PointerSized] ulong address, int handle) { KProcess currentProcess = KernelStatic.GetCurrentProcess(); KThread currentThread = KernelStatic.GetCurrentThread(); @@ -2564,7 +2659,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall // Thread synchronization - public KernelResult WaitSynchronization(out int handleIndex, ulong handlesPtr, int handlesCount, long timeout) + [Svc(0x18)] + public KernelResult WaitSynchronization(out int handleIndex, [PointerSized] ulong handlesPtr, int handlesCount, long timeout) { handleIndex = 0; @@ -2653,6 +2749,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return result; } + [Svc(0x19)] public KernelResult CancelSynchronization(int handle) { KProcess process = KernelStatic.GetCurrentProcess(); @@ -2669,7 +2766,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.Success; } - public KernelResult ArbitrateLock(int ownerHandle, ulong mutexAddress, int requesterHandle) + [Svc(0x1a)] + public KernelResult ArbitrateLock(int ownerHandle, [PointerSized] ulong mutexAddress, int requesterHandle) { if (IsPointingInsideKernel(mutexAddress)) { @@ -2686,7 +2784,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return currentProcess.AddressArbiter.ArbitrateLock(ownerHandle, mutexAddress, requesterHandle); } - public KernelResult ArbitrateUnlock(ulong mutexAddress) + [Svc(0x1b)] + public KernelResult ArbitrateUnlock([PointerSized] ulong mutexAddress) { if (IsPointingInsideKernel(mutexAddress)) { @@ -2703,9 +2802,10 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return currentProcess.AddressArbiter.ArbitrateUnlock(mutexAddress); } + [Svc(0x1c)] public KernelResult WaitProcessWideKeyAtomic( - ulong mutexAddress, - ulong condVarAddress, + [PointerSized] ulong mutexAddress, + [PointerSized] ulong condVarAddress, int handle, long timeout) { @@ -2733,7 +2833,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall timeout); } - public KernelResult SignalProcessWideKey(ulong address, int count) + [Svc(0x1d)] + public KernelResult SignalProcessWideKey([PointerSized] ulong address, int count) { KProcess currentProcess = KernelStatic.GetCurrentProcess(); @@ -2742,7 +2843,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.Success; } - public KernelResult WaitForAddress(ulong address, ArbitrationType type, int value, long timeout) + [Svc(0x34)] + public KernelResult WaitForAddress([PointerSized] ulong address, ArbitrationType type, int value, long timeout) { if (IsPointingInsideKernel(address)) { @@ -2773,7 +2875,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall }; } - public KernelResult SignalToAddress(ulong address, SignalType type, int value, int count) + [Svc(0x35)] + public KernelResult SignalToAddress([PointerSized] ulong address, SignalType type, int value, int count) { if (IsPointingInsideKernel(address)) { @@ -2799,6 +2902,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall }; } + [Svc(0x36)] public KernelResult SynchronizePreemptionState() { KernelStatic.GetCurrentThread().SynchronizePreemptionState(); @@ -2806,12 +2910,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.Success; } - private bool IsPointingInsideKernel(ulong address) + private static bool IsPointingInsideKernel(ulong address) { return (address + 0x1000000000) < 0xffffff000; } - private bool IsAddressNotWordAligned(ulong address) + private static bool IsAddressNotWordAligned(ulong address) { return (address & 3) != 0; } diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs deleted file mode 100644 index 27ff8ef7f..000000000 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall32.cs +++ /dev/null @@ -1,534 +0,0 @@ -using Ryujinx.HLE.HOS.Kernel.Common; -using Ryujinx.HLE.HOS.Kernel.Memory; -using Ryujinx.HLE.HOS.Kernel.Threading; - -namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall -{ - class Syscall32 - { - private readonly Syscall _syscall; - - public Syscall32(Syscall syscall) - { - _syscall = syscall; - } - - // IPC - - public KernelResult ConnectToNamedPort32([R(1)] uint namePtr, [R(1)] out int handle) - { - return _syscall.ConnectToNamedPort(out handle, namePtr); - } - - public KernelResult SendSyncRequest32([R(0)] int handle) - { - return _syscall.SendSyncRequest(handle); - } - - public KernelResult SendSyncRequestWithUserBuffer32([R(0)] uint messagePtr, [R(1)] uint messageSize, [R(2)] int handle) - { - return _syscall.SendSyncRequestWithUserBuffer(messagePtr, messageSize, handle); - } - - public KernelResult CreateSession32( - [R(2)] bool isLight, - [R(3)] uint namePtr, - [R(1)] out int serverSessionHandle, - [R(2)] out int clientSessionHandle) - { - return _syscall.CreateSession(out serverSessionHandle, out clientSessionHandle, isLight, namePtr); - } - - public KernelResult AcceptSession32([R(1)] int portHandle, [R(1)] out int sessionHandle) - { - return _syscall.AcceptSession(out sessionHandle, portHandle); - } - - public KernelResult ReplyAndReceive32( - [R(0)] uint timeoutLow, - [R(1)] uint handlesPtr, - [R(2)] int handlesCount, - [R(3)] int replyTargetHandle, - [R(4)] uint timeoutHigh, - [R(1)] out int handleIndex) - { - long timeout = (long)(timeoutLow | ((ulong)timeoutHigh << 32)); - - return _syscall.ReplyAndReceive(out handleIndex, handlesPtr, handlesCount, replyTargetHandle, timeout); - } - - public KernelResult CreatePort32( - [R(0)] uint namePtr, - [R(2)] int maxSessions, - [R(3)] bool isLight, - [R(1)] out int serverPortHandle, - [R(2)] out int clientPortHandle) - { - return _syscall.CreatePort(out serverPortHandle, out clientPortHandle, maxSessions, isLight, namePtr); - } - - public KernelResult ManageNamedPort32([R(1)] uint namePtr, [R(2)] int maxSessions, [R(1)] out int handle) - { - return _syscall.ManageNamedPort(out handle, namePtr, maxSessions); - } - - public KernelResult ConnectToPort32([R(1)] int clientPortHandle, [R(1)] out int clientSessionHandle) - { - return _syscall.ConnectToPort(out clientSessionHandle, clientPortHandle); - } - - // Memory - - public KernelResult SetHeapSize32([R(1)] uint size, [R(1)] out uint address) - { - KernelResult result = _syscall.SetHeapSize(out ulong address64, size); - - address = (uint)address64; - - return result; - } - - public KernelResult SetMemoryPermission32( - [R(0)] uint address, - [R(1)] uint size, - [R(2)] KMemoryPermission permission) - { - return _syscall.SetMemoryPermission(address, size, permission); - } - - public KernelResult SetMemoryAttribute32( - [R(0)] uint address, - [R(1)] uint size, - [R(2)] MemoryAttribute attributeMask, - [R(3)] MemoryAttribute attributeValue) - { - return _syscall.SetMemoryAttribute(address, size, attributeMask, attributeValue); - } - - public KernelResult MapMemory32([R(0)] uint dst, [R(1)] uint src, [R(2)] uint size) - { - return _syscall.MapMemory(dst, src, size); - } - - public KernelResult UnmapMemory32([R(0)] uint dst, [R(1)] uint src, [R(2)] uint size) - { - return _syscall.UnmapMemory(dst, src, size); - } - - public KernelResult QueryMemory32([R(0)] uint infoPtr, [R(1)] uint r1, [R(2)] uint address, [R(1)] out uint pageInfo) - { - KernelResult result = _syscall.QueryMemory(infoPtr, out ulong pageInfo64, address); - - pageInfo = (uint)pageInfo64; - - return result; - } - - 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); - } - - public KernelResult UnmapSharedMemory32([R(0)] int handle, [R(1)] uint address, [R(2)] uint size) - { - return _syscall.UnmapSharedMemory(handle, address, size); - } - - public KernelResult CreateTransferMemory32( - [R(1)] uint address, - [R(2)] uint size, - [R(3)] KMemoryPermission permission, - [R(1)] out int handle) - { - return _syscall.CreateTransferMemory(out handle, address, size, permission); - } - - public KernelResult CreateCodeMemory32([R(1)] uint address, [R(2)] uint size, [R(1)] out int handle) - { - return _syscall.CreateCodeMemory(address, size, out handle); - } - - public KernelResult ControlCodeMemory32( - [R(0)] int handle, - [R(1)] CodeMemoryOperation op, - [R(2)] uint addressLow, - [R(3)] uint addressHigh, - [R(4)] uint sizeLow, - [R(5)] uint sizeHigh, - [R(6)] KMemoryPermission permission) - { - ulong address = addressLow | ((ulong)addressHigh << 32); - ulong size = sizeLow | ((ulong)sizeHigh << 32); - - return _syscall.ControlCodeMemory(handle, op, address, size, permission); - } - - public KernelResult MapTransferMemory32([R(0)] int handle, [R(1)] uint address, [R(2)] uint size, [R(3)] KMemoryPermission permission) - { - return _syscall.MapTransferMemory(handle, address, size, permission); - } - - public KernelResult UnmapTransferMemory32([R(0)] int handle, [R(1)] uint address, [R(2)] uint size) - { - return _syscall.UnmapTransferMemory(handle, address, size); - } - - public KernelResult MapPhysicalMemory32([R(0)] uint address, [R(1)] uint size) - { - return _syscall.MapPhysicalMemory(address, size); - } - - public KernelResult UnmapPhysicalMemory32([R(0)] uint address, [R(1)] uint size) - { - return _syscall.UnmapPhysicalMemory(address, size); - } - - public KernelResult SetProcessMemoryPermission32( - [R(0)] int handle, - [R(1)] uint sizeLow, - [R(2)] uint srcLow, - [R(3)] uint srcHigh, - [R(4)] uint sizeHigh, - [R(5)] KMemoryPermission permission) - { - ulong src = srcLow | ((ulong)srcHigh << 32); - ulong size = sizeLow | ((ulong)sizeHigh << 32); - - return _syscall.SetProcessMemoryPermission(handle, src, size, permission); - } - - public KernelResult MapProcessMemory32([R(0)] uint dst, [R(1)] int handle, [R(2)] uint srcLow, [R(3)] uint srcHigh, [R(4)] uint size) - { - ulong src = srcLow | ((ulong)srcHigh << 32); - - return _syscall.MapProcessMemory(dst, handle, src, size); - } - - public KernelResult UnmapProcessMemory32([R(0)] uint dst, [R(1)] int handle, [R(2)] uint srcLow, [R(3)] uint srcHigh, [R(4)] uint size) - { - ulong src = srcLow | ((ulong)srcHigh << 32); - - return _syscall.UnmapProcessMemory(dst, handle, src, size); - } - - public KernelResult MapProcessCodeMemory32([R(0)] int handle, [R(1)] uint srcLow, [R(2)] uint dstLow, [R(3)] uint dstHigh, [R(4)] uint srcHigh, [R(5)] uint sizeLow, [R(6)] uint sizeHigh) - { - ulong src = srcLow | ((ulong)srcHigh << 32); - ulong dst = dstLow | ((ulong)dstHigh << 32); - ulong size = sizeLow | ((ulong)sizeHigh << 32); - - return _syscall.MapProcessCodeMemory(handle, dst, src, size); - } - - public KernelResult UnmapProcessCodeMemory32([R(0)] int handle, [R(1)] uint srcLow, [R(2)] uint dstLow, [R(3)] uint dstHigh, [R(4)] uint srcHigh, [R(5)] uint sizeLow, [R(6)] uint sizeHigh) - { - ulong src = srcLow | ((ulong)srcHigh << 32); - ulong dst = dstLow | ((ulong)dstHigh << 32); - ulong size = sizeLow | ((ulong)sizeHigh << 32); - - return _syscall.UnmapProcessCodeMemory(handle, dst, src, size); - } - - // System - - public void ExitProcess32() - { - _syscall.ExitProcess(); - } - - public KernelResult TerminateProcess32([R(0)] int handle) - { - return _syscall.TerminateProcess(handle); - } - - public KernelResult SignalEvent32([R(0)] int handle) - { - return _syscall.SignalEvent(handle); - } - - public KernelResult ClearEvent32([R(0)] int handle) - { - return _syscall.ClearEvent(handle); - } - - public KernelResult CloseHandle32([R(0)] int handle) - { - return _syscall.CloseHandle(handle); - } - - public KernelResult ResetSignal32([R(0)] int handle) - { - return _syscall.ResetSignal(handle); - } - - public void GetSystemTick32([R(0)] out uint resultLow, [R(1)] out uint resultHigh) - { - ulong result = _syscall.GetSystemTick(); - - resultLow = (uint)(result & uint.MaxValue); - resultHigh = (uint)(result >> 32); - } - - public KernelResult GetProcessId32([R(1)] int handle, [R(1)] out uint pidLow, [R(2)] out uint pidHigh) - { - KernelResult result = _syscall.GetProcessId(out ulong pid, handle); - - pidLow = (uint)(pid & uint.MaxValue); - pidHigh = (uint)(pid >> 32); - - return result; - } - - public void Break32([R(0)] uint reason, [R(1)] uint r1, [R(2)] uint info) - { - _syscall.Break(reason); - } - - public void OutputDebugString32([R(0)] uint strPtr, [R(1)] uint size) - { - _syscall.OutputDebugString(strPtr, size); - } - - public KernelResult GetInfo32( - [R(0)] uint subIdLow, - [R(1)] InfoType id, - [R(2)] int handle, - [R(3)] uint subIdHigh, - [R(1)] out uint valueLow, - [R(2)] out uint valueHigh) - { - long subId = (long)(subIdLow | ((ulong)subIdHigh << 32)); - - KernelResult result = _syscall.GetInfo(out ulong value, id, handle, subId); - - valueHigh = (uint)(value >> 32); - valueLow = (uint)(value & uint.MaxValue); - - return result; - } - - public KernelResult CreateEvent32([R(1)] out int wEventHandle, [R(2)] out int rEventHandle) - { - return _syscall.CreateEvent(out wEventHandle, out rEventHandle); - } - - public KernelResult GetProcessList32([R(1)] ulong address, [R(2)] int maxCount, [R(1)] out int count) - { - return _syscall.GetProcessList(out count, address, maxCount); - } - - public KernelResult GetSystemInfo32([R(1)] uint subIdLow, [R(2)] uint id, [R(3)] int handle, [R(3)] uint subIdHigh, [R(1)] out int valueLow, [R(2)] out int valueHigh) - { - long subId = (long)(subIdLow | ((ulong)subIdHigh << 32)); - - KernelResult result = _syscall.GetSystemInfo(out long value, id, handle, subId); - - valueHigh = (int)(value >> 32); - valueLow = (int)(value & uint.MaxValue); - - return result; - } - - public KernelResult GetResourceLimitLimitValue32([R(1)] int handle, [R(2)] LimitableResource resource, [R(1)] out int limitValueLow, [R(2)] out int limitValueHigh) - { - KernelResult result = _syscall.GetResourceLimitLimitValue(out long limitValue, handle, resource); - - limitValueHigh = (int)(limitValue >> 32); - limitValueLow = (int)(limitValue & uint.MaxValue); - - return result; - } - - public KernelResult GetResourceLimitCurrentValue32([R(1)] int handle, [R(2)] LimitableResource resource, [R(1)] out int limitValueLow, [R(2)] out int limitValueHigh) - { - KernelResult result = _syscall.GetResourceLimitCurrentValue(out long limitValue, handle, resource); - - limitValueHigh = (int)(limitValue >> 32); - limitValueLow = (int)(limitValue & uint.MaxValue); - - return result; - } - - public KernelResult GetResourceLimitPeakValue32([R(1)] int handle, [R(2)] LimitableResource resource, [R(1)] out int peakLow, [R(2)] out int peakHigh) - { - KernelResult result = _syscall.GetResourceLimitPeakValue(out long peak, handle, resource); - - peakHigh = (int)(peak >> 32); - peakLow = (int)(peak & uint.MaxValue); - - return result; - } - - public KernelResult CreateResourceLimit32([R(1)] out int handle) - { - return _syscall.CreateResourceLimit(out handle); - } - - public KernelResult SetResourceLimitLimitValue32([R(0)] int handle, [R(1)] LimitableResource resource, [R(2)] uint limitValueLow, [R(3)] uint limitValueHigh) - { - long limitValue = (long)(limitValueLow | ((ulong)limitValueHigh << 32)); - - return _syscall.SetResourceLimitLimitValue(handle, resource, limitValue); - } - - public KernelResult FlushProcessDataCache32( - [R(0)] uint processHandle, - [R(2)] uint addressLow, - [R(3)] uint addressHigh, - [R(1)] uint sizeLow, - [R(4)] uint sizeHigh) - { - // FIXME: This needs to be implemented as ARMv7 doesn't have any way to do cache maintenance operations on EL0. - // As we don't support (and don't actually need) to flush the cache, this is stubbed. - return KernelResult.Success; - } - - // Thread - - public KernelResult CreateThread32( - [R(1)] uint entrypoint, - [R(2)] uint argsPtr, - [R(3)] uint stackTop, - [R(0)] int priority, - [R(4)] int cpuCore, - [R(1)] out int handle) - { - return _syscall.CreateThread(out handle, entrypoint, argsPtr, stackTop, priority, cpuCore); - } - - public KernelResult StartThread32([R(0)] int handle) - { - return _syscall.StartThread(handle); - } - - public void ExitThread32() - { - _syscall.ExitThread(); - } - - public void SleepThread32([R(0)] uint timeoutLow, [R(1)] uint timeoutHigh) - { - long timeout = (long)(timeoutLow | ((ulong)timeoutHigh << 32)); - - _syscall.SleepThread(timeout); - } - - public KernelResult GetThreadPriority32([R(1)] int handle, [R(1)] out int priority) - { - return _syscall.GetThreadPriority(out priority, handle); - } - - public KernelResult SetThreadPriority32([R(0)] int handle, [R(1)] int priority) - { - return _syscall.SetThreadPriority(handle, priority); - } - - public KernelResult GetThreadCoreMask32([R(2)] int handle, [R(1)] out int preferredCore, [R(2)] out uint affinityMaskLow, [R(3)] out uint affinityMaskHigh) - { - KernelResult result = _syscall.GetThreadCoreMask(out preferredCore, out ulong affinityMask, handle); - - affinityMaskLow = (uint)(affinityMask & uint.MaxValue); - affinityMaskHigh = (uint)(affinityMask >> 32); - - return result; - } - - public KernelResult SetThreadCoreMask32([R(0)] int handle, [R(1)] int preferredCore, [R(2)] uint affinityMaskLow, [R(3)] uint affinityMaskHigh) - { - ulong affinityMask = affinityMaskLow | ((ulong)affinityMaskHigh << 32); - - return _syscall.SetThreadCoreMask(handle, preferredCore, affinityMask); - } - - public int GetCurrentProcessorNumber32() - { - return _syscall.GetCurrentProcessorNumber(); - } - - public KernelResult GetThreadId32([R(1)] int handle, [R(1)] out uint threadUidLow, [R(2)] out uint threadUidHigh) - { - ulong threadUid; - - KernelResult result = _syscall.GetThreadId(out threadUid, handle); - - threadUidLow = (uint)(threadUid >> 32); - threadUidHigh = (uint)(threadUid & uint.MaxValue); - - return result; - } - - public KernelResult SetThreadActivity32([R(0)] int handle, [R(1)] bool pause) - { - return _syscall.SetThreadActivity(handle, pause); - } - - public KernelResult GetThreadContext332([R(0)] uint address, [R(1)] int handle) - { - return _syscall.GetThreadContext3(address, handle); - } - - // Thread synchronization - - public KernelResult WaitSynchronization32( - [R(0)] uint timeoutLow, - [R(1)] uint handlesPtr, - [R(2)] int handlesCount, - [R(3)] uint timeoutHigh, - [R(1)] out int handleIndex) - { - long timeout = (long)(timeoutLow | ((ulong)timeoutHigh << 32)); - - return _syscall.WaitSynchronization(out handleIndex, handlesPtr, handlesCount, timeout); - } - - public KernelResult CancelSynchronization32([R(0)] int handle) - { - return _syscall.CancelSynchronization(handle); - } - - - public KernelResult ArbitrateLock32([R(0)] int ownerHandle, [R(1)] uint mutexAddress, [R(2)] int requesterHandle) - { - return _syscall.ArbitrateLock(ownerHandle, mutexAddress, requesterHandle); - } - - public KernelResult ArbitrateUnlock32([R(0)] uint mutexAddress) - { - return _syscall.ArbitrateUnlock(mutexAddress); - } - - public KernelResult WaitProcessWideKeyAtomic32( - [R(0)] uint mutexAddress, - [R(1)] uint condVarAddress, - [R(2)] int handle, - [R(3)] uint timeoutLow, - [R(4)] uint timeoutHigh) - { - long timeout = (long)(timeoutLow | ((ulong)timeoutHigh << 32)); - - return _syscall.WaitProcessWideKeyAtomic(mutexAddress, condVarAddress, handle, timeout); - } - - public KernelResult SignalProcessWideKey32([R(0)] uint address, [R(1)] int count) - { - return _syscall.SignalProcessWideKey(address, count); - } - - public KernelResult WaitForAddress32([R(0)] uint address, [R(1)] ArbitrationType type, [R(2)] int value, [R(3)] uint timeoutLow, [R(4)] uint timeoutHigh) - { - long timeout = (long)(timeoutLow | ((ulong)timeoutHigh << 32)); - - return _syscall.WaitForAddress(address, type, value, timeout); - } - - public KernelResult SignalToAddress32([R(0)] uint address, [R(1)] SignalType type, [R(2)] int value, [R(3)] int count) - { - return _syscall.SignalToAddress(address, type, value, count); - } - - public KernelResult SynchronizePreemptionState32() - { - return _syscall.SynchronizePreemptionState(); - } - } -} diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs deleted file mode 100644 index 76e853799..000000000 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall64.cs +++ /dev/null @@ -1,434 +0,0 @@ -using Ryujinx.HLE.HOS.Kernel.Common; -using Ryujinx.HLE.HOS.Kernel.Memory; -using Ryujinx.HLE.HOS.Kernel.Threading; - -namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall -{ - class Syscall64 - { - private readonly Syscall _syscall; - - public Syscall64(Syscall syscall) - { - _syscall = syscall; - } - - // IPC - - public KernelResult ConnectToNamedPort64([R(1)] ulong namePtr, [R(1)] out int handle) - { - return _syscall.ConnectToNamedPort(out handle, namePtr); - } - - public KernelResult SendSyncRequest64([R(0)] int handle) - { - return _syscall.SendSyncRequest(handle); - } - - public KernelResult SendSyncRequestWithUserBuffer64([R(0)] ulong messagePtr, [R(1)] ulong messageSize, [R(2)] int handle) - { - return _syscall.SendSyncRequestWithUserBuffer(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(out doneEventHandle, messagePtr, messageSize, handle); - } - - public KernelResult CreateSession64( - [R(2)] bool isLight, - [R(3)] ulong namePtr, - [R(1)] out int serverSessionHandle, - [R(2)] out int clientSessionHandle) - { - return _syscall.CreateSession(out serverSessionHandle, out clientSessionHandle, isLight, namePtr); - } - - public KernelResult AcceptSession64([R(1)] int portHandle, [R(1)] out int sessionHandle) - { - return _syscall.AcceptSession(out sessionHandle, portHandle); - } - - public KernelResult ReplyAndReceive64( - [R(1)] ulong handlesPtr, - [R(2)] int handlesCount, - [R(3)] int replyTargetHandle, - [R(4)] long timeout, - [R(1)] out int handleIndex) - { - return _syscall.ReplyAndReceive(out handleIndex, handlesPtr, handlesCount, replyTargetHandle, timeout); - } - - 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( - out handleIndex, - handlesPtr, - messagePtr, - messageSize, - handlesCount, - replyTargetHandle, - timeout); - } - - public KernelResult CreatePort64( - [R(2)] int maxSessions, - [R(3)] bool isLight, - [R(4)] ulong namePtr, - [R(1)] out int serverPortHandle, - [R(2)] out int clientPortHandle) - { - return _syscall.CreatePort(out serverPortHandle, out clientPortHandle, maxSessions, isLight, namePtr); - } - - public KernelResult ManageNamedPort64([R(1)] ulong namePtr, [R(2)] int maxSessions, [R(1)] out int handle) - { - return _syscall.ManageNamedPort(out handle, namePtr, maxSessions); - } - - public KernelResult ConnectToPort64([R(1)] int clientPortHandle, [R(1)] out int clientSessionHandle) - { - return _syscall.ConnectToPort(out clientSessionHandle, clientPortHandle); - } - - // Memory - - public KernelResult SetHeapSize64([R(1)] ulong size, [R(1)] out ulong address) - { - return _syscall.SetHeapSize(out address, size); - } - - public KernelResult SetMemoryPermission64( - [R(0)] ulong address, - [R(1)] ulong size, - [R(2)] KMemoryPermission permission) - { - return _syscall.SetMemoryPermission(address, size, permission); - } - - public KernelResult SetMemoryAttribute64( - [R(0)] ulong address, - [R(1)] ulong size, - [R(2)] MemoryAttribute attributeMask, - [R(3)] MemoryAttribute attributeValue) - { - return _syscall.SetMemoryAttribute(address, size, attributeMask, attributeValue); - } - - public KernelResult MapMemory64([R(0)] ulong dst, [R(1)] ulong src, [R(2)] ulong size) - { - return _syscall.MapMemory(dst, src, size); - } - - public KernelResult UnmapMemory64([R(0)] ulong dst, [R(1)] ulong src, [R(2)] ulong size) - { - return _syscall.UnmapMemory(dst, src, size); - } - - public KernelResult QueryMemory64([R(0)] ulong infoPtr, [R(2)] ulong address, [R(1)] out ulong pageInfo) - { - return _syscall.QueryMemory(infoPtr, out pageInfo, address); - } - - 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); - } - - public KernelResult UnmapSharedMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size) - { - return _syscall.UnmapSharedMemory(handle, address, size); - } - - public KernelResult CreateTransferMemory64( - [R(1)] ulong address, - [R(2)] ulong size, - [R(3)] KMemoryPermission permission, - [R(1)] out int handle) - { - return _syscall.CreateTransferMemory(out handle, address, size, permission); - } - - public KernelResult CreateCodeMemory64([R(1)] ulong address, [R(2)] ulong size, [R(1)] out int handle) - { - return _syscall.CreateCodeMemory(address, size, out handle); - } - - public KernelResult ControlCodeMemory64([R(0)] int handle, [R(1)] CodeMemoryOperation op, [R(2)] ulong address, [R(3)] ulong size, [R(4)] KMemoryPermission permission) - { - return _syscall.ControlCodeMemory(handle, op, address, size, permission); - } - - public KernelResult MapTransferMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size, [R(3)] KMemoryPermission permission) - { - return _syscall.MapTransferMemory(handle, address, size, permission); - } - - public KernelResult UnmapTransferMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size) - { - return _syscall.UnmapTransferMemory(handle, address, size); - } - - public KernelResult MapPhysicalMemory64([R(0)] ulong address, [R(1)] ulong size) - { - return _syscall.MapPhysicalMemory(address, size); - } - - public KernelResult UnmapPhysicalMemory64([R(0)] ulong address, [R(1)] ulong size) - { - return _syscall.UnmapPhysicalMemory(address, size); - } - - 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); - } - - public KernelResult MapProcessMemory64([R(0)] ulong dst, [R(1)] int handle, [R(2)] ulong src, [R(3)] ulong size) - { - return _syscall.MapProcessMemory(dst, handle, src, size); - } - - public KernelResult UnmapProcessMemory64([R(0)] ulong dst, [R(1)] int handle, [R(2)] ulong src, [R(3)] ulong size) - { - return _syscall.UnmapProcessMemory(dst, handle, src, size); - } - - public KernelResult MapProcessCodeMemory64([R(0)] int handle, [R(1)] ulong dst, [R(2)] ulong src, [R(3)] ulong size) - { - return _syscall.MapProcessCodeMemory(handle, dst, src, size); - } - - public KernelResult UnmapProcessCodeMemory64([R(0)] int handle, [R(1)] ulong dst, [R(2)] ulong src, [R(3)] ulong size) - { - return _syscall.UnmapProcessCodeMemory(handle, dst, src, size); - } - - // System - - public void ExitProcess64() - { - _syscall.ExitProcess(); - } - - public KernelResult TerminateProcess64([R(0)] int handle) - { - return _syscall.TerminateProcess(handle); - } - - public KernelResult SignalEvent64([R(0)] int handle) - { - return _syscall.SignalEvent(handle); - } - - public KernelResult ClearEvent64([R(0)] int handle) - { - return _syscall.ClearEvent(handle); - } - - public KernelResult CloseHandle64([R(0)] int handle) - { - return _syscall.CloseHandle(handle); - } - - public KernelResult ResetSignal64([R(0)] int handle) - { - return _syscall.ResetSignal(handle); - } - - public ulong GetSystemTick64() - { - return _syscall.GetSystemTick(); - } - - public KernelResult GetProcessId64([R(1)] int handle, [R(1)] out ulong pid) - { - return _syscall.GetProcessId(out pid, handle); - } - - public void Break64([R(0)] ulong reason, [R(1)] ulong x1, [R(2)] ulong info) - { - _syscall.Break(reason); - } - - public void OutputDebugString64([R(0)] ulong strPtr, [R(1)] ulong size) - { - _syscall.OutputDebugString(strPtr, size); - } - - public KernelResult GetInfo64([R(1)] InfoType id, [R(2)] int handle, [R(3)] long subId, [R(1)] out ulong value) - { - return _syscall.GetInfo(out value, id, handle, subId); - } - - public KernelResult CreateEvent64([R(1)] out int wEventHandle, [R(2)] out int rEventHandle) - { - return _syscall.CreateEvent(out wEventHandle, out rEventHandle); - } - - public KernelResult GetProcessList64([R(1)] ulong address, [R(2)] int maxCount, [R(1)] out int count) - { - return _syscall.GetProcessList(out count, address, maxCount); - } - - public KernelResult GetSystemInfo64([R(1)] uint id, [R(2)] int handle, [R(3)] long subId, [R(1)] out long value) - { - return _syscall.GetSystemInfo(out value, id, handle, subId); - } - - public KernelResult GetResourceLimitLimitValue64([R(1)] int handle, [R(2)] LimitableResource resource, [R(1)] out long limitValue) - { - return _syscall.GetResourceLimitLimitValue(out limitValue, handle, resource); - } - - public KernelResult GetResourceLimitCurrentValue64([R(1)] int handle, [R(2)] LimitableResource resource, [R(1)] out long limitValue) - { - return _syscall.GetResourceLimitCurrentValue(out limitValue, handle, resource); - } - - public KernelResult GetResourceLimitPeakValue64([R(1)] int handle, [R(2)] LimitableResource resource, [R(1)] out long peak) - { - return _syscall.GetResourceLimitPeakValue(out peak, handle, resource); - } - - public KernelResult CreateResourceLimit64([R(1)] out int handle) - { - return _syscall.CreateResourceLimit(out handle); - } - - public KernelResult SetResourceLimitLimitValue64([R(0)] int handle, [R(1)] LimitableResource resource, [R(2)] long limitValue) - { - return _syscall.SetResourceLimitLimitValue(handle, resource, limitValue); - } - - // Thread - - public KernelResult CreateThread64( - [R(1)] ulong entrypoint, - [R(2)] ulong argsPtr, - [R(3)] ulong stackTop, - [R(4)] int priority, - [R(5)] int cpuCore, - [R(1)] out int handle) - { - return _syscall.CreateThread(out handle, entrypoint, argsPtr, stackTop, priority, cpuCore); - } - - public KernelResult StartThread64([R(0)] int handle) - { - return _syscall.StartThread(handle); - } - - public void ExitThread64() - { - _syscall.ExitThread(); - } - - public void SleepThread64([R(0)] long timeout) - { - _syscall.SleepThread(timeout); - } - - public KernelResult GetThreadPriority64([R(1)] int handle, [R(1)] out int priority) - { - return _syscall.GetThreadPriority(out priority, handle); - } - - public KernelResult SetThreadPriority64([R(0)] int handle, [R(1)] int priority) - { - return _syscall.SetThreadPriority(handle, priority); - } - - public KernelResult GetThreadCoreMask64([R(2)] int handle, [R(1)] out int preferredCore, [R(2)] out ulong affinityMask) - { - return _syscall.GetThreadCoreMask(out preferredCore, out affinityMask, handle); - } - - public KernelResult SetThreadCoreMask64([R(0)] int handle, [R(1)] int preferredCore, [R(2)] ulong affinityMask) - { - return _syscall.SetThreadCoreMask(handle, preferredCore, affinityMask); - } - - public int GetCurrentProcessorNumber64() - { - return _syscall.GetCurrentProcessorNumber(); - } - - public KernelResult GetThreadId64([R(1)] int handle, [R(1)] out ulong threadUid) - { - return _syscall.GetThreadId(out threadUid, handle); - } - - public KernelResult SetThreadActivity64([R(0)] int handle, [R(1)] bool pause) - { - return _syscall.SetThreadActivity(handle, pause); - } - - public KernelResult GetThreadContext364([R(0)] ulong address, [R(1)] int handle) - { - return _syscall.GetThreadContext3(address, handle); - } - - // Thread synchronization - - public KernelResult WaitSynchronization64([R(1)] ulong handlesPtr, [R(2)] int handlesCount, [R(3)] long timeout, [R(1)] out int handleIndex) - { - return _syscall.WaitSynchronization(out handleIndex, handlesPtr, handlesCount, timeout); - } - - public KernelResult CancelSynchronization64([R(0)] int handle) - { - return _syscall.CancelSynchronization(handle); - } - - public KernelResult ArbitrateLock64([R(0)] int ownerHandle, [R(1)] ulong mutexAddress, [R(2)] int requesterHandle) - { - return _syscall.ArbitrateLock(ownerHandle, mutexAddress, requesterHandle); - } - - public KernelResult ArbitrateUnlock64([R(0)] ulong mutexAddress) - { - return _syscall.ArbitrateUnlock(mutexAddress); - } - - public KernelResult WaitProcessWideKeyAtomic64( - [R(0)] ulong mutexAddress, - [R(1)] ulong condVarAddress, - [R(2)] int handle, - [R(3)] long timeout) - { - return _syscall.WaitProcessWideKeyAtomic(mutexAddress, condVarAddress, handle, timeout); - } - - public KernelResult SignalProcessWideKey64([R(0)] ulong address, [R(1)] int count) - { - return _syscall.SignalProcessWideKey(address, count); - } - - public KernelResult WaitForAddress64([R(0)] ulong address, [R(1)] ArbitrationType type, [R(2)] int value, [R(3)] long timeout) - { - return _syscall.WaitForAddress(address, type, value, timeout); - } - - public KernelResult SignalToAddress64([R(0)] ulong address, [R(1)] SignalType type, [R(2)] int value, [R(3)] int count) - { - return _syscall.SignalToAddress(address, type, value, count); - } - - public KernelResult SynchronizePreemptionState64() - { - return _syscall.SynchronizePreemptionState(); - } - } -} diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallHandler.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallHandler.cs index cb693f595..710bac946 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallHandler.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallHandler.cs @@ -1,20 +1,15 @@ using Ryujinx.Cpu; using Ryujinx.HLE.HOS.Kernel.Threading; -using System; namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall { partial class SyscallHandler { private readonly KernelContext _context; - private readonly Syscall32 _syscall32; - private readonly Syscall64 _syscall64; public SyscallHandler(KernelContext context) { _context = context; - _syscall32 = new Syscall32(context.Syscall); - _syscall64 = new Syscall64(context.Syscall); } public void SvcCall(IExecutionContext context, ulong address, int id) @@ -36,25 +31,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall if (context.IsAarch32) { - var svcFunc = SyscallTable.SvcTable32[id]; - - if (svcFunc == null) - { - throw new NotImplementedException($"SVC 0x{id:X4} is not implemented."); - } - - svcFunc(_syscall32, context); + SyscallDispatch.Dispatch32(_context.Syscall, context, id); } else { - var svcFunc = SyscallTable.SvcTable64[id]; - - if (svcFunc == null) - { - throw new NotImplementedException($"SVC 0x{id:X4} is not implemented."); - } - - svcFunc(_syscall64, context); + SyscallDispatch.Dispatch64(_context.Syscall, context, id); } currentThread.HandlePostSyscall(); diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallTable.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallTable.cs deleted file mode 100644 index 8b7e7fb8f..000000000 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallTable.cs +++ /dev/null @@ -1,494 +0,0 @@ -using Ryujinx.Common.Logging; -using Ryujinx.Cpu; -using Ryujinx.HLE.HOS.Kernel.Common; -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Reflection.Emit; - -namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall -{ - static class SyscallTable - { - private const int SvcFuncMaxArguments64 = 8; - private const int SvcFuncMaxArguments32 = 4; - private const int SvcMax = 0x80; - - public static Action[] SvcTable32 { get; } - public static Action[] SvcTable64 { get; } - - static SyscallTable() - { - SvcTable32 = new Action[SvcMax]; - SvcTable64 = new Action[SvcMax]; - - Dictionary svcFuncs64 = new Dictionary - { - { 0x01, nameof(Syscall64.SetHeapSize64) }, - { 0x02, nameof(Syscall64.SetMemoryPermission64) }, - { 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) }, - { 0x30, nameof(Syscall64.GetResourceLimitLimitValue64) }, - { 0x31, nameof(Syscall64.GetResourceLimitCurrentValue64) }, - { 0x32, nameof(Syscall64.SetThreadActivity64) }, - { 0x33, nameof(Syscall64.GetThreadContext364) }, - { 0x34, nameof(Syscall64.WaitForAddress64) }, - { 0x35, nameof(Syscall64.SignalToAddress64) }, - { 0x36, nameof(Syscall64.SynchronizePreemptionState64) }, - { 0x37, nameof(Syscall64.GetResourceLimitPeakValue64) }, - { 0x40, nameof(Syscall64.CreateSession64) }, - { 0x41, nameof(Syscall64.AcceptSession64) }, - { 0x43, nameof(Syscall64.ReplyAndReceive64) }, - { 0x44, nameof(Syscall64.ReplyAndReceiveWithUserBuffer64) }, - { 0x45, nameof(Syscall64.CreateEvent64) }, - { 0x4b, nameof(Syscall64.CreateCodeMemory64) }, - { 0x4c, nameof(Syscall64.ControlCodeMemory64) }, - { 0x51, nameof(Syscall64.MapTransferMemory64) }, - { 0x52, nameof(Syscall64.UnmapTransferMemory64) }, - { 0x65, nameof(Syscall64.GetProcessList64) }, - { 0x6f, nameof(Syscall64.GetSystemInfo64) }, - { 0x70, nameof(Syscall64.CreatePort64) }, - { 0x71, nameof(Syscall64.ManageNamedPort64) }, - { 0x72, nameof(Syscall64.ConnectToPort64) }, - { 0x73, nameof(Syscall64.SetProcessMemoryPermission64) }, - { 0x74, nameof(Syscall64.MapProcessMemory64) }, - { 0x75, nameof(Syscall64.UnmapProcessMemory64) }, - { 0x77, nameof(Syscall64.MapProcessCodeMemory64) }, - { 0x78, nameof(Syscall64.UnmapProcessCodeMemory64) }, - { 0x7B, nameof(Syscall64.TerminateProcess64) }, - { 0x7D, nameof(Syscall64.CreateResourceLimit64) }, - { 0x7E, nameof(Syscall64.SetResourceLimitLimitValue64) } - }; - - foreach (KeyValuePair value in svcFuncs64) - { - SvcTable64[value.Key] = GenerateMethod(value.Value, SvcFuncMaxArguments64); - } - - Dictionary svcFuncs32 = new Dictionary - { - { 0x01, nameof(Syscall32.SetHeapSize32) }, - { 0x02, nameof(Syscall32.SetMemoryPermission32) }, - { 0x03, nameof(Syscall32.SetMemoryAttribute32) }, - { 0x04, nameof(Syscall32.MapMemory32) }, - { 0x05, nameof(Syscall32.UnmapMemory32) }, - { 0x06, nameof(Syscall32.QueryMemory32) }, - { 0x07, nameof(Syscall32.ExitProcess32) }, - { 0x08, nameof(Syscall32.CreateThread32) }, - { 0x09, nameof(Syscall32.StartThread32) }, - { 0x0a, nameof(Syscall32.ExitThread32) }, - { 0x0b, nameof(Syscall32.SleepThread32) }, - { 0x0c, nameof(Syscall32.GetThreadPriority32) }, - { 0x0d, nameof(Syscall32.SetThreadPriority32) }, - { 0x0e, nameof(Syscall32.GetThreadCoreMask32) }, - { 0x0f, nameof(Syscall32.SetThreadCoreMask32) }, - { 0x10, nameof(Syscall32.GetCurrentProcessorNumber32) }, - { 0x11, nameof(Syscall32.SignalEvent32) }, - { 0x12, nameof(Syscall32.ClearEvent32) }, - { 0x13, nameof(Syscall32.MapSharedMemory32) }, - { 0x14, nameof(Syscall32.UnmapSharedMemory32) }, - { 0x15, nameof(Syscall32.CreateTransferMemory32) }, - { 0x16, nameof(Syscall32.CloseHandle32) }, - { 0x17, nameof(Syscall32.ResetSignal32) }, - { 0x18, nameof(Syscall32.WaitSynchronization32) }, - { 0x19, nameof(Syscall32.CancelSynchronization32) }, - { 0x1a, nameof(Syscall32.ArbitrateLock32) }, - { 0x1b, nameof(Syscall32.ArbitrateUnlock32) }, - { 0x1c, nameof(Syscall32.WaitProcessWideKeyAtomic32) }, - { 0x1d, nameof(Syscall32.SignalProcessWideKey32) }, - { 0x1e, nameof(Syscall32.GetSystemTick32) }, - { 0x1f, nameof(Syscall32.ConnectToNamedPort32) }, - { 0x21, nameof(Syscall32.SendSyncRequest32) }, - { 0x22, nameof(Syscall32.SendSyncRequestWithUserBuffer32) }, - { 0x24, nameof(Syscall32.GetProcessId32) }, - { 0x25, nameof(Syscall32.GetThreadId32) }, - { 0x26, nameof(Syscall32.Break32) }, - { 0x27, nameof(Syscall32.OutputDebugString32) }, - { 0x29, nameof(Syscall32.GetInfo32) }, - { 0x2c, nameof(Syscall32.MapPhysicalMemory32) }, - { 0x2d, nameof(Syscall32.UnmapPhysicalMemory32) }, - { 0x30, nameof(Syscall32.GetResourceLimitLimitValue32) }, - { 0x31, nameof(Syscall32.GetResourceLimitCurrentValue32) }, - { 0x32, nameof(Syscall32.SetThreadActivity32) }, - { 0x33, nameof(Syscall32.GetThreadContext332) }, - { 0x34, nameof(Syscall32.WaitForAddress32) }, - { 0x35, nameof(Syscall32.SignalToAddress32) }, - { 0x36, nameof(Syscall32.SynchronizePreemptionState32) }, - { 0x37, nameof(Syscall32.GetResourceLimitPeakValue32) }, - { 0x40, nameof(Syscall32.CreateSession32) }, - { 0x41, nameof(Syscall32.AcceptSession32) }, - { 0x43, nameof(Syscall32.ReplyAndReceive32) }, - { 0x45, nameof(Syscall32.CreateEvent32) }, - { 0x4b, nameof(Syscall32.CreateCodeMemory32) }, - { 0x4c, nameof(Syscall32.ControlCodeMemory32) }, - { 0x51, nameof(Syscall32.MapTransferMemory32) }, - { 0x52, nameof(Syscall32.UnmapTransferMemory32) }, - { 0x5F, nameof(Syscall32.FlushProcessDataCache32) }, - { 0x65, nameof(Syscall32.GetProcessList32) }, - { 0x6f, nameof(Syscall32.GetSystemInfo32) }, - { 0x70, nameof(Syscall32.CreatePort32) }, - { 0x71, nameof(Syscall32.ManageNamedPort32) }, - { 0x72, nameof(Syscall32.ConnectToPort32) }, - { 0x73, nameof(Syscall32.SetProcessMemoryPermission32) }, - { 0x74, nameof(Syscall32.MapProcessMemory32) }, - { 0x75, nameof(Syscall32.UnmapProcessMemory32) }, - { 0x77, nameof(Syscall32.MapProcessCodeMemory32) }, - { 0x78, nameof(Syscall32.UnmapProcessCodeMemory32) }, - { 0x7B, nameof(Syscall32.TerminateProcess32) }, - { 0x7D, nameof(Syscall32.CreateResourceLimit32) }, - { 0x7E, nameof(Syscall32.SetResourceLimitLimitValue32) } - }; - - foreach (KeyValuePair value in svcFuncs32) - { - SvcTable32[value.Key] = GenerateMethod(value.Value, SvcFuncMaxArguments32); - } - } - - private static Action GenerateMethod(string svcName, int registerCleanCount) - { - Type[] argTypes = new Type[] { typeof(T), typeof(IExecutionContext) }; - - DynamicMethod method = new DynamicMethod(svcName, null, argTypes); - - MethodInfo methodInfo = typeof(T).GetMethod(svcName); - - ParameterInfo[] methodArgs = methodInfo.GetParameters(); - - ILGenerator generator = method.GetILGenerator(); - - void ConvertToArgType(Type sourceType) - { - CheckIfTypeIsSupported(sourceType, svcName); - - switch (Type.GetTypeCode(sourceType)) - { - case TypeCode.UInt32: generator.Emit(OpCodes.Conv_U4); break; - case TypeCode.Int32: generator.Emit(OpCodes.Conv_I4); break; - case TypeCode.UInt16: generator.Emit(OpCodes.Conv_U2); break; - case TypeCode.Int16: generator.Emit(OpCodes.Conv_I2); break; - case TypeCode.Byte: generator.Emit(OpCodes.Conv_U1); break; - case TypeCode.SByte: generator.Emit(OpCodes.Conv_I1); break; - - case TypeCode.Boolean: - generator.Emit(OpCodes.Conv_I4); - generator.Emit(OpCodes.Ldc_I4_1); - generator.Emit(OpCodes.And); - break; - } - } - - void ConvertToFieldType(Type sourceType) - { - CheckIfTypeIsSupported(sourceType, svcName); - - switch (Type.GetTypeCode(sourceType)) - { - case TypeCode.UInt32: - case TypeCode.Int32: - case TypeCode.UInt16: - case TypeCode.Int16: - case TypeCode.Byte: - case TypeCode.SByte: - case TypeCode.Boolean: - generator.Emit(OpCodes.Conv_U8); - break; - } - } - - RAttribute GetRegisterAttribute(ParameterInfo parameterInfo) - { - RAttribute argumentAttribute = (RAttribute)parameterInfo.GetCustomAttribute(typeof(RAttribute)); - - if (argumentAttribute == null) - { - throw new InvalidOperationException($"Method \"{svcName}\" is missing a {typeof(RAttribute).Name} attribute on parameter \"{parameterInfo.Name}\""); - } - - return argumentAttribute; - } - - // For functions returning output values, the first registers - // are used to hold pointers where the value will be stored, - // so they can't be used to pass argument and we must - // skip them. - int byRefArgsCount = 0; - - for (int index = 0; index < methodArgs.Length; index++) - { - if (methodArgs[index].ParameterType.IsByRef) - { - byRefArgsCount++; - } - } - - BindingFlags staticNonPublic = BindingFlags.NonPublic | BindingFlags.Static; - - // Print all the arguments for debugging purposes. - int inputArgsCount = methodArgs.Length - byRefArgsCount; - - if (inputArgsCount != 0) - { - generator.Emit(OpCodes.Ldc_I4, inputArgsCount); - - generator.Emit(OpCodes.Newarr, typeof(object)); - - string argsFormat = svcName; - - for (int index = 0; index < methodArgs.Length; index++) - { - Type argType = methodArgs[index].ParameterType; - - // Ignore out argument for printing - if (argType.IsByRef) - { - continue; - } - - RAttribute registerAttribute = GetRegisterAttribute(methodArgs[index]); - - argsFormat += $" {methodArgs[index].Name}: 0x{{{index}:X8}},"; - - generator.Emit(OpCodes.Dup); - generator.Emit(OpCodes.Ldc_I4, index); - - generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Ldc_I4, registerAttribute.Index); - - MethodInfo info = typeof(IExecutionContext).GetMethod(nameof(IExecutionContext.GetX)); - - generator.Emit(OpCodes.Callvirt, info); - - generator.Emit(OpCodes.Box, typeof(ulong)); - - generator.Emit(OpCodes.Stelem_Ref); - } - - argsFormat = argsFormat.Substring(0, argsFormat.Length - 1); - - generator.Emit(OpCodes.Ldstr, argsFormat); - } - else - { - generator.Emit(OpCodes.Ldnull); - - generator.Emit(OpCodes.Ldstr, svcName); - } - - MethodInfo printArgsMethod = typeof(SyscallTable).GetMethod(nameof(PrintArguments), staticNonPublic); - - generator.Emit(OpCodes.Call, printArgsMethod); - - // Call the SVC function handler. - generator.Emit(OpCodes.Ldarg_0); - - List<(LocalBuilder, RAttribute)> locals = new List<(LocalBuilder, RAttribute)>(); - - for (int index = 0; index < methodArgs.Length; index++) - { - Type argType = methodArgs[index].ParameterType; - RAttribute registerAttribute = GetRegisterAttribute(methodArgs[index]); - - if (argType.IsByRef) - { - argType = argType.GetElementType(); - - LocalBuilder local = generator.DeclareLocal(argType); - - locals.Add((local, registerAttribute)); - - if (!methodArgs[index].IsOut) - { - generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Ldc_I4, registerAttribute.Index); - - MethodInfo info = typeof(IExecutionContext).GetMethod(nameof(IExecutionContext.GetX)); - - generator.Emit(OpCodes.Callvirt, info); - - ConvertToArgType(argType); - - generator.Emit(OpCodes.Stloc, local); - } - - generator.Emit(OpCodes.Ldloca, local); - } - else - { - generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Ldc_I4, registerAttribute.Index); - - MethodInfo info = typeof(IExecutionContext).GetMethod(nameof(IExecutionContext.GetX)); - - generator.Emit(OpCodes.Callvirt, info); - - ConvertToArgType(argType); - } - } - - generator.Emit(OpCodes.Call, methodInfo); - - Type retType = methodInfo.ReturnType; - - // Print result code. - if (retType == typeof(KernelResult)) - { - MethodInfo printResultMethod = typeof(SyscallTable).GetMethod(nameof(PrintResult), staticNonPublic); - - generator.Emit(OpCodes.Dup); - generator.Emit(OpCodes.Ldstr, svcName); - generator.Emit(OpCodes.Call, printResultMethod); - } - - uint registerInUse = 0; - - // Save return value into register X0 (when the method has a return value). - if (retType != typeof(void)) - { - CheckIfTypeIsSupported(retType, svcName); - - LocalBuilder tempLocal = generator.DeclareLocal(retType); - - generator.Emit(OpCodes.Stloc, tempLocal); - generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Ldc_I4, 0); - generator.Emit(OpCodes.Ldloc, tempLocal); - - ConvertToFieldType(retType); - - MethodInfo info = typeof(IExecutionContext).GetMethod(nameof(IExecutionContext.SetX)); - - generator.Emit(OpCodes.Callvirt, info); - - registerInUse |= 1u << 0; - } - - for (int index = 0; index < locals.Count; index++) - { - (LocalBuilder local, RAttribute attribute) = locals[index]; - - if ((registerInUse & (1u << attribute.Index)) != 0) - { - throw new InvalidSvcException($"Method \"{svcName}\" has conflicting output values at register index \"{attribute.Index}\"."); - } - - generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Ldc_I4, attribute.Index); - generator.Emit(OpCodes.Ldloc, local); - - ConvertToFieldType(local.LocalType); - - MethodInfo info = typeof(IExecutionContext).GetMethod(nameof(IExecutionContext.SetX)); - - generator.Emit(OpCodes.Callvirt, info); - - registerInUse |= 1u << attribute.Index; - } - - // Zero out the remaining unused registers. - for (int i = 0; i < registerCleanCount; i++) - { - if ((registerInUse & (1u << i)) != 0) - { - continue; - } - - generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Ldc_I4, i); - generator.Emit(OpCodes.Ldc_I8, 0L); - - MethodInfo info = typeof(IExecutionContext).GetMethod(nameof(IExecutionContext.SetX)); - - generator.Emit(OpCodes.Callvirt, info); - } - - generator.Emit(OpCodes.Ret); - - return method.CreateDelegate>(); - } - - private static void CheckIfTypeIsSupported(Type type, string svcName) - { - switch (Type.GetTypeCode(type)) - { - case TypeCode.UInt64: - case TypeCode.Int64: - case TypeCode.UInt32: - case TypeCode.Int32: - case TypeCode.UInt16: - case TypeCode.Int16: - case TypeCode.Byte: - case TypeCode.SByte: - case TypeCode.Boolean: - return; - } - - throw new InvalidSvcException($"Method \"{svcName}\" has a invalid ref type \"{type.Name}\"."); - } - - private static void PrintArguments(object[] argValues, string formatOrSvcName) - { - if (argValues != null) - { - Logger.Trace?.Print(LogClass.KernelSvc, string.Format(formatOrSvcName, argValues)); - } - else - { - Logger.Trace?.Print(LogClass.KernelSvc, formatOrSvcName); - } - } - - private static void PrintResult(KernelResult result, string svcName) - { - if (result != KernelResult.Success && - result != KernelResult.TimedOut && - result != KernelResult.Cancelled && - result != KernelResult.PortRemoteClosed && - result != KernelResult.InvalidState) - { - Logger.Warning?.Print(LogClass.KernelSvc, $"{svcName} returned error {result}."); - } - else - { - Logger.Trace?.Print(LogClass.KernelSvc, $"{svcName} returned result {result}."); - } - } - } -} diff --git a/Ryujinx.HLE/Ryujinx.HLE.csproj b/Ryujinx.HLE/Ryujinx.HLE.csproj index 4713c9b31..91d82755c 100644 --- a/Ryujinx.HLE/Ryujinx.HLE.csproj +++ b/Ryujinx.HLE/Ryujinx.HLE.csproj @@ -11,6 +11,9 @@ + diff --git a/Ryujinx.Horizon.Generators/CodeGenerator.cs b/Ryujinx.Horizon.Generators/CodeGenerator.cs new file mode 100644 index 000000000..80a33c66c --- /dev/null +++ b/Ryujinx.Horizon.Generators/CodeGenerator.cs @@ -0,0 +1,58 @@ +using System.Text; + +namespace Ryujinx.Horizon.Generators +{ + class CodeGenerator + { + private const string Indent = " "; + private readonly StringBuilder _sb; + private string _currentIndent; + + public CodeGenerator() + { + _sb = new StringBuilder(); + } + + public void EnterScope(string header = null) + { + if (header != null) + { + AppendLine(header); + } + + AppendLine("{"); + IncreaseIndentation(); + } + + public void LeaveScope() + { + DecreaseIndentation(); + AppendLine("}"); + } + + public void IncreaseIndentation() + { + _currentIndent += Indent; + } + + public void DecreaseIndentation() + { + _currentIndent = _currentIndent.Substring(0, _currentIndent.Length - Indent.Length); + } + + public void AppendLine() + { + _sb.AppendLine(); + } + + public void AppendLine(string text) + { + _sb.AppendLine(_currentIndent + text); + } + + public override string ToString() + { + return _sb.ToString(); + } + } +} diff --git a/Ryujinx.Horizon.Generators/Kernel/SyscallGenerator.cs b/Ryujinx.Horizon.Generators/Kernel/SyscallGenerator.cs new file mode 100644 index 000000000..2681551b1 --- /dev/null +++ b/Ryujinx.Horizon.Generators/Kernel/SyscallGenerator.cs @@ -0,0 +1,524 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Ryujinx.Horizon.Generators.Kernel +{ + [Generator] + class SyscallGenerator : ISourceGenerator + { + private const string ClassNamespace = "Ryujinx.HLE.HOS.Kernel.SupervisorCall"; + private const string ClassName = "SyscallDispatch"; + private const string A32Suffix = "32"; + private const string A64Suffix = "64"; + private const string ResultVariableName = "result"; + private const string ArgVariablePrefix = "arg"; + private const string ResultCheckHelperName = "LogResultAsTrace"; + + private const string TypeSystemBoolean = "System.Boolean"; + private const string TypeSystemInt32 = "System.Int32"; + private const string TypeSystemInt64 = "System.Int64"; + private const string TypeSystemUInt32 = "System.UInt32"; + private const string TypeSystemUInt64 = "System.UInt64"; + + private const string NamespaceKernel = "Ryujinx.HLE.HOS.Kernel"; + private const string TypeSvcAttribute = NamespaceKernel + ".SupervisorCall.SvcAttribute"; + private const string TypePointerSizedAttribute = NamespaceKernel + ".SupervisorCall.PointerSizedAttribute"; + private const string TypeKernelResultName = "KernelResult"; + private const string TypeKernelResult = NamespaceKernel + ".Common." + TypeKernelResultName; + private const string TypeExecutionContext = "IExecutionContext"; + + private static readonly string[] _expectedResults = new string[] + { + $"{TypeKernelResultName}.Success", + $"{TypeKernelResultName}.TimedOut", + $"{TypeKernelResultName}.Cancelled", + $"{TypeKernelResultName}.PortRemoteClosed", + $"{TypeKernelResultName}.InvalidState" + }; + + private struct OutParameter + { + public readonly string Identifier; + public readonly bool NeedsSplit; + + public OutParameter(string identifier, bool needsSplit = false) + { + Identifier = identifier; + NeedsSplit = needsSplit; + } + } + + private struct RegisterAllocatorA32 + { + private uint _useSet; + private int _linearIndex; + + public int AllocateSingle() + { + return Allocate(); + } + + public (int, int) AllocatePair() + { + _linearIndex += _linearIndex & 1; + + return (Allocate(), Allocate()); + } + + private int Allocate() + { + int regIndex; + + if (_linearIndex < 4) + { + regIndex = _linearIndex++; + } + else + { + regIndex = -1; + + for (int i = 0; i < 32; i++) + { + if ((_useSet & (1 << i)) == 0) + { + regIndex = i; + break; + } + } + + Debug.Assert(regIndex != -1); + } + + _useSet |= 1u << regIndex; + + return regIndex; + } + + public void AdvanceLinearIndex() + { + _linearIndex++; + } + } + + private struct SyscallIdAndName : IComparable + { + public readonly int Id; + public readonly string Name; + + public SyscallIdAndName(int id, string name) + { + Id = id; + Name = name; + } + + public int CompareTo(SyscallIdAndName other) + { + return Id.CompareTo(other.Id); + } + } + + public void Execute(GeneratorExecutionContext context) + { + SyscallSyntaxReceiver syntaxReceiver = (SyscallSyntaxReceiver)context.SyntaxReceiver; + + CodeGenerator generator = new CodeGenerator(); + + generator.AppendLine("using Ryujinx.Common.Logging;"); + generator.AppendLine("using Ryujinx.Cpu;"); + generator.AppendLine($"using {NamespaceKernel}.Common;"); + generator.AppendLine($"using {NamespaceKernel}.Memory;"); + generator.AppendLine($"using {NamespaceKernel}.Process;"); + generator.AppendLine($"using {NamespaceKernel}.Threading;"); + generator.AppendLine("using System;"); + generator.AppendLine(); + generator.EnterScope($"namespace {ClassNamespace}"); + generator.EnterScope($"static class {ClassName}"); + + GenerateResultCheckHelper(generator); + generator.AppendLine(); + + List syscalls = new List(); + + foreach (var method in syntaxReceiver.SvcImplementations) + { + GenerateMethod32(generator, context.Compilation, method); + GenerateMethod64(generator, context.Compilation, method); + + foreach (var attributeList in method.AttributeLists) + { + foreach (var attribute in attributeList.Attributes) + { + if (GetCanonicalTypeName(context.Compilation, attribute) != TypeSvcAttribute) + { + continue; + } + + foreach (var attributeArg in attribute.ArgumentList.Arguments) + { + if (attributeArg.Expression.Kind() == SyntaxKind.NumericLiteralExpression) + { + LiteralExpressionSyntax numericLiteral = (LiteralExpressionSyntax)attributeArg.Expression; + syscalls.Add(new SyscallIdAndName((int)numericLiteral.Token.Value, method.Identifier.Text)); + } + } + } + } + } + + syscalls.Sort(); + + GenerateDispatch(generator, syscalls, A32Suffix); + generator.AppendLine(); + GenerateDispatch(generator, syscalls, A64Suffix); + + generator.LeaveScope(); + generator.LeaveScope(); + + context.AddSource($"{ClassName}.g.cs", generator.ToString()); + } + + private static void GenerateResultCheckHelper(CodeGenerator generator) + { + generator.EnterScope($"private static bool {ResultCheckHelperName}({TypeKernelResultName} {ResultVariableName})"); + + string[] expectedChecks = new string[_expectedResults.Length]; + + for (int i = 0; i < expectedChecks.Length; i++) + { + expectedChecks[i] = $"{ResultVariableName} == {_expectedResults[i]}"; + } + + string checks = string.Join(" || ", expectedChecks); + + generator.AppendLine($"return {checks};"); + generator.LeaveScope(); + } + + private static void GenerateMethod32(CodeGenerator generator, Compilation compilation, MethodDeclarationSyntax method) + { + generator.EnterScope($"private static void {method.Identifier.Text}{A32Suffix}(Syscall syscall, {TypeExecutionContext} context)"); + + string[] args = new string[method.ParameterList.Parameters.Count]; + int index = 0; + + RegisterAllocatorA32 regAlloc = new RegisterAllocatorA32(); + + List outParameters = new List(); + List logInArgs = new List(); + List logOutArgs = new List(); + + foreach (var methodParameter in method.ParameterList.Parameters) + { + string name = methodParameter.Identifier.Text; + string argName = GetPrefixedArgName(name); + string typeName = methodParameter.Type.ToString(); + string canonicalTypeName = GetCanonicalTypeName(compilation, methodParameter.Type); + + if (methodParameter.Modifiers.Any(SyntaxKind.OutKeyword)) + { + bool needsSplit = Is64BitInteger(canonicalTypeName) && !IsPointerSized(compilation, methodParameter); + outParameters.Add(new OutParameter(argName, needsSplit)); + logOutArgs.Add($"{name}: {GetFormattedLogValue(argName, canonicalTypeName)}"); + + argName = $"out {typeName} {argName}"; + + regAlloc.AdvanceLinearIndex(); + } + else + { + if (Is64BitInteger(canonicalTypeName)) + { + if (IsPointerSized(compilation, methodParameter)) + { + int registerIndex = regAlloc.AllocateSingle(); + + generator.AppendLine($"var {argName} = (uint)context.GetX({registerIndex});"); + } + else + { + (int registerIndex, int registerIndex2) = regAlloc.AllocatePair(); + + string valueLow = $"(ulong)(uint)context.GetX({registerIndex})"; + string valueHigh = $"(ulong)(uint)context.GetX({registerIndex2})"; + string value = $"{valueLow} | ({valueHigh} << 32)"; + + generator.AppendLine($"var {argName} = ({typeName})({value});"); + } + } + else + { + int registerIndex = regAlloc.AllocateSingle(); + + string value = GenerateCastFromUInt64($"context.GetX({registerIndex})", canonicalTypeName, typeName); + + generator.AppendLine($"var {argName} = {value};"); + } + + logInArgs.Add($"{name}: {GetFormattedLogValue(argName, canonicalTypeName)}"); + } + + args[index++] = argName; + } + + GenerateLogPrintBeforeCall(generator, method.Identifier.Text, logInArgs); + + string returnTypeName = method.ReturnType.ToString(); + string argsList = string.Join(", ", args); + int returnRegisterIndex = 0; + string result = null; + string canonicalReturnTypeName = null; + + if (returnTypeName != "void") + { + generator.AppendLine($"var {ResultVariableName} = syscall.{method.Identifier.Text}({argsList});"); + generator.AppendLine($"context.SetX({returnRegisterIndex++}, (uint){ResultVariableName});"); + + canonicalReturnTypeName = GetCanonicalTypeName(compilation, method.ReturnType); + + if (Is64BitInteger(canonicalReturnTypeName)) + { + generator.AppendLine($"context.SetX({returnRegisterIndex++}, (uint)({ResultVariableName} >> 32));"); + } + + result = GetFormattedLogValue(ResultVariableName, canonicalReturnTypeName); + } + else + { + generator.AppendLine($"syscall.{method.Identifier.Text}({argsList});"); + } + + foreach (OutParameter outParameter in outParameters) + { + generator.AppendLine($"context.SetX({returnRegisterIndex++}, (uint){outParameter.Identifier});"); + + if (outParameter.NeedsSplit) + { + generator.AppendLine($"context.SetX({returnRegisterIndex++}, (uint)({outParameter.Identifier} >> 32));"); + } + } + + while (returnRegisterIndex < 4) + { + generator.AppendLine($"context.SetX({returnRegisterIndex++}, 0);"); + } + + GenerateLogPrintAfterCall(generator, method.Identifier.Text, logOutArgs, result, canonicalReturnTypeName); + + generator.LeaveScope(); + generator.AppendLine(); + } + + private static void GenerateMethod64(CodeGenerator generator, Compilation compilation, MethodDeclarationSyntax method) + { + generator.EnterScope($"private static void {method.Identifier.Text}{A64Suffix}(Syscall syscall, {TypeExecutionContext} context)"); + + string[] args = new string[method.ParameterList.Parameters.Count]; + int registerIndex = 0; + int index = 0; + + List outParameters = new List(); + List logInArgs = new List(); + List logOutArgs = new List(); + + foreach (var methodParameter in method.ParameterList.Parameters) + { + string name = methodParameter.Identifier.Text; + string argName = GetPrefixedArgName(name); + string typeName = methodParameter.Type.ToString(); + string canonicalTypeName = GetCanonicalTypeName(compilation, methodParameter.Type); + + if (methodParameter.Modifiers.Any(SyntaxKind.OutKeyword)) + { + outParameters.Add(new OutParameter(argName)); + logOutArgs.Add($"{name}: {GetFormattedLogValue(argName, canonicalTypeName)}"); + argName = $"out {typeName} {argName}"; + registerIndex++; + } + else + { + string value = GenerateCastFromUInt64($"context.GetX({registerIndex++})", canonicalTypeName, typeName); + generator.AppendLine($"var {argName} = {value};"); + logInArgs.Add($"{name}: {GetFormattedLogValue(argName, canonicalTypeName)}"); + } + + args[index++] = argName; + } + + GenerateLogPrintBeforeCall(generator, method.Identifier.Text, logInArgs); + + string argsList = string.Join(", ", args); + int returnRegisterIndex = 0; + string result = null; + string canonicalReturnTypeName = null; + + if (method.ReturnType.ToString() != "void") + { + generator.AppendLine($"var {ResultVariableName} = syscall.{method.Identifier.Text}({argsList});"); + generator.AppendLine($"context.SetX({returnRegisterIndex++}, (ulong){ResultVariableName});"); + canonicalReturnTypeName = GetCanonicalTypeName(compilation, method.ReturnType); + result = GetFormattedLogValue(ResultVariableName, canonicalReturnTypeName); + } + else + { + generator.AppendLine($"syscall.{method.Identifier.Text}({argsList});"); + } + + foreach (OutParameter outParameter in outParameters) + { + generator.AppendLine($"context.SetX({returnRegisterIndex++}, (ulong){outParameter.Identifier});"); + } + + while (returnRegisterIndex < 8) + { + generator.AppendLine($"context.SetX({returnRegisterIndex++}, 0);"); + } + + GenerateLogPrintAfterCall(generator, method.Identifier.Text, logOutArgs, result, canonicalReturnTypeName); + + generator.LeaveScope(); + generator.AppendLine(); + } + + private static string GetFormattedLogValue(string value, string canonicalTypeName) + { + if (Is32BitInteger(canonicalTypeName)) + { + return $"0x{{{value}:X8}}"; + } + else if (Is64BitInteger(canonicalTypeName)) + { + return $"0x{{{value}:X16}}"; + } + + return $"{{{value}}}"; + } + + private static string GetPrefixedArgName(string name) + { + return ArgVariablePrefix + name[0].ToString().ToUpperInvariant() + name.Substring(1); + } + + private static string GetCanonicalTypeName(Compilation compilation, SyntaxNode syntaxNode) + { + TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode); + if (typeInfo.Type.ContainingNamespace == null) + { + return typeInfo.Type.Name; + } + + return $"{typeInfo.Type.ContainingNamespace.ToDisplayString()}.{typeInfo.Type.Name}"; + } + + private static void GenerateLogPrintBeforeCall(CodeGenerator generator, string methodName, List argList) + { + string log = $"{methodName}({string.Join(", ", argList)})"; + GenerateLogPrint(generator, "Trace", "KernelSvc", log); + } + + private static void GenerateLogPrintAfterCall( + CodeGenerator generator, + string methodName, + List argList, + string result, + string canonicalResultTypeName) + { + string log = $"{methodName}({string.Join(", ", argList)})"; + + if (result != null) + { + log += $" = {result}"; + } + + if (canonicalResultTypeName == TypeKernelResult) + { + generator.EnterScope($"if ({ResultCheckHelperName}({ResultVariableName}))"); + GenerateLogPrint(generator, "Trace", "KernelSvc", log); + generator.LeaveScope(); + generator.EnterScope("else"); + GenerateLogPrint(generator, "Warning", "KernelSvc", log); + generator.LeaveScope(); + } + else + { + GenerateLogPrint(generator, "Trace", "KernelSvc", log); + } + } + + private static void GenerateLogPrint(CodeGenerator generator, string logLevel, string logClass, string log) + { + generator.AppendLine($"Logger.{logLevel}?.PrintMsg(LogClass.{logClass}, $\"{log}\");"); + } + + private static void GenerateDispatch(CodeGenerator generator, List syscalls, string suffix) + { + generator.EnterScope($"public static void Dispatch{suffix}(Syscall syscall, {TypeExecutionContext} context, int id)"); + generator.EnterScope("switch (id)"); + + foreach (var syscall in syscalls) + { + generator.AppendLine($"case {syscall.Id}:"); + generator.IncreaseIndentation(); + + generator.AppendLine($"{syscall.Name}{suffix}(syscall, context);"); + generator.AppendLine("break;"); + + generator.DecreaseIndentation(); + } + + generator.AppendLine($"default:"); + generator.IncreaseIndentation(); + + generator.AppendLine("throw new NotImplementedException($\"SVC 0x{id:X4} is not implemented.\");"); + + generator.DecreaseIndentation(); + + generator.LeaveScope(); + generator.LeaveScope(); + } + + private static bool Is32BitInteger(string canonicalTypeName) + { + return canonicalTypeName == TypeSystemInt32 || canonicalTypeName == TypeSystemUInt32; + } + + private static bool Is64BitInteger(string canonicalTypeName) + { + return canonicalTypeName == TypeSystemInt64 || canonicalTypeName == TypeSystemUInt64; + } + + private static string GenerateCastFromUInt64(string value, string canonicalTargetTypeName, string targetTypeName) + { + if (canonicalTargetTypeName == TypeSystemBoolean) + { + return $"({value} & 1) != 0"; + } + + return $"({targetTypeName}){value}"; + } + + private static bool IsPointerSized(Compilation compilation, ParameterSyntax parameterSyntax) + { + foreach (var attributeList in parameterSyntax.AttributeLists) + { + foreach (var attribute in attributeList.Attributes) + { + if (GetCanonicalTypeName(compilation, attribute) == TypePointerSizedAttribute) + { + return true; + } + } + } + + return false; + } + + public void Initialize(GeneratorInitializationContext context) + { + context.RegisterForSyntaxNotifications(() => new SyscallSyntaxReceiver()); + } + } +} diff --git a/Ryujinx.Horizon.Generators/Kernel/SyscallSyntaxReceiver.cs b/Ryujinx.Horizon.Generators/Kernel/SyscallSyntaxReceiver.cs new file mode 100644 index 000000000..e2e8e1d35 --- /dev/null +++ b/Ryujinx.Horizon.Generators/Kernel/SyscallSyntaxReceiver.cs @@ -0,0 +1,54 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.Collections.Generic; +using System.Linq; + +namespace Ryujinx.Horizon.Generators.Kernel +{ + class SyscallSyntaxReceiver : ISyntaxReceiver + { + public List SvcImplementations { get; } + + public SyscallSyntaxReceiver() + { + SvcImplementations = new List(); + } + + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + { + if (syntaxNode is ClassDeclarationSyntax classDeclaration && classDeclaration.AttributeLists.Count != 0) + { + foreach (var attributeList in classDeclaration.AttributeLists) + { + if (attributeList.Attributes.Any(x => x.Name.GetText().ToString() == "SvcImpl")) + { + foreach (var memberDeclaration in classDeclaration.Members) + { + if (memberDeclaration is MethodDeclarationSyntax methodDeclaration) + { + VisitMethod(methodDeclaration); + } + } + + break; + } + } + } + } + + private void VisitMethod(MethodDeclarationSyntax methodDeclaration) + { + if (methodDeclaration.AttributeLists.Count != 0) + { + foreach (var attributeList in methodDeclaration.AttributeLists) + { + if (attributeList.Attributes.Any(x => x.Name.GetText().ToString() == "Svc")) + { + SvcImplementations.Add(methodDeclaration); + break; + } + } + } + } + } +} diff --git a/Ryujinx.Horizon.Generators/Ryujinx.Horizon.Generators.csproj b/Ryujinx.Horizon.Generators/Ryujinx.Horizon.Generators.csproj new file mode 100644 index 000000000..22b07eab4 --- /dev/null +++ b/Ryujinx.Horizon.Generators/Ryujinx.Horizon.Generators.csproj @@ -0,0 +1,15 @@ + + + + netstandard2.0 + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + diff --git a/Ryujinx.sln b/Ryujinx.sln index 2c6d80763..92d4e5b4f 100644 --- a/Ryujinx.sln +++ b/Ryujinx.sln @@ -70,7 +70,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmp EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Ava", "Ryujinx.Ava\Ryujinx.Ava.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Ui.Common", "Ryujinx.Ui.Common\Ryujinx.Ui.Common.csproj", "{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Ui.Common", "Ryujinx.Ui.Common\Ryujinx.Ui.Common.csproj", "{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Horizon.Generators", "Ryujinx.Horizon.Generators\Ryujinx.Horizon.Generators.csproj", "{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -206,6 +208,10 @@ Global {BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Debug|Any CPU.Build.0 = Debug|Any CPU {BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Release|Any CPU.ActiveCfg = Release|Any CPU {BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Release|Any CPU.Build.0 = Release|Any CPU + {6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE