svc: Rework 32 bit codepath

Fixing once and for all argument ordering issues.
This commit is contained in:
Thog 2020-01-04 03:33:34 +01:00
parent afe6f87c08
commit 30b067e9f0
No known key found for this signature in database
GPG key ID: 0CD291558FAFDBC6
7 changed files with 481 additions and 28 deletions

View file

@ -0,0 +1,14 @@
using System;
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
public class RAttribute : Attribute
{
public readonly int Index;
public RAttribute(int index)
{
Index = index;
}
}
}

View file

@ -35,6 +35,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return ConnectToNamedPort(namePtr, out handle);
}
public KernelResult ConnectToNamedPort32([R(1)] uint namePtr, [R(1)] out int handle)
{
return ConnectToNamedPort(namePtr, out handle);
}
private KernelResult ConnectToNamedPort(ulong namePtr, out int handle)
{
handle = 0;
@ -86,6 +91,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return SendSyncRequest((ulong)_system.Scheduler.GetCurrentThread().Context.Tpidr, 0x100, handle);
}
public KernelResult SendSyncRequest32([R(0)] int handle)
{
return SendSyncRequest((ulong)_system.Scheduler.GetCurrentThread().Context.Tpidr, 0x100, handle);
}
public KernelResult SendSyncRequestWithUserBuffer64(ulong messagePtr, ulong size, int handle)
{
return SendSyncRequest(messagePtr, size, handle);

View file

@ -11,6 +11,17 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return SetHeapSize(size, out position);
}
public KernelResult SetHeapSize32([R(1)] uint size, [R(1)] out uint position)
{
ulong temporaryPosition;
KernelResult result = SetHeapSize(size, out temporaryPosition);
position = (uint)temporaryPosition;
return result;
}
private KernelResult SetHeapSize(ulong size, out ulong position)
{
if ((size & 0xfffffffe001fffff) != 0)
@ -32,6 +43,15 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return SetMemoryAttribute(position, size, attributeMask, attributeValue);
}
public KernelResult SetMemoryAttribute32(
[R(0)] uint position,
[R(1)] uint size,
[R(2)] MemoryAttribute attributeMask,
[R(3)] MemoryAttribute attributeValue)
{
return SetMemoryAttribute(position, size, attributeMask, attributeValue);
}
private KernelResult SetMemoryAttribute(
ulong position,
ulong size,
@ -70,6 +90,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return MapMemory(dst, src, size);
}
public KernelResult MapMemory32([R(0)] uint dst, [R(1)] uint src, [R(2)] uint size)
{
return MapMemory(dst, src, size);
}
private KernelResult MapMemory(ulong dst, ulong src, ulong size)
{
if (!PageAligned(src | dst))
@ -109,6 +134,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return UnmapMemory(dst, src, size);
}
public KernelResult UnmapMemory32([R(0)] uint dst, [R(1)] uint src, [R(2)] uint size)
{
return UnmapMemory(dst, src, size);
}
private KernelResult UnmapMemory(ulong dst, ulong src, ulong size)
{
if (!PageAligned(src | dst))
@ -148,8 +178,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return QueryMemory(infoPtr, position);
}
public KernelResult QueryMemory32(uint infoPtr, uint x1, uint position)
public KernelResult QueryMemory32([R(0)] uint infoPtr, [R(1)] uint r1, [R(2)] uint position)
{
// FIXME: Nintendo here bzero the pointer info structure and then copy every element one by one if QueryMemory succeed.
return QueryMemory(infoPtr, position);
}
@ -274,6 +305,15 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return CreateTransferMemory(address, size, permission, out handle);
}
public KernelResult CreateTransferMemory32(
[R(1)] uint address,
[R(2)] uint size,
[R(3)] MemoryPermission permission,
[R(1)] out int handle)
{
return CreateTransferMemory(address, size, permission, out handle);
}
private KernelResult CreateTransferMemory(ulong address, ulong size, MemoryPermission permission, out int handle)
{
handle = 0;

View file

@ -17,6 +17,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
ExitProcess();
}
public void ExitProcess32()
{
ExitProcess();
}
public KernelResult TerminateProcess64(int handle)
{
return TerminateProcess(handle);
@ -109,6 +114,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return CloseHandle(handle);
}
public KernelResult CloseHandle32([R(0)] int handle)
{
return CloseHandle(handle);
}
private KernelResult CloseHandle(int handle)
{
KAutoObject obj = _process.HandleTable.GetObject<KAutoObject>(handle);
@ -208,6 +218,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
Break(reason);
}
public void Break32([R(0)] uint reason, [R(1)] uint r1, [R(2)] uint info)
{
Break(reason);
}
private void Break(ulong reason)
{
KThread currentThread = _system.Scheduler.GetCurrentThread();
@ -240,7 +255,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
OutputDebugString(strPtr, size);
}
public void OutputDebugString32(uint strPtr, uint size)
public void OutputDebugString32([R(0)] uint strPtr, [R(1)] uint size)
{
OutputDebugString(strPtr, size);
}
@ -257,12 +272,22 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return GetInfo(id, handle, subId, out value);
}
public KernelResult GetInfo32(uint subIdLo, uint id, int handle, uint subIdHi, out uint valueLo, out uint valueHi)
public KernelResult GetInfo32(
[R(0)] uint subIdLow,
[R(1)] uint id,
[R(2)] int handle,
[R(3)] uint subIdHigh,
[R(1)] out uint valueLow,
[R(2)] out uint valueHigh)
{
long value;
KernelResult result = GetInfo(id, handle, subIdHi | ((long)subIdLo << 32), out value);
valueLo = (uint)(value >> 32);
valueHi = (uint)value;
long subId = (long)(subIdLow | ((ulong)subIdHigh << 32));
KernelResult result = GetInfo(id, handle, subId, out value);
valueHigh = (uint)(value >> 32);
valueLow = (uint)(value & 0xFFFFFFFF);
return result;
}

View file

@ -3,6 +3,7 @@ using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Kernel.Common;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
@ -11,7 +12,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
static class SvcTable
{
private const int SvcFuncMaxArguments = 8;
private const int SvcFuncMaxArguments64 = 8;
private const int SvcFuncMaxArguments32 = 4;
private static Dictionary<int, string> _svcFuncs64;
@ -84,10 +85,30 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
_svcFuncs32 = new Dictionary<int, string>
{
{ 0x01, nameof(SvcHandler.SetHeapSize32) },
{ 0x03, nameof(SvcHandler.SetMemoryAttribute32) },
{ 0x04, nameof(SvcHandler.MapMemory32) },
{ 0x05, nameof(SvcHandler.UnmapMemory32) },
{ 0x06, nameof(SvcHandler.QueryMemory32) },
{ 0x07, nameof(SvcHandler.ExitProcess32) },
{ 0x08, nameof(SvcHandler.CreateThread32) },
{ 0x09, nameof(SvcHandler.StartThread32) },
{ 0x0a, nameof(SvcHandler.ExitThread32) },
{ 0x0b, nameof(SvcHandler.SleepThread32) },
{ 0x0c, nameof(SvcHandler.GetThreadPriority32) },
{ 0x0d, nameof(SvcHandler.SetThreadPriority32) },
{ 0x0f, nameof(SvcHandler.SetThreadCoreMask32) },
{ 0x10, nameof(SvcHandler.GetCurrentProcessorNumber32) },
{ 0x15, nameof(SvcHandler.CreateTransferMemory32) },
{ 0x16, nameof(SvcHandler.CloseHandle32) },
{ 0x18, nameof(SvcHandler.WaitSynchronization32) },
{ 0x1d, nameof(SvcHandler.SignalProcessWideKey32) },
{ 0x1f, nameof(SvcHandler.ConnectToNamedPort32) },
{ 0x21, nameof(SvcHandler.SendSyncRequest32) },
{ 0x25, nameof(SvcHandler.GetThreadId32) },
{ 0x26, nameof(SvcHandler.Break32) },
{ 0x27, nameof(SvcHandler.OutputDebugString32) },
{ 0x29, nameof(SvcHandler.GetInfo64) }
{ 0x29, nameof(SvcHandler.GetInfo32) }
};
_svcTable64 = new Action<SvcHandler, ExecutionContext>[0x80];
@ -106,19 +127,32 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
if (funcTable.TryGetValue(svcId, out string svcName))
{
if (svcId == 0x08) { }
return table[svcId] = GenerateMethod(svcName, aarch32);
Action<SvcHandler, ExecutionContext> svcFunc;
if (aarch32)
{
svcFunc = GenerateMethod32(svcName);
}
else
{
svcFunc = GenerateMethod64(svcName);
}
table[svcId] = svcFunc;
return table[svcId] = svcFunc;
}
if (aarch32 && _svcFuncs64.TryGetValue(svcId, out string svcName64))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Svc \"{svcName64}\" ({svcId}) does not have a 32-bit call signature defined - fell back to 64-bit.");
return table[svcId] = GenerateMethod(svcName64, aarch32);
throw new NotImplementedException($"Svc \"{svcName64}\" ({svcId}) does not have a 32-bit call signature defined.");
}
return null;
}
private static Action<SvcHandler, ExecutionContext> GenerateMethod(string svcName, bool aarch32)
private static Action<SvcHandler, ExecutionContext> GenerateMethod64(string svcName)
{
Type[] argTypes = new Type[] { typeof(SvcHandler), typeof(ExecutionContext) };
@ -128,12 +162,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
ParameterInfo[] methodArgs = methodInfo.GetParameters();
int maxArgs = aarch32 ? SvcFuncMaxArguments32 : SvcFuncMaxArguments;
int numArgs = methodArgs.Count(x => !x.IsOut);
if (numArgs > maxArgs)
if (methodArgs.Length > SvcFuncMaxArguments64)
{
//throw new InvalidOperationException($"Method \"{svcName}\" has too many arguments, max is {maxArgs}.");
throw new InvalidOperationException($"Method \"{svcName}\" has too many arguments, max is {SvcFuncMaxArguments64}.");
}
ILGenerator generator = method.GetILGenerator();
@ -212,8 +243,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
generator.Emit(OpCodes.Ldc_I4, index);
generator.Emit(OpCodes.Ldarg_1);
int argIndex = (aarch32 && index >= maxArgs) ? index - maxArgs : byRefArgsCount + index;
generator.Emit(OpCodes.Ldc_I4, argIndex);
generator.Emit(OpCodes.Ldc_I4, byRefArgsCount + index);
MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.GetX));
@ -275,8 +305,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
else
{
generator.Emit(OpCodes.Ldarg_1);
int argIndex = (aarch32 && index >= maxArgs) ? index - maxArgs : byRefArgsCount + index;
generator.Emit(OpCodes.Ldc_I4, argIndex);
generator.Emit(OpCodes.Ldc_I4, byRefArgsCount + index);
MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.GetX));
@ -335,7 +364,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
// Zero out the remaining unused registers.
while (outRegIndex < maxArgs)
while (outRegIndex < SvcFuncMaxArguments64)
{
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldc_I4, outRegIndex++);
@ -351,6 +380,273 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return (Action<SvcHandler, ExecutionContext>)method.CreateDelegate(typeof(Action<SvcHandler, ExecutionContext>));
}
// TODO: merge 64 bits variant
private static Action<SvcHandler, ExecutionContext> GenerateMethod32(string svcName)
{
Type[] argTypes = new Type[] { typeof(SvcHandler), typeof(ExecutionContext) };
DynamicMethod method = new DynamicMethod(svcName, null, argTypes);
MethodInfo methodInfo = typeof(SvcHandler).GetMethod(svcName);
ParameterInfo[] methodArgs = methodInfo.GetParameters();
int numArgs = methodArgs.Count(x => !x.IsOut);
ILGenerator generator = method.GetILGenerator();
void ConvertToArgType(Type sourceType)
{
CheckIfTypeIsSupported(sourceType, svcName);
switch (Type.GetTypeCode(sourceType))
{
case TypeCode.UInt32: generator.Emit(OpCodes.Conv_U4); break;
case TypeCode.Int32: generator.Emit(OpCodes.Conv_I4); break;
case TypeCode.UInt16: generator.Emit(OpCodes.Conv_U2); break;
case TypeCode.Int16: generator.Emit(OpCodes.Conv_I2); break;
case TypeCode.Byte: generator.Emit(OpCodes.Conv_U1); break;
case TypeCode.SByte: generator.Emit(OpCodes.Conv_I1); break;
case TypeCode.Boolean:
generator.Emit(OpCodes.Conv_I4);
generator.Emit(OpCodes.Ldc_I4_1);
generator.Emit(OpCodes.And);
break;
}
}
void ConvertToFieldType(Type sourceType)
{
CheckIfTypeIsSupported(sourceType, svcName);
switch (Type.GetTypeCode(sourceType))
{
case TypeCode.UInt32:
case TypeCode.Int32:
case TypeCode.UInt16:
case TypeCode.Int16:
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.Boolean:
generator.Emit(OpCodes.Conv_U8);
break;
}
}
RAttribute GetRegisterAttribute(ParameterInfo parameterInfo)
{
RAttribute argumentAttribute = (RAttribute)parameterInfo.GetCustomAttribute(typeof(RAttribute));
if (argumentAttribute == null)
{
throw new InvalidOperationException($"Method \"{svcName}\" is missing a {typeof(RAttribute).Name} attribute on parameter \"{parameterInfo.Name}\"");
}
return argumentAttribute;
}
// For functions returning output values, the first registers
// are used to hold pointers where the value will be stored,
// so they can't be used to pass argument and we must
// skip them.
int byRefArgsCount = 0;
for (int index = 0; index < methodArgs.Length; index++)
{
if (methodArgs[index].ParameterType.IsByRef)
{
byRefArgsCount++;
}
}
BindingFlags staticNonPublic = BindingFlags.NonPublic | BindingFlags.Static;
// Print all the arguments for debugging purposes.
int inputArgsCount = methodArgs.Length - byRefArgsCount;
if (inputArgsCount != 0)
{
generator.Emit(OpCodes.Ldc_I4, inputArgsCount);
generator.Emit(OpCodes.Newarr, typeof(object));
string argsFormat = svcName;
for (int index = 0; index < methodArgs.Length; index++)
{
Type argType = methodArgs[index].ParameterType;
// Ignore out argument for printing
if (argType.IsByRef)
{
continue;
}
RAttribute registerAttribute = GetRegisterAttribute(methodArgs[index]);
argsFormat += $" {methodArgs[index].Name}: 0x{{{index}:X8}},";
generator.Emit(OpCodes.Dup);
generator.Emit(OpCodes.Ldc_I4, index);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldc_I4, registerAttribute.Index);
MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.GetX));
generator.Emit(OpCodes.Call, info);
generator.Emit(OpCodes.Box, typeof(ulong));
generator.Emit(OpCodes.Stelem_Ref);
}
argsFormat = argsFormat.Substring(0, argsFormat.Length - 1);
generator.Emit(OpCodes.Ldstr, argsFormat);
}
else
{
generator.Emit(OpCodes.Ldnull);
generator.Emit(OpCodes.Ldstr, svcName);
}
MethodInfo printArgsMethod = typeof(SvcTable).GetMethod(nameof(PrintArguments), staticNonPublic);
generator.Emit(OpCodes.Call, printArgsMethod);
// Call the SVC function handler.
generator.Emit(OpCodes.Ldarg_0);
List<(LocalBuilder, RAttribute)> locals = new List<(LocalBuilder, RAttribute)>();
for (int index = 0; index < methodArgs.Length; index++)
{
Type argType = methodArgs[index].ParameterType;
RAttribute registerAttribute = GetRegisterAttribute(methodArgs[index]);
if (argType.IsByRef)
{
argType = argType.GetElementType();
LocalBuilder local = generator.DeclareLocal(argType);
locals.Add((local, registerAttribute));
if (!methodArgs[index].IsOut)
{
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldc_I4, registerAttribute.Index);
MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.GetX));
generator.Emit(OpCodes.Call, info);
ConvertToArgType(argType);
generator.Emit(OpCodes.Stloc, local);
}
generator.Emit(OpCodes.Ldloca, local);
}
else
{
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldc_I4, registerAttribute.Index);
MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.GetX));
generator.Emit(OpCodes.Call, info);
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.Ldc_I4, outRegIndex++);
generator.Emit(OpCodes.Ldloc, tempLocal);
ConvertToFieldType(retType);
MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.SetX));
generator.Emit(OpCodes.Call, info);
}
for (int index = 0; index < locals.Count; index++)
{
(LocalBuilder local, RAttribute attribute) = locals[index];
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldc_I4, attribute.Index);
generator.Emit(OpCodes.Ldloc, local);
ConvertToFieldType(local.LocalType);
MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.SetX));
generator.Emit(OpCodes.Call, info);
}
bool IsRegisterInUse(int registerIndex)
{
for (int index = 0; index < locals.Count; index++)
{
if (registerIndex == locals[index].Item2.Index)
{
return true;
}
}
return false;
}
// Zero out the remaining unused registers.
for (int i = 0; i < SvcFuncMaxArguments32; i++)
{
if (IsRegisterInUse(i))
{
continue;
}
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldc_I4, i);
generator.Emit(OpCodes.Ldc_I8, 0L);
MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.SetX));
generator.Emit(OpCodes.Call, info);
}
generator.Emit(OpCodes.Ret);
return (Action<SvcHandler, ExecutionContext>)method.CreateDelegate(typeof(Action<SvcHandler, ExecutionContext>));
}
private static void CheckIfTypeIsSupported(Type type, string svcName)
{
switch (Type.GetTypeCode(type))

View file

@ -20,13 +20,13 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
public KernelResult CreateThread32(
ulong entrypoint,
ulong argsPtr,
ulong stackTop,
int cpuCore,
int priority,
out int handle)
[R(1)] uint entrypoint,
[R(2)] uint argsPtr,
[R(3)] uint stackTop,
[R(0)] int priority,
[R(4)] int cpuCore,
[R(1)] out int handle)
{
return CreateThread(entrypoint, argsPtr, stackTop, priority, cpuCore, out handle);
}
@ -95,6 +95,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return StartThread(handle);
}
public KernelResult StartThread32([R(0)] int handle)
{
return StartThread(handle);
}
private KernelResult StartThread(int handle)
{
KThread thread = _process.HandleTable.GetKThread(handle);
@ -125,6 +130,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
ExitThread();
}
public void ExitThread32()
{
ExitThread();
}
private void ExitThread()
{
KThread currentThread = _system.Scheduler.GetCurrentThread();
@ -139,6 +149,13 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
SleepThread(timeout);
}
public void SleepThread32([R(0)] uint timeoutLow, [R(1)] uint timeoutHigh)
{
long timeout = (long)(timeoutLow | ((ulong)timeoutHigh << 32));
SleepThread(timeout);
}
private void SleepThread(long timeout)
{
KThread currentThread = _system.Scheduler.GetCurrentThread();
@ -163,6 +180,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return GetThreadPriority(handle, out priority);
}
public KernelResult GetThreadPriority32([R(1)] int handle, [R(1)] out int priority)
{
return GetThreadPriority(handle, out priority);
}
private KernelResult GetThreadPriority(int handle, out int priority)
{
KThread thread = _process.HandleTable.GetKThread(handle);
@ -186,6 +208,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return SetThreadPriority(handle, priority);
}
public KernelResult SetThreadPriority32([R(0)] int handle, [R(1)] int priority)
{
return SetThreadPriority(handle, priority);
}
public KernelResult SetThreadPriority(int handle, int priority)
{
// TODO: NPDM check.
@ -232,6 +259,13 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return SetThreadCoreMask(handle, preferredCore, affinityMask);
}
public KernelResult SetThreadCoreMask32([R(0)] int handle, [R(1)] int preferredCore, [R(2)] uint affinityMaskLow, [R(3)] uint affinityMaskHigh)
{
long affinityMask = (long)(affinityMaskLow | ((ulong)affinityMaskHigh << 32));
return SetThreadCoreMask(handle, preferredCore, affinityMask);
}
private KernelResult SetThreadCoreMask(int handle, int preferredCore, long affinityMask)
{
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
@ -283,11 +317,28 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return _system.Scheduler.GetCurrentThread().CurrentCore;
}
public int GetCurrentProcessorNumber32()
{
return _system.Scheduler.GetCurrentThread().CurrentCore;
}
public KernelResult GetThreadId64(int handle, out long threadUid)
{
return GetThreadId(handle, out threadUid);
}
public KernelResult GetThreadId32([R(1)] int handle, [R(1)] out uint threadUidLow, [R(2)] out uint threadUidHigh)
{
long threadUid;
KernelResult result = GetThreadId(handle, out threadUid);
threadUidLow = (uint)(threadUid >> 32);
threadUidHigh = (uint)(threadUid & 0xFFFFFFFF);
return result;
}
private KernelResult GetThreadId(int handle, out long threadUid)
{
KThread thread = _process.HandleTable.GetKThread(handle);

View file

@ -12,6 +12,18 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return WaitSynchronization(handlesPtr, handlesCount, timeout, out handleIndex);
}
public KernelResult WaitSynchronization32(
[R(0)] uint timeoutLow,
[R(1)] uint handlesPtr,
[R(2)] int handlesCount,
[R(3)] uint timeoutHigh,
[R(1)] out int handleIndex)
{
long timeout = (long)(timeoutLow | ((ulong)timeoutHigh << 32));
return WaitSynchronization(handlesPtr, handlesCount, timeout, out handleIndex);
}
private KernelResult WaitSynchronization(ulong handlesPtr, int handlesCount, long timeout, out int handleIndex)
{
handleIndex = 0;
@ -142,6 +154,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return SignalProcessWideKey(address, count);
}
public KernelResult SignalProcessWideKey32([R(0)] uint address, [R(1)] int count)
{
return SignalProcessWideKey(address, count);
}
private KernelResult SignalProcessWideKey(ulong address, int count)
{
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();