Move kernel state out of the Horizon class (#1107)

* Move kernel state from Horizon to KernelContext

* Merge syscalls partial classes, split 32 and 64-bit variants

* Sort usings
This commit is contained in:
gdkchan 2020-05-04 00:41:29 -03:00 committed by GitHub
parent cd48576f58
commit 15d1cc806b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
68 changed files with 3678 additions and 3570 deletions

View file

@ -1,44 +0,0 @@
using ARMeilleure.State;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading;
using System;
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
partial class SvcHandler
{
private Switch _device;
private KProcess _process;
private Horizon _system;
public SvcHandler(Switch device, KProcess process)
{
_device = device;
_process = process;
_system = device.System;
}
public void SvcCall(object sender, InstExceptionEventArgs e)
{
ExecutionContext context = (ExecutionContext)sender;
Action<SvcHandler, ExecutionContext> svcFunc = context.IsAarch32 ? SvcTable.SvcTable32[e.Id] : SvcTable.SvcTable64[e.Id];
if (svcFunc == null)
{
throw new NotImplementedException($"SVC 0x{e.Id:X4} is not implemented.");
}
svcFunc(this, context);
PostSvcHandler();
}
private void PostSvcHandler()
{
KThread currentThread = _system.Scheduler.GetCurrentThread();
currentThread.HandlePostSyscall();
}
}
}

View file

@ -1,607 +0,0 @@
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Ipc;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading;
using System.Threading;
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
partial class SvcHandler
{
private struct HleIpcMessage
{
public KThread Thread { get; private set; }
public KClientSession Session { get; private set; }
public IpcMessage Message { get; private set; }
public long MessagePtr { get; private set; }
public HleIpcMessage(
KThread thread,
KClientSession session,
IpcMessage message,
long messagePtr)
{
Thread = thread;
Session = session;
Message = message;
MessagePtr = messagePtr;
}
}
public KernelResult ConnectToNamedPort64([R(1)] ulong namePtr, [R(1)] out int handle)
{
return ConnectToNamedPort(namePtr, out handle);
}
public KernelResult ConnectToNamedPort32([R(1)] uint namePtr, [R(1)] out int handle)
{
return ConnectToNamedPort(namePtr, out handle);
}
private KernelResult ConnectToNamedPort(ulong namePtr, out int handle)
{
handle = 0;
if (!KernelTransfer.UserToKernelString(_system, namePtr, 12, out string name))
{
return KernelResult.UserCopyFailed;
}
if (name.Length > 11)
{
return KernelResult.MaximumExceeded;
}
KAutoObject autoObj = KAutoObject.FindNamedObject(_system, name);
if (!(autoObj is KClientPort clientPort))
{
return KernelResult.NotFound;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KernelResult result = currentProcess.HandleTable.ReserveHandle(out handle);
if (result != KernelResult.Success)
{
return result;
}
result = clientPort.Connect(out KClientSession clientSession);
if (result != KernelResult.Success)
{
currentProcess.HandleTable.CancelHandleReservation(handle);
return result;
}
currentProcess.HandleTable.SetReservedHandleObj(handle, clientSession);
clientSession.DecrementReferenceCount();
return result;
}
public KernelResult SendSyncRequest64([R(0)] int handle)
{
return SendSyncRequest((ulong)_system.Scheduler.GetCurrentThread().Context.Tpidr, 0x100, handle);
}
public KernelResult SendSyncRequest32([R(0)] int handle)
{
return SendSyncRequest((ulong)_system.Scheduler.GetCurrentThread().Context.Tpidr, 0x100, handle);
}
public KernelResult SendSyncRequestWithUserBuffer64([R(0)] ulong messagePtr, [R(1)] ulong size, [R(2)] int handle)
{
return SendSyncRequest(messagePtr, size, handle);
}
public KernelResult SendSyncRequestWithUserBuffer32([R(0)] uint messagePtr, [R(1)] uint size, [R(2)] int handle)
{
return SendSyncRequest(messagePtr, size, handle);
}
private KernelResult SendSyncRequest(ulong messagePtr, ulong size, int handle)
{
byte[] messageData = new byte[size];
_process.CpuMemory.Read(messagePtr, messageData);
KClientSession clientSession = _process.HandleTable.GetObject<KClientSession>(handle);
if (clientSession == null || clientSession.Service == null)
{
return SendSyncRequest_(handle);
}
if (clientSession != null)
{
_system.CriticalSection.Enter();
KThread currentThread = _system.Scheduler.GetCurrentThread();
currentThread.SignaledObj = null;
currentThread.ObjSyncResult = KernelResult.Success;
currentThread.Reschedule(ThreadSchedState.Paused);
IpcMessage message = new IpcMessage(messageData, (long)messagePtr);
ThreadPool.QueueUserWorkItem(ProcessIpcRequest, new HleIpcMessage(
currentThread,
clientSession,
message,
(long)messagePtr));
_system.ThreadCounter.AddCount();
_system.CriticalSection.Leave();
return currentThread.ObjSyncResult;
}
else
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid session handle 0x{handle:x8}!");
return KernelResult.InvalidHandle;
}
}
private void ProcessIpcRequest(object state)
{
HleIpcMessage ipcMessage = (HleIpcMessage)state;
ipcMessage.Thread.ObjSyncResult = IpcHandler.IpcCall(
_device,
_process,
_process.CpuMemory,
ipcMessage.Thread,
ipcMessage.Session,
ipcMessage.Message,
ipcMessage.MessagePtr);
_system.ThreadCounter.Signal();
ipcMessage.Thread.Reschedule(ThreadSchedState.Running);
}
private KernelResult SendSyncRequest_(int handle)
{
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KClientSession session = currentProcess.HandleTable.GetObject<KClientSession>(handle);
if (session == null)
{
return KernelResult.InvalidHandle;
}
return session.SendSyncRequest();
}
public KernelResult CreateSession64(
[R(2)] bool isLight,
[R(3)] ulong namePtr,
[R(1)] out int serverSessionHandle,
[R(2)] out int clientSessionHandle)
{
return CreateSession(isLight, namePtr, out serverSessionHandle, out clientSessionHandle);
}
public KernelResult CreateSession32(
[R(2)] bool isLight,
[R(3)] uint namePtr,
[R(1)] out int serverSessionHandle,
[R(2)] out int clientSessionHandle)
{
return CreateSession(isLight, namePtr, out serverSessionHandle, out clientSessionHandle);
}
private KernelResult CreateSession(
bool isLight,
ulong namePtr,
out int serverSessionHandle,
out int clientSessionHandle)
{
serverSessionHandle = 0;
clientSessionHandle = 0;
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KResourceLimit resourceLimit = currentProcess.ResourceLimit;
KernelResult result = KernelResult.Success;
if (resourceLimit != null && !resourceLimit.Reserve(LimitableResource.Session, 1))
{
return KernelResult.ResLimitExceeded;
}
if (isLight)
{
KLightSession session = new KLightSession(_system);
result = currentProcess.HandleTable.GenerateHandle(session.ServerSession, out serverSessionHandle);
if (result == KernelResult.Success)
{
result = currentProcess.HandleTable.GenerateHandle(session.ClientSession, out clientSessionHandle);
if (result != KernelResult.Success)
{
currentProcess.HandleTable.CloseHandle(serverSessionHandle);
serverSessionHandle = 0;
}
}
session.ServerSession.DecrementReferenceCount();
session.ClientSession.DecrementReferenceCount();
}
else
{
KSession session = new KSession(_system);
result = currentProcess.HandleTable.GenerateHandle(session.ServerSession, out serverSessionHandle);
if (result == KernelResult.Success)
{
result = currentProcess.HandleTable.GenerateHandle(session.ClientSession, out clientSessionHandle);
if (result != KernelResult.Success)
{
currentProcess.HandleTable.CloseHandle(serverSessionHandle);
serverSessionHandle = 0;
}
}
session.ServerSession.DecrementReferenceCount();
session.ClientSession.DecrementReferenceCount();
}
return result;
}
public KernelResult AcceptSession64([R(1)] int portHandle, [R(1)] out int sessionHandle)
{
return AcceptSession(portHandle, out sessionHandle);
}
public KernelResult AcceptSession32([R(1)] int portHandle, [R(1)] out int sessionHandle)
{
return AcceptSession(portHandle, out sessionHandle);
}
private KernelResult AcceptSession(int portHandle, out int sessionHandle)
{
sessionHandle = 0;
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KServerPort serverPort = currentProcess.HandleTable.GetObject<KServerPort>(portHandle);
if (serverPort == null)
{
return KernelResult.InvalidHandle;
}
KernelResult result = currentProcess.HandleTable.ReserveHandle(out int handle);
if (result != KernelResult.Success)
{
return result;
}
KAutoObject session;
if (serverPort.IsLight)
{
session = serverPort.AcceptIncomingLightConnection();
}
else
{
session = serverPort.AcceptIncomingConnection();
}
if (session != null)
{
currentProcess.HandleTable.SetReservedHandleObj(handle, session);
session.DecrementReferenceCount();
sessionHandle = handle;
result = KernelResult.Success;
}
else
{
currentProcess.HandleTable.CancelHandleReservation(handle);
result = KernelResult.NotFound;
}
return result;
}
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 ReplyAndReceive(handlesPtr, handlesCount, replyTargetHandle, timeout, out handleIndex);
}
public KernelResult ReplyAndReceive32(
[R(0)] uint timeoutLow,
[R(1)] ulong 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 ReplyAndReceive(handlesPtr, handlesCount, replyTargetHandle, timeout, out handleIndex);
}
public KernelResult ReplyAndReceive(
ulong handlesPtr,
int handlesCount,
int replyTargetHandle,
long timeout,
out int handleIndex)
{
handleIndex = 0;
if ((uint)handlesCount > 0x40)
{
return KernelResult.MaximumExceeded;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
ulong copySize = (ulong)((long)handlesCount * 4);
if (!currentProcess.MemoryManager.InsideAddrSpace(handlesPtr, copySize))
{
return KernelResult.UserCopyFailed;
}
if (handlesPtr + copySize < handlesPtr)
{
return KernelResult.UserCopyFailed;
}
int[] handles = new int[handlesCount];
if (!KernelTransfer.UserToKernelInt32Array(_system, handlesPtr, handles))
{
return KernelResult.UserCopyFailed;
}
KSynchronizationObject[] syncObjs = new KSynchronizationObject[handlesCount];
for (int index = 0; index < handlesCount; index++)
{
KSynchronizationObject obj = currentProcess.HandleTable.GetObject<KSynchronizationObject>(handles[index]);
if (obj == null)
{
return KernelResult.InvalidHandle;
}
syncObjs[index] = obj;
}
KernelResult result;
if (replyTargetHandle != 0)
{
KServerSession replyTarget = currentProcess.HandleTable.GetObject<KServerSession>(replyTargetHandle);
if (replyTarget == null)
{
return KernelResult.InvalidHandle;
}
result = replyTarget.Reply();
if (result != KernelResult.Success)
{
return result;
}
}
while ((result = _system.Synchronization.WaitFor(syncObjs, timeout, out handleIndex)) == KernelResult.Success)
{
KServerSession session = currentProcess.HandleTable.GetObject<KServerSession>(handles[handleIndex]);
if (session == null)
{
break;
}
if ((result = session.Receive()) != KernelResult.NotFound)
{
break;
}
}
return result;
}
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 CreatePort(maxSessions, isLight, namePtr, out serverPortHandle, out clientPortHandle);
}
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 CreatePort(maxSessions, isLight, namePtr, out serverPortHandle, out clientPortHandle);
}
private KernelResult CreatePort(
int maxSessions,
bool isLight,
ulong namePtr,
out int serverPortHandle,
out int clientPortHandle)
{
serverPortHandle = clientPortHandle = 0;
if (maxSessions < 1)
{
return KernelResult.MaximumExceeded;
}
KPort port = new KPort(_system, maxSessions, isLight, (long)namePtr);
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KernelResult result = currentProcess.HandleTable.GenerateHandle(port.ClientPort, out clientPortHandle);
if (result != KernelResult.Success)
{
return result;
}
result = currentProcess.HandleTable.GenerateHandle(port.ServerPort, out serverPortHandle);
if (result != KernelResult.Success)
{
currentProcess.HandleTable.CloseHandle(clientPortHandle);
}
return result;
}
public KernelResult ManageNamedPort64([R(1)] ulong namePtr, [R(2)] int maxSessions, [R(1)] out int handle)
{
return ManageNamedPort(namePtr, maxSessions, out handle);
}
public KernelResult ManageNamedPort32([R(1)] uint namePtr, [R(2)] int maxSessions, [R(1)] out int handle)
{
return ManageNamedPort(namePtr, maxSessions, out handle);
}
private KernelResult ManageNamedPort(ulong namePtr, int maxSessions, out int handle)
{
handle = 0;
if (!KernelTransfer.UserToKernelString(_system, namePtr, 12, out string name))
{
return KernelResult.UserCopyFailed;
}
if (maxSessions < 0 || name.Length > 11)
{
return KernelResult.MaximumExceeded;
}
if (maxSessions == 0)
{
return KClientPort.RemoveName(_system, name);
}
KPort port = new KPort(_system, maxSessions, false, 0);
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KernelResult result = currentProcess.HandleTable.GenerateHandle(port.ServerPort, out handle);
if (result != KernelResult.Success)
{
return result;
}
result = port.ClientPort.SetName(name);
if (result != KernelResult.Success)
{
currentProcess.HandleTable.CloseHandle(handle);
}
return result;
}
public KernelResult ConnectToPort64([R(1)] int clientPortHandle, [R(1)] out int clientSessionHandle)
{
return ConnectToPort(clientPortHandle, out clientSessionHandle);
}
public KernelResult ConnectToPort32([R(1)] int clientPortHandle, [R(1)] out int clientSessionHandle)
{
return ConnectToPort(clientPortHandle, out clientSessionHandle);
}
private KernelResult ConnectToPort(int clientPortHandle, out int clientSessionHandle)
{
clientSessionHandle = 0;
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KClientPort clientPort = currentProcess.HandleTable.GetObject<KClientPort>(clientPortHandle);
if (clientPort == null)
{
return KernelResult.InvalidHandle;
}
KernelResult result = currentProcess.HandleTable.ReserveHandle(out int handle);
if (result != KernelResult.Success)
{
return result;
}
KAutoObject session;
if (clientPort.IsLight)
{
result = clientPort.ConnectLight(out KLightClientSession clientSession);
session = clientSession;
}
else
{
result = clientPort.Connect(out KClientSession clientSession);
session = clientSession;
}
if (result != KernelResult.Success)
{
currentProcess.HandleTable.CancelHandleReservation(handle);
return result;
}
currentProcess.HandleTable.SetReservedHandleObj(handle, session);
session.DecrementReferenceCount();
clientSessionHandle = handle;
return result;
}
}
}

View file

@ -1,617 +0,0 @@
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Process;
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
partial class SvcHandler
{
public KernelResult SetHeapSize64([R(1)] ulong size, [R(1)] out ulong position)
{
return SetHeapSize(size, out position);
}
public KernelResult SetHeapSize32([R(1)] uint size, [R(1)] out uint position)
{
ulong temporaryPosition;
KernelResult result = SetHeapSize(size, out temporaryPosition);
position = (uint)temporaryPosition;
return result;
}
private KernelResult SetHeapSize(ulong size, out ulong position)
{
if ((size & 0xfffffffe001fffff) != 0)
{
position = 0;
return KernelResult.InvalidSize;
}
return _process.MemoryManager.SetHeapSize(size, out position);
}
public KernelResult SetMemoryAttribute64(
[R(0)] ulong position,
[R(1)] ulong size,
[R(2)] MemoryAttribute attributeMask,
[R(3)] MemoryAttribute attributeValue)
{
return SetMemoryAttribute(position, size, attributeMask, attributeValue);
}
public KernelResult SetMemoryAttribute32(
[R(0)] uint position,
[R(1)] uint size,
[R(2)] MemoryAttribute attributeMask,
[R(3)] MemoryAttribute attributeValue)
{
return SetMemoryAttribute(position, size, attributeMask, attributeValue);
}
private KernelResult SetMemoryAttribute(
ulong position,
ulong size,
MemoryAttribute attributeMask,
MemoryAttribute attributeValue)
{
if (!PageAligned(position))
{
return KernelResult.InvalidAddress;
}
if (!PageAligned(size) || size == 0)
{
return KernelResult.InvalidSize;
}
MemoryAttribute attributes = attributeMask | attributeValue;
if (attributes != attributeMask ||
(attributes | MemoryAttribute.Uncached) != MemoryAttribute.Uncached)
{
return KernelResult.InvalidCombination;
}
KernelResult result = _process.MemoryManager.SetMemoryAttribute(
position,
size,
attributeMask,
attributeValue);
return result;
}
public KernelResult MapMemory64([R(0)] ulong dst, [R(1)] ulong src, [R(2)] ulong size)
{
return MapMemory(dst, src, size);
}
public KernelResult MapMemory32([R(0)] uint dst, [R(1)] uint src, [R(2)] uint size)
{
return MapMemory(dst, src, size);
}
private KernelResult MapMemory(ulong dst, ulong src, ulong size)
{
if (!PageAligned(src | dst))
{
return KernelResult.InvalidAddress;
}
if (!PageAligned(size) || size == 0)
{
return KernelResult.InvalidSize;
}
if (src + size <= src || dst + size <= dst)
{
return KernelResult.InvalidMemState;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
if (!currentProcess.MemoryManager.InsideAddrSpace(src, size))
{
return KernelResult.InvalidMemState;
}
if (currentProcess.MemoryManager.OutsideStackRegion(dst, size) ||
currentProcess.MemoryManager.InsideHeapRegion (dst, size) ||
currentProcess.MemoryManager.InsideAliasRegion (dst, size))
{
return KernelResult.InvalidMemRange;
}
return _process.MemoryManager.Map(dst, src, size);
}
public KernelResult UnmapMemory64([R(0)] ulong dst, [R(1)] ulong src, [R(2)] ulong size)
{
return UnmapMemory(dst, src, size);
}
public KernelResult UnmapMemory32([R(0)] uint dst, [R(1)] uint src, [R(2)] uint size)
{
return UnmapMemory(dst, src, size);
}
private KernelResult UnmapMemory(ulong dst, ulong src, ulong size)
{
if (!PageAligned(src | dst))
{
return KernelResult.InvalidAddress;
}
if (!PageAligned(size) || size == 0)
{
return KernelResult.InvalidSize;
}
if (src + size <= src || dst + size <= dst)
{
return KernelResult.InvalidMemState;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
if (!currentProcess.MemoryManager.InsideAddrSpace(src, size))
{
return KernelResult.InvalidMemState;
}
if (currentProcess.MemoryManager.OutsideStackRegion(dst, size) ||
currentProcess.MemoryManager.InsideHeapRegion (dst, size) ||
currentProcess.MemoryManager.InsideAliasRegion (dst, size))
{
return KernelResult.InvalidMemRange;
}
return _process.MemoryManager.Unmap(dst, src, size);
}
public KernelResult QueryMemory64([R(0)] ulong infoPtr, [R(2)] ulong position, [R(1)] out ulong pageInfo)
{
return QueryMemory(infoPtr, position, out pageInfo);
}
public KernelResult QueryMemory32([R(0)] uint infoPtr, [R(1)] uint r1, [R(2)] uint position, [R(1)] out uint pageInfo)
{
KernelResult result = QueryMemory(infoPtr, position, out ulong pageInfo64);
pageInfo = (uint)pageInfo64;
return result;
}
private KernelResult QueryMemory(ulong infoPtr, ulong position, out ulong pageInfo)
{
KMemoryInfo blkInfo = _process.MemoryManager.QueryMemory(position);
_process.CpuMemory.Write(infoPtr + 0x00, blkInfo.Address);
_process.CpuMemory.Write(infoPtr + 0x08, blkInfo.Size);
_process.CpuMemory.Write(infoPtr + 0x10, (int)blkInfo.State & 0xff);
_process.CpuMemory.Write(infoPtr + 0x14, (int)blkInfo.Attribute);
_process.CpuMemory.Write(infoPtr + 0x18, (int)blkInfo.Permission);
_process.CpuMemory.Write(infoPtr + 0x1c, blkInfo.IpcRefCount);
_process.CpuMemory.Write(infoPtr + 0x20, blkInfo.DeviceRefCount);
_process.CpuMemory.Write(infoPtr + 0x24, 0);
pageInfo = 0;
return KernelResult.Success;
}
public KernelResult MapSharedMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size, [R(3)] MemoryPermission permission)
{
return MapSharedMemory(handle, address, size, permission);
}
public KernelResult MapSharedMemory32([R(0)] int handle, [R(1)] uint address, [R(2)] uint size, [R(3)] MemoryPermission permission)
{
return MapSharedMemory(handle, address, size, permission);
}
private KernelResult MapSharedMemory(int handle, ulong address, ulong size, MemoryPermission permission)
{
if (!PageAligned(address))
{
return KernelResult.InvalidAddress;
}
if (!PageAligned(size) || size == 0)
{
return KernelResult.InvalidSize;
}
if (address + size <= address)
{
return KernelResult.InvalidMemState;
}
if ((permission | MemoryPermission.Write) != MemoryPermission.ReadAndWrite)
{
return KernelResult.InvalidPermission;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KSharedMemory sharedMemory = currentProcess.HandleTable.GetObject<KSharedMemory>(handle);
if (sharedMemory == null)
{
return KernelResult.InvalidHandle;
}
if (currentProcess.MemoryManager.IsInvalidRegion (address, size) ||
currentProcess.MemoryManager.InsideHeapRegion (address, size) ||
currentProcess.MemoryManager.InsideAliasRegion(address, size))
{
return KernelResult.InvalidMemRange;
}
return sharedMemory.MapIntoProcess(
currentProcess.MemoryManager,
address,
size,
currentProcess,
permission);
}
public KernelResult UnmapSharedMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size)
{
return UnmapSharedMemory(handle, address, size);
}
public KernelResult UnmapSharedMemory32([R(0)] int handle, [R(1)] uint address, [R(2)] uint size)
{
return UnmapSharedMemory(handle, address, size);
}
private KernelResult UnmapSharedMemory(int handle, ulong address, ulong size)
{
if (!PageAligned(address))
{
return KernelResult.InvalidAddress;
}
if (!PageAligned(size) || size == 0)
{
return KernelResult.InvalidSize;
}
if (address + size <= address)
{
return KernelResult.InvalidMemState;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KSharedMemory sharedMemory = currentProcess.HandleTable.GetObject<KSharedMemory>(handle);
if (sharedMemory == null)
{
return KernelResult.InvalidHandle;
}
if (currentProcess.MemoryManager.IsInvalidRegion (address, size) ||
currentProcess.MemoryManager.InsideHeapRegion (address, size) ||
currentProcess.MemoryManager.InsideAliasRegion(address, size))
{
return KernelResult.InvalidMemRange;
}
return sharedMemory.UnmapFromProcess(
currentProcess.MemoryManager,
address,
size,
currentProcess);
}
public KernelResult CreateTransferMemory64(
[R(1)] ulong address,
[R(2)] ulong size,
[R(3)] MemoryPermission permission,
[R(1)] out int handle)
{
return CreateTransferMemory(address, size, permission, out handle);
}
public KernelResult CreateTransferMemory32(
[R(1)] uint address,
[R(2)] uint size,
[R(3)] MemoryPermission permission,
[R(1)] out int handle)
{
return CreateTransferMemory(address, size, permission, out handle);
}
private KernelResult CreateTransferMemory(ulong address, ulong size, MemoryPermission permission, out int handle)
{
handle = 0;
if (!PageAligned(address))
{
return KernelResult.InvalidAddress;
}
if (!PageAligned(size) || size == 0)
{
return KernelResult.InvalidSize;
}
if (address + size <= address)
{
return KernelResult.InvalidMemState;
}
if (permission > MemoryPermission.ReadAndWrite || permission == MemoryPermission.Write)
{
return KernelResult.InvalidPermission;
}
KernelResult result = _process.MemoryManager.ReserveTransferMemory(address, size, permission);
if (result != KernelResult.Success)
{
return result;
}
KTransferMemory transferMemory = new KTransferMemory(_system, address, size);
return _process.HandleTable.GenerateHandle(transferMemory, out handle);
}
public KernelResult MapPhysicalMemory64([R(0)] ulong address, [R(1)] ulong size)
{
return MapPhysicalMemory(address, size);
}
public KernelResult MapPhysicalMemory32([R(0)] uint address, [R(1)] uint size)
{
return MapPhysicalMemory(address, size);
}
private KernelResult MapPhysicalMemory(ulong address, ulong size)
{
if (!PageAligned(address))
{
return KernelResult.InvalidAddress;
}
if (!PageAligned(size) || size == 0)
{
return KernelResult.InvalidSize;
}
if (address + size <= address)
{
return KernelResult.InvalidMemRange;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
if ((currentProcess.PersonalMmHeapPagesCount & 0xfffffffffffff) == 0)
{
return KernelResult.InvalidState;
}
if (!currentProcess.MemoryManager.InsideAddrSpace (address, size) ||
currentProcess.MemoryManager.OutsideAliasRegion(address, size))
{
return KernelResult.InvalidMemRange;
}
return _process.MemoryManager.MapPhysicalMemory(address, size);
}
public KernelResult UnmapPhysicalMemory64([R(0)] ulong address, [R(1)] ulong size)
{
return UnmapPhysicalMemory(address, size);
}
public KernelResult UnmapPhysicalMemory32([R(0)] uint address, [R(1)] uint size)
{
return UnmapPhysicalMemory(address, size);
}
private KernelResult UnmapPhysicalMemory(ulong address, ulong size)
{
if (!PageAligned(address))
{
return KernelResult.InvalidAddress;
}
if (!PageAligned(size) || size == 0)
{
return KernelResult.InvalidSize;
}
if (address + size <= address)
{
return KernelResult.InvalidMemRange;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
if ((currentProcess.PersonalMmHeapPagesCount & 0xfffffffffffff) == 0)
{
return KernelResult.InvalidState;
}
if (!currentProcess.MemoryManager.InsideAddrSpace (address, size) ||
currentProcess.MemoryManager.OutsideAliasRegion(address, size))
{
return KernelResult.InvalidMemRange;
}
return _process.MemoryManager.UnmapPhysicalMemory(address, size);
}
public KernelResult MapProcessCodeMemory64([R(0)] int handle, [R(1)] ulong dst, [R(2)] ulong src, [R(3)] ulong size)
{
return MapProcessCodeMemory(handle, dst, 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 MapProcessCodeMemory(handle, dst, src, size);
}
public KernelResult MapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size)
{
if (!PageAligned(dst) || !PageAligned(src))
{
return KernelResult.InvalidAddress;
}
if (!PageAligned(size) || size == 0)
{
return KernelResult.InvalidSize;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KProcess targetProcess = currentProcess.HandleTable.GetObject<KProcess>(handle);
if (targetProcess == null)
{
return KernelResult.InvalidHandle;
}
if (targetProcess.MemoryManager.OutsideAddrSpace(dst, size) ||
targetProcess.MemoryManager.OutsideAddrSpace(src, size) ||
targetProcess.MemoryManager.InsideAliasRegion(dst, size) ||
targetProcess.MemoryManager.InsideHeapRegion(dst, size))
{
return KernelResult.InvalidMemRange;
}
if (size + dst <= dst || size + src <= src)
{
return KernelResult.InvalidMemState;
}
return targetProcess.MemoryManager.MapProcessCodeMemory(dst, src, size);
}
public KernelResult UnmapProcessCodeMemory64([R(0)] int handle, [R(1)] ulong dst, [R(2)] ulong src, [R(3)] ulong size)
{
return UnmapProcessCodeMemory(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 UnmapProcessCodeMemory(handle, dst, src, size);
}
public KernelResult UnmapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size)
{
if (!PageAligned(dst) || !PageAligned(src))
{
return KernelResult.InvalidAddress;
}
if (!PageAligned(size) || size == 0)
{
return KernelResult.InvalidSize;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KProcess targetProcess = currentProcess.HandleTable.GetObject<KProcess>(handle);
if (targetProcess == null)
{
return KernelResult.InvalidHandle;
}
if (targetProcess.MemoryManager.OutsideAddrSpace(dst, size) ||
targetProcess.MemoryManager.OutsideAddrSpace(src, size) ||
targetProcess.MemoryManager.InsideAliasRegion(dst, size) ||
targetProcess.MemoryManager.InsideHeapRegion(dst, size))
{
return KernelResult.InvalidMemRange;
}
if (size + dst <= dst || size + src <= src)
{
return KernelResult.InvalidMemState;
}
return targetProcess.MemoryManager.UnmapProcessCodeMemory(dst, src, size);
}
public KernelResult SetProcessMemoryPermission64([R(0)] int handle, [R(1)] ulong src, [R(2)] ulong size, [R(3)] MemoryPermission permission)
{
return SetProcessMemoryPermission(handle, src, size, permission);
}
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)] MemoryPermission permission)
{
ulong src = (srcLow | ((ulong)srcHigh << 32));
ulong size = (sizeLow | ((ulong)sizeHigh << 32));
return SetProcessMemoryPermission(handle, src, size, permission);
}
public KernelResult SetProcessMemoryPermission(int handle, ulong src, ulong size, MemoryPermission permission)
{
if (!PageAligned(src))
{
return KernelResult.InvalidAddress;
}
if (!PageAligned(size) || size == 0)
{
return KernelResult.InvalidSize;
}
if (permission != MemoryPermission.None &&
permission != MemoryPermission.Read &&
permission != MemoryPermission.ReadAndWrite &&
permission != MemoryPermission.ReadAndExecute)
{
return KernelResult.InvalidPermission;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KProcess targetProcess = currentProcess.HandleTable.GetObject<KProcess>(handle);
if (targetProcess == null)
{
return KernelResult.InvalidHandle;
}
if (targetProcess.MemoryManager.OutsideAddrSpace(src, size))
{
return KernelResult.InvalidMemState;
}
return targetProcess.MemoryManager.SetProcessMemoryPermission(src, size, permission);
}
private static bool PageAligned(ulong position)
{
return (position & (KMemoryManager.PageSize - 1)) == 0;
}
}
}

View file

@ -1,732 +0,0 @@
using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.Cpu;
using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Ipc;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading;
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
partial class SvcHandler
{
public void ExitProcess64()
{
ExitProcess();
}
public void ExitProcess32()
{
ExitProcess();
}
public KernelResult TerminateProcess64([R(0)] int handle)
{
return TerminateProcess(handle);
}
public KernelResult TerminateProcess32([R(0)] int handle)
{
return TerminateProcess(handle);
}
private KernelResult TerminateProcess(int handle)
{
KProcess process = _process.HandleTable.GetObject<KProcess>(handle);
KernelResult result;
if (process != null)
{
if (process == _system.Scheduler.GetCurrentProcess())
{
result = KernelResult.Success;
process.DecrementToZeroWhileTerminatingCurrent();
}
else
{
result = process.Terminate();
process.DecrementReferenceCount();
}
}
else
{
result = KernelResult.InvalidHandle;
}
return result;
}
private void ExitProcess()
{
_system.Scheduler.GetCurrentProcess().TerminateCurrentProcess();
}
public KernelResult SignalEvent64([R(0)] int handle)
{
return SignalEvent(handle);
}
public KernelResult SignalEvent32([R(0)] int handle)
{
return SignalEvent(handle);
}
private KernelResult SignalEvent(int handle)
{
KWritableEvent writableEvent = _process.HandleTable.GetObject<KWritableEvent>(handle);
KernelResult result;
if (writableEvent != null)
{
writableEvent.Signal();
result = KernelResult.Success;
}
else
{
result = KernelResult.InvalidHandle;
}
return result;
}
public KernelResult ClearEvent64([R(0)] int handle)
{
return ClearEvent(handle);
}
public KernelResult ClearEvent32([R(0)] int handle)
{
return ClearEvent(handle);
}
private KernelResult ClearEvent(int handle)
{
KernelResult result;
KWritableEvent writableEvent = _process.HandleTable.GetObject<KWritableEvent>(handle);
if (writableEvent == null)
{
KReadableEvent readableEvent = _process.HandleTable.GetObject<KReadableEvent>(handle);
result = readableEvent?.Clear() ?? KernelResult.InvalidHandle;
}
else
{
result = writableEvent.Clear();
}
return result;
}
public KernelResult CloseHandle64([R(0)] int handle)
{
return CloseHandle(handle);
}
public KernelResult CloseHandle32([R(0)] int handle)
{
return CloseHandle(handle);
}
private KernelResult CloseHandle(int handle)
{
KAutoObject obj = _process.HandleTable.GetObject<KAutoObject>(handle);
_process.HandleTable.CloseHandle(handle);
if (obj == null)
{
return KernelResult.InvalidHandle;
}
if (obj is KSession session)
{
session.Dispose();
}
else if (obj is KTransferMemory transferMemory)
{
_process.MemoryManager.ResetTransferMemory(
transferMemory.Address,
transferMemory.Size);
}
return KernelResult.Success;
}
public KernelResult ResetSignal64([R(0)] int handle)
{
return ResetSignal(handle);
}
public KernelResult ResetSignal32([R(0)] int handle)
{
return ResetSignal(handle);
}
private KernelResult ResetSignal(int handle)
{
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KReadableEvent readableEvent = currentProcess.HandleTable.GetObject<KReadableEvent>(handle);
KernelResult result;
if (readableEvent != null)
{
result = readableEvent.ClearIfSignaled();
}
else
{
KProcess process = currentProcess.HandleTable.GetKProcess(handle);
if (process != null)
{
result = process.ClearIfNotExited();
}
else
{
result = KernelResult.InvalidHandle;
}
}
return result;
}
public ulong GetSystemTick64()
{
return _system.Scheduler.GetCurrentThread().Context.CntpctEl0;
}
public void GetSystemTick32([R(0)] out uint resultLow, [R(1)] out uint resultHigh)
{
ulong result = _system.Scheduler.GetCurrentThread().Context.CntpctEl0;
resultLow = (uint)(result & uint.MaxValue);
resultHigh = (uint)(result >> 32);
}
public KernelResult GetProcessId64([R(1)] int handle, [R(1)] out long pid)
{
return GetProcessId(handle, out pid);
}
public KernelResult GetProcessId32([R(1)] int handle, [R(1)] out int pidLow, [R(2)] out int pidHigh)
{
KernelResult result = GetProcessId(handle, out long pid);
pidLow = (int)(pid & uint.MaxValue);
pidHigh = (int)(pid >> 32);
return result;
}
private KernelResult GetProcessId(int handle, out long pid)
{
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KProcess process = currentProcess.HandleTable.GetKProcess(handle);
if (process == null)
{
KThread thread = currentProcess.HandleTable.GetKThread(handle);
if (thread != null)
{
process = thread.Owner;
}
// TODO: KDebugEvent.
}
pid = process?.Pid ?? 0;
return process != null
? KernelResult.Success
: KernelResult.InvalidHandle;
}
public void Break64([R(0)] ulong reason, [R(1)] ulong x1, [R(2)] ulong info)
{
Break(reason);
}
public void Break32([R(0)] uint reason, [R(1)] uint r1, [R(2)] uint info)
{
Break(reason);
}
private void Break(ulong reason)
{
KThread currentThread = _system.Scheduler.GetCurrentThread();
if ((reason & (1UL << 31)) == 0)
{
currentThread.PrintGuestStackTrace();
// As the process is exiting, this is probably caused by emulation termination.
if (currentThread.Owner.State == ProcessState.Exiting)
{
return;
}
// TODO: Debug events.
currentThread.Owner.TerminateCurrentProcess();
throw new GuestBrokeExecutionException();
}
else
{
Logger.PrintInfo(LogClass.KernelSvc, "Debugger triggered.");
currentThread.PrintGuestStackTrace();
}
}
public void OutputDebugString64([R(0)] ulong strPtr, [R(1)] ulong size)
{
OutputDebugString(strPtr, size);
}
public void OutputDebugString32([R(0)] uint strPtr, [R(1)] uint size)
{
OutputDebugString(strPtr, size);
}
private void OutputDebugString(ulong strPtr, ulong size)
{
string str = MemoryHelper.ReadAsciiString(_process.CpuMemory, (long)strPtr, (long)size);
Logger.PrintWarning(LogClass.KernelSvc, str);
}
public KernelResult GetInfo64([R(1)] uint id, [R(2)] int handle, [R(3)] long subId, [R(1)] out long value)
{
return GetInfo(id, handle, subId, out value);
}
public KernelResult GetInfo32(
[R(0)] uint subIdLow,
[R(1)] uint 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 = GetInfo(id, handle, subId, out long value);
valueHigh = (uint)(value >> 32);
valueLow = (uint)(value & uint.MaxValue);
return result;
}
private KernelResult GetInfo(uint id, int handle, long subId, out long value)
{
value = 0;
switch (id)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 12:
case 13:
case 14:
case 15:
case 16:
case 17:
case 18:
case 20:
case 21:
case 22:
{
if (subId != 0)
{
return KernelResult.InvalidCombination;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KProcess process = currentProcess.HandleTable.GetKProcess(handle);
if (process == null)
{
return KernelResult.InvalidHandle;
}
switch (id)
{
case 0: value = process.Capabilities.AllowedCpuCoresMask; break;
case 1: value = process.Capabilities.AllowedThreadPriosMask; break;
case 2: value = (long)process.MemoryManager.AliasRegionStart; break;
case 3: value = (long)(process.MemoryManager.AliasRegionEnd -
process.MemoryManager.AliasRegionStart); break;
case 4: value = (long)process.MemoryManager.HeapRegionStart; break;
case 5: value = (long)(process.MemoryManager.HeapRegionEnd -
process.MemoryManager.HeapRegionStart); break;
case 6: value = (long)process.GetMemoryCapacity(); break;
case 7: value = (long)process.GetMemoryUsage(); break;
case 12: value = (long)process.MemoryManager.GetAddrSpaceBaseAddr(); break;
case 13: value = (long)process.MemoryManager.GetAddrSpaceSize(); break;
case 14: value = (long)process.MemoryManager.StackRegionStart; break;
case 15: value = (long)(process.MemoryManager.StackRegionEnd -
process.MemoryManager.StackRegionStart); break;
case 16: value = (long)process.PersonalMmHeapPagesCount * KMemoryManager.PageSize; break;
case 17:
if (process.PersonalMmHeapPagesCount != 0)
{
value = process.MemoryManager.GetMmUsedPages() * KMemoryManager.PageSize;
}
break;
case 18: value = (long)process.TitleId; break;
case 20: value = (long)process.UserExceptionContextAddress; break;
case 21: value = (long)process.GetMemoryCapacityWithoutPersonalMmHeap(); break;
case 22: value = (long)process.GetMemoryUsageWithoutPersonalMmHeap(); break;
}
break;
}
case 8:
{
if (handle != 0)
{
return KernelResult.InvalidHandle;
}
if (subId != 0)
{
return KernelResult.InvalidCombination;
}
value = _system.Scheduler.GetCurrentProcess().Debug ? 1 : 0;
break;
}
case 9:
{
if (handle != 0)
{
return KernelResult.InvalidHandle;
}
if (subId != 0)
{
return KernelResult.InvalidCombination;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
if (currentProcess.ResourceLimit != null)
{
KHandleTable handleTable = currentProcess.HandleTable;
KResourceLimit resourceLimit = currentProcess.ResourceLimit;
KernelResult result = handleTable.GenerateHandle(resourceLimit, out int resLimHandle);
if (result != KernelResult.Success)
{
return result;
}
value = (uint)resLimHandle;
}
break;
}
case 10:
{
if (handle != 0)
{
return KernelResult.InvalidHandle;
}
int currentCore = _system.Scheduler.GetCurrentThread().CurrentCore;
if (subId != -1 && subId != currentCore)
{
return KernelResult.InvalidCombination;
}
value = _system.Scheduler.CoreContexts[currentCore].TotalIdleTimeTicks;
break;
}
case 11:
{
if (handle != 0)
{
return KernelResult.InvalidHandle;
}
if ((ulong)subId > 3)
{
return KernelResult.InvalidCombination;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
value = currentProcess.RandomEntropy[subId];
break;
}
case 0xf0000002u:
{
if (subId < -1 || subId > 3)
{
return KernelResult.InvalidCombination;
}
KThread thread = _system.Scheduler.GetCurrentProcess().HandleTable.GetKThread(handle);
if (thread == null)
{
return KernelResult.InvalidHandle;
}
KThread currentThread = _system.Scheduler.GetCurrentThread();
int currentCore = currentThread.CurrentCore;
if (subId != -1 && subId != currentCore)
{
return KernelResult.Success;
}
KCoreContext coreContext = _system.Scheduler.CoreContexts[currentCore];
long timeDelta = PerformanceCounter.ElapsedMilliseconds - coreContext.LastContextSwitchTime;
if (subId != -1)
{
value = KTimeManager.ConvertMillisecondsToTicks(timeDelta);
}
else
{
long totalTimeRunning = thread.TotalTimeRunning;
if (thread == currentThread)
{
totalTimeRunning += timeDelta;
}
value = KTimeManager.ConvertMillisecondsToTicks(totalTimeRunning);
}
break;
}
default: return KernelResult.InvalidEnumValue;
}
return KernelResult.Success;
}
public KernelResult CreateEvent64([R(1)] out int wEventHandle, [R(2)] out int rEventHandle)
{
return CreateEvent(out wEventHandle, out rEventHandle);
}
public KernelResult CreateEvent32([R(1)] out int wEventHandle, [R(2)] out int rEventHandle)
{
return CreateEvent(out wEventHandle, out rEventHandle);
}
private KernelResult CreateEvent(out int wEventHandle, out int rEventHandle)
{
KEvent Event = new KEvent(_system);
KernelResult result = _process.HandleTable.GenerateHandle(Event.WritableEvent, out wEventHandle);
if (result == KernelResult.Success)
{
result = _process.HandleTable.GenerateHandle(Event.ReadableEvent, out rEventHandle);
if (result != KernelResult.Success)
{
_process.HandleTable.CloseHandle(wEventHandle);
}
}
else
{
rEventHandle = 0;
}
return result;
}
public KernelResult GetProcessList64([R(1)] ulong address, [R(2)] int maxCount, [R(1)] out int count)
{
return GetProcessList(address, maxCount, out count);
}
public KernelResult GetProcessList32([R(1)] ulong address, [R(2)] int maxCount, [R(1)] out int count)
{
return GetProcessList(address, maxCount, out count);
}
private KernelResult GetProcessList(ulong address, int maxCount, out int count)
{
count = 0;
if ((maxCount >> 28) != 0)
{
return KernelResult.MaximumExceeded;
}
if (maxCount != 0)
{
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
ulong copySize = (ulong)maxCount * 8;
if (address + copySize <= address)
{
return KernelResult.InvalidMemState;
}
if (currentProcess.MemoryManager.OutsideAddrSpace(address, copySize))
{
return KernelResult.InvalidMemState;
}
}
int copyCount = 0;
lock (_system.Processes)
{
foreach (KProcess process in _system.Processes.Values)
{
if (copyCount < maxCount)
{
if (!KernelTransfer.KernelToUserInt64(_system, address + (ulong)copyCount * 8, process.Pid))
{
return KernelResult.UserCopyFailed;
}
}
copyCount++;
}
}
count = copyCount;
return KernelResult.Success;
}
public KernelResult GetSystemInfo64([R(1)] uint id, [R(2)] int handle, [R(3)] long subId, [R(1)] out long value)
{
return GetSystemInfo(id, handle, subId, out value);
}
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 = GetSystemInfo(id, handle, subId, out long value);
valueHigh = (int)(value >> 32);
valueLow = (int)(value & uint.MaxValue);
return result;
}
private KernelResult GetSystemInfo(uint id, int handle, long subId, out long value)
{
value = 0;
if (id > 2)
{
return KernelResult.InvalidEnumValue;
}
if (handle != 0)
{
return KernelResult.InvalidHandle;
}
if (id < 2)
{
if ((ulong)subId > 3)
{
return KernelResult.InvalidCombination;
}
KMemoryRegionManager region = _system.MemoryRegions[subId];
switch (id)
{
// Memory region capacity.
case 0: value = (long)region.Size; break;
// Memory region free space.
case 1:
{
ulong freePagesCount = region.GetFreePages();
value = (long)(freePagesCount * KMemoryManager.PageSize);
break;
}
}
}
else /* if (Id == 2) */
{
if ((ulong)subId > 1)
{
return KernelResult.InvalidCombination;
}
switch (subId)
{
case 0: value = _system.PrivilegedProcessLowestId; break;
case 1: value = _system.PrivilegedProcessHighestId; break;
}
}
return KernelResult.Success;
}
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;
}
}
}

View file

@ -1,520 +0,0 @@
using ARMeilleure.State;
using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading;
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
partial class SvcHandler
{
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 CreateThread(entrypoint, argsPtr, stackTop, priority, cpuCore, out handle);
}
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 CreateThread(entrypoint, argsPtr, stackTop, priority, cpuCore, out handle);
}
private KernelResult CreateThread(
ulong entrypoint,
ulong argsPtr,
ulong stackTop,
int priority,
int cpuCore,
out int handle)
{
handle = 0;
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
if (cpuCore == -2)
{
cpuCore = currentProcess.DefaultCpuCore;
}
if ((uint)cpuCore >= KScheduler.CpuCoresCount || !currentProcess.IsCpuCoreAllowed(cpuCore))
{
return KernelResult.InvalidCpuCore;
}
if ((uint)priority >= KScheduler.PrioritiesCount || !currentProcess.IsPriorityAllowed(priority))
{
return KernelResult.InvalidPriority;
}
long timeout = KTimeManager.ConvertMillisecondsToNanoseconds(100);
if (currentProcess.ResourceLimit != null &&
!currentProcess.ResourceLimit.Reserve(LimitableResource.Thread, 1, timeout))
{
return KernelResult.ResLimitExceeded;
}
KThread thread = new KThread(_system);
KernelResult result = currentProcess.InitializeThread(
thread,
entrypoint,
argsPtr,
stackTop,
priority,
cpuCore);
if (result == KernelResult.Success)
{
result = _process.HandleTable.GenerateHandle(thread, out handle);
}
else
{
currentProcess.ResourceLimit?.Release(LimitableResource.Thread, 1);
}
thread.DecrementReferenceCount();
return result;
}
public KernelResult StartThread64([R(0)] int handle)
{
return StartThread(handle);
}
public KernelResult StartThread32([R(0)] int handle)
{
return StartThread(handle);
}
private KernelResult StartThread(int handle)
{
KThread thread = _process.HandleTable.GetKThread(handle);
if (thread != null)
{
thread.IncrementReferenceCount();
KernelResult result = thread.Start();
if (result == KernelResult.Success)
{
thread.IncrementReferenceCount();
}
thread.DecrementReferenceCount();
return result;
}
else
{
return KernelResult.InvalidHandle;
}
}
public void ExitThread64()
{
ExitThread();
}
public void ExitThread32()
{
ExitThread();
}
private void ExitThread()
{
KThread currentThread = _system.Scheduler.GetCurrentThread();
_system.Scheduler.ExitThread(currentThread);
currentThread.Exit();
}
public void SleepThread64([R(0)] long timeout)
{
SleepThread(timeout);
}
public void SleepThread32([R(0)] uint timeoutLow, [R(1)] uint timeoutHigh)
{
long timeout = (long)(timeoutLow | ((ulong)timeoutHigh << 32));
SleepThread(timeout);
}
private void SleepThread(long timeout)
{
KThread currentThread = _system.Scheduler.GetCurrentThread();
if (timeout < 1)
{
switch (timeout)
{
case 0: currentThread.Yield(); break;
case -1: currentThread.YieldWithLoadBalancing(); break;
case -2: currentThread.YieldAndWaitForLoadBalancing(); break;
}
}
else
{
currentThread.Sleep(timeout);
}
}
public KernelResult GetThreadPriority64([R(1)] int handle, [R(1)] out int priority)
{
return GetThreadPriority(handle, out priority);
}
public KernelResult GetThreadPriority32([R(1)] int handle, [R(1)] out int priority)
{
return GetThreadPriority(handle, out priority);
}
private KernelResult GetThreadPriority(int handle, out int priority)
{
KThread thread = _process.HandleTable.GetKThread(handle);
if (thread != null)
{
priority = thread.DynamicPriority;
return KernelResult.Success;
}
else
{
priority = 0;
return KernelResult.InvalidHandle;
}
}
public KernelResult SetThreadPriority64([R(0)] int handle, [R(1)] int priority)
{
return SetThreadPriority(handle, priority);
}
public KernelResult SetThreadPriority32([R(0)] int handle, [R(1)] int priority)
{
return SetThreadPriority(handle, priority);
}
public KernelResult SetThreadPriority(int handle, int priority)
{
// TODO: NPDM check.
KThread thread = _process.HandleTable.GetKThread(handle);
if (thread == null)
{
return KernelResult.InvalidHandle;
}
thread.SetPriority(priority);
return KernelResult.Success;
}
public KernelResult GetThreadCoreMask64([R(2)] int handle, [R(1)] out int preferredCore, [R(2)] out long affinityMask)
{
return GetThreadCoreMask(handle, out preferredCore, out affinityMask);
}
public KernelResult GetThreadCoreMask32([R(2)] int handle, [R(1)] out int preferredCore, [R(2)] out int affinityMaskLow, [R(3)] out int affinityMaskHigh)
{
KernelResult result = GetThreadCoreMask(handle, out preferredCore, out long affinityMask);
affinityMaskLow = (int)(affinityMask >> 32);
affinityMaskHigh = (int)(affinityMask & uint.MaxValue);
return result;
}
private KernelResult GetThreadCoreMask(int handle, out int preferredCore, out long affinityMask)
{
KThread thread = _process.HandleTable.GetKThread(handle);
if (thread != null)
{
preferredCore = thread.PreferredCore;
affinityMask = thread.AffinityMask;
return KernelResult.Success;
}
else
{
preferredCore = 0;
affinityMask = 0;
return KernelResult.InvalidHandle;
}
}
public KernelResult SetThreadCoreMask64([R(0)] int handle, [R(1)] int preferredCore, [R(2)] long affinityMask)
{
return SetThreadCoreMask(handle, preferredCore, affinityMask);
}
public KernelResult SetThreadCoreMask32([R(0)] int handle, [R(1)] int preferredCore, [R(2)] uint affinityMaskLow, [R(3)] uint affinityMaskHigh)
{
long affinityMask = (long)(affinityMaskLow | ((ulong)affinityMaskHigh << 32));
return SetThreadCoreMask(handle, preferredCore, affinityMask);
}
private KernelResult SetThreadCoreMask(int handle, int preferredCore, long affinityMask)
{
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
if (preferredCore == -2)
{
preferredCore = currentProcess.DefaultCpuCore;
affinityMask = 1 << preferredCore;
}
else
{
if ((currentProcess.Capabilities.AllowedCpuCoresMask | affinityMask) !=
currentProcess.Capabilities.AllowedCpuCoresMask)
{
return KernelResult.InvalidCpuCore;
}
if (affinityMask == 0)
{
return KernelResult.InvalidCombination;
}
if ((uint)preferredCore > 3)
{
if ((preferredCore | 2) != -1)
{
return KernelResult.InvalidCpuCore;
}
}
else if ((affinityMask & (1 << preferredCore)) == 0)
{
return KernelResult.InvalidCombination;
}
}
KThread thread = _process.HandleTable.GetKThread(handle);
if (thread == null)
{
return KernelResult.InvalidHandle;
}
return thread.SetCoreAndAffinityMask(preferredCore, affinityMask);
}
public int GetCurrentProcessorNumber64()
{
return _system.Scheduler.GetCurrentThread().CurrentCore;
}
public int GetCurrentProcessorNumber32()
{
return _system.Scheduler.GetCurrentThread().CurrentCore;
}
public KernelResult GetThreadId64([R(1)] int handle, [R(1)] out long threadUid)
{
return GetThreadId(handle, out threadUid);
}
public KernelResult GetThreadId32([R(1)] int handle, [R(1)] out uint threadUidLow, [R(2)] out uint threadUidHigh)
{
long threadUid;
KernelResult result = GetThreadId(handle, out threadUid);
threadUidLow = (uint)(threadUid >> 32);
threadUidHigh = (uint)(threadUid & uint.MaxValue);
return result;
}
private KernelResult GetThreadId(int handle, out long threadUid)
{
KThread thread = _process.HandleTable.GetKThread(handle);
if (thread != null)
{
threadUid = thread.ThreadUid;
return KernelResult.Success;
}
else
{
threadUid = 0;
return KernelResult.InvalidHandle;
}
}
public KernelResult SetThreadActivity64([R(0)] int handle, [R(1)] bool pause)
{
return SetThreadActivity(handle, pause);
}
public KernelResult SetThreadActivity32([R(0)] int handle, [R(1)] bool pause)
{
return SetThreadActivity(handle, pause);
}
private KernelResult SetThreadActivity(int handle, bool pause)
{
KThread thread = _process.HandleTable.GetObject<KThread>(handle);
if (thread == null)
{
return KernelResult.InvalidHandle;
}
if (thread.Owner != _system.Scheduler.GetCurrentProcess())
{
return KernelResult.InvalidHandle;
}
if (thread == _system.Scheduler.GetCurrentThread())
{
return KernelResult.InvalidThread;
}
return thread.SetActivity(pause);
}
public KernelResult GetThreadContext364([R(0)] ulong address, [R(1)] int handle)
{
return GetThreadContext3(address, handle);
}
public KernelResult GetThreadContext332([R(0)] uint address, [R(1)] int handle)
{
return GetThreadContext3(address, handle);
}
private KernelResult GetThreadContext3(ulong address, int handle)
{
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KThread currentThread = _system.Scheduler.GetCurrentThread();
KThread thread = _process.HandleTable.GetObject<KThread>(handle);
if (thread == null)
{
return KernelResult.InvalidHandle;
}
if (thread.Owner != currentProcess)
{
return KernelResult.InvalidHandle;
}
if (currentThread == thread)
{
return KernelResult.InvalidThread;
}
MemoryManager memory = currentProcess.CpuMemory;
memory.Write(address + 0x0, thread.Context.GetX(0));
memory.Write(address + 0x8, thread.Context.GetX(1));
memory.Write(address + 0x10, thread.Context.GetX(2));
memory.Write(address + 0x18, thread.Context.GetX(3));
memory.Write(address + 0x20, thread.Context.GetX(4));
memory.Write(address + 0x28, thread.Context.GetX(5));
memory.Write(address + 0x30, thread.Context.GetX(6));
memory.Write(address + 0x38, thread.Context.GetX(7));
memory.Write(address + 0x40, thread.Context.GetX(8));
memory.Write(address + 0x48, thread.Context.GetX(9));
memory.Write(address + 0x50, thread.Context.GetX(10));
memory.Write(address + 0x58, thread.Context.GetX(11));
memory.Write(address + 0x60, thread.Context.GetX(12));
memory.Write(address + 0x68, thread.Context.GetX(13));
memory.Write(address + 0x70, thread.Context.GetX(14));
memory.Write(address + 0x78, thread.Context.GetX(15));
memory.Write(address + 0x80, thread.Context.GetX(16));
memory.Write(address + 0x88, thread.Context.GetX(17));
memory.Write(address + 0x90, thread.Context.GetX(18));
memory.Write(address + 0x98, thread.Context.GetX(19));
memory.Write(address + 0xa0, thread.Context.GetX(20));
memory.Write(address + 0xa8, thread.Context.GetX(21));
memory.Write(address + 0xb0, thread.Context.GetX(22));
memory.Write(address + 0xb8, thread.Context.GetX(23));
memory.Write(address + 0xc0, thread.Context.GetX(24));
memory.Write(address + 0xc8, thread.Context.GetX(25));
memory.Write(address + 0xd0, thread.Context.GetX(26));
memory.Write(address + 0xd8, thread.Context.GetX(27));
memory.Write(address + 0xe0, thread.Context.GetX(28));
memory.Write(address + 0xe8, thread.Context.GetX(29));
memory.Write(address + 0xf0, thread.Context.GetX(30));
memory.Write(address + 0xf8, thread.Context.GetX(31));
memory.Write(address + 0x100, thread.LastPc);
memory.Write(address + 0x108, (ulong)GetPsr(thread.Context));
memory.Write(address + 0x110, thread.Context.GetV(0));
memory.Write(address + 0x120, thread.Context.GetV(1));
memory.Write(address + 0x130, thread.Context.GetV(2));
memory.Write(address + 0x140, thread.Context.GetV(3));
memory.Write(address + 0x150, thread.Context.GetV(4));
memory.Write(address + 0x160, thread.Context.GetV(5));
memory.Write(address + 0x170, thread.Context.GetV(6));
memory.Write(address + 0x180, thread.Context.GetV(7));
memory.Write(address + 0x190, thread.Context.GetV(8));
memory.Write(address + 0x1a0, thread.Context.GetV(9));
memory.Write(address + 0x1b0, thread.Context.GetV(10));
memory.Write(address + 0x1c0, thread.Context.GetV(11));
memory.Write(address + 0x1d0, thread.Context.GetV(12));
memory.Write(address + 0x1e0, thread.Context.GetV(13));
memory.Write(address + 0x1f0, thread.Context.GetV(14));
memory.Write(address + 0x200, thread.Context.GetV(15));
memory.Write(address + 0x210, thread.Context.GetV(16));
memory.Write(address + 0x220, thread.Context.GetV(17));
memory.Write(address + 0x230, thread.Context.GetV(18));
memory.Write(address + 0x240, thread.Context.GetV(19));
memory.Write(address + 0x250, thread.Context.GetV(20));
memory.Write(address + 0x260, thread.Context.GetV(21));
memory.Write(address + 0x270, thread.Context.GetV(22));
memory.Write(address + 0x280, thread.Context.GetV(23));
memory.Write(address + 0x290, thread.Context.GetV(24));
memory.Write(address + 0x2a0, thread.Context.GetV(25));
memory.Write(address + 0x2b0, thread.Context.GetV(26));
memory.Write(address + 0x2c0, thread.Context.GetV(27));
memory.Write(address + 0x2d0, thread.Context.GetV(28));
memory.Write(address + 0x2e0, thread.Context.GetV(29));
memory.Write(address + 0x2f0, thread.Context.GetV(30));
memory.Write(address + 0x300, thread.Context.GetV(31));
memory.Write(address + 0x310, (int)thread.Context.Fpcr);
memory.Write(address + 0x314, (int)thread.Context.Fpsr);
memory.Write(address + 0x318, thread.Context.Tpidr);
return KernelResult.Success;
}
private static int GetPsr(ExecutionContext context)
{
return (context.GetPstateFlag(PState.NFlag) ? (1 << 31) : 0) |
(context.GetPstateFlag(PState.ZFlag) ? (1 << 30) : 0) |
(context.GetPstateFlag(PState.CFlag) ? (1 << 29) : 0) |
(context.GetPstateFlag(PState.VFlag) ? (1 << 28) : 0);
}
}
}

View file

@ -1,306 +0,0 @@
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading;
using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
partial class SvcHandler
{
public KernelResult WaitSynchronization64([R(1)] ulong handlesPtr, [R(2)] int handlesCount, [R(3)] long timeout, [R(1)] out int handleIndex)
{
return WaitSynchronization(handlesPtr, handlesCount, timeout, out handleIndex);
}
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 WaitSynchronization(handlesPtr, handlesCount, timeout, out handleIndex);
}
private KernelResult WaitSynchronization(ulong handlesPtr, int handlesCount, long timeout, out int handleIndex)
{
handleIndex = 0;
if ((uint)handlesCount > 0x40)
{
return KernelResult.MaximumExceeded;
}
List<KSynchronizationObject> syncObjs = new List<KSynchronizationObject>();
for (int index = 0; index < handlesCount; index++)
{
int handle = _process.CpuMemory.Read<int>(handlesPtr + (ulong)index * 4);
KSynchronizationObject syncObj = _process.HandleTable.GetObject<KSynchronizationObject>(handle);
if (syncObj == null)
{
break;
}
syncObjs.Add(syncObj);
}
return _system.Synchronization.WaitFor(syncObjs.ToArray(), timeout, out handleIndex);
}
public KernelResult CancelSynchronization64([R(0)] int handle)
{
return CancelSynchronization(handle);
}
public KernelResult CancelSynchronization32([R(0)] int handle)
{
return CancelSynchronization(handle);
}
private KernelResult CancelSynchronization(int handle)
{
KThread thread = _process.HandleTable.GetKThread(handle);
if (thread == null)
{
return KernelResult.InvalidHandle;
}
thread.CancelSynchronization();
return KernelResult.Success;
}
public KernelResult ArbitrateLock64([R(0)] int ownerHandle, [R(1)] ulong mutexAddress, [R(2)] int requesterHandle)
{
return ArbitrateLock(ownerHandle, mutexAddress, requesterHandle);
}
public KernelResult ArbitrateLock32([R(0)] int ownerHandle, [R(1)] uint mutexAddress, [R(2)] int requesterHandle)
{
return ArbitrateLock(ownerHandle, mutexAddress, requesterHandle);
}
private KernelResult ArbitrateLock(int ownerHandle, ulong mutexAddress, int requesterHandle)
{
if (IsPointingInsideKernel(mutexAddress))
{
return KernelResult.InvalidMemState;
}
if (IsAddressNotWordAligned(mutexAddress))
{
return KernelResult.InvalidAddress;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
return currentProcess.AddressArbiter.ArbitrateLock(ownerHandle, mutexAddress, requesterHandle);
}
public KernelResult ArbitrateUnlock64([R(0)] ulong mutexAddress)
{
return ArbitrateUnlock(mutexAddress);
}
public KernelResult ArbitrateUnlock32([R(0)] uint mutexAddress)
{
return ArbitrateUnlock(mutexAddress);
}
private KernelResult ArbitrateUnlock(ulong mutexAddress)
{
if (IsPointingInsideKernel(mutexAddress))
{
return KernelResult.InvalidMemState;
}
if (IsAddressNotWordAligned(mutexAddress))
{
return KernelResult.InvalidAddress;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
return currentProcess.AddressArbiter.ArbitrateUnlock(mutexAddress);
}
public KernelResult WaitProcessWideKeyAtomic64(
[R(0)] ulong mutexAddress,
[R(1)] ulong condVarAddress,
[R(2)] int handle,
[R(3)] long timeout)
{
return WaitProcessWideKeyAtomic(mutexAddress, condVarAddress, handle, timeout);
}
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 WaitProcessWideKeyAtomic(mutexAddress, condVarAddress, handle, timeout);
}
private KernelResult WaitProcessWideKeyAtomic(
ulong mutexAddress,
ulong condVarAddress,
int handle,
long timeout)
{
if (IsPointingInsideKernel(mutexAddress))
{
return KernelResult.InvalidMemState;
}
if (IsAddressNotWordAligned(mutexAddress))
{
return KernelResult.InvalidAddress;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
return currentProcess.AddressArbiter.WaitProcessWideKeyAtomic(
mutexAddress,
condVarAddress,
handle,
timeout);
}
public KernelResult SignalProcessWideKey64([R(0)] ulong address, [R(1)] int count)
{
return SignalProcessWideKey(address, count);
}
public KernelResult SignalProcessWideKey32([R(0)] uint address, [R(1)] int count)
{
return SignalProcessWideKey(address, count);
}
private KernelResult SignalProcessWideKey(ulong address, int count)
{
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
currentProcess.AddressArbiter.SignalProcessWideKey(address, count);
return KernelResult.Success;
}
public KernelResult WaitForAddress64([R(0)] ulong address, [R(1)] ArbitrationType type, [R(2)] int value, [R(3)] long timeout)
{
return WaitForAddress(address, type, value, timeout);
}
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 WaitForAddress(address, type, value, timeout);
}
private KernelResult WaitForAddress(ulong address, ArbitrationType type, int value, long timeout)
{
if (IsPointingInsideKernel(address))
{
return KernelResult.InvalidMemState;
}
if (IsAddressNotWordAligned(address))
{
return KernelResult.InvalidAddress;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KernelResult result;
switch (type)
{
case ArbitrationType.WaitIfLessThan:
result = currentProcess.AddressArbiter.WaitForAddressIfLessThan(address, value, false, timeout);
break;
case ArbitrationType.DecrementAndWaitIfLessThan:
result = currentProcess.AddressArbiter.WaitForAddressIfLessThan(address, value, true, timeout);
break;
case ArbitrationType.WaitIfEqual:
result = currentProcess.AddressArbiter.WaitForAddressIfEqual(address, value, timeout);
break;
default:
result = KernelResult.InvalidEnumValue;
break;
}
return result;
}
public KernelResult SignalToAddress64([R(0)] ulong address, [R(1)] SignalType type, [R(2)] int value, [R(3)] int count)
{
return SignalToAddress(address, type, value, count);
}
public KernelResult SignalToAddress32([R(0)] uint address, [R(1)] SignalType type, [R(2)] int value, [R(3)] int count)
{
return SignalToAddress(address, type, value, count);
}
private KernelResult SignalToAddress(ulong address, SignalType type, int value, int count)
{
if (IsPointingInsideKernel(address))
{
return KernelResult.InvalidMemState;
}
if (IsAddressNotWordAligned(address))
{
return KernelResult.InvalidAddress;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KernelResult result;
switch (type)
{
case SignalType.Signal:
result = currentProcess.AddressArbiter.Signal(address, count);
break;
case SignalType.SignalAndIncrementIfEqual:
result = currentProcess.AddressArbiter.SignalAndIncrementIfEqual(address, value, count);
break;
case SignalType.SignalAndModifyIfEqual:
result = currentProcess.AddressArbiter.SignalAndModifyIfEqual(address, value, count);
break;
default:
result = KernelResult.InvalidEnumValue;
break;
}
return result;
}
private bool IsPointingInsideKernel(ulong address)
{
return (address + 0x1000000000) < 0xffffff000;
}
private bool IsAddressNotWordAligned(ulong address)
{
return (address & 3) != 0;
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,435 @@
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(namePtr, out handle);
}
public KernelResult SendSyncRequest32([R(0)] int handle)
{
return _syscall.SendSyncRequest(handle);
}
public KernelResult SendSyncRequestWithUserBuffer32([R(0)] uint messagePtr, [R(1)] uint size, [R(2)] int handle)
{
return _syscall.SendSyncRequestWithUserBuffer(messagePtr, size, 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(isLight, namePtr, out serverSessionHandle, out clientSessionHandle);
}
public KernelResult AcceptSession32([R(1)] int portHandle, [R(1)] out int sessionHandle)
{
return _syscall.AcceptSession(portHandle, out sessionHandle);
}
public KernelResult ReplyAndReceive32(
[R(0)] uint timeoutLow,
[R(1)] ulong 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(handlesPtr, handlesCount, replyTargetHandle, timeout, out handleIndex);
}
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(maxSessions, isLight, namePtr, out serverPortHandle, out clientPortHandle);
}
public KernelResult ManageNamedPort32([R(1)] uint namePtr, [R(2)] int maxSessions, [R(1)] out int handle)
{
return _syscall.ManageNamedPort(namePtr, maxSessions, out handle);
}
public KernelResult ConnectToPort32([R(1)] int clientPortHandle, [R(1)] out int clientSessionHandle)
{
return _syscall.ConnectToPort(clientPortHandle, out clientSessionHandle);
}
// Memory
public KernelResult SetHeapSize32([R(1)] uint size, [R(1)] out uint position)
{
KernelResult result = _syscall.SetHeapSize(size, out ulong temporaryPosition);
position = (uint)temporaryPosition;
return result;
}
public KernelResult SetMemoryAttribute32(
[R(0)] uint position,
[R(1)] uint size,
[R(2)] MemoryAttribute attributeMask,
[R(3)] MemoryAttribute attributeValue)
{
return _syscall.SetMemoryAttribute(position, 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 position, [R(1)] out uint pageInfo)
{
KernelResult result = _syscall.QueryMemory(infoPtr, position, out ulong pageInfo64);
pageInfo = (uint)pageInfo64;
return result;
}
public KernelResult MapSharedMemory32([R(0)] int handle, [R(1)] uint address, [R(2)] uint size, [R(3)] MemoryPermission 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)] MemoryPermission permission,
[R(1)] out int handle)
{
return _syscall.CreateTransferMemory(address, size, permission, out handle);
}
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 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);
}
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)] MemoryPermission permission)
{
ulong src = srcLow | ((ulong)srcHigh << 32);
ulong size = sizeLow | ((ulong)sizeHigh << 32);
return _syscall.SetProcessMemoryPermission(handle, src, size, permission);
}
// 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 int pidLow, [R(2)] out int pidHigh)
{
KernelResult result = _syscall.GetProcessId(handle, out long pid);
pidLow = (int)(pid & uint.MaxValue);
pidHigh = (int)(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)] uint 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(id, handle, subId, out long value);
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(address, maxCount, out count);
}
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(id, handle, subId, out long value);
valueHigh = (int)(value >> 32);
valueLow = (int)(value & uint.MaxValue);
return result;
}
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(entrypoint, argsPtr, stackTop, priority, cpuCore, out handle);
}
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(handle, out priority);
}
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 int affinityMaskLow, [R(3)] out int affinityMaskHigh)
{
KernelResult result = _syscall.GetThreadCoreMask(handle, out preferredCore, out long affinityMask);
affinityMaskLow = (int)(affinityMask >> 32);
affinityMaskHigh = (int)(affinityMask & uint.MaxValue);
return result;
}
public KernelResult SetThreadCoreMask32([R(0)] int handle, [R(1)] int preferredCore, [R(2)] uint affinityMaskLow, [R(3)] uint affinityMaskHigh)
{
long affinityMask = (long)(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)
{
long threadUid;
KernelResult result = _syscall.GetThreadId(handle, out threadUid);
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(handlesPtr, handlesCount, timeout, out handleIndex);
}
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);
}
}
}

View file

@ -0,0 +1,338 @@
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(namePtr, out handle);
}
public KernelResult SendSyncRequest64([R(0)] int handle)
{
return _syscall.SendSyncRequest(handle);
}
public KernelResult SendSyncRequestWithUserBuffer64([R(0)] ulong messagePtr, [R(1)] ulong size, [R(2)] int handle)
{
return _syscall.SendSyncRequestWithUserBuffer(messagePtr, size, 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(isLight, namePtr, out serverSessionHandle, out clientSessionHandle);
}
public KernelResult AcceptSession64([R(1)] int portHandle, [R(1)] out int sessionHandle)
{
return _syscall.AcceptSession(portHandle, out sessionHandle);
}
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(handlesPtr, handlesCount, replyTargetHandle, timeout, out handleIndex);
}
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(maxSessions, isLight, namePtr, out serverPortHandle, out clientPortHandle);
}
public KernelResult ManageNamedPort64([R(1)] ulong namePtr, [R(2)] int maxSessions, [R(1)] out int handle)
{
return _syscall.ManageNamedPort(namePtr, maxSessions, out handle);
}
public KernelResult ConnectToPort64([R(1)] int clientPortHandle, [R(1)] out int clientSessionHandle)
{
return _syscall.ConnectToPort(clientPortHandle, out clientSessionHandle);
}
// Memory
public KernelResult SetHeapSize64([R(1)] ulong size, [R(1)] out ulong position)
{
return _syscall.SetHeapSize(size, out position);
}
public KernelResult SetMemoryAttribute64(
[R(0)] ulong position,
[R(1)] ulong size,
[R(2)] MemoryAttribute attributeMask,
[R(3)] MemoryAttribute attributeValue)
{
return _syscall.SetMemoryAttribute(position, 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 position, [R(1)] out ulong pageInfo)
{
return _syscall.QueryMemory(infoPtr, position, out pageInfo);
}
public KernelResult MapSharedMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size, [R(3)] MemoryPermission 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)] MemoryPermission permission,
[R(1)] out int handle)
{
return _syscall.CreateTransferMemory(address, size, permission, out handle);
}
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 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);
}
public KernelResult SetProcessMemoryPermission64([R(0)] int handle, [R(1)] ulong src, [R(2)] ulong size, [R(3)] MemoryPermission permission)
{
return _syscall.SetProcessMemoryPermission(handle, src, size, permission);
}
// 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 long pid)
{
return _syscall.GetProcessId(handle, out pid);
}
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)] uint id, [R(2)] int handle, [R(3)] long subId, [R(1)] out long value)
{
return _syscall.GetInfo(id, handle, subId, out value);
}
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(address, maxCount, out count);
}
public KernelResult GetSystemInfo64([R(1)] uint id, [R(2)] int handle, [R(3)] long subId, [R(1)] out long value)
{
return _syscall.GetSystemInfo(id, handle, subId, out value);
}
// 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(entrypoint, argsPtr, stackTop, priority, cpuCore, out handle);
}
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(handle, out priority);
}
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 long affinityMask)
{
return _syscall.GetThreadCoreMask(handle, out preferredCore, out affinityMask);
}
public KernelResult SetThreadCoreMask64([R(0)] int handle, [R(1)] int preferredCore, [R(2)] long affinityMask)
{
return _syscall.SetThreadCoreMask(handle, preferredCore, affinityMask);
}
public int GetCurrentProcessorNumber64()
{
return _syscall.GetCurrentProcessorNumber();
}
public KernelResult GetThreadId64([R(1)] int handle, [R(1)] out long threadUid)
{
return _syscall.GetThreadId(handle, out threadUid);
}
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(handlesPtr, handlesCount, timeout, out handleIndex);
}
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);
}
}
}

View file

@ -0,0 +1,57 @@
using ARMeilleure.State;
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(object sender, InstExceptionEventArgs e)
{
ExecutionContext context = (ExecutionContext)sender;
if (context.IsAarch32)
{
var svcFunc = SyscallTable.SvcTable32[e.Id];
if (svcFunc == null)
{
throw new NotImplementedException($"SVC 0x{e.Id:X4} is not implemented.");
}
svcFunc(_syscall32, context);
}
else
{
var svcFunc = SyscallTable.SvcTable64[e.Id];
if (svcFunc == null)
{
throw new NotImplementedException($"SVC 0x{e.Id:X4} is not implemented.");
}
svcFunc(_syscall64, context);
}
PostSvcHandler();
}
private void PostSvcHandler()
{
KThread currentThread = _context.Scheduler.GetCurrentThread();
currentThread.HandlePostSyscall();
}
}
}

View file

@ -3,165 +3,164 @@ using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Kernel.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
static class SvcTable
static class SyscallTable
{
private const int SvcFuncMaxArguments64 = 8;
private const int SvcFuncMaxArguments32 = 4;
private const int SvcMax = 0x80;
public static Action<SvcHandler, ExecutionContext>[] SvcTable32 { get; }
public static Action<SvcHandler, ExecutionContext>[] SvcTable64 { get; }
public static Action<Syscall32, ExecutionContext>[] SvcTable32 { get; }
public static Action<Syscall64, ExecutionContext>[] SvcTable64 { get; }
static SvcTable()
static SyscallTable()
{
SvcTable32 = new Action<SvcHandler, ExecutionContext>[SvcMax];
SvcTable64 = new Action<SvcHandler, ExecutionContext>[SvcMax];
SvcTable32 = new Action<Syscall32, ExecutionContext>[SvcMax];
SvcTable64 = new Action<Syscall64, ExecutionContext>[SvcMax];
Dictionary<int, string> svcFuncs64 = new Dictionary<int, string>
{
{ 0x01, nameof(SvcHandler.SetHeapSize64) },
{ 0x03, nameof(SvcHandler.SetMemoryAttribute64) },
{ 0x04, nameof(SvcHandler.MapMemory64) },
{ 0x05, nameof(SvcHandler.UnmapMemory64) },
{ 0x06, nameof(SvcHandler.QueryMemory64) },
{ 0x07, nameof(SvcHandler.ExitProcess64) },
{ 0x08, nameof(SvcHandler.CreateThread64) },
{ 0x09, nameof(SvcHandler.StartThread64) },
{ 0x0a, nameof(SvcHandler.ExitThread64) },
{ 0x0b, nameof(SvcHandler.SleepThread64) },
{ 0x0c, nameof(SvcHandler.GetThreadPriority64) },
{ 0x0d, nameof(SvcHandler.SetThreadPriority64) },
{ 0x0e, nameof(SvcHandler.GetThreadCoreMask64) },
{ 0x0f, nameof(SvcHandler.SetThreadCoreMask64) },
{ 0x10, nameof(SvcHandler.GetCurrentProcessorNumber64) },
{ 0x11, nameof(SvcHandler.SignalEvent64) },
{ 0x12, nameof(SvcHandler.ClearEvent64) },
{ 0x13, nameof(SvcHandler.MapSharedMemory64) },
{ 0x14, nameof(SvcHandler.UnmapSharedMemory64) },
{ 0x15, nameof(SvcHandler.CreateTransferMemory64) },
{ 0x16, nameof(SvcHandler.CloseHandle64) },
{ 0x17, nameof(SvcHandler.ResetSignal64) },
{ 0x18, nameof(SvcHandler.WaitSynchronization64) },
{ 0x19, nameof(SvcHandler.CancelSynchronization64) },
{ 0x1a, nameof(SvcHandler.ArbitrateLock64) },
{ 0x1b, nameof(SvcHandler.ArbitrateUnlock64) },
{ 0x1c, nameof(SvcHandler.WaitProcessWideKeyAtomic64) },
{ 0x1d, nameof(SvcHandler.SignalProcessWideKey64) },
{ 0x1e, nameof(SvcHandler.GetSystemTick64) },
{ 0x1f, nameof(SvcHandler.ConnectToNamedPort64) },
{ 0x21, nameof(SvcHandler.SendSyncRequest64) },
{ 0x22, nameof(SvcHandler.SendSyncRequestWithUserBuffer64) },
{ 0x24, nameof(SvcHandler.GetProcessId64) },
{ 0x25, nameof(SvcHandler.GetThreadId64) },
{ 0x26, nameof(SvcHandler.Break64) },
{ 0x27, nameof(SvcHandler.OutputDebugString64) },
{ 0x29, nameof(SvcHandler.GetInfo64) },
{ 0x2c, nameof(SvcHandler.MapPhysicalMemory64) },
{ 0x2d, nameof(SvcHandler.UnmapPhysicalMemory64) },
{ 0x32, nameof(SvcHandler.SetThreadActivity64) },
{ 0x33, nameof(SvcHandler.GetThreadContext364) },
{ 0x34, nameof(SvcHandler.WaitForAddress64) },
{ 0x35, nameof(SvcHandler.SignalToAddress64) },
{ 0x40, nameof(SvcHandler.CreateSession64) },
{ 0x41, nameof(SvcHandler.AcceptSession64) },
{ 0x43, nameof(SvcHandler.ReplyAndReceive64) },
{ 0x45, nameof(SvcHandler.CreateEvent64) },
{ 0x65, nameof(SvcHandler.GetProcessList64) },
{ 0x6f, nameof(SvcHandler.GetSystemInfo64) },
{ 0x70, nameof(SvcHandler.CreatePort64) },
{ 0x71, nameof(SvcHandler.ManageNamedPort64) },
{ 0x72, nameof(SvcHandler.ConnectToPort64) },
{ 0x73, nameof(SvcHandler.SetProcessMemoryPermission64) },
{ 0x77, nameof(SvcHandler.MapProcessCodeMemory64) },
{ 0x78, nameof(SvcHandler.UnmapProcessCodeMemory64) },
{ 0x7B, nameof(SvcHandler.TerminateProcess64) }
{ 0x01, nameof(Syscall64.SetHeapSize64) },
{ 0x03, nameof(Syscall64.SetMemoryAttribute64) },
{ 0x04, nameof(Syscall64.MapMemory64) },
{ 0x05, nameof(Syscall64.UnmapMemory64) },
{ 0x06, nameof(Syscall64.QueryMemory64) },
{ 0x07, nameof(Syscall64.ExitProcess64) },
{ 0x08, nameof(Syscall64.CreateThread64) },
{ 0x09, nameof(Syscall64.StartThread64) },
{ 0x0a, nameof(Syscall64.ExitThread64) },
{ 0x0b, nameof(Syscall64.SleepThread64) },
{ 0x0c, nameof(Syscall64.GetThreadPriority64) },
{ 0x0d, nameof(Syscall64.SetThreadPriority64) },
{ 0x0e, nameof(Syscall64.GetThreadCoreMask64) },
{ 0x0f, nameof(Syscall64.SetThreadCoreMask64) },
{ 0x10, nameof(Syscall64.GetCurrentProcessorNumber64) },
{ 0x11, nameof(Syscall64.SignalEvent64) },
{ 0x12, nameof(Syscall64.ClearEvent64) },
{ 0x13, nameof(Syscall64.MapSharedMemory64) },
{ 0x14, nameof(Syscall64.UnmapSharedMemory64) },
{ 0x15, nameof(Syscall64.CreateTransferMemory64) },
{ 0x16, nameof(Syscall64.CloseHandle64) },
{ 0x17, nameof(Syscall64.ResetSignal64) },
{ 0x18, nameof(Syscall64.WaitSynchronization64) },
{ 0x19, nameof(Syscall64.CancelSynchronization64) },
{ 0x1a, nameof(Syscall64.ArbitrateLock64) },
{ 0x1b, nameof(Syscall64.ArbitrateUnlock64) },
{ 0x1c, nameof(Syscall64.WaitProcessWideKeyAtomic64) },
{ 0x1d, nameof(Syscall64.SignalProcessWideKey64) },
{ 0x1e, nameof(Syscall64.GetSystemTick64) },
{ 0x1f, nameof(Syscall64.ConnectToNamedPort64) },
{ 0x21, nameof(Syscall64.SendSyncRequest64) },
{ 0x22, nameof(Syscall64.SendSyncRequestWithUserBuffer64) },
{ 0x24, nameof(Syscall64.GetProcessId64) },
{ 0x25, nameof(Syscall64.GetThreadId64) },
{ 0x26, nameof(Syscall64.Break64) },
{ 0x27, nameof(Syscall64.OutputDebugString64) },
{ 0x29, nameof(Syscall64.GetInfo64) },
{ 0x2c, nameof(Syscall64.MapPhysicalMemory64) },
{ 0x2d, nameof(Syscall64.UnmapPhysicalMemory64) },
{ 0x32, nameof(Syscall64.SetThreadActivity64) },
{ 0x33, nameof(Syscall64.GetThreadContext364) },
{ 0x34, nameof(Syscall64.WaitForAddress64) },
{ 0x35, nameof(Syscall64.SignalToAddress64) },
{ 0x40, nameof(Syscall64.CreateSession64) },
{ 0x41, nameof(Syscall64.AcceptSession64) },
{ 0x43, nameof(Syscall64.ReplyAndReceive64) },
{ 0x45, nameof(Syscall64.CreateEvent64) },
{ 0x65, nameof(Syscall64.GetProcessList64) },
{ 0x6f, nameof(Syscall64.GetSystemInfo64) },
{ 0x70, nameof(Syscall64.CreatePort64) },
{ 0x71, nameof(Syscall64.ManageNamedPort64) },
{ 0x72, nameof(Syscall64.ConnectToPort64) },
{ 0x73, nameof(Syscall64.SetProcessMemoryPermission64) },
{ 0x77, nameof(Syscall64.MapProcessCodeMemory64) },
{ 0x78, nameof(Syscall64.UnmapProcessCodeMemory64) },
{ 0x7B, nameof(Syscall64.TerminateProcess64) }
};
foreach (KeyValuePair<int, string> value in svcFuncs64)
{
SvcTable64[value.Key] = GenerateMethod(value.Value, SvcFuncMaxArguments64);
SvcTable64[value.Key] = GenerateMethod<Syscall64>(value.Value, SvcFuncMaxArguments64);
}
Dictionary<int, string> svcFuncs32 = new Dictionary<int, string>
{
{ 0x01, nameof(SvcHandler.SetHeapSize32) },
{ 0x03, nameof(SvcHandler.SetMemoryAttribute32) },
{ 0x04, nameof(SvcHandler.MapMemory32) },
{ 0x05, nameof(SvcHandler.UnmapMemory32) },
{ 0x06, nameof(SvcHandler.QueryMemory32) },
{ 0x07, nameof(SvcHandler.ExitProcess32) },
{ 0x08, nameof(SvcHandler.CreateThread32) },
{ 0x09, nameof(SvcHandler.StartThread32) },
{ 0x0a, nameof(SvcHandler.ExitThread32) },
{ 0x0b, nameof(SvcHandler.SleepThread32) },
{ 0x0c, nameof(SvcHandler.GetThreadPriority32) },
{ 0x0d, nameof(SvcHandler.SetThreadPriority32) },
{ 0x0e, nameof(SvcHandler.GetThreadCoreMask32) },
{ 0x0f, nameof(SvcHandler.SetThreadCoreMask32) },
{ 0x10, nameof(SvcHandler.GetCurrentProcessorNumber32) },
{ 0x11, nameof(SvcHandler.SignalEvent32) },
{ 0x12, nameof(SvcHandler.ClearEvent32) },
{ 0x13, nameof(SvcHandler.MapSharedMemory32) },
{ 0x14, nameof(SvcHandler.UnmapSharedMemory32) },
{ 0x15, nameof(SvcHandler.CreateTransferMemory32) },
{ 0x16, nameof(SvcHandler.CloseHandle32) },
{ 0x17, nameof(SvcHandler.ResetSignal32) },
{ 0x18, nameof(SvcHandler.WaitSynchronization32) },
{ 0x19, nameof(SvcHandler.CancelSynchronization32) },
{ 0x1a, nameof(SvcHandler.ArbitrateLock32) },
{ 0x1b, nameof(SvcHandler.ArbitrateUnlock32) },
{ 0x1c, nameof(SvcHandler.WaitProcessWideKeyAtomic32) },
{ 0x1d, nameof(SvcHandler.SignalProcessWideKey32) },
{ 0x1e, nameof(SvcHandler.GetSystemTick32) },
{ 0x1f, nameof(SvcHandler.ConnectToNamedPort32) },
{ 0x21, nameof(SvcHandler.SendSyncRequest32) },
{ 0x22, nameof(SvcHandler.SendSyncRequestWithUserBuffer32) },
{ 0x24, nameof(SvcHandler.GetProcessId32) },
{ 0x25, nameof(SvcHandler.GetThreadId32) },
{ 0x26, nameof(SvcHandler.Break32) },
{ 0x27, nameof(SvcHandler.OutputDebugString32) },
{ 0x29, nameof(SvcHandler.GetInfo32) },
{ 0x2c, nameof(SvcHandler.MapPhysicalMemory32) },
{ 0x2d, nameof(SvcHandler.UnmapPhysicalMemory32) },
{ 0x32, nameof(SvcHandler.SetThreadActivity32) },
{ 0x33, nameof(SvcHandler.GetThreadContext332) },
{ 0x34, nameof(SvcHandler.WaitForAddress32) },
{ 0x35, nameof(SvcHandler.SignalToAddress32) },
{ 0x40, nameof(SvcHandler.CreateSession32) },
{ 0x41, nameof(SvcHandler.AcceptSession32) },
{ 0x43, nameof(SvcHandler.ReplyAndReceive32) },
{ 0x45, nameof(SvcHandler.CreateEvent32) },
{ 0x5F, nameof(SvcHandler.FlushProcessDataCache32) },
{ 0x65, nameof(SvcHandler.GetProcessList32) },
{ 0x6f, nameof(SvcHandler.GetSystemInfo32) },
{ 0x70, nameof(SvcHandler.CreatePort32) },
{ 0x71, nameof(SvcHandler.ManageNamedPort32) },
{ 0x72, nameof(SvcHandler.ConnectToPort32) },
{ 0x73, nameof(SvcHandler.SetProcessMemoryPermission32) },
{ 0x77, nameof(SvcHandler.MapProcessCodeMemory32) },
{ 0x78, nameof(SvcHandler.UnmapProcessCodeMemory32) },
{ 0x7B, nameof(SvcHandler.TerminateProcess32) }
{ 0x01, nameof(Syscall32.SetHeapSize32) },
{ 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) },
{ 0x32, nameof(Syscall32.SetThreadActivity32) },
{ 0x33, nameof(Syscall32.GetThreadContext332) },
{ 0x34, nameof(Syscall32.WaitForAddress32) },
{ 0x35, nameof(Syscall32.SignalToAddress32) },
{ 0x40, nameof(Syscall32.CreateSession32) },
{ 0x41, nameof(Syscall32.AcceptSession32) },
{ 0x43, nameof(Syscall32.ReplyAndReceive32) },
{ 0x45, nameof(Syscall32.CreateEvent32) },
{ 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) },
{ 0x77, nameof(Syscall32.MapProcessCodeMemory32) },
{ 0x78, nameof(Syscall32.UnmapProcessCodeMemory32) },
{ 0x7B, nameof(Syscall32.TerminateProcess32) }
};
foreach (KeyValuePair<int, string> value in svcFuncs32)
{
SvcTable32[value.Key] = GenerateMethod(value.Value, SvcFuncMaxArguments32);
SvcTable32[value.Key] = GenerateMethod<Syscall32>(value.Value, SvcFuncMaxArguments32);
}
}
private static Action<SvcHandler, ExecutionContext> GenerateMethod(string svcName, int registerCleanCount)
private static Action<T, ExecutionContext> GenerateMethod<T>(string svcName, int registerCleanCount)
{
Type[] argTypes = new Type[] { typeof(SvcHandler), typeof(ExecutionContext) };
Type[] argTypes = new Type[] { typeof(T), typeof(ExecutionContext) };
DynamicMethod method = new DynamicMethod(svcName, null, argTypes);
MethodInfo methodInfo = typeof(SvcHandler).GetMethod(svcName);
MethodInfo methodInfo = typeof(T).GetMethod(svcName);
ParameterInfo[] methodArgs = methodInfo.GetParameters();
@ -285,7 +284,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
generator.Emit(OpCodes.Ldstr, svcName);
}
MethodInfo printArgsMethod = typeof(SvcTable).GetMethod(nameof(PrintArguments), staticNonPublic);
MethodInfo printArgsMethod = typeof(SyscallTable).GetMethod(nameof(PrintArguments), staticNonPublic);
generator.Emit(OpCodes.Call, printArgsMethod);
@ -343,7 +342,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
// Print result code.
if (retType == typeof(KernelResult))
{
MethodInfo printResultMethod = typeof(SvcTable).GetMethod(nameof(PrintResult), staticNonPublic);
MethodInfo printResultMethod = typeof(SyscallTable).GetMethod(nameof(PrintResult), staticNonPublic);
generator.Emit(OpCodes.Dup);
generator.Emit(OpCodes.Ldstr, svcName);
@ -414,7 +413,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
generator.Emit(OpCodes.Ret);
return (Action<SvcHandler, ExecutionContext>)method.CreateDelegate(typeof(Action<SvcHandler, ExecutionContext>));
return (Action<T, ExecutionContext>)method.CreateDelegate(typeof(Action<T, ExecutionContext>));
}
private static void CheckIfTypeIsSupported(Type type, string svcName)