Rewrite SVC handler using source generators rather than IL emit (#3371)
* Implement syscall handlers using a source generator * Copy FlushProcessDataCache implementation to Syscall since it was only implemented on Syscall32 * Fix wrong argument order in some syscalls * Delete old Reflection.Emit based syscall handling code * Improvements to the code generation * ControlCodeMemory address and size is always 64-bit
This commit is contained in:
parent
0c87bf9ea4
commit
e546e5933f
16 changed files with 845 additions and 1553 deletions
|
@ -1,9 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||
{
|
||||
class InvalidSvcException : Exception
|
||||
{
|
||||
public InvalidSvcException(string message) : base(message) { }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
|
||||
class PointerSizedAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
15
Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcAttribute.cs
Normal file
15
Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcAttribute.cs
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
|
||||
class SvcImplAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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<Syscall32, IExecutionContext>[] SvcTable32 { get; }
|
||||
public static Action<Syscall64, IExecutionContext>[] SvcTable64 { get; }
|
||||
|
||||
static SyscallTable()
|
||||
{
|
||||
SvcTable32 = new Action<Syscall32, IExecutionContext>[SvcMax];
|
||||
SvcTable64 = new Action<Syscall64, IExecutionContext>[SvcMax];
|
||||
|
||||
Dictionary<int, string> svcFuncs64 = new Dictionary<int, string>
|
||||
{
|
||||
{ 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<int, string> value in svcFuncs64)
|
||||
{
|
||||
SvcTable64[value.Key] = GenerateMethod<Syscall64>(value.Value, SvcFuncMaxArguments64);
|
||||
}
|
||||
|
||||
Dictionary<int, string> svcFuncs32 = new Dictionary<int, string>
|
||||
{
|
||||
{ 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<int, string> value in svcFuncs32)
|
||||
{
|
||||
SvcTable32[value.Key] = GenerateMethod<Syscall32>(value.Value, SvcFuncMaxArguments32);
|
||||
}
|
||||
}
|
||||
|
||||
private static Action<T, IExecutionContext> GenerateMethod<T>(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<Action<T, IExecutionContext>>();
|
||||
}
|
||||
|
||||
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}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue