Refactor SVC handler

This commit is contained in:
gdkchan 2018-12-12 01:04:18 -03:00
commit 3126f0c357
11 changed files with 904 additions and 1051 deletions

View file

@ -0,0 +1,9 @@
using System;
namespace Ryujinx.HLE.HOS.Kernel
{
public class InvalidSvcException : Exception
{
public InvalidSvcException(string message) : base(message) { }
}
}

View file

@ -22,7 +22,7 @@ namespace Ryujinx.HLE.HOS.Kernel
ArbiterThreads = new List<KThread>(); ArbiterThreads = new List<KThread>();
} }
public long ArbitrateLock(int ownerHandle, long mutexAddress, int requesterHandle) public KernelResult ArbitrateLock(int ownerHandle, ulong mutexAddress, int requesterHandle)
{ {
KThread currentThread = _system.Scheduler.GetCurrentThread(); KThread currentThread = _system.Scheduler.GetCurrentThread();
@ -37,7 +37,7 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); return KernelResult.InvalidMemState;
} }
if (mutexValue != (ownerHandle | HasListenersMask)) if (mutexValue != (ownerHandle | HasListenersMask))
@ -53,7 +53,7 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); return KernelResult.InvalidHandle;
} }
currentThread.MutexAddress = mutexAddress; currentThread.MutexAddress = mutexAddress;
@ -73,18 +73,18 @@ namespace Ryujinx.HLE.HOS.Kernel
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return (uint)currentThread.ObjSyncResult; return (KernelResult)currentThread.ObjSyncResult;
} }
public long ArbitrateUnlock(long mutexAddress) public KernelResult ArbitrateUnlock(ulong mutexAddress)
{ {
_system.CriticalSection.Enter(); _system.CriticalSection.Enter();
KThread currentThread = _system.Scheduler.GetCurrentThread(); KThread currentThread = _system.Scheduler.GetCurrentThread();
(long result, KThread newOwnerThread) = MutexUnlock(currentThread, mutexAddress); (KernelResult result, KThread newOwnerThread) = MutexUnlock(currentThread, mutexAddress);
if (result != 0 && newOwnerThread != null) if (result != KernelResult.Success && newOwnerThread != null)
{ {
newOwnerThread.SignaledObj = null; newOwnerThread.SignaledObj = null;
newOwnerThread.ObjSyncResult = (int)result; newOwnerThread.ObjSyncResult = (int)result;
@ -95,11 +95,11 @@ namespace Ryujinx.HLE.HOS.Kernel
return result; return result;
} }
public long WaitProcessWideKeyAtomic( public KernelResult WaitProcessWideKeyAtomic(
long mutexAddress, ulong mutexAddress,
long condVarAddress, ulong condVarAddress,
int threadHandle, int threadHandle,
long timeout) long timeout)
{ {
_system.CriticalSection.Enter(); _system.CriticalSection.Enter();
@ -113,12 +113,12 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.ThreadTerminating); return KernelResult.ThreadTerminating;
} }
(long result, _) = MutexUnlock(currentThread, mutexAddress); (KernelResult result, _) = MutexUnlock(currentThread, mutexAddress);
if (result != 0) if (result != KernelResult.Success)
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
@ -159,10 +159,10 @@ namespace Ryujinx.HLE.HOS.Kernel
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return (uint)currentThread.ObjSyncResult; return (KernelResult)currentThread.ObjSyncResult;
} }
private (long, KThread) MutexUnlock(KThread currentThread, long mutexAddress) private (KernelResult, KThread) MutexUnlock(KThread currentThread, ulong mutexAddress)
{ {
KThread newOwnerThread = currentThread.RelinquishMutex(mutexAddress, out int count); KThread newOwnerThread = currentThread.RelinquishMutex(mutexAddress, out int count);
@ -183,17 +183,17 @@ namespace Ryujinx.HLE.HOS.Kernel
newOwnerThread.ReleaseAndResume(); newOwnerThread.ReleaseAndResume();
} }
long result = 0; KernelResult result = KernelResult.Success;
if (!KernelTransfer.KernelToUserInt32(_system, mutexAddress, mutexValue)) if (!KernelTransfer.KernelToUserInt32(_system, mutexAddress, mutexValue))
{ {
result = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); result = KernelResult.InvalidMemState;
} }
return (result, newOwnerThread); return (result, newOwnerThread);
} }
public void SignalProcessWideKey(long address, int count) public void SignalProcessWideKey(ulong address, int count)
{ {
Queue<KThread> signaledThreads = new Queue<KThread>(); Queue<KThread> signaledThreads = new Queue<KThread>();
@ -224,11 +224,11 @@ namespace Ryujinx.HLE.HOS.Kernel
private KThread TryAcquireMutex(KThread requester) private KThread TryAcquireMutex(KThread requester)
{ {
long address = requester.MutexAddress; ulong address = requester.MutexAddress;
KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
currentProcess.CpuMemory.SetExclusive(0, address); currentProcess.CpuMemory.SetExclusive(0, (long)address);
if (!KernelTransfer.UserToKernelInt32(_system, address, out int mutexValue)) if (!KernelTransfer.UserToKernelInt32(_system, address, out int mutexValue))
{ {
@ -243,17 +243,17 @@ namespace Ryujinx.HLE.HOS.Kernel
while (true) while (true)
{ {
if (currentProcess.CpuMemory.TestExclusive(0, address)) if (currentProcess.CpuMemory.TestExclusive(0, (long)address))
{ {
if (mutexValue != 0) if (mutexValue != 0)
{ {
//Update value to indicate there is a mutex waiter now. //Update value to indicate there is a mutex waiter now.
currentProcess.CpuMemory.WriteInt32(address, mutexValue | HasListenersMask); currentProcess.CpuMemory.WriteInt32((long)address, mutexValue | HasListenersMask);
} }
else else
{ {
//No thread owning the mutex, assign to requesting thread. //No thread owning the mutex, assign to requesting thread.
currentProcess.CpuMemory.WriteInt32(address, requester.ThreadHandleForUserMutex); currentProcess.CpuMemory.WriteInt32((long)address, requester.ThreadHandleForUserMutex);
} }
currentProcess.CpuMemory.ClearExclusiveForStore(0); currentProcess.CpuMemory.ClearExclusiveForStore(0);
@ -261,9 +261,9 @@ namespace Ryujinx.HLE.HOS.Kernel
break; break;
} }
currentProcess.CpuMemory.SetExclusive(0, address); currentProcess.CpuMemory.SetExclusive(0, (long)address);
mutexValue = currentProcess.CpuMemory.ReadInt32(address); mutexValue = currentProcess.CpuMemory.ReadInt32((long)address);
} }
if (mutexValue == 0) if (mutexValue == 0)
@ -298,7 +298,7 @@ namespace Ryujinx.HLE.HOS.Kernel
return mutexOwner; return mutexOwner;
} }
public long WaitForAddressIfEqual(long address, int value, long timeout) public KernelResult WaitForAddressIfEqual(ulong address, int value, long timeout)
{ {
KThread currentThread = _system.Scheduler.GetCurrentThread(); KThread currentThread = _system.Scheduler.GetCurrentThread();
@ -309,7 +309,7 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.ThreadTerminating); return KernelResult.ThreadTerminating;
} }
currentThread.SignaledObj = null; currentThread.SignaledObj = null;
@ -319,7 +319,7 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); return KernelResult.InvalidMemState;
} }
if (currentValue == value) if (currentValue == value)
@ -328,7 +328,7 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.Timeout); return KernelResult.TimedOut;
} }
currentThread.MutexAddress = address; currentThread.MutexAddress = address;
@ -361,15 +361,19 @@ namespace Ryujinx.HLE.HOS.Kernel
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return currentThread.ObjSyncResult; return (KernelResult)currentThread.ObjSyncResult;
} }
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.InvalidState); return KernelResult.InvalidState;
} }
public long WaitForAddressIfLessThan(long address, int value, bool shouldDecrement, long timeout) public KernelResult WaitForAddressIfLessThan(
ulong address,
int value,
bool shouldDecrement,
long timeout)
{ {
KThread currentThread = _system.Scheduler.GetCurrentThread(); KThread currentThread = _system.Scheduler.GetCurrentThread();
@ -380,7 +384,7 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.ThreadTerminating); return KernelResult.ThreadTerminating;
} }
currentThread.SignaledObj = null; currentThread.SignaledObj = null;
@ -389,31 +393,31 @@ namespace Ryujinx.HLE.HOS.Kernel
KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
//If ShouldDecrement is true, do atomic decrement of the value at Address. //If ShouldDecrement is true, do atomic decrement of the value at Address.
currentProcess.CpuMemory.SetExclusive(0, address); currentProcess.CpuMemory.SetExclusive(0, (long)address);
if (!KernelTransfer.UserToKernelInt32(_system, address, out int currentValue)) if (!KernelTransfer.UserToKernelInt32(_system, address, out int currentValue))
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); return KernelResult.InvalidMemState;
} }
if (shouldDecrement) if (shouldDecrement)
{ {
while (currentValue < value) while (currentValue < value)
{ {
if (currentProcess.CpuMemory.TestExclusive(0, address)) if (currentProcess.CpuMemory.TestExclusive(0, (long)address))
{ {
currentProcess.CpuMemory.WriteInt32(address, currentValue - 1); currentProcess.CpuMemory.WriteInt32((long)address, currentValue - 1);
currentProcess.CpuMemory.ClearExclusiveForStore(0); currentProcess.CpuMemory.ClearExclusiveForStore(0);
break; break;
} }
currentProcess.CpuMemory.SetExclusive(0, address); currentProcess.CpuMemory.SetExclusive(0, (long)address);
currentValue = currentProcess.CpuMemory.ReadInt32(address); currentValue = currentProcess.CpuMemory.ReadInt32((long)address);
} }
} }
@ -425,7 +429,7 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.Timeout); return KernelResult.TimedOut;
} }
currentThread.MutexAddress = address; currentThread.MutexAddress = address;
@ -458,12 +462,12 @@ namespace Ryujinx.HLE.HOS.Kernel
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return currentThread.ObjSyncResult; return (KernelResult)currentThread.ObjSyncResult;
} }
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.InvalidState); return KernelResult.InvalidState;
} }
private void InsertSortedByPriority(List<KThread> threads, KThread thread) private void InsertSortedByPriority(List<KThread> threads, KThread thread)
@ -490,7 +494,7 @@ namespace Ryujinx.HLE.HOS.Kernel
} }
} }
public long Signal(long address, int count) public KernelResult Signal(ulong address, int count)
{ {
_system.CriticalSection.Enter(); _system.CriticalSection.Enter();
@ -498,38 +502,38 @@ namespace Ryujinx.HLE.HOS.Kernel
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return 0; return KernelResult.Success;
} }
public long SignalAndIncrementIfEqual(long address, int value, int count) public KernelResult SignalAndIncrementIfEqual(ulong address, int value, int count)
{ {
_system.CriticalSection.Enter(); _system.CriticalSection.Enter();
KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
currentProcess.CpuMemory.SetExclusive(0, address); currentProcess.CpuMemory.SetExclusive(0, (long)address);
if (!KernelTransfer.UserToKernelInt32(_system, address, out int currentValue)) if (!KernelTransfer.UserToKernelInt32(_system, address, out int currentValue))
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); return KernelResult.InvalidMemState;
} }
while (currentValue == value) while (currentValue == value)
{ {
if (currentProcess.CpuMemory.TestExclusive(0, address)) if (currentProcess.CpuMemory.TestExclusive(0, (long)address))
{ {
currentProcess.CpuMemory.WriteInt32(address, currentValue + 1); currentProcess.CpuMemory.WriteInt32((long)address, currentValue + 1);
currentProcess.CpuMemory.ClearExclusiveForStore(0); currentProcess.CpuMemory.ClearExclusiveForStore(0);
break; break;
} }
currentProcess.CpuMemory.SetExclusive(0, address); currentProcess.CpuMemory.SetExclusive(0, (long)address);
currentValue = currentProcess.CpuMemory.ReadInt32(address); currentValue = currentProcess.CpuMemory.ReadInt32((long)address);
} }
currentProcess.CpuMemory.ClearExclusive(0); currentProcess.CpuMemory.ClearExclusive(0);
@ -538,17 +542,17 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.InvalidState); return KernelResult.InvalidState;
} }
WakeArbiterThreads(address, count); WakeArbiterThreads(address, count);
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return 0; return KernelResult.Success;
} }
public long SignalAndModifyIfEqual(long address, int value, int count) public KernelResult SignalAndModifyIfEqual(ulong address, int value, int count)
{ {
_system.CriticalSection.Enter(); _system.CriticalSection.Enter();
@ -578,29 +582,29 @@ namespace Ryujinx.HLE.HOS.Kernel
KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
currentProcess.CpuMemory.SetExclusive(0, address); currentProcess.CpuMemory.SetExclusive(0, (long)address);
if (!KernelTransfer.UserToKernelInt32(_system, address, out int currentValue)) if (!KernelTransfer.UserToKernelInt32(_system, address, out int currentValue))
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); return KernelResult.InvalidMemState;
} }
while (currentValue == value) while (currentValue == value)
{ {
if (currentProcess.CpuMemory.TestExclusive(0, address)) if (currentProcess.CpuMemory.TestExclusive(0, (long)address))
{ {
currentProcess.CpuMemory.WriteInt32(address, currentValue + offset); currentProcess.CpuMemory.WriteInt32((long)address, currentValue + offset);
currentProcess.CpuMemory.ClearExclusiveForStore(0); currentProcess.CpuMemory.ClearExclusiveForStore(0);
break; break;
} }
currentProcess.CpuMemory.SetExclusive(0, address); currentProcess.CpuMemory.SetExclusive(0, (long)address);
currentValue = currentProcess.CpuMemory.ReadInt32(address); currentValue = currentProcess.CpuMemory.ReadInt32((long)address);
} }
currentProcess.CpuMemory.ClearExclusive(0); currentProcess.CpuMemory.ClearExclusive(0);
@ -609,17 +613,17 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.InvalidState); return KernelResult.InvalidState;
} }
WakeArbiterThreads(address, count); WakeArbiterThreads(address, count);
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return 0; return KernelResult.Success;
} }
private void WakeArbiterThreads(long address, int count) private void WakeArbiterThreads(ulong address, int count)
{ {
Queue<KThread> signaledThreads = new Queue<KThread>(); Queue<KThread> signaledThreads = new Queue<KThread>();

View file

@ -1,7 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.HLE.HOS.ErrorCode;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel
{ {
class KSynchronization class KSynchronization
@ -13,9 +11,11 @@ namespace Ryujinx.HLE.HOS.Kernel
_system = system; _system = system;
} }
public long WaitFor(KSynchronizationObject[] syncObjs, long timeout, ref int hndIndex) public KernelResult WaitFor(KSynchronizationObject[] syncObjs, long timeout, out int handleIndex)
{ {
long result = MakeError(ErrorModule.Kernel, KernelErr.Timeout); handleIndex = 0;
KernelResult result = KernelResult.TimedOut;
_system.CriticalSection.Enter(); _system.CriticalSection.Enter();
@ -27,7 +27,7 @@ namespace Ryujinx.HLE.HOS.Kernel
continue; continue;
} }
hndIndex = index; handleIndex = index;
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
@ -46,13 +46,13 @@ namespace Ryujinx.HLE.HOS.Kernel
if (currentThread.ShallBeTerminated || if (currentThread.ShallBeTerminated ||
currentThread.SchedFlags == ThreadSchedState.TerminationPending) currentThread.SchedFlags == ThreadSchedState.TerminationPending)
{ {
result = MakeError(ErrorModule.Kernel, KernelErr.ThreadTerminating); result = KernelResult.ThreadTerminating;
} }
else if (currentThread.SyncCancelled) else if (currentThread.SyncCancelled)
{ {
currentThread.SyncCancelled = false; currentThread.SyncCancelled = false;
result = MakeError(ErrorModule.Kernel, KernelErr.Cancelled); result = KernelResult.Cancelled;
} }
else else
{ {
@ -85,9 +85,9 @@ namespace Ryujinx.HLE.HOS.Kernel
_system.CriticalSection.Enter(); _system.CriticalSection.Enter();
result = (uint)currentThread.ObjSyncResult; result = (KernelResult)currentThread.ObjSyncResult;
hndIndex = -1; handleIndex = -1;
for (int index = 0; index < syncObjs.Length; index++) for (int index = 0; index < syncObjs.Length; index++)
{ {
@ -95,7 +95,7 @@ namespace Ryujinx.HLE.HOS.Kernel
if (syncObjs[index] == currentThread.SignaledObj) if (syncObjs[index] == currentThread.SignaledObj)
{ {
hndIndex = index; handleIndex = index;
} }
} }
} }

View file

@ -20,11 +20,11 @@ namespace Ryujinx.HLE.HOS.Kernel
public KSynchronizationObject SignaledObj { get; set; } public KSynchronizationObject SignaledObj { get; set; }
public long CondVarAddress { get; set; } public ulong CondVarAddress { get; set; }
private ulong _entrypoint; private ulong _entrypoint;
public long MutexAddress { get; set; } public ulong MutexAddress { get; set; }
public KProcess Owner { get; private set; } public KProcess Owner { get; private set; }
@ -468,9 +468,9 @@ namespace Ryujinx.HLE.HOS.Kernel
System.CriticalSection.Leave(); System.CriticalSection.Leave();
} }
public long SetActivity(bool pause) public KernelResult SetActivity(bool pause)
{ {
long result = 0; KernelResult result = KernelResult.Success;
System.CriticalSection.Enter(); System.CriticalSection.Enter();
@ -480,7 +480,7 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
System.CriticalSection.Leave(); System.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.InvalidState); return KernelResult.InvalidState;
} }
System.CriticalSection.Enter(); System.CriticalSection.Enter();
@ -498,7 +498,7 @@ namespace Ryujinx.HLE.HOS.Kernel
} }
else else
{ {
result = MakeError(ErrorModule.Kernel, KernelErr.InvalidState); result = KernelResult.InvalidState;
} }
} }
else else
@ -521,7 +521,7 @@ namespace Ryujinx.HLE.HOS.Kernel
} }
else else
{ {
result = MakeError(ErrorModule.Kernel, KernelErr.InvalidState); result = KernelResult.InvalidState;
} }
} }
} }
@ -716,7 +716,7 @@ namespace Ryujinx.HLE.HOS.Kernel
UpdatePriorityInheritance(); UpdatePriorityInheritance();
} }
public KThread RelinquishMutex(long mutexAddress, out int count) public KThread RelinquishMutex(ulong mutexAddress, out int count)
{ {
count = 0; count = 0;

View file

@ -4,14 +4,14 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
static class KernelTransfer static class KernelTransfer
{ {
public static bool UserToKernelInt32(Horizon system, long address, out int value) public static bool UserToKernelInt32(Horizon system, ulong address, out int value)
{ {
KProcess currentProcess = system.Scheduler.GetCurrentProcess(); KProcess currentProcess = system.Scheduler.GetCurrentProcess();
if (currentProcess.CpuMemory.IsMapped(address) && if (currentProcess.CpuMemory.IsMapped((long)address) &&
currentProcess.CpuMemory.IsMapped(address + 3)) currentProcess.CpuMemory.IsMapped((long)address + 3))
{ {
value = currentProcess.CpuMemory.ReadInt32(address); value = currentProcess.CpuMemory.ReadInt32((long)address);
return true; return true;
} }
@ -21,14 +21,14 @@ namespace Ryujinx.HLE.HOS.Kernel
return false; return false;
} }
public static bool UserToKernelString(Horizon system, long address, int size, out string value) public static bool UserToKernelString(Horizon system, ulong address, int size, out string value)
{ {
KProcess currentProcess = system.Scheduler.GetCurrentProcess(); KProcess currentProcess = system.Scheduler.GetCurrentProcess();
if (currentProcess.CpuMemory.IsMapped(address) && if (currentProcess.CpuMemory.IsMapped((long)address) &&
currentProcess.CpuMemory.IsMapped(address + size - 1)) currentProcess.CpuMemory.IsMapped((long)address + size - 1))
{ {
value = MemoryHelper.ReadAsciiString(currentProcess.CpuMemory, address, size); value = MemoryHelper.ReadAsciiString(currentProcess.CpuMemory, (long)address, size);
return true; return true;
} }
@ -38,14 +38,14 @@ namespace Ryujinx.HLE.HOS.Kernel
return false; return false;
} }
public static bool KernelToUserInt32(Horizon system, long address, int value) public static bool KernelToUserInt32(Horizon system, ulong address, int value)
{ {
KProcess currentProcess = system.Scheduler.GetCurrentProcess(); KProcess currentProcess = system.Scheduler.GetCurrentProcess();
if (currentProcess.CpuMemory.IsMapped(address) && if (currentProcess.CpuMemory.IsMapped((long)address) &&
currentProcess.CpuMemory.IsMapped(address + 3)) currentProcess.CpuMemory.IsMapped((long)address + 3))
{ {
currentProcess.CpuMemory.WriteInt32ToSharedAddr(address, value); currentProcess.CpuMemory.WriteInt32ToSharedAddr((long)address, value);
return true; return true;
} }
@ -53,14 +53,14 @@ namespace Ryujinx.HLE.HOS.Kernel
return false; return false;
} }
public static bool KernelToUserInt64(Horizon system, long address, long value) public static bool KernelToUserInt64(Horizon system, ulong address, long value)
{ {
KProcess currentProcess = system.Scheduler.GetCurrentProcess(); KProcess currentProcess = system.Scheduler.GetCurrentProcess();
if (currentProcess.CpuMemory.IsMapped(address) && if (currentProcess.CpuMemory.IsMapped((long)address) &&
currentProcess.CpuMemory.IsMapped(address + 7)) currentProcess.CpuMemory.IsMapped((long)address + 7))
{ {
currentProcess.CpuMemory.WriteInt64(address, value); currentProcess.CpuMemory.WriteInt64((long)address, value);
return true; return true;
} }

View file

@ -2,18 +2,12 @@ using ChocolArm64.Events;
using ChocolArm64.Memory; using ChocolArm64.Memory;
using ChocolArm64.State; using ChocolArm64.State;
using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.Common.Logging;
using System; using System;
using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel
{ {
partial class SvcHandler partial class SvcHandler
{ {
private delegate void SvcFunc(CpuThreadState threadState);
private Dictionary<int, SvcFunc> _svcFuncs;
private Switch _device; private Switch _device;
private KProcess _process; private KProcess _process;
private Horizon _system; private Horizon _system;
@ -41,58 +35,6 @@ namespace Ryujinx.HLE.HOS.Kernel
public SvcHandler(Switch device, KProcess process) public SvcHandler(Switch device, KProcess process)
{ {
_svcFuncs = new Dictionary<int, SvcFunc>
{
{ 0x01, SvcSetHeapSize },
{ 0x03, SvcSetMemoryAttribute },
{ 0x04, SvcMapMemory },
{ 0x05, SvcUnmapMemory },
{ 0x06, SvcQueryMemory },
{ 0x07, SvcExitProcess },
{ 0x08, CreateThread64 },
{ 0x09, SvcStartThread },
{ 0x0a, SvcExitThread },
{ 0x0b, SvcSleepThread },
{ 0x0c, SvcGetThreadPriority },
{ 0x0d, SvcSetThreadPriority },
{ 0x0e, SvcGetThreadCoreMask },
{ 0x0f, SetThreadCoreMask64 },
{ 0x10, SvcGetCurrentProcessorNumber },
{ 0x11, SignalEvent64 },
{ 0x12, ClearEvent64 },
{ 0x13, SvcMapSharedMemory },
{ 0x14, SvcUnmapSharedMemory },
{ 0x15, SvcCreateTransferMemory },
{ 0x16, SvcCloseHandle },
{ 0x17, ResetSignal64 },
{ 0x18, SvcWaitSynchronization },
{ 0x19, SvcCancelSynchronization },
{ 0x1a, SvcArbitrateLock },
{ 0x1b, SvcArbitrateUnlock },
{ 0x1c, SvcWaitProcessWideKeyAtomic },
{ 0x1d, SvcSignalProcessWideKey },
{ 0x1e, SvcGetSystemTick },
{ 0x1f, SvcConnectToNamedPort },
{ 0x21, SvcSendSyncRequest },
{ 0x22, SvcSendSyncRequestWithUserBuffer },
{ 0x24, GetProcessId64 },
{ 0x25, SvcGetThreadId },
{ 0x26, SvcBreak },
{ 0x27, SvcOutputDebugString },
{ 0x29, GetInfo64 },
{ 0x2c, SvcMapPhysicalMemory },
{ 0x2d, SvcUnmapPhysicalMemory },
{ 0x32, SvcSetThreadActivity },
{ 0x33, SvcGetThreadContext3 },
{ 0x34, SvcWaitForAddress },
{ 0x35, SvcSignalToAddress },
{ 0x45, CreateEvent64 },
{ 0x65, GetProcessList64 },
{ 0x6f, GetSystemInfo64 },
{ 0x70, CreatePort64 },
{ 0x71, ManageNamedPort64 }
};
_device = device; _device = device;
_process = process; _process = process;
_system = device.System; _system = device.System;
@ -101,22 +43,16 @@ namespace Ryujinx.HLE.HOS.Kernel
public void SvcCall(object sender, InstExceptionEventArgs e) public void SvcCall(object sender, InstExceptionEventArgs e)
{ {
Action<SvcHandler, CpuThreadState> svcFunc = SvcTable.GetSvcFunc(e.Id);
if (svcFunc == null)
{
throw new NotImplementedException($"SVC 0x{e.Id:X4} is not implemented.");
}
CpuThreadState threadState = (CpuThreadState)sender; CpuThreadState threadState = (CpuThreadState)sender;
if (_svcFuncs.TryGetValue(e.Id, out SvcFunc func)) svcFunc(this, threadState);
{
Logger.PrintDebug(LogClass.KernelSvc, $"{func.Method.Name} called.");
func(threadState);
Logger.PrintDebug(LogClass.KernelSvc, $"{func.Method.Name} ended.");
}
else
{
//Process.PrintStackTrace(ThreadState);
throw new NotImplementedException($"0x{e.Id:x4}");
}
} }
} }
} }

View file

@ -1,75 +1,55 @@
using ChocolArm64.State;
using Ryujinx.Common.Logging;
using static Ryujinx.HLE.HOS.ErrorCode;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel
{ {
partial class SvcHandler partial class SvcHandler
{ {
private void SvcSetHeapSize(CpuThreadState threadState) public KernelResult SetHeapSize64(ulong size, out ulong position)
{ {
ulong size = threadState.X1; return SetHeapSize(size, out position);
if ((size & 0xfffffffe001fffff) != 0)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Heap size 0x{size:x16} is not aligned!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
return;
}
KernelResult result = _process.MemoryManager.SetHeapSize(size, out ulong position);
threadState.X0 = (ulong)result;
if (result == KernelResult.Success)
{
threadState.X1 = position;
}
else
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{result}\".");
}
} }
private void SvcSetMemoryAttribute(CpuThreadState threadState) private KernelResult SetHeapSize(ulong size, out ulong position)
{ {
ulong position = threadState.X0; if ((size & 0xfffffffe001fffff) != 0)
ulong size = threadState.X1; {
position = 0;
return KernelResult.InvalidSize;
}
return _process.MemoryManager.SetHeapSize(size, out position);
}
public KernelResult SetMemoryAttribute64(
ulong position,
ulong size,
MemoryAttribute attributeMask,
MemoryAttribute attributeValue)
{
return SetMemoryAttribute(position, size, attributeMask, attributeValue);
}
private KernelResult SetMemoryAttribute(
ulong position,
ulong size,
MemoryAttribute attributeMask,
MemoryAttribute attributeValue)
{
if (!PageAligned(position)) if (!PageAligned(position))
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{position:x16} is not page aligned!"); return KernelResult.InvalidAddress;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
} }
if (!PageAligned(size) || size == 0) if (!PageAligned(size) || size == 0)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{size:x16} is not page aligned or is zero!"); return KernelResult.InvalidSize;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
return;
} }
MemoryAttribute attributeMask = (MemoryAttribute)threadState.X2;
MemoryAttribute attributeValue = (MemoryAttribute)threadState.X3;
MemoryAttribute attributes = attributeMask | attributeValue; MemoryAttribute attributes = attributeMask | attributeValue;
if (attributes != attributeMask || if (attributes != attributeMask ||
(attributes | MemoryAttribute.Uncached) != MemoryAttribute.Uncached) (attributes | MemoryAttribute.Uncached) != MemoryAttribute.Uncached)
{ {
Logger.PrintWarning(LogClass.KernelSvc, "Invalid memory attributes!"); return KernelResult.InvalidCombination;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMaskValue);
return;
} }
KernelResult result = _process.MemoryManager.SetMemoryAttribute( KernelResult result = _process.MemoryManager.SetMemoryAttribute(
@ -78,210 +58,138 @@ namespace Ryujinx.HLE.HOS.Kernel
attributeMask, attributeMask,
attributeValue); attributeValue);
if (result != KernelResult.Success) if (result == KernelResult.Success)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{result}\".");
}
else
{ {
_memory.StopObservingRegion((long)position, (long)size); _memory.StopObservingRegion((long)position, (long)size);
} }
threadState.X0 = (ulong)result; return result;
} }
private void SvcMapMemory(CpuThreadState threadState) public KernelResult MapMemory64(ulong dst, ulong src, ulong size)
{ {
ulong dst = threadState.X0; return MapMemory(dst, src, size);
ulong src = threadState.X1; }
ulong size = threadState.X2;
private KernelResult MapMemory(ulong dst, ulong src, ulong size)
{
if (!PageAligned(src | dst)) if (!PageAligned(src | dst))
{ {
Logger.PrintWarning(LogClass.KernelSvc, "Addresses are not page aligned!"); return KernelResult.InvalidAddress;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
} }
if (!PageAligned(size) || size == 0) if (!PageAligned(size) || size == 0)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{size:x16} is not page aligned or is zero!"); return KernelResult.InvalidSize;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
return;
} }
if (src + size <= src || dst + size <= dst) if (src + size <= src || dst + size <= dst)
{ {
Logger.PrintWarning(LogClass.KernelSvc, "Addresses outside of range!"); return KernelResult.InvalidMemState;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
} }
KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
if (!currentProcess.MemoryManager.InsideAddrSpace(src, size)) if (!currentProcess.MemoryManager.InsideAddrSpace(src, size))
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Src address 0x{src:x16} out of range!"); return KernelResult.InvalidMemState;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
} }
if (currentProcess.MemoryManager.OutsideStackRegion(dst, size) || if (currentProcess.MemoryManager.OutsideStackRegion(dst, size) ||
currentProcess.MemoryManager.InsideHeapRegion (dst, size) || currentProcess.MemoryManager.InsideHeapRegion (dst, size) ||
currentProcess.MemoryManager.InsideAliasRegion (dst, size)) currentProcess.MemoryManager.InsideAliasRegion (dst, size))
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Dst address 0x{dst:x16} out of range!"); return KernelResult.InvalidMemRange;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
return;
} }
KernelResult result = _process.MemoryManager.Map(dst, src, size); return _process.MemoryManager.Map(dst, src, size);
if (result != KernelResult.Success)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
threadState.X0 = (ulong)result;
} }
private void SvcUnmapMemory(CpuThreadState threadState) public KernelResult UnmapMemory64(ulong dst, ulong src, ulong size)
{ {
ulong dst = threadState.X0; return UnmapMemory(dst, src, size);
ulong src = threadState.X1; }
ulong size = threadState.X2;
private KernelResult UnmapMemory(ulong dst, ulong src, ulong size)
{
if (!PageAligned(src | dst)) if (!PageAligned(src | dst))
{ {
Logger.PrintWarning(LogClass.KernelSvc, "Addresses are not page aligned!"); return KernelResult.InvalidAddress;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
} }
if (!PageAligned(size) || size == 0) if (!PageAligned(size) || size == 0)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{size:x16} is not page aligned or is zero!"); return KernelResult.InvalidSize;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
return;
} }
if (src + size <= src || dst + size <= dst) if (src + size <= src || dst + size <= dst)
{ {
Logger.PrintWarning(LogClass.KernelSvc, "Addresses outside of range!"); return KernelResult.InvalidMemState;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
} }
KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
if (!currentProcess.MemoryManager.InsideAddrSpace(src, size)) if (!currentProcess.MemoryManager.InsideAddrSpace(src, size))
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Src address 0x{src:x16} out of range!"); return KernelResult.InvalidMemState;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
} }
if (currentProcess.MemoryManager.OutsideStackRegion(dst, size) || if (currentProcess.MemoryManager.OutsideStackRegion(dst, size) ||
currentProcess.MemoryManager.InsideHeapRegion (dst, size) || currentProcess.MemoryManager.InsideHeapRegion (dst, size) ||
currentProcess.MemoryManager.InsideAliasRegion (dst, size)) currentProcess.MemoryManager.InsideAliasRegion (dst, size))
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Dst address 0x{dst:x16} out of range!"); return KernelResult.InvalidMemRange;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
return;
} }
KernelResult result = _process.MemoryManager.Unmap(dst, src, size); return _process.MemoryManager.Unmap(dst, src, size);
if (result != KernelResult.Success)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
threadState.X0 = (ulong)result;
} }
private void SvcQueryMemory(CpuThreadState threadState) public KernelResult QueryMemory64(ulong infoPtr, ulong x1, ulong position)
{ {
long infoPtr = (long)threadState.X0; return QueryMemory(infoPtr, position);
ulong position = threadState.X2; }
private KernelResult QueryMemory(ulong infoPtr, ulong position)
{
KMemoryInfo blkInfo = _process.MemoryManager.QueryMemory(position); KMemoryInfo blkInfo = _process.MemoryManager.QueryMemory(position);
_memory.WriteUInt64(infoPtr + 0x00, blkInfo.Address); _memory.WriteUInt64((long)infoPtr + 0x00, blkInfo.Address);
_memory.WriteUInt64(infoPtr + 0x08, blkInfo.Size); _memory.WriteUInt64((long)infoPtr + 0x08, blkInfo.Size);
_memory.WriteInt32 (infoPtr + 0x10, (int)blkInfo.State & 0xff); _memory.WriteInt32 ((long)infoPtr + 0x10, (int)blkInfo.State & 0xff);
_memory.WriteInt32 (infoPtr + 0x14, (int)blkInfo.Attribute); _memory.WriteInt32 ((long)infoPtr + 0x14, (int)blkInfo.Attribute);
_memory.WriteInt32 (infoPtr + 0x18, (int)blkInfo.Permission); _memory.WriteInt32 ((long)infoPtr + 0x18, (int)blkInfo.Permission);
_memory.WriteInt32 (infoPtr + 0x1c, blkInfo.IpcRefCount); _memory.WriteInt32 ((long)infoPtr + 0x1c, blkInfo.IpcRefCount);
_memory.WriteInt32 (infoPtr + 0x20, blkInfo.DeviceRefCount); _memory.WriteInt32 ((long)infoPtr + 0x20, blkInfo.DeviceRefCount);
_memory.WriteInt32 (infoPtr + 0x24, 0); _memory.WriteInt32 ((long)infoPtr + 0x24, 0);
threadState.X0 = 0; return KernelResult.Success;
threadState.X1 = 0;
} }
private void SvcMapSharedMemory(CpuThreadState threadState) public KernelResult MapSharedMemory64(int handle, ulong address, ulong size, MemoryPermission permission)
{ {
int handle = (int)threadState.X0; return MapSharedMemory(handle, address, size, permission);
ulong address = threadState.X1; }
ulong size = threadState.X2;
private KernelResult MapSharedMemory(int handle, ulong address, ulong size, MemoryPermission permission)
{
if (!PageAligned(address)) if (!PageAligned(address))
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{address:x16} is not page aligned!"); return KernelResult.InvalidAddress;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
} }
if (!PageAligned(size) || size == 0) if (!PageAligned(size) || size == 0)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{size:x16} is not page aligned or is zero!"); return KernelResult.InvalidSize;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
return;
} }
if (address + size <= address) if (address + size <= address)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{address:x16} / size 0x{size:x16}!"); return KernelResult.InvalidMemState;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
} }
MemoryPermission permission = (MemoryPermission)threadState.X3;
if ((permission | MemoryPermission.Write) != MemoryPermission.ReadAndWrite) if ((permission | MemoryPermission.Write) != MemoryPermission.ReadAndWrite)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid permission {permission}!"); return KernelResult.InvalidPermission;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidPermission);
return;
} }
KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
@ -290,70 +198,44 @@ namespace Ryujinx.HLE.HOS.Kernel
if (sharedMemory == null) if (sharedMemory == null)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid shared memory handle 0x{handle:x8}!"); return KernelResult.InvalidHandle;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
return;
} }
if (currentProcess.MemoryManager.IsInvalidRegion (address, size) || if (currentProcess.MemoryManager.IsInvalidRegion (address, size) ||
currentProcess.MemoryManager.InsideHeapRegion (address, size) || currentProcess.MemoryManager.InsideHeapRegion (address, size) ||
currentProcess.MemoryManager.InsideAliasRegion(address, size)) currentProcess.MemoryManager.InsideAliasRegion(address, size))
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{address:x16} out of range!"); return KernelResult.InvalidMemRange;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
} }
KernelResult result = sharedMemory.MapIntoProcess( return sharedMemory.MapIntoProcess(
currentProcess.MemoryManager, currentProcess.MemoryManager,
address, address,
size, size,
currentProcess, currentProcess,
permission); permission);
if (result != KernelResult.Success)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{result}\".");
}
threadState.X0 = (ulong)result;
} }
private void SvcUnmapSharedMemory(CpuThreadState threadState) public KernelResult UnmapSharedMemory64(int handle, ulong address, ulong size)
{ {
int handle = (int)threadState.X0; return UnmapSharedMemory(handle, address, size);
ulong address = threadState.X1; }
ulong size = threadState.X2;
private KernelResult UnmapSharedMemory(int handle, ulong address, ulong size)
{
if (!PageAligned(address)) if (!PageAligned(address))
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{address:x16} is not page aligned!"); return KernelResult.InvalidAddress;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
} }
if (!PageAligned(size) || size == 0) if (!PageAligned(size) || size == 0)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{size:x16} is not page aligned or is zero!"); return KernelResult.InvalidSize;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
return;
} }
if (address + size <= address) if (address + size <= address)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{address:x16} / size 0x{size:x16}!"); return KernelResult.InvalidMemState;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
} }
KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
@ -362,215 +244,142 @@ namespace Ryujinx.HLE.HOS.Kernel
if (sharedMemory == null) if (sharedMemory == null)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid shared memory handle 0x{handle:x8}!"); return KernelResult.InvalidHandle;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
return;
} }
if (currentProcess.MemoryManager.IsInvalidRegion (address, size) || if (currentProcess.MemoryManager.IsInvalidRegion (address, size) ||
currentProcess.MemoryManager.InsideHeapRegion (address, size) || currentProcess.MemoryManager.InsideHeapRegion (address, size) ||
currentProcess.MemoryManager.InsideAliasRegion(address, size)) currentProcess.MemoryManager.InsideAliasRegion(address, size))
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{address:x16} out of range!"); return KernelResult.InvalidMemRange;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
} }
KernelResult result = sharedMemory.UnmapFromProcess( return sharedMemory.UnmapFromProcess(
currentProcess.MemoryManager, currentProcess.MemoryManager,
address, address,
size, size,
currentProcess); currentProcess);
if (result != KernelResult.Success)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{result}\".");
}
threadState.X0 = (ulong)result;
} }
private void SvcCreateTransferMemory(CpuThreadState threadState) public KernelResult CreateTransferMemory64(
ulong address,
ulong size,
MemoryPermission permission,
out int handle)
{ {
ulong address = threadState.X1; return CreateTransferMemory(address, size, permission, out handle);
ulong size = threadState.X2; }
private KernelResult CreateTransferMemory(ulong address, ulong size, MemoryPermission permission, out int handle)
{
handle = 0;
if (!PageAligned(address)) if (!PageAligned(address))
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{address:x16} is not page aligned!"); return KernelResult.InvalidAddress;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
} }
if (!PageAligned(size) || size == 0) if (!PageAligned(size) || size == 0)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{size:x16} is not page aligned or is zero!"); return KernelResult.InvalidSize;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
} }
if (address + size <= address) if (address + size <= address)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{address:x16} / size 0x{size:x16}!"); return KernelResult.InvalidMemState;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
} }
MemoryPermission permission = (MemoryPermission)threadState.X3;
if (permission > MemoryPermission.ReadAndWrite || permission == MemoryPermission.Write) if (permission > MemoryPermission.ReadAndWrite || permission == MemoryPermission.Write)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid permission {permission}!"); return KernelResult.InvalidPermission;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidPermission);
return;
} }
_process.MemoryManager.ReserveTransferMemory(address, size, permission); KernelResult result = _process.MemoryManager.ReserveTransferMemory(address, size, permission);
if (result != KernelResult.Success)
{
return result;
}
KTransferMemory transferMemory = new KTransferMemory(address, size); KTransferMemory transferMemory = new KTransferMemory(address, size);
KernelResult result = _process.HandleTable.GenerateHandle(transferMemory, out int handle); return _process.HandleTable.GenerateHandle(transferMemory, out handle);
threadState.X0 = (uint)result;
threadState.X1 = (ulong)handle;
} }
private void SvcMapPhysicalMemory(CpuThreadState threadState) public KernelResult MapPhysicalMemory64(ulong address, ulong size)
{ {
ulong address = threadState.X0; return MapPhysicalMemory(address, size);
ulong size = threadState.X1; }
private KernelResult MapPhysicalMemory(ulong address, ulong size)
{
if (!PageAligned(address)) if (!PageAligned(address))
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{address:x16} is not page aligned!"); return KernelResult.InvalidAddress;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
} }
if (!PageAligned(size) || size == 0) if (!PageAligned(size) || size == 0)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{size:x16} is not page aligned or is zero!"); return KernelResult.InvalidSize;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
return;
} }
if (address + size <= address) if (address + size <= address)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{address:x16} / size 0x{size:x16}!"); return KernelResult.InvalidMemRange;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
} }
KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
if ((currentProcess.PersonalMmHeapPagesCount & 0xfffffffffffff) == 0) if ((currentProcess.PersonalMmHeapPagesCount & 0xfffffffffffff) == 0)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"System resource size is zero."); return KernelResult.InvalidState;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidState);
return;
} }
if (!currentProcess.MemoryManager.InsideAddrSpace (address, size) || if (!currentProcess.MemoryManager.InsideAddrSpace (address, size) ||
currentProcess.MemoryManager.OutsideAliasRegion(address, size)) currentProcess.MemoryManager.OutsideAliasRegion(address, size))
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid address {address:x16}."); return KernelResult.InvalidMemRange;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
} }
KernelResult result = _process.MemoryManager.MapPhysicalMemory(address, size); return _process.MemoryManager.MapPhysicalMemory(address, size);
if (result != KernelResult.Success)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
threadState.X0 = (ulong)result;
} }
private void SvcUnmapPhysicalMemory(CpuThreadState threadState) public KernelResult UnmapPhysicalMemory64(ulong address, ulong size)
{ {
ulong address = threadState.X0; return MapPhysicalMemory(address, size);
ulong size = threadState.X1; }
private KernelResult UnmapPhysicalMemory(ulong address, ulong size)
{
if (!PageAligned(address)) if (!PageAligned(address))
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{address:x16} is not page aligned!"); return KernelResult.InvalidAddress;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
} }
if (!PageAligned(size) || size == 0) if (!PageAligned(size) || size == 0)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{size:x16} is not page aligned or is zero!"); return KernelResult.InvalidSize;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
return;
} }
if (address + size <= address) if (address + size <= address)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{address:x16} / size 0x{size:x16}!"); return KernelResult.InvalidMemRange;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
} }
KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
if ((currentProcess.PersonalMmHeapPagesCount & 0xfffffffffffff) == 0) if ((currentProcess.PersonalMmHeapPagesCount & 0xfffffffffffff) == 0)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"System resource size is zero."); return KernelResult.InvalidState;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidState);
return;
} }
if (!currentProcess.MemoryManager.InsideAddrSpace (address, size) || if (!currentProcess.MemoryManager.InsideAddrSpace (address, size) ||
currentProcess.MemoryManager.OutsideAliasRegion(address, size)) currentProcess.MemoryManager.OutsideAliasRegion(address, size))
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid address {address:x16}."); return KernelResult.InvalidMemRange;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
} }
KernelResult result = _process.MemoryManager.UnmapPhysicalMemory(address, size); return _process.MemoryManager.UnmapPhysicalMemory(address, size);
if (result != KernelResult.Success)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
threadState.X0 = (ulong)result;
} }
private static bool PageAligned(ulong position) private static bool PageAligned(ulong position)

View file

@ -1,27 +1,28 @@
using ChocolArm64.Memory; using ChocolArm64.Memory;
using ChocolArm64.State;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Services; using Ryujinx.HLE.HOS.Services;
using System;
using System.Threading; using System.Threading;
using static Ryujinx.HLE.HOS.ErrorCode;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel
{ {
partial class SvcHandler partial class SvcHandler
{ {
private void SvcExitProcess(CpuThreadState threadState) public void ExitProcess64()
{
ExitProcess();
}
private void ExitProcess()
{ {
_system.Scheduler.GetCurrentProcess().Terminate(); _system.Scheduler.GetCurrentProcess().Terminate();
} }
private void SignalEvent64(CpuThreadState threadState) public KernelResult SignalEvent64(int handle)
{ {
threadState.X0 = (ulong)SignalEvent((int)threadState.X0); return SignalEvent(handle);
} }
private KernelResult SignalEvent(int handle) private KernelResult SignalEvent(int handle)
@ -41,17 +42,12 @@ namespace Ryujinx.HLE.HOS.Kernel
result = KernelResult.InvalidHandle; result = KernelResult.InvalidHandle;
} }
if (result != KernelResult.Success)
{
Logger.PrintWarning(LogClass.KernelSvc, "Operation failed with error: " + result + "!");
}
return result; return result;
} }
private void ClearEvent64(CpuThreadState threadState) public KernelResult ClearEvent64(int handle)
{ {
threadState.X0 = (ulong)ClearEvent((int)threadState.X0); return ClearEvent(handle);
} }
private KernelResult ClearEvent(int handle) private KernelResult ClearEvent(int handle)
@ -71,29 +67,23 @@ namespace Ryujinx.HLE.HOS.Kernel
result = writableEvent.Clear(); result = writableEvent.Clear();
} }
if (result != KernelResult.Success)
{
Logger.PrintWarning(LogClass.KernelSvc, "Operation failed with error: " + result + "!");
}
return result; return result;
} }
private void SvcCloseHandle(CpuThreadState threadState) public KernelResult CloseHandle64(int handle)
{ {
int handle = (int)threadState.X0; return CloseHandle(handle);
}
private KernelResult CloseHandle(int handle)
{
object obj = _process.HandleTable.GetObject<object>(handle); object obj = _process.HandleTable.GetObject<object>(handle);
_process.HandleTable.CloseHandle(handle); _process.HandleTable.CloseHandle(handle);
if (obj == null) if (obj == null)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid handle 0x{handle:x8}!"); return KernelResult.InvalidHandle;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
return;
} }
if (obj is KSession session) if (obj is KSession session)
@ -107,12 +97,12 @@ namespace Ryujinx.HLE.HOS.Kernel
transferMemory.Size); transferMemory.Size);
} }
threadState.X0 = 0; return KernelResult.Success;
} }
private void ResetSignal64(CpuThreadState threadState) public KernelResult ResetSignal64(int handle)
{ {
threadState.X0 = (ulong)ResetSignal((int)threadState.X0); return ResetSignal(handle);
} }
private KernelResult ResetSignal(int handle) private KernelResult ResetSignal(int handle)
@ -141,60 +131,43 @@ namespace Ryujinx.HLE.HOS.Kernel
} }
} }
if (result == KernelResult.InvalidState)
{
Logger.PrintDebug(LogClass.KernelSvc, "Operation failed with error: " + result + "!");
}
else if (result != KernelResult.Success)
{
Logger.PrintWarning(LogClass.KernelSvc, "Operation failed with error: " + result + "!");
}
return result; return result;
} }
private void SvcGetSystemTick(CpuThreadState threadState) public ulong GetSystemTick64()
{ {
threadState.X0 = threadState.CntpctEl0; return _system.Scheduler.GetCurrentThread().Context.ThreadState.CntpctEl0;
} }
private void SvcConnectToNamedPort(CpuThreadState threadState) public KernelResult ConnectToNamedPort64(ulong namePtr, out int handle)
{ {
long stackPtr = (long)threadState.X0; return ConnectToNamedPort(namePtr, out handle);
long namePtr = (long)threadState.X1; }
string name = MemoryHelper.ReadAsciiString(_memory, namePtr, 8); private KernelResult ConnectToNamedPort(ulong namePtr, out int handle)
{
string name = MemoryHelper.ReadAsciiString(_memory, (long)namePtr, 8);
//TODO: Validate that app has perms to access the service, and that the service //TODO: Validate that app has perms to access the service, and that the service
//actually exists, return error codes otherwise. //actually exists, return error codes otherwise.
KSession session = new KSession(ServiceFactory.MakeService(_system, name), name); KSession session = new KSession(ServiceFactory.MakeService(_system, name), name);
if (_process.HandleTable.GenerateHandle(session, out int handle) != KernelResult.Success) return _process.HandleTable.GenerateHandle(session, out handle);
{
throw new InvalidOperationException("Out of handles!");
}
threadState.X0 = 0;
threadState.X1 = (uint)handle;
} }
private void SvcSendSyncRequest(CpuThreadState threadState) public KernelResult SendSyncRequest64(int handle)
{ {
SendSyncRequest(threadState, threadState.Tpidr, 0x100, (int)threadState.X0); return SendSyncRequest((ulong)_system.Scheduler.GetCurrentThread().Context.ThreadState.Tpidr, 0x100, handle);
} }
private void SvcSendSyncRequestWithUserBuffer(CpuThreadState threadState) public KernelResult SendSyncRequestWithUserBuffer64(ulong messagePtr, ulong size, int handle)
{ {
SendSyncRequest( return SendSyncRequest(messagePtr, size, handle);
threadState,
(long)threadState.X0,
(long)threadState.X1,
(int)threadState.X2);
} }
private void SendSyncRequest(CpuThreadState threadState, long messagePtr, long size, int handle) private KernelResult SendSyncRequest(ulong messagePtr, ulong size, int handle)
{ {
byte[] messageData = _memory.ReadBytes(messagePtr, size); byte[] messageData = _memory.ReadBytes((long)messagePtr, (long)size);
KSession session = _process.HandleTable.GetObject<KSession>(handle); KSession session = _process.HandleTable.GetObject<KSession>(handle);
@ -209,25 +182,25 @@ namespace Ryujinx.HLE.HOS.Kernel
currentThread.Reschedule(ThreadSchedState.Paused); currentThread.Reschedule(ThreadSchedState.Paused);
IpcMessage message = new IpcMessage(messageData, messagePtr); IpcMessage message = new IpcMessage(messageData, (long)messagePtr);
ThreadPool.QueueUserWorkItem(ProcessIpcRequest, new HleIpcMessage( ThreadPool.QueueUserWorkItem(ProcessIpcRequest, new HleIpcMessage(
currentThread, currentThread,
session, session,
message, message,
messagePtr)); (long)messagePtr));
_system.ThreadCounter.AddCount(); _system.ThreadCounter.AddCount();
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
threadState.X0 = (ulong)currentThread.ObjSyncResult; return (KernelResult)currentThread.ObjSyncResult;
} }
else else
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid session handle 0x{handle:x8}!"); Logger.PrintWarning(LogClass.KernelSvc, $"Invalid session handle 0x{handle:x8}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); return KernelResult.InvalidHandle;
} }
} }
@ -248,14 +221,9 @@ namespace Ryujinx.HLE.HOS.Kernel
ipcMessage.Thread.Reschedule(ThreadSchedState.Running); ipcMessage.Thread.Reschedule(ThreadSchedState.Running);
} }
private void GetProcessId64(CpuThreadState threadState) public KernelResult GetProcessId64(int handle, out long pid)
{ {
int handle = (int)threadState.X1; return GetProcessId(handle, out pid);
KernelResult result = GetProcessId(handle, out long pid);
threadState.X0 = (ulong)result;
threadState.X1 = (ulong)pid;
} }
private KernelResult GetProcessId(int handle, out long pid) private KernelResult GetProcessId(int handle, out long pid)
@ -283,15 +251,16 @@ namespace Ryujinx.HLE.HOS.Kernel
: KernelResult.InvalidHandle; : KernelResult.InvalidHandle;
} }
private void SvcBreak(CpuThreadState threadState) public void Break64(ulong reason, ulong x1, ulong info)
{ {
long reason = (long)threadState.X0; Break(reason);
long unknown = (long)threadState.X1; }
long info = (long)threadState.X2;
private void Break(ulong reason)
{
KThread currentThread = _system.Scheduler.GetCurrentThread(); KThread currentThread = _system.Scheduler.GetCurrentThread();
if ((reason & (1 << 31)) == 0) if ((reason & (1UL << 31)) == 0)
{ {
currentThread.PrintGuestStackTrace(); currentThread.PrintGuestStackTrace();
@ -305,29 +274,21 @@ namespace Ryujinx.HLE.HOS.Kernel
} }
} }
private void SvcOutputDebugString(CpuThreadState threadState) public void OutputDebugString64(ulong strPtr, ulong size)
{ {
long position = (long)threadState.X0; OutputDebugString(strPtr, size);
long size = (long)threadState.X1;
string str = MemoryHelper.ReadAsciiString(_memory, position, size);
Logger.PrintWarning(LogClass.KernelSvc, str);
threadState.X0 = 0;
} }
private void GetInfo64(CpuThreadState threadState) private void OutputDebugString(ulong strPtr, ulong size)
{ {
long stackPtr = (long)threadState.X0; string str = MemoryHelper.ReadAsciiString(_memory, (long)strPtr, (long)size);
uint id = (uint)threadState.X1;
int handle = (int)threadState.X2;
long subId = (long)threadState.X3;
KernelResult result = GetInfo(id, handle, subId, out long value); Logger.PrintWarning(LogClass.KernelSvc, str);
}
threadState.X0 = (ulong)result; public KernelResult GetInfo64(uint id, int handle, long subId, out long value)
threadState.X1 = (ulong)value; {
return GetInfo(id, handle, subId, out value);
} }
private KernelResult GetInfo(uint id, int handle, long subId, out long value) private KernelResult GetInfo(uint id, int handle, long subId, out long value)
@ -556,13 +517,9 @@ namespace Ryujinx.HLE.HOS.Kernel
return KernelResult.Success; return KernelResult.Success;
} }
private void CreateEvent64(CpuThreadState state) public KernelResult CreateEvent64(out int wEventHandle, out int rEventHandle)
{ {
KernelResult result = CreateEvent(out int wEventHandle, out int rEventHandle); return CreateEvent(out wEventHandle, out rEventHandle);
state.X0 = (ulong)result;
state.X1 = (ulong)wEventHandle;
state.X2 = (ulong)rEventHandle;
} }
private KernelResult CreateEvent(out int wEventHandle, out int rEventHandle) private KernelResult CreateEvent(out int wEventHandle, out int rEventHandle)
@ -588,15 +545,9 @@ namespace Ryujinx.HLE.HOS.Kernel
return result; return result;
} }
private void GetProcessList64(CpuThreadState state) public KernelResult GetProcessList64(ulong address, int maxCount, out int count)
{ {
ulong address = state.X1; return GetProcessList(address, maxCount, out count);
int maxOut = (int)state.X2;
KernelResult result = GetProcessList(address, maxOut, out int count);
state.X0 = (ulong)result;
state.X1 = (ulong)count;
} }
private KernelResult GetProcessList(ulong address, int maxCount, out int count) private KernelResult GetProcessList(ulong address, int maxCount, out int count)
@ -633,7 +584,7 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
if (copyCount < maxCount) if (copyCount < maxCount)
{ {
if (!KernelTransfer.KernelToUserInt64(_system, (long)address + copyCount * 8, process.Pid)) if (!KernelTransfer.KernelToUserInt64(_system, address + (ulong)copyCount * 8, process.Pid))
{ {
return KernelResult.UserCopyFailed; return KernelResult.UserCopyFailed;
} }
@ -648,16 +599,9 @@ namespace Ryujinx.HLE.HOS.Kernel
return KernelResult.Success; return KernelResult.Success;
} }
private void GetSystemInfo64(CpuThreadState state) public KernelResult GetSystemInfo64(uint id, int handle, long subId, out long value)
{ {
uint id = (uint)state.X1; return GetSystemInfo(id, handle, subId, out value);
int handle = (int)state.X2;
long subId = (long)state.X3;
KernelResult result = GetSystemInfo(id, handle, subId, out long value);
state.X0 = (ulong)result;
state.X1 = (ulong)value;
} }
private KernelResult GetSystemInfo(uint id, int handle, long subId, out long value) private KernelResult GetSystemInfo(uint id, int handle, long subId, out long value)
@ -716,28 +660,20 @@ namespace Ryujinx.HLE.HOS.Kernel
return KernelResult.Success; return KernelResult.Success;
} }
private void CreatePort64(CpuThreadState state) public KernelResult CreatePort64(
int maxSessions,
bool isLight,
ulong namePtr,
out int serverPortHandle,
out int clientPortHandle)
{ {
int maxSessions = (int)state.X2; return CreatePort(maxSessions, isLight, namePtr, out serverPortHandle, out clientPortHandle);
bool isLight = (state.X3 & 1) != 0;
long nameAddress = (long)state.X4;
KernelResult result = CreatePort(
maxSessions,
isLight,
nameAddress,
out int serverPortHandle,
out int clientPortHandle);
state.X0 = (ulong)result;
state.X1 = (ulong)serverPortHandle;
state.X2 = (ulong)clientPortHandle;
} }
private KernelResult CreatePort( private KernelResult CreatePort(
int maxSessions, int maxSessions,
bool isLight, bool isLight,
long nameAddress, ulong namePtr,
out int serverPortHandle, out int serverPortHandle,
out int clientPortHandle) out int clientPortHandle)
{ {
@ -750,7 +686,7 @@ namespace Ryujinx.HLE.HOS.Kernel
KPort port = new KPort(_system); KPort port = new KPort(_system);
port.Initialize(maxSessions, isLight, nameAddress); port.Initialize(maxSessions, isLight, (long)namePtr);
KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
@ -771,22 +707,16 @@ namespace Ryujinx.HLE.HOS.Kernel
return result; return result;
} }
private void ManageNamedPort64(CpuThreadState state) public KernelResult ManageNamedPort64(ulong namePtr, int maxSessions, out int handle)
{ {
long nameAddress = (long)state.X1; return ManageNamedPort(namePtr, maxSessions, out handle);
int maxSessions = (int)state.X2;
KernelResult result = ManageNamedPort(nameAddress, maxSessions, out int handle);
state.X0 = (ulong)result;
state.X1 = (ulong)handle;
} }
private KernelResult ManageNamedPort(long nameAddress, int maxSessions, out int handle) private KernelResult ManageNamedPort(ulong namePtr, int maxSessions, out int handle)
{ {
handle = 0; handle = 0;
if (!KernelTransfer.UserToKernelString(_system, nameAddress, 12, out string name)) if (!KernelTransfer.UserToKernelString(_system, namePtr, 12, out string name))
{ {
return KernelResult.UserCopyFailed; return KernelResult.UserCopyFailed;
} }

View file

@ -0,0 +1,339 @@
using ChocolArm64.State;
using Ryujinx.Common.Logging;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
namespace Ryujinx.HLE.HOS.Kernel
{
static class SvcTable
{
private const int SvcFuncMaxArguments = 8;
private static Dictionary<int, string> _svcFuncs64;
private static Action<SvcHandler, CpuThreadState>[] _svcTable64;
static SvcTable()
{
_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) },
{ 0x45, nameof(SvcHandler.CreateEvent64) },
{ 0x65, nameof(SvcHandler.GetProcessList64) },
{ 0x6f, nameof(SvcHandler.GetSystemInfo64) },
{ 0x70, nameof(SvcHandler.CreatePort64) },
{ 0x71, nameof(SvcHandler.ManageNamedPort64) }
};
_svcTable64 = new Action<SvcHandler, CpuThreadState>[0x80];
}
public static Action<SvcHandler, CpuThreadState> GetSvcFunc(int svcId)
{
if (_svcTable64[svcId] != null)
{
return _svcTable64[svcId];
}
if (_svcFuncs64.TryGetValue(svcId, out string svcName))
{
return _svcTable64[svcId] = GenerateMethod(svcName);
}
return null;
}
private static Action<SvcHandler, CpuThreadState> GenerateMethod(string svcName)
{
Type[] argTypes = new Type[] { typeof(SvcHandler), typeof(CpuThreadState) };
DynamicMethod method = new DynamicMethod(svcName, null, argTypes);
MethodInfo methodInfo = typeof(SvcHandler).GetMethod(svcName);
ParameterInfo[] methodArgs = methodInfo.GetParameters();
if (methodArgs.Length > SvcFuncMaxArguments)
{
throw new InvalidOperationException($"Method \"{svcName}\" has too many arguments, max is 8.");
}
ILGenerator generator = method.GetILGenerator();
void ConvertToArgType(Type sourceType)
{
CheckIfTypeIsSupported(sourceType, svcName);
switch (Type.GetTypeCode(sourceType))
{
case TypeCode.UInt32: generator.Emit(OpCodes.Conv_U4); break;
case TypeCode.Int32: generator.Emit(OpCodes.Conv_I4); break;
case TypeCode.UInt16: generator.Emit(OpCodes.Conv_U2); break;
case TypeCode.Int16: generator.Emit(OpCodes.Conv_I2); break;
case TypeCode.Byte: generator.Emit(OpCodes.Conv_U1); break;
case TypeCode.SByte: generator.Emit(OpCodes.Conv_I1); break;
case TypeCode.Boolean:
generator.Emit(OpCodes.Conv_I4);
generator.Emit(OpCodes.Ldc_I4_1);
generator.Emit(OpCodes.And);
break;
}
}
void ConvertToFieldType(Type sourceType)
{
CheckIfTypeIsSupported(sourceType, svcName);
switch (Type.GetTypeCode(sourceType))
{
case TypeCode.UInt32:
case TypeCode.Int32:
case TypeCode.UInt16:
case TypeCode.Int16:
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.Boolean:
generator.Emit(OpCodes.Conv_U8);
break;
}
}
//For functions returning output values, the first registers
//are used to hold pointers where the value will be stored,
//so they can't be used to pass argument and we must
//skip them.
int byRefArgsCount = 0;
for (int index = 0; index < methodArgs.Length; index++)
{
if (methodArgs[index].ParameterType.IsByRef)
{
byRefArgsCount++;
}
}
//Print all the arguments for debugging purposes.
int inputArgsCount = methodArgs.Length - byRefArgsCount;
generator.Emit(OpCodes.Ldc_I4_S, inputArgsCount);
generator.Emit(OpCodes.Newarr, typeof(object));
string argsFormat = svcName;
for (int index = 0; index < inputArgsCount; index++)
{
argsFormat += $" {methodArgs[index].Name}: 0x{{{index}:X8}},";
generator.Emit(OpCodes.Dup);
generator.Emit(OpCodes.Ldc_I4_S, index);
generator.Emit(OpCodes.Conv_I);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldfld, GetStateFieldX(byRefArgsCount + index));
generator.Emit(OpCodes.Box, typeof(ulong));
generator.Emit(OpCodes.Stelem_Ref);
}
argsFormat = argsFormat.Substring(0, argsFormat.Length - 1);
generator.Emit(OpCodes.Ldstr, argsFormat);
BindingFlags staticNonPublic = BindingFlags.NonPublic | BindingFlags.Static;
MethodInfo printArgsMethod = typeof(SvcTable).GetMethod(nameof(PrintArguments), staticNonPublic);
generator.Emit(OpCodes.Call, printArgsMethod);
//Call the SVC function handler.
generator.Emit(OpCodes.Ldarg_0);
List<LocalBuilder> locals = new List<LocalBuilder>();
for (int index = 0; index < methodArgs.Length; index++)
{
Type argType = methodArgs[index].ParameterType;
if (argType.IsByRef)
{
argType = argType.GetElementType();
LocalBuilder local = generator.DeclareLocal(argType);
locals.Add(local);
if (!methodArgs[index].IsOut)
{
throw new InvalidOperationException($"Method \"{svcName}\" has a invalid ref type \"{argType.Name}\".");
}
generator.Emit(OpCodes.Ldloca_S, (byte)local.LocalIndex);
}
else
{
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldfld, GetStateFieldX(byRefArgsCount + index));
ConvertToArgType(argType);
}
}
generator.Emit(OpCodes.Call, methodInfo);
int outRegIndex = 0;
Type retType = methodInfo.ReturnType;
//Print result code.
if (retType == typeof(KernelResult))
{
MethodInfo printResultMethod = typeof(SvcTable).GetMethod(nameof(PrintResult), staticNonPublic);
generator.Emit(OpCodes.Dup);
generator.Emit(OpCodes.Ldstr, svcName);
generator.Emit(OpCodes.Call, printResultMethod);
}
//Save return value into register X0 (when the method has a return value).
if (retType != typeof(void))
{
CheckIfTypeIsSupported(retType, svcName);
LocalBuilder tempLocal = generator.DeclareLocal(retType);
generator.Emit(OpCodes.Stloc, tempLocal);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldloc, tempLocal);
ConvertToFieldType(retType);
generator.Emit(OpCodes.Stfld, GetStateFieldX(outRegIndex++));
}
for (int index = 0; index < locals.Count; index++)
{
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldloc, locals[index]);
ConvertToFieldType(locals[index].LocalType);
generator.Emit(OpCodes.Stfld, GetStateFieldX(outRegIndex++));
}
//Zero out the remaining unused registers.
while (outRegIndex < SvcFuncMaxArguments)
{
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldc_I8, 0L);
generator.Emit(OpCodes.Stfld, GetStateFieldX(outRegIndex++));
}
generator.Emit(OpCodes.Ret);
return (Action<SvcHandler, CpuThreadState>)method.CreateDelegate(typeof(Action<SvcHandler, CpuThreadState>));
}
private static FieldInfo GetStateFieldX(int index)
{
switch (index)
{
case 0: return typeof(CpuThreadState).GetField(nameof(CpuThreadState.X0));
case 1: return typeof(CpuThreadState).GetField(nameof(CpuThreadState.X1));
case 2: return typeof(CpuThreadState).GetField(nameof(CpuThreadState.X2));
case 3: return typeof(CpuThreadState).GetField(nameof(CpuThreadState.X3));
case 4: return typeof(CpuThreadState).GetField(nameof(CpuThreadState.X4));
case 5: return typeof(CpuThreadState).GetField(nameof(CpuThreadState.X5));
case 6: return typeof(CpuThreadState).GetField(nameof(CpuThreadState.X6));
case 7: return typeof(CpuThreadState).GetField(nameof(CpuThreadState.X7));
}
throw new ArgumentOutOfRangeException(nameof(index));
}
private static void CheckIfTypeIsSupported(Type type, string svcName)
{
switch (Type.GetTypeCode(type))
{
case TypeCode.UInt64:
case TypeCode.Int64:
case TypeCode.UInt32:
case TypeCode.Int32:
case TypeCode.UInt16:
case TypeCode.Int16:
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.Boolean:
return;
}
throw new InvalidSvcException($"Method \"{svcName}\" has a invalid ref type \"{type.Name}\".");
}
private static void PrintResult(KernelResult result, string svcName)
{
if (result != KernelResult.Success &&
result != KernelResult.TimedOut &&
result != KernelResult.Cancelled &&
result != KernelResult.InvalidState)
{
Logger.PrintWarning(LogClass.KernelSvc, $"{svcName} returned error {result}.");
}
else
{
Logger.PrintDebug(LogClass.KernelSvc, $"{svcName} returned result {result}.");
}
}
private static void PrintArguments(object[] argValues, string format)
{
Logger.PrintDebug(LogClass.KernelSvc, string.Format(format, argValues));
}
}
}

View file

@ -1,24 +1,16 @@
using ChocolArm64.State;
using Ryujinx.Common.Logging;
using static Ryujinx.HLE.HOS.ErrorCode;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel
{ {
partial class SvcHandler partial class SvcHandler
{ {
private void CreateThread64(CpuThreadState threadState) public KernelResult CreateThread64(
ulong entrypoint,
ulong argsPtr,
ulong stackTop,
int priority,
int cpuCore,
out int handle)
{ {
ulong entrypoint = threadState.X1; return CreateThread(entrypoint, argsPtr, stackTop, priority, cpuCore, out handle);
ulong argsPtr = threadState.X2;
ulong stackTop = threadState.X3;
int priority = (int)threadState.X4;
int cpuCore = (int)threadState.X5;
KernelResult result = CreateThread(entrypoint, argsPtr, stackTop, priority, cpuCore, out int handle);
threadState.X0 = (ulong)result;
threadState.X1 = (ulong)handle;
} }
private KernelResult CreateThread( private KernelResult CreateThread(
@ -85,32 +77,31 @@ namespace Ryujinx.HLE.HOS.Kernel
return result; return result;
} }
private void SvcStartThread(CpuThreadState threadState) public KernelResult StartThread64(int handle)
{ {
int handle = (int)threadState.X0; return StartThread(handle);
}
private KernelResult StartThread(int handle)
{
KThread thread = _process.HandleTable.GetObject<KThread>(handle); KThread thread = _process.HandleTable.GetObject<KThread>(handle);
if (thread != null) if (thread != null)
{ {
KernelResult result = thread.Start(); return thread.Start();
if (result != KernelResult.Success)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{result}\".");
}
threadState.X0 = (ulong)result;
} }
else else
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!"); return KernelResult.InvalidHandle;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
} }
} }
private void SvcExitThread(CpuThreadState threadState) public void ExitThread64()
{
ExitThread();
}
private void ExitThread()
{ {
KThread currentThread = _system.Scheduler.GetCurrentThread(); KThread currentThread = _system.Scheduler.GetCurrentThread();
@ -119,12 +110,13 @@ namespace Ryujinx.HLE.HOS.Kernel
currentThread.Exit(); currentThread.Exit();
} }
private void SvcSleepThread(CpuThreadState threadState) public void SleepThread64(long timeout)
{ {
long timeout = (long)threadState.X0; SleepThread(timeout);
}
Logger.PrintDebug(LogClass.KernelSvc, "Timeout = 0x" + timeout.ToString("x16"));
private void SleepThread(long timeout)
{
KThread currentThread = _system.Scheduler.GetCurrentThread(); KThread currentThread = _system.Scheduler.GetCurrentThread();
if (timeout < 1) if (timeout < 1)
@ -139,98 +131,81 @@ namespace Ryujinx.HLE.HOS.Kernel
else else
{ {
currentThread.Sleep(timeout); currentThread.Sleep(timeout);
threadState.X0 = 0;
} }
} }
private void SvcGetThreadPriority(CpuThreadState threadState) public KernelResult GetThreadPriority64(int handle, out int priority)
{ {
int handle = (int)threadState.X1; return GetThreadPriority(handle, out priority);
}
private KernelResult GetThreadPriority(int handle, out int priority)
{
KThread thread = _process.HandleTable.GetKThread(handle); KThread thread = _process.HandleTable.GetKThread(handle);
if (thread != null) if (thread != null)
{ {
threadState.X0 = 0; priority = thread.DynamicPriority;
threadState.X1 = (ulong)thread.DynamicPriority;
return KernelResult.Success;
} }
else else
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!"); priority = 0;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); return KernelResult.InvalidHandle;
} }
} }
private void SvcSetThreadPriority(CpuThreadState threadState) public KernelResult SetThreadPriority64(int handle, int priority)
{ {
int handle = (int)threadState.X0; return SetThreadPriority(handle, priority);
int priority = (int)threadState.X1; }
Logger.PrintDebug(LogClass.KernelSvc,
"Handle = 0x" + handle .ToString("x8") + ", " +
"Priority = 0x" + priority.ToString("x8"));
public KernelResult SetThreadPriority(int handle, int priority)
{
//TODO: NPDM check. //TODO: NPDM check.
KThread thread = _process.HandleTable.GetKThread(handle); KThread thread = _process.HandleTable.GetKThread(handle);
if (thread == null) if (thread == null)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!"); return KernelResult.InvalidHandle;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
return;
} }
thread.SetPriority(priority); thread.SetPriority(priority);
threadState.X0 = 0; return KernelResult.Success;
} }
private void SvcGetThreadCoreMask(CpuThreadState threadState) public KernelResult GetThreadCoreMask64(int handle, out int preferredCore, out long affinityMask)
{ {
int handle = (int)threadState.X2; return GetThreadCoreMask(handle, out preferredCore, out affinityMask);
}
Logger.PrintDebug(LogClass.KernelSvc, "Handle = 0x" + handle.ToString("x8"));
private KernelResult GetThreadCoreMask(int handle, out int preferredCore, out long affinityMask)
{
KThread thread = _process.HandleTable.GetKThread(handle); KThread thread = _process.HandleTable.GetKThread(handle);
if (thread != null) if (thread != null)
{ {
threadState.X0 = 0; preferredCore = thread.PreferredCore;
threadState.X1 = (ulong)thread.PreferredCore; affinityMask = thread.AffinityMask;
threadState.X2 = (ulong)thread.AffinityMask;
return KernelResult.Success;
} }
else else
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!"); preferredCore = 0;
affinityMask = 0;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); return KernelResult.InvalidHandle;
} }
} }
private void SetThreadCoreMask64(CpuThreadState threadState) public KernelResult SetThreadCoreMask64(int handle, int preferredCore, long affinityMask)
{ {
int handle = (int)threadState.X0; return SetThreadCoreMask(handle, preferredCore, affinityMask);
int preferredCore = (int)threadState.X1;
long affinityMask = (long)threadState.X2;
Logger.PrintDebug(LogClass.KernelSvc,
"Handle = 0x" + handle .ToString("x8") + ", " +
"PreferredCore = 0x" + preferredCore.ToString("x8") + ", " +
"AffinityMask = 0x" + affinityMask .ToString("x16"));
KernelResult result = SetThreadCoreMask(handle, preferredCore, affinityMask);
if (result != KernelResult.Success)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{result}\".");
}
threadState.X0 = (ulong)result;
} }
private KernelResult SetThreadCoreMask(int handle, int preferredCore, long affinityMask) private KernelResult SetThreadCoreMask(int handle, int preferredCore, long affinityMask)
@ -279,79 +254,68 @@ namespace Ryujinx.HLE.HOS.Kernel
return thread.SetCoreAndAffinityMask(preferredCore, affinityMask); return thread.SetCoreAndAffinityMask(preferredCore, affinityMask);
} }
private void SvcGetCurrentProcessorNumber(CpuThreadState threadState) public int GetCurrentProcessorNumber64()
{ {
threadState.X0 = (ulong)_system.Scheduler.GetCurrentThread().CurrentCore; return _system.Scheduler.GetCurrentThread().CurrentCore;
} }
private void SvcGetThreadId(CpuThreadState threadState) public KernelResult GetThreadId64(int handle, out long threadUid)
{ {
int handle = (int)threadState.X1; return GetThreadId(handle, out threadUid);
}
private KernelResult GetThreadId(int handle, out long threadUid)
{
KThread thread = _process.HandleTable.GetKThread(handle); KThread thread = _process.HandleTable.GetKThread(handle);
if (thread != null) if (thread != null)
{ {
threadState.X0 = 0; threadUid = thread.ThreadUid;
threadState.X1 = (ulong)thread.ThreadUid;
return KernelResult.Success;
} }
else else
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!"); threadUid = 0;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); return KernelResult.InvalidHandle;
} }
} }
private void SvcSetThreadActivity(CpuThreadState threadState) public KernelResult SetThreadActivity64(int handle, bool pause)
{ {
int handle = (int)threadState.X0; return SetThreadActivity(handle, pause);
bool pause = (int)threadState.X1 == 1; }
private KernelResult SetThreadActivity(int handle, bool pause)
{
KThread thread = _process.HandleTable.GetObject<KThread>(handle); KThread thread = _process.HandleTable.GetObject<KThread>(handle);
if (thread == null) if (thread == null)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!"); return KernelResult.InvalidHandle;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
return;
} }
if (thread.Owner != _system.Scheduler.GetCurrentProcess()) if (thread.Owner != _system.Scheduler.GetCurrentProcess())
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread, it belongs to another process."); return KernelResult.InvalidHandle;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
return;
} }
if (thread == _system.Scheduler.GetCurrentThread()) if (thread == _system.Scheduler.GetCurrentThread())
{ {
Logger.PrintWarning(LogClass.KernelSvc, "Invalid thread, current thread is not accepted."); return KernelResult.InvalidThread;
threadState.X0 = (ulong)KernelResult.InvalidThread;
return;
} }
long result = thread.SetActivity(pause); return thread.SetActivity(pause);
if (result != 0)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
threadState.X0 = (ulong)result;
} }
private void SvcGetThreadContext3(CpuThreadState threadState) public KernelResult GetThreadContext364(ulong address, int handle)
{ {
long position = (long)threadState.X0; return GetThreadContext3(address, handle);
int handle = (int)threadState.X1; }
private KernelResult GetThreadContext3(ulong address, int handle)
{
KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KThread currentThread = _system.Scheduler.GetCurrentThread(); KThread currentThread = _system.Scheduler.GetCurrentThread();
@ -359,106 +323,94 @@ namespace Ryujinx.HLE.HOS.Kernel
if (thread == null) if (thread == null)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!"); return KernelResult.InvalidHandle;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
return;
} }
if (thread.Owner != currentProcess) if (thread.Owner != currentProcess)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread, it belongs to another process."); return KernelResult.InvalidHandle;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
return;
} }
if (currentThread == thread) if (currentThread == thread)
{ {
Logger.PrintWarning(LogClass.KernelSvc, "Invalid thread, current thread is not accepted."); return KernelResult.InvalidThread;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidThread);
return;
} }
_memory.WriteUInt64(position + 0x0, thread.Context.ThreadState.X0); _memory.WriteUInt64((long)address + 0x0, thread.Context.ThreadState.X0);
_memory.WriteUInt64(position + 0x8, thread.Context.ThreadState.X1); _memory.WriteUInt64((long)address + 0x8, thread.Context.ThreadState.X1);
_memory.WriteUInt64(position + 0x10, thread.Context.ThreadState.X2); _memory.WriteUInt64((long)address + 0x10, thread.Context.ThreadState.X2);
_memory.WriteUInt64(position + 0x18, thread.Context.ThreadState.X3); _memory.WriteUInt64((long)address + 0x18, thread.Context.ThreadState.X3);
_memory.WriteUInt64(position + 0x20, thread.Context.ThreadState.X4); _memory.WriteUInt64((long)address + 0x20, thread.Context.ThreadState.X4);
_memory.WriteUInt64(position + 0x28, thread.Context.ThreadState.X5); _memory.WriteUInt64((long)address + 0x28, thread.Context.ThreadState.X5);
_memory.WriteUInt64(position + 0x30, thread.Context.ThreadState.X6); _memory.WriteUInt64((long)address + 0x30, thread.Context.ThreadState.X6);
_memory.WriteUInt64(position + 0x38, thread.Context.ThreadState.X7); _memory.WriteUInt64((long)address + 0x38, thread.Context.ThreadState.X7);
_memory.WriteUInt64(position + 0x40, thread.Context.ThreadState.X8); _memory.WriteUInt64((long)address + 0x40, thread.Context.ThreadState.X8);
_memory.WriteUInt64(position + 0x48, thread.Context.ThreadState.X9); _memory.WriteUInt64((long)address + 0x48, thread.Context.ThreadState.X9);
_memory.WriteUInt64(position + 0x50, thread.Context.ThreadState.X10); _memory.WriteUInt64((long)address + 0x50, thread.Context.ThreadState.X10);
_memory.WriteUInt64(position + 0x58, thread.Context.ThreadState.X11); _memory.WriteUInt64((long)address + 0x58, thread.Context.ThreadState.X11);
_memory.WriteUInt64(position + 0x60, thread.Context.ThreadState.X12); _memory.WriteUInt64((long)address + 0x60, thread.Context.ThreadState.X12);
_memory.WriteUInt64(position + 0x68, thread.Context.ThreadState.X13); _memory.WriteUInt64((long)address + 0x68, thread.Context.ThreadState.X13);
_memory.WriteUInt64(position + 0x70, thread.Context.ThreadState.X14); _memory.WriteUInt64((long)address + 0x70, thread.Context.ThreadState.X14);
_memory.WriteUInt64(position + 0x78, thread.Context.ThreadState.X15); _memory.WriteUInt64((long)address + 0x78, thread.Context.ThreadState.X15);
_memory.WriteUInt64(position + 0x80, thread.Context.ThreadState.X16); _memory.WriteUInt64((long)address + 0x80, thread.Context.ThreadState.X16);
_memory.WriteUInt64(position + 0x88, thread.Context.ThreadState.X17); _memory.WriteUInt64((long)address + 0x88, thread.Context.ThreadState.X17);
_memory.WriteUInt64(position + 0x90, thread.Context.ThreadState.X18); _memory.WriteUInt64((long)address + 0x90, thread.Context.ThreadState.X18);
_memory.WriteUInt64(position + 0x98, thread.Context.ThreadState.X19); _memory.WriteUInt64((long)address + 0x98, thread.Context.ThreadState.X19);
_memory.WriteUInt64(position + 0xa0, thread.Context.ThreadState.X20); _memory.WriteUInt64((long)address + 0xa0, thread.Context.ThreadState.X20);
_memory.WriteUInt64(position + 0xa8, thread.Context.ThreadState.X21); _memory.WriteUInt64((long)address + 0xa8, thread.Context.ThreadState.X21);
_memory.WriteUInt64(position + 0xb0, thread.Context.ThreadState.X22); _memory.WriteUInt64((long)address + 0xb0, thread.Context.ThreadState.X22);
_memory.WriteUInt64(position + 0xb8, thread.Context.ThreadState.X23); _memory.WriteUInt64((long)address + 0xb8, thread.Context.ThreadState.X23);
_memory.WriteUInt64(position + 0xc0, thread.Context.ThreadState.X24); _memory.WriteUInt64((long)address + 0xc0, thread.Context.ThreadState.X24);
_memory.WriteUInt64(position + 0xc8, thread.Context.ThreadState.X25); _memory.WriteUInt64((long)address + 0xc8, thread.Context.ThreadState.X25);
_memory.WriteUInt64(position + 0xd0, thread.Context.ThreadState.X26); _memory.WriteUInt64((long)address + 0xd0, thread.Context.ThreadState.X26);
_memory.WriteUInt64(position + 0xd8, thread.Context.ThreadState.X27); _memory.WriteUInt64((long)address + 0xd8, thread.Context.ThreadState.X27);
_memory.WriteUInt64(position + 0xe0, thread.Context.ThreadState.X28); _memory.WriteUInt64((long)address + 0xe0, thread.Context.ThreadState.X28);
_memory.WriteUInt64(position + 0xe8, thread.Context.ThreadState.X29); _memory.WriteUInt64((long)address + 0xe8, thread.Context.ThreadState.X29);
_memory.WriteUInt64(position + 0xf0, thread.Context.ThreadState.X30); _memory.WriteUInt64((long)address + 0xf0, thread.Context.ThreadState.X30);
_memory.WriteUInt64(position + 0xf8, thread.Context.ThreadState.X31); _memory.WriteUInt64((long)address + 0xf8, thread.Context.ThreadState.X31);
_memory.WriteInt64(position + 0x100, thread.LastPc); _memory.WriteInt64((long)address + 0x100, thread.LastPc);
_memory.WriteUInt64(position + 0x108, (ulong)thread.Context.ThreadState.Psr); _memory.WriteUInt64((long)address + 0x108, (ulong)thread.Context.ThreadState.Psr);
_memory.WriteVector128(position + 0x110, thread.Context.ThreadState.V0); _memory.WriteVector128((long)address + 0x110, thread.Context.ThreadState.V0);
_memory.WriteVector128(position + 0x120, thread.Context.ThreadState.V1); _memory.WriteVector128((long)address + 0x120, thread.Context.ThreadState.V1);
_memory.WriteVector128(position + 0x130, thread.Context.ThreadState.V2); _memory.WriteVector128((long)address + 0x130, thread.Context.ThreadState.V2);
_memory.WriteVector128(position + 0x140, thread.Context.ThreadState.V3); _memory.WriteVector128((long)address + 0x140, thread.Context.ThreadState.V3);
_memory.WriteVector128(position + 0x150, thread.Context.ThreadState.V4); _memory.WriteVector128((long)address + 0x150, thread.Context.ThreadState.V4);
_memory.WriteVector128(position + 0x160, thread.Context.ThreadState.V5); _memory.WriteVector128((long)address + 0x160, thread.Context.ThreadState.V5);
_memory.WriteVector128(position + 0x170, thread.Context.ThreadState.V6); _memory.WriteVector128((long)address + 0x170, thread.Context.ThreadState.V6);
_memory.WriteVector128(position + 0x180, thread.Context.ThreadState.V7); _memory.WriteVector128((long)address + 0x180, thread.Context.ThreadState.V7);
_memory.WriteVector128(position + 0x190, thread.Context.ThreadState.V8); _memory.WriteVector128((long)address + 0x190, thread.Context.ThreadState.V8);
_memory.WriteVector128(position + 0x1a0, thread.Context.ThreadState.V9); _memory.WriteVector128((long)address + 0x1a0, thread.Context.ThreadState.V9);
_memory.WriteVector128(position + 0x1b0, thread.Context.ThreadState.V10); _memory.WriteVector128((long)address + 0x1b0, thread.Context.ThreadState.V10);
_memory.WriteVector128(position + 0x1c0, thread.Context.ThreadState.V11); _memory.WriteVector128((long)address + 0x1c0, thread.Context.ThreadState.V11);
_memory.WriteVector128(position + 0x1d0, thread.Context.ThreadState.V12); _memory.WriteVector128((long)address + 0x1d0, thread.Context.ThreadState.V12);
_memory.WriteVector128(position + 0x1e0, thread.Context.ThreadState.V13); _memory.WriteVector128((long)address + 0x1e0, thread.Context.ThreadState.V13);
_memory.WriteVector128(position + 0x1f0, thread.Context.ThreadState.V14); _memory.WriteVector128((long)address + 0x1f0, thread.Context.ThreadState.V14);
_memory.WriteVector128(position + 0x200, thread.Context.ThreadState.V15); _memory.WriteVector128((long)address + 0x200, thread.Context.ThreadState.V15);
_memory.WriteVector128(position + 0x210, thread.Context.ThreadState.V16); _memory.WriteVector128((long)address + 0x210, thread.Context.ThreadState.V16);
_memory.WriteVector128(position + 0x220, thread.Context.ThreadState.V17); _memory.WriteVector128((long)address + 0x220, thread.Context.ThreadState.V17);
_memory.WriteVector128(position + 0x230, thread.Context.ThreadState.V18); _memory.WriteVector128((long)address + 0x230, thread.Context.ThreadState.V18);
_memory.WriteVector128(position + 0x240, thread.Context.ThreadState.V19); _memory.WriteVector128((long)address + 0x240, thread.Context.ThreadState.V19);
_memory.WriteVector128(position + 0x250, thread.Context.ThreadState.V20); _memory.WriteVector128((long)address + 0x250, thread.Context.ThreadState.V20);
_memory.WriteVector128(position + 0x260, thread.Context.ThreadState.V21); _memory.WriteVector128((long)address + 0x260, thread.Context.ThreadState.V21);
_memory.WriteVector128(position + 0x270, thread.Context.ThreadState.V22); _memory.WriteVector128((long)address + 0x270, thread.Context.ThreadState.V22);
_memory.WriteVector128(position + 0x280, thread.Context.ThreadState.V23); _memory.WriteVector128((long)address + 0x280, thread.Context.ThreadState.V23);
_memory.WriteVector128(position + 0x290, thread.Context.ThreadState.V24); _memory.WriteVector128((long)address + 0x290, thread.Context.ThreadState.V24);
_memory.WriteVector128(position + 0x2a0, thread.Context.ThreadState.V25); _memory.WriteVector128((long)address + 0x2a0, thread.Context.ThreadState.V25);
_memory.WriteVector128(position + 0x2b0, thread.Context.ThreadState.V26); _memory.WriteVector128((long)address + 0x2b0, thread.Context.ThreadState.V26);
_memory.WriteVector128(position + 0x2c0, thread.Context.ThreadState.V27); _memory.WriteVector128((long)address + 0x2c0, thread.Context.ThreadState.V27);
_memory.WriteVector128(position + 0x2d0, thread.Context.ThreadState.V28); _memory.WriteVector128((long)address + 0x2d0, thread.Context.ThreadState.V28);
_memory.WriteVector128(position + 0x2e0, thread.Context.ThreadState.V29); _memory.WriteVector128((long)address + 0x2e0, thread.Context.ThreadState.V29);
_memory.WriteVector128(position + 0x2f0, thread.Context.ThreadState.V30); _memory.WriteVector128((long)address + 0x2f0, thread.Context.ThreadState.V30);
_memory.WriteVector128(position + 0x300, thread.Context.ThreadState.V31); _memory.WriteVector128((long)address + 0x300, thread.Context.ThreadState.V31);
_memory.WriteInt32(position + 0x310, thread.Context.ThreadState.Fpcr); _memory.WriteInt32((long)address + 0x310, thread.Context.ThreadState.Fpcr);
_memory.WriteInt32(position + 0x314, thread.Context.ThreadState.Fpsr); _memory.WriteInt32((long)address + 0x314, thread.Context.ThreadState.Fpsr);
_memory.WriteInt64(position + 0x318, thread.Context.ThreadState.Tpidr); _memory.WriteInt64((long)address + 0x318, thread.Context.ThreadState.Tpidr);
threadState.X0 = 0; return KernelResult.Success;
} }
} }
} }

View file

@ -1,38 +1,28 @@
using ChocolArm64.State;
using Ryujinx.Common.Logging;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.HLE.HOS.ErrorCode;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel
{ {
partial class SvcHandler partial class SvcHandler
{ {
private void SvcWaitSynchronization(CpuThreadState threadState) public KernelResult WaitSynchronization64(ulong handlesPtr, int handlesCount, long timeout, out int handleIndex)
{ {
long handlesPtr = (long)threadState.X1; return WaitSynchronization(handlesPtr, handlesCount, timeout, out handleIndex);
int handlesCount = (int)threadState.X2; }
long timeout = (long)threadState.X3;
Logger.PrintDebug(LogClass.KernelSvc, private KernelResult WaitSynchronization(ulong handlesPtr, int handlesCount, long timeout, out int handleIndex)
"HandlesPtr = 0x" + handlesPtr .ToString("x16") + ", " + {
"HandlesCount = 0x" + handlesCount.ToString("x8") + ", " + handleIndex = 0;
"Timeout = 0x" + timeout .ToString("x16"));
if ((uint)handlesCount > 0x40) if ((uint)handlesCount > 0x40)
{ {
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.CountOutOfRange); return KernelResult.MaximumExceeded;
return;
} }
List<KSynchronizationObject> syncObjs = new List<KSynchronizationObject>(); List<KSynchronizationObject> syncObjs = new List<KSynchronizationObject>();
for (int index = 0; index < handlesCount; index++) for (int index = 0; index < handlesCount; index++)
{ {
int handle = _memory.ReadInt32(handlesPtr + index * 4); int handle = _memory.ReadInt32((long)handlesPtr + index * 4);
Logger.PrintDebug(LogClass.KernelSvc, $"Sync handle 0x{handle:x8}");
KSynchronizationObject syncObj = _process.HandleTable.GetObject<KSynchronizationObject>(handle); KSynchronizationObject syncObj = _process.HandleTable.GetObject<KSynchronizationObject>(handle);
@ -44,232 +34,140 @@ namespace Ryujinx.HLE.HOS.Kernel
syncObjs.Add(syncObj); syncObjs.Add(syncObj);
} }
int hndIndex = (int)threadState.X1; return _system.Synchronization.WaitFor(syncObjs.ToArray(), timeout, out handleIndex);
ulong high = threadState.X1 & (0xffffffffUL << 32);
long result = _system.Synchronization.WaitFor(syncObjs.ToArray(), timeout, ref hndIndex);
if (result != 0)
{
if (result == MakeError(ErrorModule.Kernel, KernelErr.Timeout) ||
result == MakeError(ErrorModule.Kernel, KernelErr.Cancelled))
{
Logger.PrintDebug(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
else
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
}
threadState.X0 = (ulong)result;
threadState.X1 = (uint)hndIndex | high;
} }
private void SvcCancelSynchronization(CpuThreadState threadState) public KernelResult CancelSynchronization64(int handle)
{ {
int threadHandle = (int)threadState.X0; return CancelSynchronization(handle);
}
Logger.PrintDebug(LogClass.KernelSvc, "ThreadHandle = 0x" + threadHandle.ToString("x8")); private KernelResult CancelSynchronization(int handle)
{
KThread thread = _process.HandleTable.GetKThread(threadHandle); KThread thread = _process.HandleTable.GetKThread(handle);
if (thread == null) if (thread == null)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{threadHandle:x8}!"); return KernelResult.InvalidHandle;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
return;
} }
thread.CancelSynchronization(); thread.CancelSynchronization();
threadState.X0 = 0; return KernelResult.Success;
} }
private void SvcArbitrateLock(CpuThreadState threadState) public KernelResult ArbitrateLock64(int ownerHandle, ulong mutexAddress, int requesterHandle)
{ {
int ownerHandle = (int)threadState.X0; return ArbitrateLock(ownerHandle, mutexAddress, requesterHandle);
long mutexAddress = (long)threadState.X1; }
int requesterHandle = (int)threadState.X2;
Logger.PrintDebug(LogClass.KernelSvc,
"OwnerHandle = 0x" + ownerHandle .ToString("x8") + ", " +
"MutexAddress = 0x" + mutexAddress .ToString("x16") + ", " +
"RequesterHandle = 0x" + requesterHandle.ToString("x8"));
private KernelResult ArbitrateLock(int ownerHandle, ulong mutexAddress, int requesterHandle)
{
if (IsPointingInsideKernel(mutexAddress)) if (IsPointingInsideKernel(mutexAddress))
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{mutexAddress:x16}!"); return KernelResult.InvalidMemState;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
} }
if (IsAddressNotWordAligned(mutexAddress)) if (IsAddressNotWordAligned(mutexAddress))
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{mutexAddress:x16}!"); return KernelResult.InvalidAddress;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
} }
KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
long result = currentProcess.AddressArbiter.ArbitrateLock(ownerHandle, mutexAddress, requesterHandle); return currentProcess.AddressArbiter.ArbitrateLock(ownerHandle, mutexAddress, requesterHandle);
if (result != 0)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
threadState.X0 = (ulong)result;
} }
private void SvcArbitrateUnlock(CpuThreadState threadState) public KernelResult ArbitrateUnlock64(ulong mutexAddress)
{ {
long mutexAddress = (long)threadState.X0; return ArbitrateUnlock(mutexAddress);
}
Logger.PrintDebug(LogClass.KernelSvc, "MutexAddress = 0x" + mutexAddress.ToString("x16"));
private KernelResult ArbitrateUnlock(ulong mutexAddress)
{
if (IsPointingInsideKernel(mutexAddress)) if (IsPointingInsideKernel(mutexAddress))
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{mutexAddress:x16}!"); return KernelResult.InvalidMemState;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
} }
if (IsAddressNotWordAligned(mutexAddress)) if (IsAddressNotWordAligned(mutexAddress))
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{mutexAddress:x16}!"); return KernelResult.InvalidAddress;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
} }
KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
long result = currentProcess.AddressArbiter.ArbitrateUnlock(mutexAddress); return currentProcess.AddressArbiter.ArbitrateUnlock(mutexAddress);
if (result != 0)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
threadState.X0 = (ulong)result;
} }
private void SvcWaitProcessWideKeyAtomic(CpuThreadState threadState) public KernelResult WaitProcessWideKeyAtomic64(
ulong mutexAddress,
ulong condVarAddress,
int handle,
long timeout)
{ {
long mutexAddress = (long)threadState.X0; return WaitProcessWideKeyAtomic(mutexAddress, condVarAddress, handle, timeout);
long condVarAddress = (long)threadState.X1; }
int threadHandle = (int)threadState.X2;
long timeout = (long)threadState.X3;
Logger.PrintDebug(LogClass.KernelSvc,
"MutexAddress = 0x" + mutexAddress .ToString("x16") + ", " +
"CondVarAddress = 0x" + condVarAddress.ToString("x16") + ", " +
"ThreadHandle = 0x" + threadHandle .ToString("x8") + ", " +
"Timeout = 0x" + timeout .ToString("x16"));
private KernelResult WaitProcessWideKeyAtomic(
ulong mutexAddress,
ulong condVarAddress,
int handle,
long timeout)
{
if (IsPointingInsideKernel(mutexAddress)) if (IsPointingInsideKernel(mutexAddress))
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{mutexAddress:x16}!"); return KernelResult.InvalidMemState;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
} }
if (IsAddressNotWordAligned(mutexAddress)) if (IsAddressNotWordAligned(mutexAddress))
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{mutexAddress:x16}!"); return KernelResult.InvalidAddress;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
} }
KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
long result = currentProcess.AddressArbiter.WaitProcessWideKeyAtomic( return currentProcess.AddressArbiter.WaitProcessWideKeyAtomic(
mutexAddress, mutexAddress,
condVarAddress, condVarAddress,
threadHandle, handle,
timeout); timeout);
if (result != 0)
{
if (result == MakeError(ErrorModule.Kernel, KernelErr.Timeout))
{
Logger.PrintDebug(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
else
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
}
threadState.X0 = (ulong)result;
} }
private void SvcSignalProcessWideKey(CpuThreadState threadState) public KernelResult SignalProcessWideKey64(ulong address, int count)
{ {
long address = (long)threadState.X0; return SignalProcessWideKey(address, count);
int count = (int)threadState.X1; }
Logger.PrintDebug(LogClass.KernelSvc,
"Address = 0x" + address.ToString("x16") + ", " +
"Count = 0x" + count .ToString("x8"));
private KernelResult SignalProcessWideKey(ulong address, int count)
{
KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
currentProcess.AddressArbiter.SignalProcessWideKey(address, count); currentProcess.AddressArbiter.SignalProcessWideKey(address, count);
threadState.X0 = 0; return KernelResult.Success;
} }
private void SvcWaitForAddress(CpuThreadState threadState) public KernelResult WaitForAddress64(ulong address, ArbitrationType type, int value, long timeout)
{ {
long address = (long)threadState.X0; return WaitForAddress(address, type, value, timeout);
ArbitrationType type = (ArbitrationType)threadState.X1; }
int value = (int)threadState.X2;
long timeout = (long)threadState.X3;
Logger.PrintDebug(LogClass.KernelSvc,
"Address = 0x" + address.ToString("x16") + ", " +
"Type = " + type .ToString() + ", " +
"Value = 0x" + value .ToString("x8") + ", " +
"Timeout = 0x" + timeout.ToString("x16"));
private KernelResult WaitForAddress(ulong address, ArbitrationType type, int value, long timeout)
{
if (IsPointingInsideKernel(address)) if (IsPointingInsideKernel(address))
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid address 0x{address:x16}!"); return KernelResult.InvalidMemState;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
} }
if (IsAddressNotWordAligned(address)) if (IsAddressNotWordAligned(address))
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Unaligned address 0x{address:x16}!"); return KernelResult.InvalidAddress;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
} }
KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
long result; KernelResult result;
switch (type) switch (type)
{ {
@ -286,52 +184,33 @@ namespace Ryujinx.HLE.HOS.Kernel
break; break;
default: default:
result = MakeError(ErrorModule.Kernel, KernelErr.InvalidEnumValue); result = KernelResult.InvalidEnumValue;
break; break;
} }
if (result != 0) return result;
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
threadState.X0 = (ulong)result;
} }
private void SvcSignalToAddress(CpuThreadState threadState) public KernelResult SignalToAddress64(ulong address, SignalType type, int value, int count)
{ {
long address = (long)threadState.X0; return SignalToAddress(address, type, value, count);
SignalType type = (SignalType)threadState.X1; }
int value = (int)threadState.X2;
int count = (int)threadState.X3;
Logger.PrintDebug(LogClass.KernelSvc,
"Address = 0x" + address.ToString("x16") + ", " +
"Type = " + type .ToString() + ", " +
"Value = 0x" + value .ToString("x8") + ", " +
"Count = 0x" + count .ToString("x8"));
private KernelResult SignalToAddress(ulong address, SignalType type, int value, int count)
{
if (IsPointingInsideKernel(address)) if (IsPointingInsideKernel(address))
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid address 0x{address:x16}!"); return KernelResult.InvalidMemState;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
} }
if (IsAddressNotWordAligned(address)) if (IsAddressNotWordAligned(address))
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Unaligned address 0x{address:x16}!"); return KernelResult.InvalidAddress;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
} }
KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
long result; KernelResult result;
switch (type) switch (type)
{ {
@ -348,24 +227,19 @@ namespace Ryujinx.HLE.HOS.Kernel
break; break;
default: default:
result = MakeError(ErrorModule.Kernel, KernelErr.InvalidEnumValue); result = KernelResult.InvalidEnumValue;
break; break;
} }
if (result != 0) return result;
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
threadState.X0 = (ulong)result;
} }
private bool IsPointingInsideKernel(long address) private bool IsPointingInsideKernel(ulong address)
{ {
return ((ulong)address + 0x1000000000) < 0xffffff000; return (address + 0x1000000000) < 0xffffff000;
} }
private bool IsAddressNotWordAligned(long address) private bool IsAddressNotWordAligned(ulong address)
{ {
return (address & 3) != 0; return (address & 3) != 0;
} }