Compare commits

..

5 Commits

Author SHA1 Message Date
a3e7bb8eb4 Copy dependency for multisample and non-multisample textures (#3382)
* Use copy dependency for textures that differs in multisample but are otherwise compatible

* Remove allowMs flag as it's no longer required for correctness, it's just an optimization now

* Dispose intermmediate pool
2022-06-05 14:06:47 -03:00
2073ba2919 Fix a potential GPFIFO submission race (#3378)
The syncpoint maximum value represents the maximum possible syncpt value at a given time, however due to PBs being submitted before max was incremented, for a brief moment of time this is not the case which could lead to invalid behaviour if a game waits on the fence at that specific time.
2022-06-04 21:36:36 +02:00
d03124a992 Fix 3D semaphore counter type 0 handling (#3380)
Counter type 0 actually releases the semaphore payload rather than a constant zero as was previously thought. This is required by Skyrim.
2022-06-02 19:51:36 -03:00
59490d54b5 infra: Switch to win10-x64 RID and fix PR comment for Avalonia and SDL2 artifact rename (#3375)
* infra: Switch to win10-x64 RID and fix PR comment for Avalonia and SDL2 artifact rename

* Address gdkchan's comments
2022-06-01 02:01:16 +02:00
e546e5933f Rewrite SVC handler using source generators rather than IL emit (#3371)
* Implement syscall handlers using a source generator

* Copy FlushProcessDataCache implementation to Syscall since it was only implemented on Syscall32

* Fix wrong argument order in some syscalls

* Delete old Reflection.Emit based syscall handling code

* Improvements to the code generation

* ControlCodeMemory address and size is always 64-bit
2022-05-31 17:12:46 -03:00
34 changed files with 1091 additions and 1600 deletions

View File

@ -39,7 +39,7 @@ jobs:
- os: windows-latest
OS_NAME: Windows x64
DOTNET_RUNTIME_IDENTIFIER: win-x64
DOTNET_RUNTIME_IDENTIFIER: win10-x64
RELEASE_ZIP_OS_NAME: win_x64
fail-fast: false

View File

@ -36,19 +36,24 @@ jobs:
return core.error(`No artifacts found`);
}
let body = `Download the artifacts for this pull request:\n`;
let hidden_avalonia_artifacts = `\n\n <details><summary>Experimental GUI (Avalonia)</summary>\n`;
let hidden_headless_artifacts = `\n\n <details><summary>GUI-less (SDL2)</summary>\n`;
let hidden_debug_artifacts = `\n\n <details><summary>Only for Developers</summary>\n`;
for (const art of artifacts) {
if(art.name.includes('Debug')) {
hidden_debug_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
} else if(art.name.includes('headless-sdl2')) {
} else if(art.name.includes('ava-ryujinx')) {
hidden_avalonia_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
} else if(art.name.includes('sdl2-ryujinx-headless')) {
hidden_headless_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
} else {
body += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
}
}
hidden_avalonia_artifacts += `\n</details>`;
hidden_headless_artifacts += `\n</details>`;
hidden_debug_artifacts += `\n</details>`;
body += hidden_avalonia_artifacts;
body += hidden_headless_artifacts;
body += hidden_debug_artifacts;

View File

@ -51,9 +51,9 @@ jobs:
run: "mkdir release_output"
- name: Publish Windows
run: |
dotnet publish -c Release -r win-x64 -o ./publish_windows/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx --self-contained
dotnet publish -c Release -r win-x64 -o ./publish_windows_sdl2_headless/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained
dotnet publish -c Release -r win-x64 -o ./publish_windows_ava/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Ava --self-contained
dotnet publish -c Release -r win10-x64 -o ./publish_windows/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx --self-contained
dotnet publish -c Release -r win10-x64 -o ./publish_windows_sdl2_headless/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained
dotnet publish -c Release -r win10-x64 -o ./publish_windows_ava/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Ava --self-contained
- name: Packing Windows builds
run: |
pushd publish_windows

View File

@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<RuntimeIdentifiers>win10-x64;linux-x64;osx-x64</RuntimeIdentifiers>
</PropertyGroup>
<ItemGroup>
@ -15,11 +15,11 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>libsoundio.dll</TargetPath>
</ContentWithTargetPath>
<ContentWithTargetPath Include="Native\libsoundio\libs\libsoundio.dylib" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'win-x64'">
<ContentWithTargetPath Include="Native\libsoundio\libs\libsoundio.dylib" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'win10-x64'">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>libsoundio.dylib</TargetPath>
</ContentWithTargetPath>
<ContentWithTargetPath Include="Native\libsoundio\libs\libsoundio.so" Condition="'$(RuntimeIdentifier)' != 'win-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'">
<ContentWithTargetPath Include="Native\libsoundio\libs\libsoundio.so" Condition="'$(RuntimeIdentifier)' != 'win10-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<TargetPath>libsoundio.so</TargetPath>
</ContentWithTargetPath>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64</RuntimeIdentifiers>
<RuntimeIdentifiers>win10-x64;osx-x64;linux-x64</RuntimeIdentifiers>
<OutputType>Exe</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>1.0.0-dirty</Version>

View File

@ -13,4 +13,12 @@ namespace Ryujinx.Graphics.GAL
CubemapArray,
TextureBuffer
}
public static class TargetExtensions
{
public static bool IsMultisample(this Target target)
{
return target == Target.Texture2DMultisample || target == Target.Texture2DMultisampleArray;
}
}
}

View File

@ -44,7 +44,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// </summary>
private enum ReportCounterType
{
Zero = 0,
Payload = 0,
InputVertices = 1,
InputPrimitives = 3,
VertexShaderInvocations = 5,
@ -169,8 +169,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
switch (type)
{
case ReportCounterType.Zero:
resultHandler(null, 0);
case ReportCounterType.Payload:
resultHandler(null, (ulong)_state.State.SemaphorePayload);
break;
case ReportCounterType.SamplesPassed:
counter = _context.Renderer.ReportCounter(CounterType.SamplesPassed, resultHandler, false);

View File

@ -1136,32 +1136,22 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="range">Texture view physical memory ranges</param>
/// <param name="layerSize">Layer size on the given texture</param>
/// <param name="caps">Host GPU capabilities</param>
/// <param name="allowMs">Indicates that multisample textures are allowed to match non-multisample requested textures</param>
/// <param name="firstLayer">Texture view initial layer on this texture</param>
/// <param name="firstLevel">Texture view first mipmap level on this texture</param>
/// <returns>The level of compatiblilty a view with the given parameters created from this texture has</returns>
public TextureViewCompatibility IsViewCompatible(TextureInfo info, MultiRange range, int layerSize, Capabilities caps, bool allowMs, out int firstLayer, out int firstLevel)
public TextureViewCompatibility IsViewCompatible(TextureInfo info, MultiRange range, int layerSize, Capabilities caps, out int firstLayer, out int firstLevel)
{
TextureViewCompatibility result = TextureViewCompatibility.Full;
result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewFormatCompatible(Info, info, caps));
if (result != TextureViewCompatibility.Incompatible)
{
bool msTargetCompatible = false;
result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewTargetCompatible(Info, info));
if (allowMs)
bool bothMs = Info.Target.IsMultisample() && info.Target.IsMultisample();
if (bothMs && (Info.SamplesInX != info.SamplesInX || Info.SamplesInY != info.SamplesInY))
{
msTargetCompatible = Info.Target == Target.Texture2DMultisample && info.Target == Target.Texture2D;
}
if (!msTargetCompatible)
{
result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewTargetCompatible(Info, info));
if (Info.SamplesInX != info.SamplesInX || Info.SamplesInY != info.SamplesInY)
{
result = TextureViewCompatibility.Incompatible;
}
result = TextureViewCompatibility.Incompatible;
}
if (result == TextureViewCompatibility.Full && Info.FormatInfo.Format != info.FormatInfo.Format && !_context.Capabilities.SupportsMismatchingViewFormat)

View File

@ -547,7 +547,6 @@ namespace Ryujinx.Graphics.Gpu.Image
range.Value,
sizeInfo.LayerSize,
_context.Capabilities,
flags.HasFlag(TextureSearchFlags.ForCopy),
out int firstLayer,
out int firstLevel);
@ -662,7 +661,6 @@ namespace Ryujinx.Graphics.Gpu.Image
overlap.Range,
overlap.LayerSize,
_context.Capabilities,
false,
out int firstLayer,
out int firstLevel);

View File

@ -2,7 +2,6 @@ using Ryujinx.Common;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Texture;
using System;
using System.Numerics;
namespace Ryujinx.Graphics.Gpu.Image
{
@ -657,6 +656,11 @@ namespace Ryujinx.Graphics.Gpu.Image
case Target.Texture2DMultisample:
case Target.Texture2DMultisampleArray:
if (rhs.Target == Target.Texture2D || rhs.Target == Target.Texture2DArray)
{
return TextureViewCompatibility.CopyOnly;
}
result = rhs.Target == Target.Texture2DMultisample ||
rhs.Target == Target.Texture2DMultisampleArray;
break;

View File

@ -0,0 +1,98 @@
using Ryujinx.Graphics.GAL;
using System;
using System.Collections.Generic;
namespace Ryujinx.Graphics.OpenGL.Image
{
class IntermmediatePool : IDisposable
{
private readonly Renderer _renderer;
private readonly List<TextureView> _entries;
public IntermmediatePool(Renderer renderer)
{
_renderer = renderer;
_entries = new List<TextureView>();
}
public TextureView GetOrCreateWithAtLeast(
Target target,
int blockWidth,
int blockHeight,
int bytesPerPixel,
Format format,
int width,
int height,
int depth,
int levels)
{
TextureView entry;
for (int i = 0; i < _entries.Count; i++)
{
entry = _entries[i];
if (entry.Target == target && entry.Format == format)
{
if (entry.Width < width || entry.Height < height || entry.Info.Depth < depth || entry.Info.Levels < levels)
{
width = Math.Max(width, entry.Width);
height = Math.Max(height, entry.Height);
depth = Math.Max(depth, entry.Info.Depth);
levels = Math.Max(levels, entry.Info.Levels);
entry.Dispose();
entry = CreateNew(target, blockWidth, blockHeight, bytesPerPixel, format, width, height, depth, levels);
_entries[i] = entry;
}
return entry;
}
}
entry = CreateNew(target, blockWidth, blockHeight, bytesPerPixel, format, width, height, depth, levels);
_entries.Add(entry);
return entry;
}
private TextureView CreateNew(
Target target,
int blockWidth,
int blockHeight,
int bytesPerPixel,
Format format,
int width,
int height,
int depth,
int levels)
{
return (TextureView)_renderer.CreateTexture(new TextureCreateInfo(
width,
height,
depth,
levels,
1,
blockWidth,
blockHeight,
bytesPerPixel,
format,
DepthStencilMode.Depth,
target,
SwizzleComponent.Red,
SwizzleComponent.Green,
SwizzleComponent.Blue,
SwizzleComponent.Alpha), 1f);
}
public void Dispose()
{
foreach (TextureView entry in _entries)
{
entry.Dispose();
}
_entries.Clear();
}
}
}

View File

@ -9,6 +9,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
{
private readonly Renderer _renderer;
public IntermmediatePool IntermmediatePool { get; }
private int _srcFramebuffer;
private int _dstFramebuffer;
@ -18,6 +20,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
public TextureCopy(Renderer renderer)
{
_renderer = renderer;
IntermmediatePool = new IntermmediatePool(renderer);
}
public void Copy(
@ -25,7 +28,30 @@ namespace Ryujinx.Graphics.OpenGL.Image
TextureView dst,
Extents2D srcRegion,
Extents2D dstRegion,
bool linearFilter)
bool linearFilter,
int srcLayer = 0,
int dstLayer = 0,
int srcLevel = 0,
int dstLevel = 0)
{
int levels = Math.Min(src.Info.Levels - srcLevel, dst.Info.Levels - dstLevel);
int layers = Math.Min(src.Info.GetLayers() - srcLayer, dst.Info.GetLayers() - dstLayer);
Copy(src, dst, srcRegion, dstRegion, linearFilter, srcLayer, dstLayer, srcLevel, dstLevel, layers, levels);
}
public void Copy(
TextureView src,
TextureView dst,
Extents2D srcRegion,
Extents2D dstRegion,
bool linearFilter,
int srcLayer,
int dstLayer,
int srcLevel,
int dstLevel,
int layers,
int levels)
{
TextureView srcConverted = src.Format.IsBgr() != dst.Format.IsBgr() ? BgraSwap(src) : src;
@ -34,22 +60,29 @@ namespace Ryujinx.Graphics.OpenGL.Image
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, GetSrcFramebufferLazy());
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, GetDstFramebufferLazy());
int levels = Math.Min(src.Info.Levels, dst.Info.Levels);
int layers = Math.Min(src.Info.GetLayers(), dst.Info.GetLayers());
if (srcLevel != 0)
{
srcRegion = srcRegion.Reduce(srcLevel);
}
if (dstLevel != 0)
{
dstRegion = dstRegion.Reduce(dstLevel);
}
for (int level = 0; level < levels; level++)
{
for (int layer = 0; layer < layers; layer++)
{
if (layers > 1)
if ((srcLayer | dstLayer) != 0 || layers > 1)
{
Attach(FramebufferTarget.ReadFramebuffer, src.Format, srcConverted.Handle, level, layer);
Attach(FramebufferTarget.DrawFramebuffer, dst.Format, dst.Handle, level, layer);
Attach(FramebufferTarget.ReadFramebuffer, src.Format, srcConverted.Handle, srcLevel + level, srcLayer + layer);
Attach(FramebufferTarget.DrawFramebuffer, dst.Format, dst.Handle, dstLevel + level, dstLayer + layer);
}
else
{
Attach(FramebufferTarget.ReadFramebuffer, src.Format, srcConverted.Handle, level);
Attach(FramebufferTarget.DrawFramebuffer, dst.Format, dst.Handle, level);
Attach(FramebufferTarget.ReadFramebuffer, src.Format, srcConverted.Handle, srcLevel + level);
Attach(FramebufferTarget.DrawFramebuffer, dst.Format, dst.Handle, dstLevel + level);
}
ClearBufferMask mask = GetMask(src.Format);
@ -484,6 +517,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
_copyPboHandle = 0;
}
IntermmediatePool.Dispose();
}
}
}

View File

@ -115,14 +115,77 @@ namespace Ryujinx.Graphics.OpenGL.Image
{
TextureView destinationView = (TextureView)destination;
_renderer.TextureCopy.CopyUnscaled(this, destinationView, 0, firstLayer, 0, firstLevel);
if (destinationView.Target.IsMultisample() || Target.IsMultisample())
{
Extents2D srcRegion = new Extents2D(0, 0, Width, Height);
Extents2D dstRegion = new Extents2D(0, 0, destinationView.Width, destinationView.Height);
TextureView intermmediate = _renderer.TextureCopy.IntermmediatePool.GetOrCreateWithAtLeast(
GetIntermmediateTarget(Target),
Info.BlockWidth,
Info.BlockHeight,
Info.BytesPerPixel,
Format,
Width,
Height,
Info.Depth,
Info.Levels);
GL.Disable(EnableCap.FramebufferSrgb);
_renderer.TextureCopy.Copy(this, intermmediate, srcRegion, srcRegion, true);
_renderer.TextureCopy.Copy(intermmediate, destinationView, srcRegion, dstRegion, true, 0, firstLayer, 0, firstLevel);
GL.Enable(EnableCap.FramebufferSrgb);
}
else
{
_renderer.TextureCopy.CopyUnscaled(this, destinationView, 0, firstLayer, 0, firstLevel);
}
}
public void CopyTo(ITexture destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel)
{
TextureView destinationView = (TextureView)destination;
TextureView destinationView = (TextureView)destination;
_renderer.TextureCopy.CopyUnscaled(this, destinationView, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1);
if (destinationView.Target.IsMultisample() || Target.IsMultisample())
{
Extents2D srcRegion = new Extents2D(0, 0, Width, Height);
Extents2D dstRegion = new Extents2D(0, 0, destinationView.Width, destinationView.Height);
TextureView intermmediate = _renderer.TextureCopy.IntermmediatePool.GetOrCreateWithAtLeast(
GetIntermmediateTarget(Target),
Info.BlockWidth,
Info.BlockHeight,
Info.BytesPerPixel,
Format,
Math.Max(1, Width >> srcLevel),
Math.Max(1, Height >> srcLevel),
1,
1);
GL.Disable(EnableCap.FramebufferSrgb);
_renderer.TextureCopy.Copy(this, intermmediate, srcRegion, srcRegion, true, srcLayer, 0, srcLevel, 0, 1, 1);
_renderer.TextureCopy.Copy(intermmediate, destinationView, srcRegion, dstRegion, true, 0, dstLayer, 0, dstLevel, 1, 1);
GL.Enable(EnableCap.FramebufferSrgb);
}
else
{
_renderer.TextureCopy.CopyUnscaled(this, destinationView, srcLayer, dstLayer, srcLevel, dstLevel, 1, 1);
}
}
private static Target GetIntermmediateTarget(Target srcTarget)
{
return srcTarget switch
{
Target.Texture2D => Target.Texture2DMultisample,
Target.Texture2DArray => Target.Texture2DMultisampleArray,
Target.Texture2DMultisampleArray => Target.Texture2DArray,
_ => Target.Texture2D
};
}
public void CopyTo(ITexture destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter)

View File

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

View File

@ -0,0 +1,9 @@
using System;
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
class PointerSizedAttribute : Attribute
{
}
}

View File

@ -1,15 +0,0 @@
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

@ -0,0 +1,15 @@
using System;
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
class SvcAttribute : Attribute
{
public int Id { get; }
public SvcAttribute(int id)
{
Id = id;
}
}
}

View File

@ -0,0 +1,9 @@
using System;
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
class SvcImplAttribute : Attribute
{
}
}

View File

@ -12,6 +12,7 @@ using System.Threading;
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
[SvcImpl]
class Syscall
{
private readonly KernelContext _context;
@ -23,6 +24,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
// Process
[Svc(0x24)]
public KernelResult GetProcessId(out ulong pid, int handle)
{
KProcess currentProcess = KernelStatic.GetCurrentProcess();
@ -167,9 +169,18 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.Success;
}
[Svc(0x5f)]
public KernelResult FlushProcessDataCache(int processHandle, ulong address, ulong size)
{
// FIXME: This needs to be implemented as ARMv7 doesn't have any way to do cache maintenance operations on EL0.
// As we don't support (and don't actually need) to flush the cache, this is stubbed.
return KernelResult.Success;
}
// IPC
public KernelResult ConnectToNamedPort(out int handle, ulong namePtr)
[Svc(0x1f)]
public KernelResult ConnectToNamedPort(out int handle, [PointerSized] ulong namePtr)
{
handle = 0;
@ -222,6 +233,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result;
}
[Svc(0x21)]
public KernelResult SendSyncRequest(int handle)
{
KProcess currentProcess = KernelStatic.GetCurrentProcess();
@ -236,7 +248,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return session.SendSyncRequest();
}
public KernelResult SendSyncRequestWithUserBuffer(ulong messagePtr, ulong messageSize, int handle)
[Svc(0x22)]
public KernelResult SendSyncRequestWithUserBuffer(
[PointerSized] ulong messagePtr,
[PointerSized] ulong messageSize,
int handle)
{
if (!PageAligned(messagePtr))
{
@ -283,7 +299,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result;
}
public KernelResult SendAsyncRequestWithUserBuffer(out int doneEventHandle, ulong messagePtr, ulong messageSize, int handle)
[Svc(0x23)]
public KernelResult SendAsyncRequestWithUserBuffer(
out int doneEventHandle,
[PointerSized] ulong messagePtr,
[PointerSized] ulong messageSize,
int handle)
{
doneEventHandle = 0;
@ -353,11 +374,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result;
}
[Svc(0x40)]
public KernelResult CreateSession(
out int serverSessionHandle,
out int clientSessionHandle,
bool isLight,
ulong namePtr)
[PointerSized] ulong namePtr)
{
serverSessionHandle = 0;
clientSessionHandle = 0;
@ -419,6 +441,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result;
}
[Svc(0x41)]
public KernelResult AcceptSession(out int sessionHandle, int portHandle)
{
sessionHandle = 0;
@ -470,9 +493,10 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result;
}
[Svc(0x43)]
public KernelResult ReplyAndReceive(
out int handleIndex,
ulong handlesPtr,
[PointerSized] ulong handlesPtr,
int handlesCount,
int replyTargetHandle,
long timeout)
@ -575,11 +599,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result;
}
[Svc(0x44)]
public KernelResult ReplyAndReceiveWithUserBuffer(
out int handleIndex,
ulong handlesPtr,
ulong messagePtr,
ulong messageSize,
[PointerSized] ulong messagePtr,
[PointerSized] ulong messageSize,
[PointerSized] ulong handlesPtr,
int handlesCount,
int replyTargetHandle,
long timeout)
@ -679,12 +704,13 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result;
}
[Svc(0x70)]
public KernelResult CreatePort(
out int serverPortHandle,
out int clientPortHandle,
int maxSessions,
bool isLight,
ulong namePtr)
[PointerSized] ulong namePtr)
{
serverPortHandle = clientPortHandle = 0;
@ -714,7 +740,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result;
}
public KernelResult ManageNamedPort(out int handle, ulong namePtr, int maxSessions)
[Svc(0x71)]
public KernelResult ManageNamedPort(out int handle, [PointerSized] ulong namePtr, int maxSessions)
{
handle = 0;
@ -766,6 +793,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result;
}
[Svc(0x72)]
public KernelResult ConnectToPort(out int clientSessionHandle, int clientPortHandle)
{
clientSessionHandle = 0;
@ -819,7 +847,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
// Memory
public KernelResult SetHeapSize(out ulong address, ulong size)
[Svc(1)]
public KernelResult SetHeapSize([PointerSized] out ulong address, [PointerSized] ulong size)
{
if ((size & 0xfffffffe001fffff) != 0)
{
@ -833,7 +862,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return process.MemoryManager.SetHeapSize(size, out address);
}
public KernelResult SetMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
[Svc(2)]
public KernelResult SetMemoryPermission([PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
{
if (!PageAligned(address))
{
@ -865,9 +895,10 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return currentProcess.MemoryManager.SetMemoryPermission(address, size, permission);
}
[Svc(3)]
public KernelResult SetMemoryAttribute(
ulong address,
ulong size,
[PointerSized] ulong address,
[PointerSized] ulong size,
MemoryAttribute attributeMask,
MemoryAttribute attributeValue)
{
@ -905,7 +936,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result;
}
public KernelResult MapMemory(ulong dst, ulong src, ulong size)
[Svc(4)]
public KernelResult MapMemory([PointerSized] ulong dst, [PointerSized] ulong src, [PointerSized] ulong size)
{
if (!PageAligned(src | dst))
{
@ -941,7 +973,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return process.MemoryManager.Map(dst, src, size);
}
public KernelResult UnmapMemory(ulong dst, ulong src, ulong size)
[Svc(5)]
public KernelResult UnmapMemory([PointerSized] ulong dst, [PointerSized] ulong src, [PointerSized] ulong size)
{
if (!PageAligned(src | dst))
{
@ -977,7 +1010,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return process.MemoryManager.Unmap(dst, src, size);
}
public KernelResult QueryMemory(ulong infoPtr, out ulong pageInfo, ulong address)
[Svc(6)]
public KernelResult QueryMemory([PointerSized] ulong infoPtr, [PointerSized] out ulong pageInfo, [PointerSized] ulong address)
{
KernelResult result = QueryMemory(out MemoryInfo info, out pageInfo, address);
@ -1011,7 +1045,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.Success;
}
public KernelResult MapSharedMemory(int handle, ulong address, ulong size, KMemoryPermission permission)
[Svc(0x13)]
public KernelResult MapSharedMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
{
if (!PageAligned(address))
{
@ -1057,7 +1092,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
permission);
}
public KernelResult UnmapSharedMemory(int handle, ulong address, ulong size)
[Svc(0x14)]
public KernelResult UnmapSharedMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size)
{
if (!PageAligned(address))
{
@ -1097,7 +1133,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
currentProcess);
}
public KernelResult CreateTransferMemory(out int handle, ulong address, ulong size, KMemoryPermission permission)
[Svc(0x15)]
public KernelResult CreateTransferMemory(out int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
{
handle = 0;
@ -1160,7 +1197,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result;
}
public KernelResult MapTransferMemory(int handle, ulong address, ulong size, KMemoryPermission permission)
[Svc(0x51)]
public KernelResult MapTransferMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size, KMemoryPermission permission)
{
if (!PageAligned(address))
{
@ -1206,7 +1244,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
permission);
}
public KernelResult UnmapTransferMemory(int handle, ulong address, ulong size)
[Svc(0x52)]
public KernelResult UnmapTransferMemory(int handle, [PointerSized] ulong address, [PointerSized] ulong size)
{
if (!PageAligned(address))
{
@ -1246,7 +1285,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
currentProcess);
}
public KernelResult MapPhysicalMemory(ulong address, ulong size)
[Svc(0x2c)]
public KernelResult MapPhysicalMemory([PointerSized] ulong address, [PointerSized] ulong size)
{
if (!PageAligned(address))
{
@ -1281,7 +1321,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return process.MemoryManager.MapPhysicalMemory(address, size);
}
public KernelResult UnmapPhysicalMemory(ulong address, ulong size)
[Svc(0x2d)]
public KernelResult UnmapPhysicalMemory([PointerSized] ulong address, [PointerSized] ulong size)
{
if (!PageAligned(address))
{
@ -1316,7 +1357,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return process.MemoryManager.UnmapPhysicalMemory(address, size);
}
public KernelResult CreateCodeMemory(ulong address, ulong size, out int handle)
[Svc(0x4b)]
public KernelResult CreateCodeMemory(out int handle, [PointerSized] ulong address, [PointerSized] ulong size)
{
handle = 0;
@ -1356,7 +1398,13 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return currentProcess.HandleTable.GenerateHandle(codeMemory, out handle);
}
public KernelResult ControlCodeMemory(int handle, CodeMemoryOperation op, ulong address, ulong size, KMemoryPermission permission)
[Svc(0x4c)]
public KernelResult ControlCodeMemory(
int handle,
CodeMemoryOperation op,
ulong address,
ulong size,
KMemoryPermission permission)
{
KProcess currentProcess = KernelStatic.GetCurrentProcess();
@ -1428,7 +1476,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
}
public KernelResult SetProcessMemoryPermission(int handle, ulong src, ulong size, KMemoryPermission permission)
[Svc(0x73)]
public KernelResult SetProcessMemoryPermission(
int handle,
[PointerSized] ulong src,
[PointerSized] ulong size,
KMemoryPermission permission)
{
if (!PageAligned(src))
{
@ -1465,7 +1518,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return targetProcess.MemoryManager.SetProcessMemoryPermission(src, size, permission);
}
public KernelResult MapProcessMemory(ulong dst, int handle, ulong src, ulong size)
[Svc(0x74)]
public KernelResult MapProcessMemory(
[PointerSized] ulong dst,
int handle,
ulong src,
[PointerSized] ulong size)
{
if (!PageAligned(src) || !PageAligned(dst))
{
@ -1517,7 +1575,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return dstProcess.MemoryManager.MapPages(dst, pageList, MemoryState.ProcessMemory, KMemoryPermission.ReadAndWrite);
}
public KernelResult UnmapProcessMemory(ulong dst, int handle, ulong src, ulong size)
[Svc(0x75)]
public KernelResult UnmapProcessMemory(
[PointerSized] ulong dst,
int handle,
ulong src,
[PointerSized] ulong size)
{
if (!PageAligned(src) || !PageAligned(dst))
{
@ -1558,6 +1621,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.Success;
}
[Svc(0x77)]
public KernelResult MapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size)
{
if (!PageAligned(dst) || !PageAligned(src))
@ -1595,6 +1659,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return targetProcess.MemoryManager.MapProcessCodeMemory(dst, src, size);
}
[Svc(0x78)]
public KernelResult UnmapProcessCodeMemory(int handle, ulong dst, ulong src, ulong size)
{
if (!PageAligned(dst) || !PageAligned(src))
@ -1639,6 +1704,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
// System
[Svc(0x7b)]
public KernelResult TerminateProcess(int handle)
{
KProcess process = KernelStatic.GetCurrentProcess();
@ -1668,11 +1734,13 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result;
}
[Svc(7)]
public void ExitProcess()
{
KernelStatic.GetCurrentProcess().TerminateCurrentProcess();
}
[Svc(0x11)]
public KernelResult SignalEvent(int handle)
{
KProcess process = KernelStatic.GetCurrentProcess();
@ -1695,6 +1763,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result;
}
[Svc(0x12)]
public KernelResult ClearEvent(int handle)
{
KernelResult result;
@ -1717,6 +1786,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result;
}
[Svc(0x16)]
public KernelResult CloseHandle(int handle)
{
KProcess currentProcess = KernelStatic.GetCurrentProcess();
@ -1724,6 +1794,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return currentProcess.HandleTable.CloseHandle(handle) ? KernelResult.Success : KernelResult.InvalidHandle;
}
[Svc(0x17)]
public KernelResult ResetSignal(int handle)
{
KProcess currentProcess = KernelStatic.GetCurrentProcess();
@ -1753,11 +1824,13 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result;
}
[Svc(0x1e)]
public ulong GetSystemTick()
{
return _context.TickSource.Counter;
}
[Svc(0x26)]
public void Break(ulong reason)
{
KThread currentThread = KernelStatic.GetCurrentThread();
@ -1784,7 +1857,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
}
public void OutputDebugString(ulong strPtr, ulong size)
[Svc(0x27)]
public void OutputDebugString([PointerSized] ulong strPtr, [PointerSized] ulong size)
{
KProcess process = KernelStatic.GetCurrentProcess();
@ -1793,6 +1867,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
Logger.Warning?.Print(LogClass.KernelSvc, str);
}
[Svc(0x29)]
public KernelResult GetInfo(out ulong value, InfoType id, int handle, long subId)
{
value = 0;
@ -2038,6 +2113,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.Success;
}
[Svc(0x45)]
public KernelResult CreateEvent(out int wEventHandle, out int rEventHandle)
{
KEvent Event = new KEvent(_context);
@ -2063,7 +2139,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result;
}
public KernelResult GetProcessList(out int count, ulong address, int maxCount)
[Svc(0x65)]
public KernelResult GetProcessList(out int count, [PointerSized] ulong address, int maxCount)
{
count = 0;
@ -2112,6 +2189,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.Success;
}
[Svc(0x6f)]
public KernelResult GetSystemInfo(out long value, uint id, int handle, long subId)
{
value = 0;
@ -2168,6 +2246,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.Success;
}
[Svc(0x30)]
public KernelResult GetResourceLimitLimitValue(out long limitValue, int handle, LimitableResource resource)
{
limitValue = 0;
@ -2189,6 +2268,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.Success;
}
[Svc(0x31)]
public KernelResult GetResourceLimitCurrentValue(out long limitValue, int handle, LimitableResource resource)
{
limitValue = 0;
@ -2210,6 +2290,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.Success;
}
[Svc(0x37)]
public KernelResult GetResourceLimitPeakValue(out long peak, int handle, LimitableResource resource)
{
peak = 0;
@ -2231,6 +2312,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.Success;
}
[Svc(0x7d)]
public KernelResult CreateResourceLimit(out int handle)
{
KResourceLimit limit = new KResourceLimit(_context);
@ -2240,6 +2322,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return process.HandleTable.GenerateHandle(limit, out handle);
}
[Svc(0x7e)]
public KernelResult SetResourceLimitLimitValue(int handle, LimitableResource resource, long limitValue)
{
if (resource >= LimitableResource.Count)
@ -2259,11 +2342,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
// Thread
[Svc(8)]
public KernelResult CreateThread(
out int handle,
ulong entrypoint,
ulong argsPtr,
ulong stackTop,
[PointerSized] ulong entrypoint,
[PointerSized] ulong argsPtr,
[PointerSized] ulong stackTop,
int priority,
int cpuCore)
{
@ -2320,6 +2404,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result;
}
[Svc(9)]
public KernelResult StartThread(int handle)
{
KProcess process = KernelStatic.GetCurrentProcess();
@ -2347,6 +2432,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
}
[Svc(0xa)]
public void ExitThread()
{
KThread currentThread = KernelStatic.GetCurrentThread();
@ -2354,6 +2440,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
currentThread.Exit();
}
[Svc(0xb)]
public void SleepThread(long timeout)
{
if (timeout < 1)
@ -2371,6 +2458,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
}
[Svc(0xc)]
public KernelResult GetThreadPriority(out int priority, int handle)
{
KProcess process = KernelStatic.GetCurrentProcess();
@ -2391,6 +2479,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
}
[Svc(0xd)]
public KernelResult SetThreadPriority(int handle, int priority)
{
// TODO: NPDM check.
@ -2409,6 +2498,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.Success;
}
[Svc(0xe)]
public KernelResult GetThreadCoreMask(out int preferredCore, out ulong affinityMask, int handle)
{
KProcess process = KernelStatic.GetCurrentProcess();
@ -2431,6 +2521,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
}
[Svc(0xf)]
public KernelResult SetThreadCoreMask(int handle, int preferredCore, ulong affinityMask)
{
KProcess currentProcess = KernelStatic.GetCurrentProcess();
@ -2479,11 +2570,13 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return thread.SetCoreAndAffinityMask(preferredCore, affinityMask);
}
[Svc(0x10)]
public int GetCurrentProcessorNumber()
{
return KernelStatic.GetCurrentThread().CurrentCore;
}
[Svc(0x25)]
public KernelResult GetThreadId(out ulong threadUid, int handle)
{
KProcess process = KernelStatic.GetCurrentProcess();
@ -2504,6 +2597,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
}
}
[Svc(0x32)]
public KernelResult SetThreadActivity(int handle, bool pause)
{
KProcess process = KernelStatic.GetCurrentProcess();
@ -2528,7 +2622,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return thread.SetActivity(pause);
}
public KernelResult GetThreadContext3(ulong address, int handle)
[Svc(0x33)]
public KernelResult GetThreadContext3([PointerSized] ulong address, int handle)
{
KProcess currentProcess = KernelStatic.GetCurrentProcess();
KThread currentThread = KernelStatic.GetCurrentThread();
@ -2564,7 +2659,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
// Thread synchronization
public KernelResult WaitSynchronization(out int handleIndex, ulong handlesPtr, int handlesCount, long timeout)
[Svc(0x18)]
public KernelResult WaitSynchronization(out int handleIndex, [PointerSized] ulong handlesPtr, int handlesCount, long timeout)
{
handleIndex = 0;
@ -2653,6 +2749,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return result;
}
[Svc(0x19)]
public KernelResult CancelSynchronization(int handle)
{
KProcess process = KernelStatic.GetCurrentProcess();
@ -2669,7 +2766,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.Success;
}
public KernelResult ArbitrateLock(int ownerHandle, ulong mutexAddress, int requesterHandle)
[Svc(0x1a)]
public KernelResult ArbitrateLock(int ownerHandle, [PointerSized] ulong mutexAddress, int requesterHandle)
{
if (IsPointingInsideKernel(mutexAddress))
{
@ -2686,7 +2784,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return currentProcess.AddressArbiter.ArbitrateLock(ownerHandle, mutexAddress, requesterHandle);
}
public KernelResult ArbitrateUnlock(ulong mutexAddress)
[Svc(0x1b)]
public KernelResult ArbitrateUnlock([PointerSized] ulong mutexAddress)
{
if (IsPointingInsideKernel(mutexAddress))
{
@ -2703,9 +2802,10 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return currentProcess.AddressArbiter.ArbitrateUnlock(mutexAddress);
}
[Svc(0x1c)]
public KernelResult WaitProcessWideKeyAtomic(
ulong mutexAddress,
ulong condVarAddress,
[PointerSized] ulong mutexAddress,
[PointerSized] ulong condVarAddress,
int handle,
long timeout)
{
@ -2733,7 +2833,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
timeout);
}
public KernelResult SignalProcessWideKey(ulong address, int count)
[Svc(0x1d)]
public KernelResult SignalProcessWideKey([PointerSized] ulong address, int count)
{
KProcess currentProcess = KernelStatic.GetCurrentProcess();
@ -2742,7 +2843,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.Success;
}
public KernelResult WaitForAddress(ulong address, ArbitrationType type, int value, long timeout)
[Svc(0x34)]
public KernelResult WaitForAddress([PointerSized] ulong address, ArbitrationType type, int value, long timeout)
{
if (IsPointingInsideKernel(address))
{
@ -2773,7 +2875,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
};
}
public KernelResult SignalToAddress(ulong address, SignalType type, int value, int count)
[Svc(0x35)]
public KernelResult SignalToAddress([PointerSized] ulong address, SignalType type, int value, int count)
{
if (IsPointingInsideKernel(address))
{
@ -2799,6 +2902,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
};
}
[Svc(0x36)]
public KernelResult SynchronizePreemptionState()
{
KernelStatic.GetCurrentThread().SynchronizePreemptionState();
@ -2806,12 +2910,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return KernelResult.Success;
}
private bool IsPointingInsideKernel(ulong address)
private static bool IsPointingInsideKernel(ulong address)
{
return (address + 0x1000000000) < 0xffffff000;
}
private bool IsAddressNotWordAligned(ulong address)
private static bool IsAddressNotWordAligned(ulong address)
{
return (address & 3) != 0;
}

View File

@ -1,534 +0,0 @@
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Threading;
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
class Syscall32
{
private readonly Syscall _syscall;
public Syscall32(Syscall syscall)
{
_syscall = syscall;
}
// IPC
public KernelResult ConnectToNamedPort32([R(1)] uint namePtr, [R(1)] out int handle)
{
return _syscall.ConnectToNamedPort(out handle, namePtr);
}
public KernelResult SendSyncRequest32([R(0)] int handle)
{
return _syscall.SendSyncRequest(handle);
}
public KernelResult SendSyncRequestWithUserBuffer32([R(0)] uint messagePtr, [R(1)] uint messageSize, [R(2)] int handle)
{
return _syscall.SendSyncRequestWithUserBuffer(messagePtr, messageSize, handle);
}
public KernelResult CreateSession32(
[R(2)] bool isLight,
[R(3)] uint namePtr,
[R(1)] out int serverSessionHandle,
[R(2)] out int clientSessionHandle)
{
return _syscall.CreateSession(out serverSessionHandle, out clientSessionHandle, isLight, namePtr);
}
public KernelResult AcceptSession32([R(1)] int portHandle, [R(1)] out int sessionHandle)
{
return _syscall.AcceptSession(out sessionHandle, portHandle);
}
public KernelResult ReplyAndReceive32(
[R(0)] uint timeoutLow,
[R(1)] uint handlesPtr,
[R(2)] int handlesCount,
[R(3)] int replyTargetHandle,
[R(4)] uint timeoutHigh,
[R(1)] out int handleIndex)
{
long timeout = (long)(timeoutLow | ((ulong)timeoutHigh << 32));
return _syscall.ReplyAndReceive(out handleIndex, handlesPtr, handlesCount, replyTargetHandle, timeout);
}
public KernelResult CreatePort32(
[R(0)] uint namePtr,
[R(2)] int maxSessions,
[R(3)] bool isLight,
[R(1)] out int serverPortHandle,
[R(2)] out int clientPortHandle)
{
return _syscall.CreatePort(out serverPortHandle, out clientPortHandle, maxSessions, isLight, namePtr);
}
public KernelResult ManageNamedPort32([R(1)] uint namePtr, [R(2)] int maxSessions, [R(1)] out int handle)
{
return _syscall.ManageNamedPort(out handle, namePtr, maxSessions);
}
public KernelResult ConnectToPort32([R(1)] int clientPortHandle, [R(1)] out int clientSessionHandle)
{
return _syscall.ConnectToPort(out clientSessionHandle, clientPortHandle);
}
// Memory
public KernelResult SetHeapSize32([R(1)] uint size, [R(1)] out uint address)
{
KernelResult result = _syscall.SetHeapSize(out ulong address64, size);
address = (uint)address64;
return result;
}
public KernelResult SetMemoryPermission32(
[R(0)] uint address,
[R(1)] uint size,
[R(2)] KMemoryPermission permission)
{
return _syscall.SetMemoryPermission(address, size, permission);
}
public KernelResult SetMemoryAttribute32(
[R(0)] uint address,
[R(1)] uint size,
[R(2)] MemoryAttribute attributeMask,
[R(3)] MemoryAttribute attributeValue)
{
return _syscall.SetMemoryAttribute(address, size, attributeMask, attributeValue);
}
public KernelResult MapMemory32([R(0)] uint dst, [R(1)] uint src, [R(2)] uint size)
{
return _syscall.MapMemory(dst, src, size);
}
public KernelResult UnmapMemory32([R(0)] uint dst, [R(1)] uint src, [R(2)] uint size)
{
return _syscall.UnmapMemory(dst, src, size);
}
public KernelResult QueryMemory32([R(0)] uint infoPtr, [R(1)] uint r1, [R(2)] uint address, [R(1)] out uint pageInfo)
{
KernelResult result = _syscall.QueryMemory(infoPtr, out ulong pageInfo64, address);
pageInfo = (uint)pageInfo64;
return result;
}
public KernelResult MapSharedMemory32([R(0)] int handle, [R(1)] uint address, [R(2)] uint size, [R(3)] KMemoryPermission permission)
{
return _syscall.MapSharedMemory(handle, address, size, permission);
}
public KernelResult UnmapSharedMemory32([R(0)] int handle, [R(1)] uint address, [R(2)] uint size)
{
return _syscall.UnmapSharedMemory(handle, address, size);
}
public KernelResult CreateTransferMemory32(
[R(1)] uint address,
[R(2)] uint size,
[R(3)] KMemoryPermission permission,
[R(1)] out int handle)
{
return _syscall.CreateTransferMemory(out handle, address, size, permission);
}
public KernelResult CreateCodeMemory32([R(1)] uint address, [R(2)] uint size, [R(1)] out int handle)
{
return _syscall.CreateCodeMemory(address, size, out handle);
}
public KernelResult ControlCodeMemory32(
[R(0)] int handle,
[R(1)] CodeMemoryOperation op,
[R(2)] uint addressLow,
[R(3)] uint addressHigh,
[R(4)] uint sizeLow,
[R(5)] uint sizeHigh,
[R(6)] KMemoryPermission permission)
{
ulong address = addressLow | ((ulong)addressHigh << 32);
ulong size = sizeLow | ((ulong)sizeHigh << 32);
return _syscall.ControlCodeMemory(handle, op, address, size, permission);
}
public KernelResult MapTransferMemory32([R(0)] int handle, [R(1)] uint address, [R(2)] uint size, [R(3)] KMemoryPermission permission)
{
return _syscall.MapTransferMemory(handle, address, size, permission);
}
public KernelResult UnmapTransferMemory32([R(0)] int handle, [R(1)] uint address, [R(2)] uint size)
{
return _syscall.UnmapTransferMemory(handle, address, size);
}
public KernelResult MapPhysicalMemory32([R(0)] uint address, [R(1)] uint size)
{
return _syscall.MapPhysicalMemory(address, size);
}
public KernelResult UnmapPhysicalMemory32([R(0)] uint address, [R(1)] uint size)
{
return _syscall.UnmapPhysicalMemory(address, size);
}
public KernelResult SetProcessMemoryPermission32(
[R(0)] int handle,
[R(1)] uint sizeLow,
[R(2)] uint srcLow,
[R(3)] uint srcHigh,
[R(4)] uint sizeHigh,
[R(5)] KMemoryPermission permission)
{
ulong src = srcLow | ((ulong)srcHigh << 32);
ulong size = sizeLow | ((ulong)sizeHigh << 32);
return _syscall.SetProcessMemoryPermission(handle, src, size, permission);
}
public KernelResult MapProcessMemory32([R(0)] uint dst, [R(1)] int handle, [R(2)] uint srcLow, [R(3)] uint srcHigh, [R(4)] uint size)
{
ulong src = srcLow | ((ulong)srcHigh << 32);
return _syscall.MapProcessMemory(dst, handle, src, size);
}
public KernelResult UnmapProcessMemory32([R(0)] uint dst, [R(1)] int handle, [R(2)] uint srcLow, [R(3)] uint srcHigh, [R(4)] uint size)
{
ulong src = srcLow | ((ulong)srcHigh << 32);
return _syscall.UnmapProcessMemory(dst, handle, src, size);
}
public KernelResult MapProcessCodeMemory32([R(0)] int handle, [R(1)] uint srcLow, [R(2)] uint dstLow, [R(3)] uint dstHigh, [R(4)] uint srcHigh, [R(5)] uint sizeLow, [R(6)] uint sizeHigh)
{
ulong src = srcLow | ((ulong)srcHigh << 32);
ulong dst = dstLow | ((ulong)dstHigh << 32);
ulong size = sizeLow | ((ulong)sizeHigh << 32);
return _syscall.MapProcessCodeMemory(handle, dst, src, size);
}
public KernelResult UnmapProcessCodeMemory32([R(0)] int handle, [R(1)] uint srcLow, [R(2)] uint dstLow, [R(3)] uint dstHigh, [R(4)] uint srcHigh, [R(5)] uint sizeLow, [R(6)] uint sizeHigh)
{
ulong src = srcLow | ((ulong)srcHigh << 32);
ulong dst = dstLow | ((ulong)dstHigh << 32);
ulong size = sizeLow | ((ulong)sizeHigh << 32);
return _syscall.UnmapProcessCodeMemory(handle, dst, src, size);
}
// System
public void ExitProcess32()
{
_syscall.ExitProcess();
}
public KernelResult TerminateProcess32([R(0)] int handle)
{
return _syscall.TerminateProcess(handle);
}
public KernelResult SignalEvent32([R(0)] int handle)
{
return _syscall.SignalEvent(handle);
}
public KernelResult ClearEvent32([R(0)] int handle)
{
return _syscall.ClearEvent(handle);
}
public KernelResult CloseHandle32([R(0)] int handle)
{
return _syscall.CloseHandle(handle);
}
public KernelResult ResetSignal32([R(0)] int handle)
{
return _syscall.ResetSignal(handle);
}
public void GetSystemTick32([R(0)] out uint resultLow, [R(1)] out uint resultHigh)
{
ulong result = _syscall.GetSystemTick();
resultLow = (uint)(result & uint.MaxValue);
resultHigh = (uint)(result >> 32);
}
public KernelResult GetProcessId32([R(1)] int handle, [R(1)] out uint pidLow, [R(2)] out uint pidHigh)
{
KernelResult result = _syscall.GetProcessId(out ulong pid, handle);
pidLow = (uint)(pid & uint.MaxValue);
pidHigh = (uint)(pid >> 32);
return result;
}
public void Break32([R(0)] uint reason, [R(1)] uint r1, [R(2)] uint info)
{
_syscall.Break(reason);
}
public void OutputDebugString32([R(0)] uint strPtr, [R(1)] uint size)
{
_syscall.OutputDebugString(strPtr, size);
}
public KernelResult GetInfo32(
[R(0)] uint subIdLow,
[R(1)] InfoType id,
[R(2)] int handle,
[R(3)] uint subIdHigh,
[R(1)] out uint valueLow,
[R(2)] out uint valueHigh)
{
long subId = (long)(subIdLow | ((ulong)subIdHigh << 32));
KernelResult result = _syscall.GetInfo(out ulong value, id, handle, subId);
valueHigh = (uint)(value >> 32);
valueLow = (uint)(value & uint.MaxValue);
return result;
}
public KernelResult CreateEvent32([R(1)] out int wEventHandle, [R(2)] out int rEventHandle)
{
return _syscall.CreateEvent(out wEventHandle, out rEventHandle);
}
public KernelResult GetProcessList32([R(1)] ulong address, [R(2)] int maxCount, [R(1)] out int count)
{
return _syscall.GetProcessList(out count, address, maxCount);
}
public KernelResult GetSystemInfo32([R(1)] uint subIdLow, [R(2)] uint id, [R(3)] int handle, [R(3)] uint subIdHigh, [R(1)] out int valueLow, [R(2)] out int valueHigh)
{
long subId = (long)(subIdLow | ((ulong)subIdHigh << 32));
KernelResult result = _syscall.GetSystemInfo(out long value, id, handle, subId);
valueHigh = (int)(value >> 32);
valueLow = (int)(value & uint.MaxValue);
return result;
}
public KernelResult GetResourceLimitLimitValue32([R(1)] int handle, [R(2)] LimitableResource resource, [R(1)] out int limitValueLow, [R(2)] out int limitValueHigh)
{
KernelResult result = _syscall.GetResourceLimitLimitValue(out long limitValue, handle, resource);
limitValueHigh = (int)(limitValue >> 32);
limitValueLow = (int)(limitValue & uint.MaxValue);
return result;
}
public KernelResult GetResourceLimitCurrentValue32([R(1)] int handle, [R(2)] LimitableResource resource, [R(1)] out int limitValueLow, [R(2)] out int limitValueHigh)
{
KernelResult result = _syscall.GetResourceLimitCurrentValue(out long limitValue, handle, resource);
limitValueHigh = (int)(limitValue >> 32);
limitValueLow = (int)(limitValue & uint.MaxValue);
return result;
}
public KernelResult GetResourceLimitPeakValue32([R(1)] int handle, [R(2)] LimitableResource resource, [R(1)] out int peakLow, [R(2)] out int peakHigh)
{
KernelResult result = _syscall.GetResourceLimitPeakValue(out long peak, handle, resource);
peakHigh = (int)(peak >> 32);
peakLow = (int)(peak & uint.MaxValue);
return result;
}
public KernelResult CreateResourceLimit32([R(1)] out int handle)
{
return _syscall.CreateResourceLimit(out handle);
}
public KernelResult SetResourceLimitLimitValue32([R(0)] int handle, [R(1)] LimitableResource resource, [R(2)] uint limitValueLow, [R(3)] uint limitValueHigh)
{
long limitValue = (long)(limitValueLow | ((ulong)limitValueHigh << 32));
return _syscall.SetResourceLimitLimitValue(handle, resource, limitValue);
}
public KernelResult FlushProcessDataCache32(
[R(0)] uint processHandle,
[R(2)] uint addressLow,
[R(3)] uint addressHigh,
[R(1)] uint sizeLow,
[R(4)] uint sizeHigh)
{
// FIXME: This needs to be implemented as ARMv7 doesn't have any way to do cache maintenance operations on EL0.
// As we don't support (and don't actually need) to flush the cache, this is stubbed.
return KernelResult.Success;
}
// Thread
public KernelResult CreateThread32(
[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 _syscall.CreateThread(out handle, entrypoint, argsPtr, stackTop, priority, cpuCore);
}
public KernelResult StartThread32([R(0)] int handle)
{
return _syscall.StartThread(handle);
}
public void ExitThread32()
{
_syscall.ExitThread();
}
public void SleepThread32([R(0)] uint timeoutLow, [R(1)] uint timeoutHigh)
{
long timeout = (long)(timeoutLow | ((ulong)timeoutHigh << 32));
_syscall.SleepThread(timeout);
}
public KernelResult GetThreadPriority32([R(1)] int handle, [R(1)] out int priority)
{
return _syscall.GetThreadPriority(out priority, handle);
}
public KernelResult SetThreadPriority32([R(0)] int handle, [R(1)] int priority)
{
return _syscall.SetThreadPriority(handle, priority);
}
public KernelResult GetThreadCoreMask32([R(2)] int handle, [R(1)] out int preferredCore, [R(2)] out uint affinityMaskLow, [R(3)] out uint affinityMaskHigh)
{
KernelResult result = _syscall.GetThreadCoreMask(out preferredCore, out ulong affinityMask, handle);
affinityMaskLow = (uint)(affinityMask & uint.MaxValue);
affinityMaskHigh = (uint)(affinityMask >> 32);
return result;
}
public KernelResult SetThreadCoreMask32([R(0)] int handle, [R(1)] int preferredCore, [R(2)] uint affinityMaskLow, [R(3)] uint affinityMaskHigh)
{
ulong affinityMask = affinityMaskLow | ((ulong)affinityMaskHigh << 32);
return _syscall.SetThreadCoreMask(handle, preferredCore, affinityMask);
}
public int GetCurrentProcessorNumber32()
{
return _syscall.GetCurrentProcessorNumber();
}
public KernelResult GetThreadId32([R(1)] int handle, [R(1)] out uint threadUidLow, [R(2)] out uint threadUidHigh)
{
ulong threadUid;
KernelResult result = _syscall.GetThreadId(out threadUid, handle);
threadUidLow = (uint)(threadUid >> 32);
threadUidHigh = (uint)(threadUid & uint.MaxValue);
return result;
}
public KernelResult SetThreadActivity32([R(0)] int handle, [R(1)] bool pause)
{
return _syscall.SetThreadActivity(handle, pause);
}
public KernelResult GetThreadContext332([R(0)] uint address, [R(1)] int handle)
{
return _syscall.GetThreadContext3(address, handle);
}
// Thread synchronization
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 _syscall.WaitSynchronization(out handleIndex, handlesPtr, handlesCount, timeout);
}
public KernelResult CancelSynchronization32([R(0)] int handle)
{
return _syscall.CancelSynchronization(handle);
}
public KernelResult ArbitrateLock32([R(0)] int ownerHandle, [R(1)] uint mutexAddress, [R(2)] int requesterHandle)
{
return _syscall.ArbitrateLock(ownerHandle, mutexAddress, requesterHandle);
}
public KernelResult ArbitrateUnlock32([R(0)] uint mutexAddress)
{
return _syscall.ArbitrateUnlock(mutexAddress);
}
public KernelResult WaitProcessWideKeyAtomic32(
[R(0)] uint mutexAddress,
[R(1)] uint condVarAddress,
[R(2)] int handle,
[R(3)] uint timeoutLow,
[R(4)] uint timeoutHigh)
{
long timeout = (long)(timeoutLow | ((ulong)timeoutHigh << 32));
return _syscall.WaitProcessWideKeyAtomic(mutexAddress, condVarAddress, handle, timeout);
}
public KernelResult SignalProcessWideKey32([R(0)] uint address, [R(1)] int count)
{
return _syscall.SignalProcessWideKey(address, count);
}
public KernelResult WaitForAddress32([R(0)] uint address, [R(1)] ArbitrationType type, [R(2)] int value, [R(3)] uint timeoutLow, [R(4)] uint timeoutHigh)
{
long timeout = (long)(timeoutLow | ((ulong)timeoutHigh << 32));
return _syscall.WaitForAddress(address, type, value, timeout);
}
public KernelResult SignalToAddress32([R(0)] uint address, [R(1)] SignalType type, [R(2)] int value, [R(3)] int count)
{
return _syscall.SignalToAddress(address, type, value, count);
}
public KernelResult SynchronizePreemptionState32()
{
return _syscall.SynchronizePreemptionState();
}
}
}

View File

@ -1,434 +0,0 @@
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Threading;
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
class Syscall64
{
private readonly Syscall _syscall;
public Syscall64(Syscall syscall)
{
_syscall = syscall;
}
// IPC
public KernelResult ConnectToNamedPort64([R(1)] ulong namePtr, [R(1)] out int handle)
{
return _syscall.ConnectToNamedPort(out handle, namePtr);
}
public KernelResult SendSyncRequest64([R(0)] int handle)
{
return _syscall.SendSyncRequest(handle);
}
public KernelResult SendSyncRequestWithUserBuffer64([R(0)] ulong messagePtr, [R(1)] ulong messageSize, [R(2)] int handle)
{
return _syscall.SendSyncRequestWithUserBuffer(messagePtr, messageSize, handle);
}
public KernelResult SendAsyncRequestWithUserBuffer64(
[R(1)] ulong messagePtr,
[R(2)] ulong messageSize,
[R(3)] int handle,
[R(1)] out int doneEventHandle)
{
return _syscall.SendAsyncRequestWithUserBuffer(out doneEventHandle, messagePtr, messageSize, handle);
}
public KernelResult CreateSession64(
[R(2)] bool isLight,
[R(3)] ulong namePtr,
[R(1)] out int serverSessionHandle,
[R(2)] out int clientSessionHandle)
{
return _syscall.CreateSession(out serverSessionHandle, out clientSessionHandle, isLight, namePtr);
}
public KernelResult AcceptSession64([R(1)] int portHandle, [R(1)] out int sessionHandle)
{
return _syscall.AcceptSession(out sessionHandle, portHandle);
}
public KernelResult ReplyAndReceive64(
[R(1)] ulong handlesPtr,
[R(2)] int handlesCount,
[R(3)] int replyTargetHandle,
[R(4)] long timeout,
[R(1)] out int handleIndex)
{
return _syscall.ReplyAndReceive(out handleIndex, handlesPtr, handlesCount, replyTargetHandle, timeout);
}
public KernelResult ReplyAndReceiveWithUserBuffer64(
[R(1)] ulong messagePtr,
[R(2)] ulong messageSize,
[R(3)] ulong handlesPtr,
[R(4)] int handlesCount,
[R(5)] int replyTargetHandle,
[R(6)] long timeout,
[R(1)] out int handleIndex)
{
return _syscall.ReplyAndReceiveWithUserBuffer(
out handleIndex,
handlesPtr,
messagePtr,
messageSize,
handlesCount,
replyTargetHandle,
timeout);
}
public KernelResult CreatePort64(
[R(2)] int maxSessions,
[R(3)] bool isLight,
[R(4)] ulong namePtr,
[R(1)] out int serverPortHandle,
[R(2)] out int clientPortHandle)
{
return _syscall.CreatePort(out serverPortHandle, out clientPortHandle, maxSessions, isLight, namePtr);
}
public KernelResult ManageNamedPort64([R(1)] ulong namePtr, [R(2)] int maxSessions, [R(1)] out int handle)
{
return _syscall.ManageNamedPort(out handle, namePtr, maxSessions);
}
public KernelResult ConnectToPort64([R(1)] int clientPortHandle, [R(1)] out int clientSessionHandle)
{
return _syscall.ConnectToPort(out clientSessionHandle, clientPortHandle);
}
// Memory
public KernelResult SetHeapSize64([R(1)] ulong size, [R(1)] out ulong address)
{
return _syscall.SetHeapSize(out address, size);
}
public KernelResult SetMemoryPermission64(
[R(0)] ulong address,
[R(1)] ulong size,
[R(2)] KMemoryPermission permission)
{
return _syscall.SetMemoryPermission(address, size, permission);
}
public KernelResult SetMemoryAttribute64(
[R(0)] ulong address,
[R(1)] ulong size,
[R(2)] MemoryAttribute attributeMask,
[R(3)] MemoryAttribute attributeValue)
{
return _syscall.SetMemoryAttribute(address, size, attributeMask, attributeValue);
}
public KernelResult MapMemory64([R(0)] ulong dst, [R(1)] ulong src, [R(2)] ulong size)
{
return _syscall.MapMemory(dst, src, size);
}
public KernelResult UnmapMemory64([R(0)] ulong dst, [R(1)] ulong src, [R(2)] ulong size)
{
return _syscall.UnmapMemory(dst, src, size);
}
public KernelResult QueryMemory64([R(0)] ulong infoPtr, [R(2)] ulong address, [R(1)] out ulong pageInfo)
{
return _syscall.QueryMemory(infoPtr, out pageInfo, address);
}
public KernelResult MapSharedMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size, [R(3)] KMemoryPermission permission)
{
return _syscall.MapSharedMemory(handle, address, size, permission);
}
public KernelResult UnmapSharedMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size)
{
return _syscall.UnmapSharedMemory(handle, address, size);
}
public KernelResult CreateTransferMemory64(
[R(1)] ulong address,
[R(2)] ulong size,
[R(3)] KMemoryPermission permission,
[R(1)] out int handle)
{
return _syscall.CreateTransferMemory(out handle, address, size, permission);
}
public KernelResult CreateCodeMemory64([R(1)] ulong address, [R(2)] ulong size, [R(1)] out int handle)
{
return _syscall.CreateCodeMemory(address, size, out handle);
}
public KernelResult ControlCodeMemory64([R(0)] int handle, [R(1)] CodeMemoryOperation op, [R(2)] ulong address, [R(3)] ulong size, [R(4)] KMemoryPermission permission)
{
return _syscall.ControlCodeMemory(handle, op, address, size, permission);
}
public KernelResult MapTransferMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size, [R(3)] KMemoryPermission permission)
{
return _syscall.MapTransferMemory(handle, address, size, permission);
}
public KernelResult UnmapTransferMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size)
{
return _syscall.UnmapTransferMemory(handle, address, size);
}
public KernelResult MapPhysicalMemory64([R(0)] ulong address, [R(1)] ulong size)
{
return _syscall.MapPhysicalMemory(address, size);
}
public KernelResult UnmapPhysicalMemory64([R(0)] ulong address, [R(1)] ulong size)
{
return _syscall.UnmapPhysicalMemory(address, size);
}
public KernelResult SetProcessMemoryPermission64([R(0)] int handle, [R(1)] ulong src, [R(2)] ulong size, [R(3)] KMemoryPermission permission)
{
return _syscall.SetProcessMemoryPermission(handle, src, size, permission);
}
public KernelResult MapProcessMemory64([R(0)] ulong dst, [R(1)] int handle, [R(2)] ulong src, [R(3)] ulong size)
{
return _syscall.MapProcessMemory(dst, handle, src, size);
}
public KernelResult UnmapProcessMemory64([R(0)] ulong dst, [R(1)] int handle, [R(2)] ulong src, [R(3)] ulong size)
{
return _syscall.UnmapProcessMemory(dst, handle, src, size);
}
public KernelResult MapProcessCodeMemory64([R(0)] int handle, [R(1)] ulong dst, [R(2)] ulong src, [R(3)] ulong size)
{
return _syscall.MapProcessCodeMemory(handle, dst, src, size);
}
public KernelResult UnmapProcessCodeMemory64([R(0)] int handle, [R(1)] ulong dst, [R(2)] ulong src, [R(3)] ulong size)
{
return _syscall.UnmapProcessCodeMemory(handle, dst, src, size);
}
// System
public void ExitProcess64()
{
_syscall.ExitProcess();
}
public KernelResult TerminateProcess64([R(0)] int handle)
{
return _syscall.TerminateProcess(handle);
}
public KernelResult SignalEvent64([R(0)] int handle)
{
return _syscall.SignalEvent(handle);
}
public KernelResult ClearEvent64([R(0)] int handle)
{
return _syscall.ClearEvent(handle);
}
public KernelResult CloseHandle64([R(0)] int handle)
{
return _syscall.CloseHandle(handle);
}
public KernelResult ResetSignal64([R(0)] int handle)
{
return _syscall.ResetSignal(handle);
}
public ulong GetSystemTick64()
{
return _syscall.GetSystemTick();
}
public KernelResult GetProcessId64([R(1)] int handle, [R(1)] out ulong pid)
{
return _syscall.GetProcessId(out pid, handle);
}
public void Break64([R(0)] ulong reason, [R(1)] ulong x1, [R(2)] ulong info)
{
_syscall.Break(reason);
}
public void OutputDebugString64([R(0)] ulong strPtr, [R(1)] ulong size)
{
_syscall.OutputDebugString(strPtr, size);
}
public KernelResult GetInfo64([R(1)] InfoType id, [R(2)] int handle, [R(3)] long subId, [R(1)] out ulong value)
{
return _syscall.GetInfo(out value, id, handle, subId);
}
public KernelResult CreateEvent64([R(1)] out int wEventHandle, [R(2)] out int rEventHandle)
{
return _syscall.CreateEvent(out wEventHandle, out rEventHandle);
}
public KernelResult GetProcessList64([R(1)] ulong address, [R(2)] int maxCount, [R(1)] out int count)
{
return _syscall.GetProcessList(out count, address, maxCount);
}
public KernelResult GetSystemInfo64([R(1)] uint id, [R(2)] int handle, [R(3)] long subId, [R(1)] out long value)
{
return _syscall.GetSystemInfo(out value, id, handle, subId);
}
public KernelResult GetResourceLimitLimitValue64([R(1)] int handle, [R(2)] LimitableResource resource, [R(1)] out long limitValue)
{
return _syscall.GetResourceLimitLimitValue(out limitValue, handle, resource);
}
public KernelResult GetResourceLimitCurrentValue64([R(1)] int handle, [R(2)] LimitableResource resource, [R(1)] out long limitValue)
{
return _syscall.GetResourceLimitCurrentValue(out limitValue, handle, resource);
}
public KernelResult GetResourceLimitPeakValue64([R(1)] int handle, [R(2)] LimitableResource resource, [R(1)] out long peak)
{
return _syscall.GetResourceLimitPeakValue(out peak, handle, resource);
}
public KernelResult CreateResourceLimit64([R(1)] out int handle)
{
return _syscall.CreateResourceLimit(out handle);
}
public KernelResult SetResourceLimitLimitValue64([R(0)] int handle, [R(1)] LimitableResource resource, [R(2)] long limitValue)
{
return _syscall.SetResourceLimitLimitValue(handle, resource, limitValue);
}
// Thread
public KernelResult CreateThread64(
[R(1)] ulong entrypoint,
[R(2)] ulong argsPtr,
[R(3)] ulong stackTop,
[R(4)] int priority,
[R(5)] int cpuCore,
[R(1)] out int handle)
{
return _syscall.CreateThread(out handle, entrypoint, argsPtr, stackTop, priority, cpuCore);
}
public KernelResult StartThread64([R(0)] int handle)
{
return _syscall.StartThread(handle);
}
public void ExitThread64()
{
_syscall.ExitThread();
}
public void SleepThread64([R(0)] long timeout)
{
_syscall.SleepThread(timeout);
}
public KernelResult GetThreadPriority64([R(1)] int handle, [R(1)] out int priority)
{
return _syscall.GetThreadPriority(out priority, handle);
}
public KernelResult SetThreadPriority64([R(0)] int handle, [R(1)] int priority)
{
return _syscall.SetThreadPriority(handle, priority);
}
public KernelResult GetThreadCoreMask64([R(2)] int handle, [R(1)] out int preferredCore, [R(2)] out ulong affinityMask)
{
return _syscall.GetThreadCoreMask(out preferredCore, out affinityMask, handle);
}
public KernelResult SetThreadCoreMask64([R(0)] int handle, [R(1)] int preferredCore, [R(2)] ulong affinityMask)
{
return _syscall.SetThreadCoreMask(handle, preferredCore, affinityMask);
}
public int GetCurrentProcessorNumber64()
{
return _syscall.GetCurrentProcessorNumber();
}
public KernelResult GetThreadId64([R(1)] int handle, [R(1)] out ulong threadUid)
{
return _syscall.GetThreadId(out threadUid, handle);
}
public KernelResult SetThreadActivity64([R(0)] int handle, [R(1)] bool pause)
{
return _syscall.SetThreadActivity(handle, pause);
}
public KernelResult GetThreadContext364([R(0)] ulong address, [R(1)] int handle)
{
return _syscall.GetThreadContext3(address, handle);
}
// Thread synchronization
public KernelResult WaitSynchronization64([R(1)] ulong handlesPtr, [R(2)] int handlesCount, [R(3)] long timeout, [R(1)] out int handleIndex)
{
return _syscall.WaitSynchronization(out handleIndex, handlesPtr, handlesCount, timeout);
}
public KernelResult CancelSynchronization64([R(0)] int handle)
{
return _syscall.CancelSynchronization(handle);
}
public KernelResult ArbitrateLock64([R(0)] int ownerHandle, [R(1)] ulong mutexAddress, [R(2)] int requesterHandle)
{
return _syscall.ArbitrateLock(ownerHandle, mutexAddress, requesterHandle);
}
public KernelResult ArbitrateUnlock64([R(0)] ulong mutexAddress)
{
return _syscall.ArbitrateUnlock(mutexAddress);
}
public KernelResult WaitProcessWideKeyAtomic64(
[R(0)] ulong mutexAddress,
[R(1)] ulong condVarAddress,
[R(2)] int handle,
[R(3)] long timeout)
{
return _syscall.WaitProcessWideKeyAtomic(mutexAddress, condVarAddress, handle, timeout);
}
public KernelResult SignalProcessWideKey64([R(0)] ulong address, [R(1)] int count)
{
return _syscall.SignalProcessWideKey(address, count);
}
public KernelResult WaitForAddress64([R(0)] ulong address, [R(1)] ArbitrationType type, [R(2)] int value, [R(3)] long timeout)
{
return _syscall.WaitForAddress(address, type, value, timeout);
}
public KernelResult SignalToAddress64([R(0)] ulong address, [R(1)] SignalType type, [R(2)] int value, [R(3)] int count)
{
return _syscall.SignalToAddress(address, type, value, count);
}
public KernelResult SynchronizePreemptionState64()
{
return _syscall.SynchronizePreemptionState();
}
}
}

View File

@ -1,20 +1,15 @@
using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Kernel.Threading;
using System;
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
partial class SyscallHandler
{
private readonly KernelContext _context;
private readonly Syscall32 _syscall32;
private readonly Syscall64 _syscall64;
public SyscallHandler(KernelContext context)
{
_context = context;
_syscall32 = new Syscall32(context.Syscall);
_syscall64 = new Syscall64(context.Syscall);
}
public void SvcCall(IExecutionContext context, ulong address, int id)
@ -36,25 +31,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
if (context.IsAarch32)
{
var svcFunc = SyscallTable.SvcTable32[id];
if (svcFunc == null)
{
throw new NotImplementedException($"SVC 0x{id:X4} is not implemented.");
}
svcFunc(_syscall32, context);
SyscallDispatch.Dispatch32(_context.Syscall, context, id);
}
else
{
var svcFunc = SyscallTable.SvcTable64[id];
if (svcFunc == null)
{
throw new NotImplementedException($"SVC 0x{id:X4} is not implemented.");
}
svcFunc(_syscall64, context);
SyscallDispatch.Dispatch64(_context.Syscall, context, id);
}
currentThread.HandlePostSyscall();

View File

@ -1,494 +0,0 @@
using Ryujinx.Common.Logging;
using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Kernel.Common;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
static class SyscallTable
{
private const int SvcFuncMaxArguments64 = 8;
private const int SvcFuncMaxArguments32 = 4;
private const int SvcMax = 0x80;
public static Action<Syscall32, IExecutionContext>[] SvcTable32 { get; }
public static Action<Syscall64, IExecutionContext>[] SvcTable64 { get; }
static SyscallTable()
{
SvcTable32 = new Action<Syscall32, IExecutionContext>[SvcMax];
SvcTable64 = new Action<Syscall64, IExecutionContext>[SvcMax];
Dictionary<int, string> svcFuncs64 = new Dictionary<int, string>
{
{ 0x01, nameof(Syscall64.SetHeapSize64) },
{ 0x02, nameof(Syscall64.SetMemoryPermission64) },
{ 0x03, nameof(Syscall64.SetMemoryAttribute64) },
{ 0x04, nameof(Syscall64.MapMemory64) },
{ 0x05, nameof(Syscall64.UnmapMemory64) },
{ 0x06, nameof(Syscall64.QueryMemory64) },
{ 0x07, nameof(Syscall64.ExitProcess64) },
{ 0x08, nameof(Syscall64.CreateThread64) },
{ 0x09, nameof(Syscall64.StartThread64) },
{ 0x0a, nameof(Syscall64.ExitThread64) },
{ 0x0b, nameof(Syscall64.SleepThread64) },
{ 0x0c, nameof(Syscall64.GetThreadPriority64) },
{ 0x0d, nameof(Syscall64.SetThreadPriority64) },
{ 0x0e, nameof(Syscall64.GetThreadCoreMask64) },
{ 0x0f, nameof(Syscall64.SetThreadCoreMask64) },
{ 0x10, nameof(Syscall64.GetCurrentProcessorNumber64) },
{ 0x11, nameof(Syscall64.SignalEvent64) },
{ 0x12, nameof(Syscall64.ClearEvent64) },
{ 0x13, nameof(Syscall64.MapSharedMemory64) },
{ 0x14, nameof(Syscall64.UnmapSharedMemory64) },
{ 0x15, nameof(Syscall64.CreateTransferMemory64) },
{ 0x16, nameof(Syscall64.CloseHandle64) },
{ 0x17, nameof(Syscall64.ResetSignal64) },
{ 0x18, nameof(Syscall64.WaitSynchronization64) },
{ 0x19, nameof(Syscall64.CancelSynchronization64) },
{ 0x1a, nameof(Syscall64.ArbitrateLock64) },
{ 0x1b, nameof(Syscall64.ArbitrateUnlock64) },
{ 0x1c, nameof(Syscall64.WaitProcessWideKeyAtomic64) },
{ 0x1d, nameof(Syscall64.SignalProcessWideKey64) },
{ 0x1e, nameof(Syscall64.GetSystemTick64) },
{ 0x1f, nameof(Syscall64.ConnectToNamedPort64) },
{ 0x21, nameof(Syscall64.SendSyncRequest64) },
{ 0x22, nameof(Syscall64.SendSyncRequestWithUserBuffer64) },
{ 0x23, nameof(Syscall64.SendAsyncRequestWithUserBuffer64) },
{ 0x24, nameof(Syscall64.GetProcessId64) },
{ 0x25, nameof(Syscall64.GetThreadId64) },
{ 0x26, nameof(Syscall64.Break64) },
{ 0x27, nameof(Syscall64.OutputDebugString64) },
{ 0x29, nameof(Syscall64.GetInfo64) },
{ 0x2c, nameof(Syscall64.MapPhysicalMemory64) },
{ 0x2d, nameof(Syscall64.UnmapPhysicalMemory64) },
{ 0x30, nameof(Syscall64.GetResourceLimitLimitValue64) },
{ 0x31, nameof(Syscall64.GetResourceLimitCurrentValue64) },
{ 0x32, nameof(Syscall64.SetThreadActivity64) },
{ 0x33, nameof(Syscall64.GetThreadContext364) },
{ 0x34, nameof(Syscall64.WaitForAddress64) },
{ 0x35, nameof(Syscall64.SignalToAddress64) },
{ 0x36, nameof(Syscall64.SynchronizePreemptionState64) },
{ 0x37, nameof(Syscall64.GetResourceLimitPeakValue64) },
{ 0x40, nameof(Syscall64.CreateSession64) },
{ 0x41, nameof(Syscall64.AcceptSession64) },
{ 0x43, nameof(Syscall64.ReplyAndReceive64) },
{ 0x44, nameof(Syscall64.ReplyAndReceiveWithUserBuffer64) },
{ 0x45, nameof(Syscall64.CreateEvent64) },
{ 0x4b, nameof(Syscall64.CreateCodeMemory64) },
{ 0x4c, nameof(Syscall64.ControlCodeMemory64) },
{ 0x51, nameof(Syscall64.MapTransferMemory64) },
{ 0x52, nameof(Syscall64.UnmapTransferMemory64) },
{ 0x65, nameof(Syscall64.GetProcessList64) },
{ 0x6f, nameof(Syscall64.GetSystemInfo64) },
{ 0x70, nameof(Syscall64.CreatePort64) },
{ 0x71, nameof(Syscall64.ManageNamedPort64) },
{ 0x72, nameof(Syscall64.ConnectToPort64) },
{ 0x73, nameof(Syscall64.SetProcessMemoryPermission64) },
{ 0x74, nameof(Syscall64.MapProcessMemory64) },
{ 0x75, nameof(Syscall64.UnmapProcessMemory64) },
{ 0x77, nameof(Syscall64.MapProcessCodeMemory64) },
{ 0x78, nameof(Syscall64.UnmapProcessCodeMemory64) },
{ 0x7B, nameof(Syscall64.TerminateProcess64) },
{ 0x7D, nameof(Syscall64.CreateResourceLimit64) },
{ 0x7E, nameof(Syscall64.SetResourceLimitLimitValue64) }
};
foreach (KeyValuePair<int, string> value in svcFuncs64)
{
SvcTable64[value.Key] = GenerateMethod<Syscall64>(value.Value, SvcFuncMaxArguments64);
}
Dictionary<int, string> svcFuncs32 = new Dictionary<int, string>
{
{ 0x01, nameof(Syscall32.SetHeapSize32) },
{ 0x02, nameof(Syscall32.SetMemoryPermission32) },
{ 0x03, nameof(Syscall32.SetMemoryAttribute32) },
{ 0x04, nameof(Syscall32.MapMemory32) },
{ 0x05, nameof(Syscall32.UnmapMemory32) },
{ 0x06, nameof(Syscall32.QueryMemory32) },
{ 0x07, nameof(Syscall32.ExitProcess32) },
{ 0x08, nameof(Syscall32.CreateThread32) },
{ 0x09, nameof(Syscall32.StartThread32) },
{ 0x0a, nameof(Syscall32.ExitThread32) },
{ 0x0b, nameof(Syscall32.SleepThread32) },
{ 0x0c, nameof(Syscall32.GetThreadPriority32) },
{ 0x0d, nameof(Syscall32.SetThreadPriority32) },
{ 0x0e, nameof(Syscall32.GetThreadCoreMask32) },
{ 0x0f, nameof(Syscall32.SetThreadCoreMask32) },
{ 0x10, nameof(Syscall32.GetCurrentProcessorNumber32) },
{ 0x11, nameof(Syscall32.SignalEvent32) },
{ 0x12, nameof(Syscall32.ClearEvent32) },
{ 0x13, nameof(Syscall32.MapSharedMemory32) },
{ 0x14, nameof(Syscall32.UnmapSharedMemory32) },
{ 0x15, nameof(Syscall32.CreateTransferMemory32) },
{ 0x16, nameof(Syscall32.CloseHandle32) },
{ 0x17, nameof(Syscall32.ResetSignal32) },
{ 0x18, nameof(Syscall32.WaitSynchronization32) },
{ 0x19, nameof(Syscall32.CancelSynchronization32) },
{ 0x1a, nameof(Syscall32.ArbitrateLock32) },
{ 0x1b, nameof(Syscall32.ArbitrateUnlock32) },
{ 0x1c, nameof(Syscall32.WaitProcessWideKeyAtomic32) },
{ 0x1d, nameof(Syscall32.SignalProcessWideKey32) },
{ 0x1e, nameof(Syscall32.GetSystemTick32) },
{ 0x1f, nameof(Syscall32.ConnectToNamedPort32) },
{ 0x21, nameof(Syscall32.SendSyncRequest32) },
{ 0x22, nameof(Syscall32.SendSyncRequestWithUserBuffer32) },
{ 0x24, nameof(Syscall32.GetProcessId32) },
{ 0x25, nameof(Syscall32.GetThreadId32) },
{ 0x26, nameof(Syscall32.Break32) },
{ 0x27, nameof(Syscall32.OutputDebugString32) },
{ 0x29, nameof(Syscall32.GetInfo32) },
{ 0x2c, nameof(Syscall32.MapPhysicalMemory32) },
{ 0x2d, nameof(Syscall32.UnmapPhysicalMemory32) },
{ 0x30, nameof(Syscall32.GetResourceLimitLimitValue32) },
{ 0x31, nameof(Syscall32.GetResourceLimitCurrentValue32) },
{ 0x32, nameof(Syscall32.SetThreadActivity32) },
{ 0x33, nameof(Syscall32.GetThreadContext332) },
{ 0x34, nameof(Syscall32.WaitForAddress32) },
{ 0x35, nameof(Syscall32.SignalToAddress32) },
{ 0x36, nameof(Syscall32.SynchronizePreemptionState32) },
{ 0x37, nameof(Syscall32.GetResourceLimitPeakValue32) },
{ 0x40, nameof(Syscall32.CreateSession32) },
{ 0x41, nameof(Syscall32.AcceptSession32) },
{ 0x43, nameof(Syscall32.ReplyAndReceive32) },
{ 0x45, nameof(Syscall32.CreateEvent32) },
{ 0x4b, nameof(Syscall32.CreateCodeMemory32) },
{ 0x4c, nameof(Syscall32.ControlCodeMemory32) },
{ 0x51, nameof(Syscall32.MapTransferMemory32) },
{ 0x52, nameof(Syscall32.UnmapTransferMemory32) },
{ 0x5F, nameof(Syscall32.FlushProcessDataCache32) },
{ 0x65, nameof(Syscall32.GetProcessList32) },
{ 0x6f, nameof(Syscall32.GetSystemInfo32) },
{ 0x70, nameof(Syscall32.CreatePort32) },
{ 0x71, nameof(Syscall32.ManageNamedPort32) },
{ 0x72, nameof(Syscall32.ConnectToPort32) },
{ 0x73, nameof(Syscall32.SetProcessMemoryPermission32) },
{ 0x74, nameof(Syscall32.MapProcessMemory32) },
{ 0x75, nameof(Syscall32.UnmapProcessMemory32) },
{ 0x77, nameof(Syscall32.MapProcessCodeMemory32) },
{ 0x78, nameof(Syscall32.UnmapProcessCodeMemory32) },
{ 0x7B, nameof(Syscall32.TerminateProcess32) },
{ 0x7D, nameof(Syscall32.CreateResourceLimit32) },
{ 0x7E, nameof(Syscall32.SetResourceLimitLimitValue32) }
};
foreach (KeyValuePair<int, string> value in svcFuncs32)
{
SvcTable32[value.Key] = GenerateMethod<Syscall32>(value.Value, SvcFuncMaxArguments32);
}
}
private static Action<T, IExecutionContext> GenerateMethod<T>(string svcName, int registerCleanCount)
{
Type[] argTypes = new Type[] { typeof(T), typeof(IExecutionContext) };
DynamicMethod method = new DynamicMethod(svcName, null, argTypes);
MethodInfo methodInfo = typeof(T).GetMethod(svcName);
ParameterInfo[] methodArgs = methodInfo.GetParameters();
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(IExecutionContext).GetMethod(nameof(IExecutionContext.GetX));
generator.Emit(OpCodes.Callvirt, 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(SyscallTable).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(IExecutionContext).GetMethod(nameof(IExecutionContext.GetX));
generator.Emit(OpCodes.Callvirt, 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(IExecutionContext).GetMethod(nameof(IExecutionContext.GetX));
generator.Emit(OpCodes.Callvirt, info);
ConvertToArgType(argType);
}
}
generator.Emit(OpCodes.Call, methodInfo);
Type retType = methodInfo.ReturnType;
// Print result code.
if (retType == typeof(KernelResult))
{
MethodInfo printResultMethod = typeof(SyscallTable).GetMethod(nameof(PrintResult), staticNonPublic);
generator.Emit(OpCodes.Dup);
generator.Emit(OpCodes.Ldstr, svcName);
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))
{
CheckIfTypeIsSupported(retType, svcName);
LocalBuilder tempLocal = generator.DeclareLocal(retType);
generator.Emit(OpCodes.Stloc, tempLocal);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldc_I4, 0);
generator.Emit(OpCodes.Ldloc, tempLocal);
ConvertToFieldType(retType);
MethodInfo info = typeof(IExecutionContext).GetMethod(nameof(IExecutionContext.SetX));
generator.Emit(OpCodes.Callvirt, info);
registerInUse |= 1u << 0;
}
for (int index = 0; index < locals.Count; index++)
{
(LocalBuilder local, RAttribute attribute) = locals[index];
if ((registerInUse & (1u << attribute.Index)) != 0)
{
throw new InvalidSvcException($"Method \"{svcName}\" has conflicting output values at register index \"{attribute.Index}\".");
}
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldc_I4, attribute.Index);
generator.Emit(OpCodes.Ldloc, local);
ConvertToFieldType(local.LocalType);
MethodInfo info = typeof(IExecutionContext).GetMethod(nameof(IExecutionContext.SetX));
generator.Emit(OpCodes.Callvirt, info);
registerInUse |= 1u << attribute.Index;
}
// Zero out the remaining unused registers.
for (int i = 0; i < registerCleanCount; i++)
{
if ((registerInUse & (1u << i)) != 0)
{
continue;
}
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldc_I4, i);
generator.Emit(OpCodes.Ldc_I8, 0L);
MethodInfo info = typeof(IExecutionContext).GetMethod(nameof(IExecutionContext.SetX));
generator.Emit(OpCodes.Callvirt, info);
}
generator.Emit(OpCodes.Ret);
return method.CreateDelegate<Action<T, IExecutionContext>>();
}
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 PrintArguments(object[] argValues, string formatOrSvcName)
{
if (argValues != null)
{
Logger.Trace?.Print(LogClass.KernelSvc, string.Format(formatOrSvcName, argValues));
}
else
{
Logger.Trace?.Print(LogClass.KernelSvc, formatOrSvcName);
}
}
private static void PrintResult(KernelResult result, string svcName)
{
if (result != KernelResult.Success &&
result != KernelResult.TimedOut &&
result != KernelResult.Cancelled &&
result != KernelResult.PortRemoteClosed &&
result != KernelResult.InvalidState)
{
Logger.Warning?.Print(LogClass.KernelSvc, $"{svcName} returned error {result}.");
}
else
{
Logger.Trace?.Print(LogClass.KernelSvc, $"{svcName} returned result {result}.");
}
}
}
}

View File

@ -429,8 +429,6 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
Channel.PushHostCommandBuffer(CreateWaitCommandBuffer(header.Fence));
}
Channel.PushEntries(entries);
header.Fence.Id = _channelSyncpoint.Id;
if (header.Flags.HasFlag(SubmitGpfifoFlags.FenceIncrement) || header.Flags.HasFlag(SubmitGpfifoFlags.IncrementWithValue))
@ -449,6 +447,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
header.Fence.Value = _device.System.HostSyncpoint.ReadSyncpointMaxValue(header.Fence.Id);
}
Channel.PushEntries(entries);
if (header.Flags.HasFlag(SubmitGpfifoFlags.FenceIncrement))
{
Channel.PushHostCommandBuffer(CreateIncrementCommandBuffer(ref header.Fence, header.Flags));

View File

@ -11,6 +11,9 @@
<ProjectReference Include="..\Ryujinx.Graphics.Host1x\Ryujinx.Graphics.Host1x.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Nvdec\Ryujinx.Graphics.Nvdec.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Vic\Ryujinx.Graphics.Vic.csproj" />
<ProjectReference Include="..\Ryujinx.Horizon.Generators\Ryujinx.Horizon.Generators.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />
<ProjectReference Include="..\Ryujinx.Memory\Ryujinx.Memory.csproj" />
<ProjectReference Include="..\ARMeilleure\ARMeilleure.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj" />

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64</RuntimeIdentifiers>
<RuntimeIdentifiers>win10-x64;osx-x64;linux-x64</RuntimeIdentifiers>
<OutputType>Exe</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>1.0.0-dirty</Version>

View File

@ -0,0 +1,58 @@
using System.Text;
namespace Ryujinx.Horizon.Generators
{
class CodeGenerator
{
private const string Indent = " ";
private readonly StringBuilder _sb;
private string _currentIndent;
public CodeGenerator()
{
_sb = new StringBuilder();
}
public void EnterScope(string header = null)
{
if (header != null)
{
AppendLine(header);
}
AppendLine("{");
IncreaseIndentation();
}
public void LeaveScope()
{
DecreaseIndentation();
AppendLine("}");
}
public void IncreaseIndentation()
{
_currentIndent += Indent;
}
public void DecreaseIndentation()
{
_currentIndent = _currentIndent.Substring(0, _currentIndent.Length - Indent.Length);
}
public void AppendLine()
{
_sb.AppendLine();
}
public void AppendLine(string text)
{
_sb.AppendLine(_currentIndent + text);
}
public override string ToString()
{
return _sb.ToString();
}
}
}

View File

@ -0,0 +1,524 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System;
using System.Collections.Generic;
using System.Diagnostics;
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 TypeSvcAttribute = NamespaceKernel + ".SupervisorCall.SvcAttribute";
private const string TypePointerSizedAttribute = NamespaceKernel + ".SupervisorCall.PointerSizedAttribute";
private const string TypeKernelResultName = "KernelResult";
private const string TypeKernelResult = NamespaceKernel + ".Common." + TypeKernelResultName;
private const string TypeExecutionContext = "IExecutionContext";
private static readonly string[] _expectedResults = new string[]
{
$"{TypeKernelResultName}.Success",
$"{TypeKernelResultName}.TimedOut",
$"{TypeKernelResultName}.Cancelled",
$"{TypeKernelResultName}.PortRemoteClosed",
$"{TypeKernelResultName}.InvalidState"
};
private 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 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 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 (var attributeList in method.AttributeLists)
{
foreach (var attribute in attributeList.Attributes)
{
if (GetCanonicalTypeName(context.Compilation, attribute) != TypeSvcAttribute)
{
continue;
}
foreach (var attributeArg in attribute.ArgumentList.Arguments)
{
if (attributeArg.Expression.Kind() == SyntaxKind.NumericLiteralExpression)
{
LiteralExpressionSyntax numericLiteral = (LiteralExpressionSyntax)attributeArg.Expression;
syscalls.Add(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}({TypeKernelResultName} {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 returnTypeName = method.ReturnType.ToString();
string argsList = string.Join(", ", args);
int returnRegisterIndex = 0;
string result = null;
string canonicalReturnTypeName = null;
if (returnTypeName != "void")
{
generator.AppendLine($"var {ResultVariableName} = syscall.{method.Identifier.Text}({argsList});");
generator.AppendLine($"context.SetX({returnRegisterIndex++}, (uint){ResultVariableName});");
canonicalReturnTypeName = GetCanonicalTypeName(compilation, method.ReturnType);
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});");
generator.AppendLine($"context.SetX({returnRegisterIndex++}, (ulong){ResultVariableName});");
canonicalReturnTypeName = GetCanonicalTypeName(compilation, method.ReturnType);
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 + name[0].ToString().ToUpperInvariant() + 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 == TypeKernelResult)
{
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)
{
if (canonicalTargetTypeName == TypeSystemBoolean)
{
return $"({value} & 1) != 0";
}
return $"({targetTypeName}){value}";
}
private static bool IsPointerSized(Compilation compilation, ParameterSyntax parameterSyntax)
{
foreach (var attributeList in parameterSyntax.AttributeLists)
{
foreach (var attribute in attributeList.Attributes)
{
if (GetCanonicalTypeName(compilation, attribute) == TypePointerSizedAttribute)
{
return true;
}
}
}
return false;
}
public void Initialize(GeneratorInitializationContext context)
{
context.RegisterForSyntaxNotifications(() => new SyscallSyntaxReceiver());
}
}
}

View File

@ -0,0 +1,54 @@
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)
{
foreach (var attributeList in classDeclaration.AttributeLists)
{
if (attributeList.Attributes.Any(x => x.Name.GetText().ToString() == "SvcImpl"))
{
foreach (var memberDeclaration in classDeclaration.Members)
{
if (memberDeclaration is MethodDeclarationSyntax methodDeclaration)
{
VisitMethod(methodDeclaration);
}
}
break;
}
}
}
}
private void VisitMethod(MethodDeclarationSyntax methodDeclaration)
{
if (methodDeclaration.AttributeLists.Count != 0)
{
foreach (var attributeList in methodDeclaration.AttributeLists)
{
if (attributeList.Attributes.Any(x => x.Name.GetText().ToString() == "Svc"))
{
SvcImplementations.Add(methodDeclaration);
break;
}
}
}
}
}
}

View File

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.2.0" />
</ItemGroup>
</Project>

View File

@ -2,7 +2,6 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64</RuntimeIdentifiers>
<OutputType>Exe</OutputType>
<Configurations>Debug;Release</Configurations>
</PropertyGroup>

View File

@ -2,7 +2,6 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64</RuntimeIdentifiers>
<OutputType>Exe</OutputType>
<IsPackable>false</IsPackable>

View File

@ -70,7 +70,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmp
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Ava", "Ryujinx.Ava\Ryujinx.Ava.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Ui.Common", "Ryujinx.Ui.Common\Ryujinx.Ui.Common.csproj", "{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Ui.Common", "Ryujinx.Ui.Common\Ryujinx.Ui.Common.csproj", "{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Horizon.Generators", "Ryujinx.Horizon.Generators\Ryujinx.Horizon.Generators.csproj", "{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -206,6 +208,10 @@ Global
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Release|Any CPU.Build.0 = Release|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64</RuntimeIdentifiers>
<RuntimeIdentifiers>win10-x64;osx-x64;linux-x64</RuntimeIdentifiers>
<OutputType>Exe</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>1.0.0-dirty</Version>