diff options
Diffstat (limited to 'Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcTable.cs')
| -rw-r--r-- | Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcTable.cs | 105 |
1 files changed, 68 insertions, 37 deletions
diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcTable.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcTable.cs index 1c2121f0..27aa70fc 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcTable.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcTable.cs @@ -3,6 +3,7 @@ using Ryujinx.Common.Logging; using Ryujinx.HLE.HOS.Kernel.Common; using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; using System.Reflection.Emit; @@ -10,15 +11,19 @@ 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 const int SvcMax = 0x80; - private static Dictionary<int, string> _svcFuncs64; - - private static Action<SvcHandler, ExecutionContext>[] _svcTable64; + public static Action<SvcHandler, ExecutionContext>[] SvcTable32 { get; } + public static Action<SvcHandler, ExecutionContext>[] SvcTable64 { get; } static SvcTable() { - _svcFuncs64 = new Dictionary<int, string> + SvcTable32 = new Action<SvcHandler, ExecutionContext>[SvcMax]; + SvcTable64 = new Action<SvcHandler, ExecutionContext>[SvcMax]; + + Dictionary<int, string> svcFuncs64 = new Dictionary<int, string> { { 0x01, nameof(SvcHandler.SetHeapSize64) }, { 0x03, nameof(SvcHandler.SetMemoryAttribute64) }, @@ -78,25 +83,23 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall { 0x7B, nameof(SvcHandler.TerminateProcess64) } }; - _svcTable64 = new Action<SvcHandler, ExecutionContext>[0x80]; - } - - public static Action<SvcHandler, ExecutionContext> GetSvcFunc(int svcId) - { - if (_svcTable64[svcId] != null) + foreach (KeyValuePair<int, string> value in svcFuncs64) { - return _svcTable64[svcId]; + SvcTable64[value.Key] = GenerateMethod(value.Value, SvcFuncMaxArguments64); } - if (_svcFuncs64.TryGetValue(svcId, out string svcName)) + Dictionary<int, string> svcFuncs32 = new Dictionary<int, string> { - return _svcTable64[svcId] = GenerateMethod(svcName); - } + // TODO + }; - return null; + foreach (KeyValuePair<int, string> value in svcFuncs32) + { + SvcTable32[value.Key] = GenerateMethod(value.Value, SvcFuncMaxArguments32); + } } - private static Action<SvcHandler, ExecutionContext> GenerateMethod(string svcName) + private static Action<SvcHandler, ExecutionContext> GenerateMethod(string svcName, int registerCleanCount) { Type[] argTypes = new Type[] { typeof(SvcHandler), typeof(ExecutionContext) }; @@ -106,11 +109,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall 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) @@ -152,6 +150,18 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } } + 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 @@ -179,15 +189,25 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall string argsFormat = svcName; - for (int index = 0; index < inputArgsCount; index++) + 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, byRefArgsCount + index); + generator.Emit(OpCodes.Ldc_I4, registerAttribute.Index); MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.GetX)); @@ -200,7 +220,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall argsFormat = argsFormat.Substring(0, argsFormat.Length - 1); - generator.Emit(OpCodes.Ldstr, argsFormat); + generator.Emit(OpCodes.Ldstr, argsFormat); } else { @@ -216,11 +236,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall // Call the SVC function handler. generator.Emit(OpCodes.Ldarg_0); - List<LocalBuilder> locals = new List<LocalBuilder>(); + 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) { @@ -228,12 +249,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall LocalBuilder local = generator.DeclareLocal(argType); - locals.Add(local); + locals.Add((local, registerAttribute)); if (!methodArgs[index].IsOut) { generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Ldc_I4, index); + generator.Emit(OpCodes.Ldc_I4, registerAttribute.Index); MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.GetX)); @@ -249,7 +270,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall else { generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Ldc_I4, byRefArgsCount + index); + generator.Emit(OpCodes.Ldc_I4, registerAttribute.Index); MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.GetX)); @@ -261,8 +282,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall generator.Emit(OpCodes.Call, methodInfo); - int outRegIndex = 0; - Type retType = methodInfo.ReturnType; // Print result code. @@ -275,6 +294,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall generator.Emit(OpCodes.Call, printResultMethod); } + uint registerInUse = 0; + // Save return value into register X0 (when the method has a return value). if (retType != typeof(void)) { @@ -284,7 +305,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall generator.Emit(OpCodes.Stloc, tempLocal); generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Ldc_I4, outRegIndex++); + generator.Emit(OpCodes.Ldc_I4, 0); generator.Emit(OpCodes.Ldloc, tempLocal); ConvertToFieldType(retType); @@ -292,26 +313,36 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.SetX)); generator.Emit(OpCodes.Call, info); + + registerInUse |= 1u << 0; } for (int index = 0; index < locals.Count; index++) { + (LocalBuilder local, RAttribute attribute) = locals[index]; generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Ldc_I4, outRegIndex++); - generator.Emit(OpCodes.Ldloc, locals[index]); + generator.Emit(OpCodes.Ldc_I4, attribute.Index); + generator.Emit(OpCodes.Ldloc, local); - ConvertToFieldType(locals[index].LocalType); + ConvertToFieldType(local.LocalType); MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.SetX)); generator.Emit(OpCodes.Call, info); + + registerInUse |= 1u << attribute.Index; } // Zero out the remaining unused registers. - while (outRegIndex < SvcFuncMaxArguments) + for (int i = 0; i < registerCleanCount; i++) { + if ((registerInUse & (1u << i)) != 0) + { + continue; + } + generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Ldc_I4, outRegIndex++); + generator.Emit(OpCodes.Ldc_I4, i); generator.Emit(OpCodes.Ldc_I8, 0L); MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.SetX)); |
