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

View file

@ -11,6 +11,17 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return SetHeapSize(size, out position); return SetHeapSize(size, out position);
} }
public KernelResult SetHeapSize32([R(1)] uint size, [R(1)] out uint position)
{
ulong temporaryPosition;
KernelResult result = SetHeapSize(size, out temporaryPosition);
position = (uint)temporaryPosition;
return result;
}
private KernelResult SetHeapSize(ulong size, out ulong position) private KernelResult SetHeapSize(ulong size, out ulong position)
{ {
if ((size & 0xfffffffe001fffff) != 0) if ((size & 0xfffffffe001fffff) != 0)
@ -32,6 +43,15 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return SetMemoryAttribute(position, size, attributeMask, attributeValue); return SetMemoryAttribute(position, size, attributeMask, attributeValue);
} }
public KernelResult SetMemoryAttribute32(
[R(0)] uint position,
[R(1)] uint size,
[R(2)] MemoryAttribute attributeMask,
[R(3)] MemoryAttribute attributeValue)
{
return SetMemoryAttribute(position, size, attributeMask, attributeValue);
}
private KernelResult SetMemoryAttribute( private KernelResult SetMemoryAttribute(
ulong position, ulong position,
ulong size, ulong size,
@ -70,6 +90,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return MapMemory(dst, src, size); return MapMemory(dst, src, size);
} }
public KernelResult MapMemory32([R(0)] uint dst, [R(1)] uint src, [R(2)] uint size)
{
return MapMemory(dst, src, size);
}
private KernelResult MapMemory(ulong dst, ulong src, ulong size) private KernelResult MapMemory(ulong dst, ulong src, ulong size)
{ {
if (!PageAligned(src | dst)) if (!PageAligned(src | dst))
@ -109,6 +134,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return UnmapMemory(dst, src, size); return UnmapMemory(dst, src, size);
} }
public KernelResult UnmapMemory32([R(0)] uint dst, [R(1)] uint src, [R(2)] uint size)
{
return UnmapMemory(dst, src, size);
}
private KernelResult UnmapMemory(ulong dst, ulong src, ulong size) private KernelResult UnmapMemory(ulong dst, ulong src, ulong size)
{ {
if (!PageAligned(src | dst)) if (!PageAligned(src | dst))
@ -148,8 +178,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return QueryMemory(infoPtr, position); 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); return QueryMemory(infoPtr, position);
} }
@ -274,6 +305,15 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return CreateTransferMemory(address, size, permission, out handle); return CreateTransferMemory(address, size, permission, out handle);
} }
public KernelResult CreateTransferMemory32(
[R(1)] uint address,
[R(2)] uint size,
[R(3)] MemoryPermission permission,
[R(1)] out int handle)
{
return CreateTransferMemory(address, size, permission, out handle);
}
private KernelResult CreateTransferMemory(ulong address, ulong size, MemoryPermission permission, out int handle) private KernelResult CreateTransferMemory(ulong address, ulong size, MemoryPermission permission, out int handle)
{ {
handle = 0; handle = 0;

View file

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

View file

@ -3,6 +3,7 @@ using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Common;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Reflection.Emit; using System.Reflection.Emit;
@ -11,7 +12,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{ {
static class SvcTable static class SvcTable
{ {
private const int SvcFuncMaxArguments = 8; private const int SvcFuncMaxArguments64 = 8;
private const int SvcFuncMaxArguments32 = 4; private const int SvcFuncMaxArguments32 = 4;
private static Dictionary<int, string> _svcFuncs64; private static Dictionary<int, string> _svcFuncs64;
@ -84,10 +85,30 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
_svcFuncs32 = new Dictionary<int, string> _svcFuncs32 = new Dictionary<int, string>
{ {
{ 0x01, nameof(SvcHandler.SetHeapSize32) },
{ 0x03, nameof(SvcHandler.SetMemoryAttribute32) },
{ 0x04, nameof(SvcHandler.MapMemory32) },
{ 0x05, nameof(SvcHandler.UnmapMemory32) },
{ 0x06, nameof(SvcHandler.QueryMemory32) }, { 0x06, nameof(SvcHandler.QueryMemory32) },
{ 0x07, nameof(SvcHandler.ExitProcess32) },
{ 0x08, nameof(SvcHandler.CreateThread32) }, { 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) }, { 0x27, nameof(SvcHandler.OutputDebugString32) },
{ 0x29, nameof(SvcHandler.GetInfo64) } { 0x29, nameof(SvcHandler.GetInfo32) }
}; };
_svcTable64 = new Action<SvcHandler, ExecutionContext>[0x80]; _svcTable64 = new Action<SvcHandler, ExecutionContext>[0x80];
@ -106,19 +127,32 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
if (funcTable.TryGetValue(svcId, out string svcName)) if (funcTable.TryGetValue(svcId, out string svcName))
{ {
if (svcId == 0x08) { } 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)) 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."); 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; 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) }; Type[] argTypes = new Type[] { typeof(SvcHandler), typeof(ExecutionContext) };
@ -128,12 +162,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
ParameterInfo[] methodArgs = methodInfo.GetParameters(); ParameterInfo[] methodArgs = methodInfo.GetParameters();
int maxArgs = aarch32 ? SvcFuncMaxArguments32 : SvcFuncMaxArguments; if (methodArgs.Length > SvcFuncMaxArguments64)
int numArgs = methodArgs.Count(x => !x.IsOut);
if (numArgs > maxArgs)
{ {
//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(); ILGenerator generator = method.GetILGenerator();
@ -212,8 +243,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
generator.Emit(OpCodes.Ldc_I4, index); generator.Emit(OpCodes.Ldc_I4, index);
generator.Emit(OpCodes.Ldarg_1); generator.Emit(OpCodes.Ldarg_1);
int argIndex = (aarch32 && index >= maxArgs) ? index - maxArgs : byRefArgsCount + index; generator.Emit(OpCodes.Ldc_I4, byRefArgsCount + index);
generator.Emit(OpCodes.Ldc_I4, argIndex);
MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.GetX)); MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.GetX));
@ -275,8 +305,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
else else
{ {
generator.Emit(OpCodes.Ldarg_1); generator.Emit(OpCodes.Ldarg_1);
int argIndex = (aarch32 && index >= maxArgs) ? index - maxArgs : byRefArgsCount + index; generator.Emit(OpCodes.Ldc_I4, byRefArgsCount + index);
generator.Emit(OpCodes.Ldc_I4, argIndex);
MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.GetX)); MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.GetX));
@ -335,7 +364,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
} }
// Zero out the remaining unused registers. // Zero out the remaining unused registers.
while (outRegIndex < maxArgs) while (outRegIndex < SvcFuncMaxArguments64)
{ {
generator.Emit(OpCodes.Ldarg_1); generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldc_I4, outRegIndex++); 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>)); 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) private static void CheckIfTypeIsSupported(Type type, string svcName)
{ {
switch (Type.GetTypeCode(type)) switch (Type.GetTypeCode(type))

View file

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