diff options
Diffstat (limited to 'src/Ryujinx.Horizon.Kernel.Generators/Kernel')
| -rw-r--r-- | src/Ryujinx.Horizon.Kernel.Generators/Kernel/SyscallGenerator.cs | 520 | ||||
| -rw-r--r-- | src/Ryujinx.Horizon.Kernel.Generators/Kernel/SyscallSyntaxReceiver.cs | 53 |
2 files changed, 0 insertions, 573 deletions
diff --git a/src/Ryujinx.Horizon.Kernel.Generators/Kernel/SyscallGenerator.cs b/src/Ryujinx.Horizon.Kernel.Generators/Kernel/SyscallGenerator.cs deleted file mode 100644 index 51da2187..00000000 --- a/src/Ryujinx.Horizon.Kernel.Generators/Kernel/SyscallGenerator.cs +++ /dev/null @@ -1,520 +0,0 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; - -namespace Ryujinx.Horizon.Generators.Kernel -{ - [Generator] - class SyscallGenerator : ISourceGenerator - { - private const string ClassNamespace = "Ryujinx.HLE.HOS.Kernel.SupervisorCall"; - private const string ClassName = "SyscallDispatch"; - private const string A32Suffix = "32"; - private const string A64Suffix = "64"; - private const string ResultVariableName = "result"; - private const string ArgVariablePrefix = "arg"; - private const string ResultCheckHelperName = "LogResultAsTrace"; - - private const string TypeSystemBoolean = "System.Boolean"; - private const string TypeSystemInt32 = "System.Int32"; - private const string TypeSystemInt64 = "System.Int64"; - private const string TypeSystemUInt32 = "System.UInt32"; - private const string TypeSystemUInt64 = "System.UInt64"; - - private const string NamespaceKernel = "Ryujinx.HLE.HOS.Kernel"; - private const string NamespaceHorizonCommon = "Ryujinx.Horizon.Common"; - private const string TypeSvcAttribute = NamespaceKernel + ".SupervisorCall.SvcAttribute"; - private const string TypePointerSizedAttribute = NamespaceKernel + ".SupervisorCall.PointerSizedAttribute"; - private const string TypeResultName = "Result"; - private const string TypeKernelResultName = "KernelResult"; - private const string TypeResult = NamespaceHorizonCommon + "." + TypeResultName; - private const string TypeExecutionContext = "IExecutionContext"; - - private static readonly string[] _expectedResults = new string[] - { - $"{TypeResultName}.Success", - $"{TypeKernelResultName}.TimedOut", - $"{TypeKernelResultName}.Cancelled", - $"{TypeKernelResultName}.PortRemoteClosed", - $"{TypeKernelResultName}.InvalidState" - }; - - private readonly struct OutParameter - { - public readonly string Identifier; - public readonly bool NeedsSplit; - - public OutParameter(string identifier, bool needsSplit = false) - { - Identifier = identifier; - NeedsSplit = needsSplit; - } - } - - private struct RegisterAllocatorA32 - { - private uint _useSet; - private int _linearIndex; - - public int AllocateSingle() - { - return Allocate(); - } - - public (int, int) AllocatePair() - { - _linearIndex += _linearIndex & 1; - - return (Allocate(), Allocate()); - } - - private int Allocate() - { - int regIndex; - - if (_linearIndex < 4) - { - regIndex = _linearIndex++; - } - else - { - regIndex = -1; - - for (int i = 0; i < 32; i++) - { - if ((_useSet & (1 << i)) == 0) - { - regIndex = i; - break; - } - } - - Debug.Assert(regIndex != -1); - } - - _useSet |= 1u << regIndex; - - return regIndex; - } - - public void AdvanceLinearIndex() - { - _linearIndex++; - } - } - - private readonly struct SyscallIdAndName : IComparable<SyscallIdAndName> - { - public readonly int Id; - public readonly string Name; - - public SyscallIdAndName(int id, string name) - { - Id = id; - Name = name; - } - - public int CompareTo(SyscallIdAndName other) - { - return Id.CompareTo(other.Id); - } - } - - public void Execute(GeneratorExecutionContext context) - { - SyscallSyntaxReceiver syntaxReceiver = (SyscallSyntaxReceiver)context.SyntaxReceiver; - - CodeGenerator generator = new CodeGenerator(); - - generator.AppendLine("using Ryujinx.Common.Logging;"); - generator.AppendLine("using Ryujinx.Cpu;"); - generator.AppendLine($"using {NamespaceKernel}.Common;"); - generator.AppendLine($"using {NamespaceKernel}.Memory;"); - generator.AppendLine($"using {NamespaceKernel}.Process;"); - generator.AppendLine($"using {NamespaceKernel}.Threading;"); - generator.AppendLine($"using {NamespaceHorizonCommon};"); - generator.AppendLine("using System;"); - generator.AppendLine(); - generator.EnterScope($"namespace {ClassNamespace}"); - generator.EnterScope($"static class {ClassName}"); - - GenerateResultCheckHelper(generator); - generator.AppendLine(); - - List<SyscallIdAndName> syscalls = new List<SyscallIdAndName>(); - - foreach (var method in syntaxReceiver.SvcImplementations) - { - GenerateMethod32(generator, context.Compilation, method); - GenerateMethod64(generator, context.Compilation, method); - - foreach (AttributeSyntax attribute in method.AttributeLists.SelectMany(attributeList => - attributeList.Attributes.Where(attribute => - GetCanonicalTypeName(context.Compilation, attribute) == TypeSvcAttribute))) - { - syscalls.AddRange(from attributeArg in attribute.ArgumentList.Arguments - where attributeArg.Expression.Kind() == SyntaxKind.NumericLiteralExpression - select (LiteralExpressionSyntax)attributeArg.Expression - into numericLiteral - select new SyscallIdAndName((int)numericLiteral.Token.Value, method.Identifier.Text)); - } - } - - syscalls.Sort(); - - GenerateDispatch(generator, syscalls, A32Suffix); - generator.AppendLine(); - GenerateDispatch(generator, syscalls, A64Suffix); - - generator.LeaveScope(); - generator.LeaveScope(); - - context.AddSource($"{ClassName}.g.cs", generator.ToString()); - } - - private static void GenerateResultCheckHelper(CodeGenerator generator) - { - generator.EnterScope($"private static bool {ResultCheckHelperName}({TypeResultName} {ResultVariableName})"); - - string[] expectedChecks = new string[_expectedResults.Length]; - - for (int i = 0; i < expectedChecks.Length; i++) - { - expectedChecks[i] = $"{ResultVariableName} == {_expectedResults[i]}"; - } - - string checks = string.Join(" || ", expectedChecks); - - generator.AppendLine($"return {checks};"); - generator.LeaveScope(); - } - - private static void GenerateMethod32(CodeGenerator generator, Compilation compilation, MethodDeclarationSyntax method) - { - generator.EnterScope($"private static void {method.Identifier.Text}{A32Suffix}(Syscall syscall, {TypeExecutionContext} context)"); - - string[] args = new string[method.ParameterList.Parameters.Count]; - int index = 0; - - RegisterAllocatorA32 regAlloc = new RegisterAllocatorA32(); - - List<OutParameter> outParameters = new List<OutParameter>(); - List<string> logInArgs = new List<string>(); - List<string> logOutArgs = new List<string>(); - - foreach (var methodParameter in method.ParameterList.Parameters) - { - string name = methodParameter.Identifier.Text; - string argName = GetPrefixedArgName(name); - string typeName = methodParameter.Type.ToString(); - string canonicalTypeName = GetCanonicalTypeName(compilation, methodParameter.Type); - - if (methodParameter.Modifiers.Any(SyntaxKind.OutKeyword)) - { - bool needsSplit = Is64BitInteger(canonicalTypeName) && !IsPointerSized(compilation, methodParameter); - outParameters.Add(new OutParameter(argName, needsSplit)); - logOutArgs.Add($"{name}: {GetFormattedLogValue(argName, canonicalTypeName)}"); - - argName = $"out {typeName} {argName}"; - - regAlloc.AdvanceLinearIndex(); - } - else - { - if (Is64BitInteger(canonicalTypeName)) - { - if (IsPointerSized(compilation, methodParameter)) - { - int registerIndex = regAlloc.AllocateSingle(); - - generator.AppendLine($"var {argName} = (uint)context.GetX({registerIndex});"); - } - else - { - (int registerIndex, int registerIndex2) = regAlloc.AllocatePair(); - - string valueLow = $"(ulong)(uint)context.GetX({registerIndex})"; - string valueHigh = $"(ulong)(uint)context.GetX({registerIndex2})"; - string value = $"{valueLow} | ({valueHigh} << 32)"; - - generator.AppendLine($"var {argName} = ({typeName})({value});"); - } - } - else - { - int registerIndex = regAlloc.AllocateSingle(); - - string value = GenerateCastFromUInt64($"context.GetX({registerIndex})", canonicalTypeName, typeName); - - generator.AppendLine($"var {argName} = {value};"); - } - - logInArgs.Add($"{name}: {GetFormattedLogValue(argName, canonicalTypeName)}"); - } - - args[index++] = argName; - } - - GenerateLogPrintBeforeCall(generator, method.Identifier.Text, logInArgs); - - string argsList = string.Join(", ", args); - int returnRegisterIndex = 0; - string result = null; - string canonicalReturnTypeName = null; - - if (method.ReturnType.ToString() != "void") - { - generator.AppendLine($"var {ResultVariableName} = syscall.{method.Identifier.Text}({argsList});"); - canonicalReturnTypeName = GetCanonicalTypeName(compilation, method.ReturnType); - - if (canonicalReturnTypeName == TypeResult) - { - generator.AppendLine($"context.SetX({returnRegisterIndex++}, (uint){ResultVariableName}.ErrorCode);"); - } - else - { - generator.AppendLine($"context.SetX({returnRegisterIndex++}, (uint){ResultVariableName});"); - } - - if (Is64BitInteger(canonicalReturnTypeName)) - { - generator.AppendLine($"context.SetX({returnRegisterIndex++}, (uint)({ResultVariableName} >> 32));"); - } - - result = GetFormattedLogValue(ResultVariableName, canonicalReturnTypeName); - } - else - { - generator.AppendLine($"syscall.{method.Identifier.Text}({argsList});"); - } - - foreach (OutParameter outParameter in outParameters) - { - generator.AppendLine($"context.SetX({returnRegisterIndex++}, (uint){outParameter.Identifier});"); - - if (outParameter.NeedsSplit) - { - generator.AppendLine($"context.SetX({returnRegisterIndex++}, (uint)({outParameter.Identifier} >> 32));"); - } - } - - while (returnRegisterIndex < 4) - { - generator.AppendLine($"context.SetX({returnRegisterIndex++}, 0);"); - } - - GenerateLogPrintAfterCall(generator, method.Identifier.Text, logOutArgs, result, canonicalReturnTypeName); - - generator.LeaveScope(); - generator.AppendLine(); - } - - private static void GenerateMethod64(CodeGenerator generator, Compilation compilation, MethodDeclarationSyntax method) - { - generator.EnterScope($"private static void {method.Identifier.Text}{A64Suffix}(Syscall syscall, {TypeExecutionContext} context)"); - - string[] args = new string[method.ParameterList.Parameters.Count]; - int registerIndex = 0; - int index = 0; - - List<OutParameter> outParameters = new List<OutParameter>(); - List<string> logInArgs = new List<string>(); - List<string> logOutArgs = new List<string>(); - - foreach (var methodParameter in method.ParameterList.Parameters) - { - string name = methodParameter.Identifier.Text; - string argName = GetPrefixedArgName(name); - string typeName = methodParameter.Type.ToString(); - string canonicalTypeName = GetCanonicalTypeName(compilation, methodParameter.Type); - - if (methodParameter.Modifiers.Any(SyntaxKind.OutKeyword)) - { - outParameters.Add(new OutParameter(argName)); - logOutArgs.Add($"{name}: {GetFormattedLogValue(argName, canonicalTypeName)}"); - argName = $"out {typeName} {argName}"; - registerIndex++; - } - else - { - string value = GenerateCastFromUInt64($"context.GetX({registerIndex++})", canonicalTypeName, typeName); - generator.AppendLine($"var {argName} = {value};"); - logInArgs.Add($"{name}: {GetFormattedLogValue(argName, canonicalTypeName)}"); - } - - args[index++] = argName; - } - - GenerateLogPrintBeforeCall(generator, method.Identifier.Text, logInArgs); - - string argsList = string.Join(", ", args); - int returnRegisterIndex = 0; - string result = null; - string canonicalReturnTypeName = null; - - if (method.ReturnType.ToString() != "void") - { - generator.AppendLine($"var {ResultVariableName} = syscall.{method.Identifier.Text}({argsList});"); - canonicalReturnTypeName = GetCanonicalTypeName(compilation, method.ReturnType); - - if (canonicalReturnTypeName == TypeResult) - { - generator.AppendLine($"context.SetX({returnRegisterIndex++}, (ulong){ResultVariableName}.ErrorCode);"); - } - else - { - generator.AppendLine($"context.SetX({returnRegisterIndex++}, (ulong){ResultVariableName});"); - } - - result = GetFormattedLogValue(ResultVariableName, canonicalReturnTypeName); - } - else - { - generator.AppendLine($"syscall.{method.Identifier.Text}({argsList});"); - } - - foreach (OutParameter outParameter in outParameters) - { - generator.AppendLine($"context.SetX({returnRegisterIndex++}, (ulong){outParameter.Identifier});"); - } - - while (returnRegisterIndex < 8) - { - generator.AppendLine($"context.SetX({returnRegisterIndex++}, 0);"); - } - - GenerateLogPrintAfterCall(generator, method.Identifier.Text, logOutArgs, result, canonicalReturnTypeName); - - generator.LeaveScope(); - generator.AppendLine(); - } - - private static string GetFormattedLogValue(string value, string canonicalTypeName) - { - if (Is32BitInteger(canonicalTypeName)) - { - return $"0x{{{value}:X8}}"; - } - else if (Is64BitInteger(canonicalTypeName)) - { - return $"0x{{{value}:X16}}"; - } - - return $"{{{value}}}"; - } - - private static string GetPrefixedArgName(string name) - { - return ArgVariablePrefix + char.ToUpperInvariant(name[0]) + name.Substring(1); - } - - private static string GetCanonicalTypeName(Compilation compilation, SyntaxNode syntaxNode) - { - TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode); - if (typeInfo.Type.ContainingNamespace == null) - { - return typeInfo.Type.Name; - } - - return $"{typeInfo.Type.ContainingNamespace.ToDisplayString()}.{typeInfo.Type.Name}"; - } - - private static void GenerateLogPrintBeforeCall(CodeGenerator generator, string methodName, List<string> argList) - { - string log = $"{methodName}({string.Join(", ", argList)})"; - GenerateLogPrint(generator, "Trace", "KernelSvc", log); - } - - private static void GenerateLogPrintAfterCall( - CodeGenerator generator, - string methodName, - List<string> argList, - string result, - string canonicalResultTypeName) - { - string log = $"{methodName}({string.Join(", ", argList)})"; - - if (result != null) - { - log += $" = {result}"; - } - - if (canonicalResultTypeName == TypeResult) - { - generator.EnterScope($"if ({ResultCheckHelperName}({ResultVariableName}))"); - GenerateLogPrint(generator, "Trace", "KernelSvc", log); - generator.LeaveScope(); - generator.EnterScope("else"); - GenerateLogPrint(generator, "Warning", "KernelSvc", log); - generator.LeaveScope(); - } - else - { - GenerateLogPrint(generator, "Trace", "KernelSvc", log); - } - } - - private static void GenerateLogPrint(CodeGenerator generator, string logLevel, string logClass, string log) - { - generator.AppendLine($"Logger.{logLevel}?.PrintMsg(LogClass.{logClass}, $\"{log}\");"); - } - - private static void GenerateDispatch(CodeGenerator generator, List<SyscallIdAndName> syscalls, string suffix) - { - generator.EnterScope($"public static void Dispatch{suffix}(Syscall syscall, {TypeExecutionContext} context, int id)"); - generator.EnterScope("switch (id)"); - - foreach (var syscall in syscalls) - { - generator.AppendLine($"case {syscall.Id}:"); - generator.IncreaseIndentation(); - - generator.AppendLine($"{syscall.Name}{suffix}(syscall, context);"); - generator.AppendLine("break;"); - - generator.DecreaseIndentation(); - } - - generator.AppendLine($"default:"); - generator.IncreaseIndentation(); - - generator.AppendLine("throw new NotImplementedException($\"SVC 0x{id:X4} is not implemented.\");"); - - generator.DecreaseIndentation(); - - generator.LeaveScope(); - generator.LeaveScope(); - } - - private static bool Is32BitInteger(string canonicalTypeName) - { - return canonicalTypeName == TypeSystemInt32 || canonicalTypeName == TypeSystemUInt32; - } - - private static bool Is64BitInteger(string canonicalTypeName) - { - return canonicalTypeName == TypeSystemInt64 || canonicalTypeName == TypeSystemUInt64; - } - - private static string GenerateCastFromUInt64(string value, string canonicalTargetTypeName, string targetTypeName) - { - return canonicalTargetTypeName == TypeSystemBoolean ? $"({value} & 1) != 0" : $"({targetTypeName}){value}"; - } - - private static bool IsPointerSized(Compilation compilation, ParameterSyntax parameterSyntax) - { - return parameterSyntax.AttributeLists.Any(attributeList => - attributeList.Attributes.Any(attribute => - GetCanonicalTypeName(compilation, attribute) == TypePointerSizedAttribute)); - } - - public void Initialize(GeneratorInitializationContext context) - { - context.RegisterForSyntaxNotifications(() => new SyscallSyntaxReceiver()); - } - } -} diff --git a/src/Ryujinx.Horizon.Kernel.Generators/Kernel/SyscallSyntaxReceiver.cs b/src/Ryujinx.Horizon.Kernel.Generators/Kernel/SyscallSyntaxReceiver.cs deleted file mode 100644 index e480a859..00000000 --- a/src/Ryujinx.Horizon.Kernel.Generators/Kernel/SyscallSyntaxReceiver.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using System.Collections.Generic; -using System.Linq; - -namespace Ryujinx.Horizon.Generators.Kernel -{ - class SyscallSyntaxReceiver : ISyntaxReceiver - { - public List<MethodDeclarationSyntax> SvcImplementations { get; } - - public SyscallSyntaxReceiver() - { - SvcImplementations = new List<MethodDeclarationSyntax>(); - } - - public void OnVisitSyntaxNode(SyntaxNode syntaxNode) - { - if (!(syntaxNode is ClassDeclarationSyntax classDeclaration) || classDeclaration.AttributeLists.Count == 0) - { - return; - } - - if (!classDeclaration.AttributeLists.Any(attributeList => - attributeList.Attributes.Any(x => x.Name.GetText().ToString() == "SvcImpl"))) - { - return; - } - - foreach (var memberDeclaration in classDeclaration.Members) - { - if (memberDeclaration is MethodDeclarationSyntax methodDeclaration) - { - VisitMethod(methodDeclaration); - } - } - } - - private void VisitMethod(MethodDeclarationSyntax methodDeclaration) - { - if (methodDeclaration.AttributeLists.Count == 0) - { - return; - } - - if (methodDeclaration.AttributeLists.Any(attributeList => - attributeList.Attributes.Any(x => x.Name.GetText().ToString() == "Svc"))) - { - SvcImplementations.Add(methodDeclaration); - } - } - } -} |
