Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
59490d54b5 | |||
e546e5933f | |||
0c87bf9ea4 | |||
9827dc35e1 | |||
448723d3b3 | |||
89294b7772 | |||
7b9c4757dd | |||
b8fc97adf2 | |||
c1a7b5bcdb | |||
be1c375589 | |||
378d19f87a | |||
f59f65ec4f |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -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
|
||||
|
7
.github/workflows/nightly_pr_comment.yml
vendored
7
.github/workflows/nightly_pr_comment.yml
vendored
@ -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;
|
||||
|
||||
|
18
.github/workflows/release.yml
vendored
18
.github/workflows/release.yml
vendored
@ -51,8 +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 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
|
||||
@ -60,7 +61,11 @@ jobs:
|
||||
popd
|
||||
|
||||
pushd publish_windows_sdl2_headless
|
||||
7z a ../release_output/ryujinx-headless-sdl2-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
|
||||
7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
|
||||
popd
|
||||
|
||||
pushd publish_windows_ava
|
||||
7z a ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
@ -68,6 +73,7 @@ jobs:
|
||||
run: |
|
||||
dotnet publish -c Release -r linux-x64 -o ./publish_linux/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 linux-x64 -o ./publish_linux_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 linux-x64 -o ./publish_linux_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 Linux builds
|
||||
run: |
|
||||
@ -76,7 +82,11 @@ jobs:
|
||||
popd
|
||||
|
||||
pushd publish_linux_sdl2_headless
|
||||
tar -czvf ../release_output/ryujinx-headless-sdl2-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
||||
tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
||||
popd
|
||||
|
||||
pushd publish_linux_ava
|
||||
tar -czvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
|
@ -33,13 +33,13 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
switch (GetPackedId(op))
|
||||
{
|
||||
case 0b11_011_0000_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)); break;
|
||||
case 0b11_011_0000_0000_111: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)); break;
|
||||
case 0b11_011_0100_0010_000: EmitGetNzcv(context); return;
|
||||
case 0b11_011_0100_0100_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcr)); break;
|
||||
case 0b11_011_0100_0100_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr)); break;
|
||||
case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)); break;
|
||||
case 0b11_011_1101_0000_011: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidr)); break;
|
||||
case 0b11_011_0000_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)); break;
|
||||
case 0b11_011_0000_0000_111: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)); break;
|
||||
case 0b11_011_0100_0010_000: EmitGetNzcv(context); return;
|
||||
case 0b11_011_0100_0100_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcr)); break;
|
||||
case 0b11_011_0100_0100_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr)); break;
|
||||
case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)); break;
|
||||
case 0b11_011_1101_0000_011: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0)); break;
|
||||
case 0b11_011_1110_0000_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)); break;
|
||||
case 0b11_011_1110_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0)); break;
|
||||
case 0b11_011_1110_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0)); break;
|
||||
|
@ -107,14 +107,14 @@ namespace ARMeilleure.Instructions
|
||||
return (uint)GetContext().TpidrEl0;
|
||||
}
|
||||
|
||||
public static ulong GetTpidr()
|
||||
public static ulong GetTpidrroEl0()
|
||||
{
|
||||
return (ulong)GetContext().Tpidr;
|
||||
return (ulong)GetContext().TpidrroEl0;
|
||||
}
|
||||
|
||||
public static uint GetTpidr32()
|
||||
{
|
||||
return (uint)GetContext().Tpidr;
|
||||
return (uint)GetContext().TpidrroEl0;
|
||||
}
|
||||
|
||||
public static ulong GetCntfrqEl0()
|
||||
|
5
ARMeilleure/State/ExceptionCallback.cs
Normal file
5
ARMeilleure/State/ExceptionCallback.cs
Normal file
@ -0,0 +1,5 @@
|
||||
namespace ARMeilleure.State
|
||||
{
|
||||
public delegate void ExceptionCallbackNoArgs(ExecutionContext context);
|
||||
public delegate void ExceptionCallback(ExecutionContext context, ulong address, int id);
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
using ARMeilleure.Memory;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace ARMeilleure.State
|
||||
{
|
||||
@ -14,34 +13,22 @@ namespace ARMeilleure.State
|
||||
|
||||
private bool _interrupted;
|
||||
|
||||
private static Stopwatch _tickCounter;
|
||||
private readonly ICounter _counter;
|
||||
|
||||
private static double _hostTickFreq;
|
||||
public ulong Pc => _nativeContext.GetPc();
|
||||
|
||||
public uint CtrEl0 => 0x8444c004;
|
||||
public uint CtrEl0 => 0x8444c004;
|
||||
public uint DczidEl0 => 0x00000004;
|
||||
|
||||
public ulong CntfrqEl0 { get; set; }
|
||||
public ulong CntpctEl0
|
||||
{
|
||||
get
|
||||
{
|
||||
double ticks = _tickCounter.ElapsedTicks * _hostTickFreq;
|
||||
|
||||
return (ulong)(ticks * CntfrqEl0);
|
||||
}
|
||||
}
|
||||
public ulong CntfrqEl0 => _counter.Frequency;
|
||||
public ulong CntpctEl0 => _counter.Counter;
|
||||
|
||||
// CNTVCT_EL0 = CNTPCT_EL0 - CNTVOFF_EL2
|
||||
// Since EL2 isn't implemented, CNTVOFF_EL2 = 0
|
||||
public ulong CntvctEl0 => CntpctEl0;
|
||||
|
||||
public static TimeSpan ElapsedTime => _tickCounter.Elapsed;
|
||||
public static long ElapsedTicks => _tickCounter.ElapsedTicks;
|
||||
public static double TickFrequency => _hostTickFreq;
|
||||
|
||||
public long TpidrEl0 { get; set; }
|
||||
public long Tpidr { get; set; }
|
||||
public long TpidrroEl0 { get; set; }
|
||||
|
||||
public uint Pstate
|
||||
{
|
||||
@ -78,35 +65,38 @@ namespace ARMeilleure.State
|
||||
private set => _nativeContext.SetRunning(value);
|
||||
}
|
||||
|
||||
public event EventHandler<EventArgs> Interrupt;
|
||||
public event EventHandler<InstExceptionEventArgs> Break;
|
||||
public event EventHandler<InstExceptionEventArgs> SupervisorCall;
|
||||
public event EventHandler<InstUndefinedEventArgs> Undefined;
|
||||
private readonly ExceptionCallbackNoArgs _interruptCallback;
|
||||
private readonly ExceptionCallback _breakCallback;
|
||||
private readonly ExceptionCallback _supervisorCallback;
|
||||
private readonly ExceptionCallback _undefinedCallback;
|
||||
|
||||
static ExecutionContext()
|
||||
{
|
||||
_hostTickFreq = 1.0 / Stopwatch.Frequency;
|
||||
|
||||
_tickCounter = new Stopwatch();
|
||||
_tickCounter.Start();
|
||||
}
|
||||
|
||||
public ExecutionContext(IJitMemoryAllocator allocator)
|
||||
public ExecutionContext(
|
||||
IJitMemoryAllocator allocator,
|
||||
ICounter counter,
|
||||
ExceptionCallbackNoArgs interruptCallback = null,
|
||||
ExceptionCallback breakCallback = null,
|
||||
ExceptionCallback supervisorCallback = null,
|
||||
ExceptionCallback undefinedCallback = null)
|
||||
{
|
||||
_nativeContext = new NativeContext(allocator);
|
||||
_counter = counter;
|
||||
_interruptCallback = interruptCallback;
|
||||
_breakCallback = breakCallback;
|
||||
_supervisorCallback = supervisorCallback;
|
||||
_undefinedCallback = undefinedCallback;
|
||||
|
||||
Running = true;
|
||||
|
||||
_nativeContext.SetCounter(MinCountForCheck);
|
||||
}
|
||||
|
||||
public ulong GetX(int index) => _nativeContext.GetX(index);
|
||||
public void SetX(int index, ulong value) => _nativeContext.SetX(index, value);
|
||||
public ulong GetX(int index) => _nativeContext.GetX(index);
|
||||
public void SetX(int index, ulong value) => _nativeContext.SetX(index, value);
|
||||
|
||||
public V128 GetV(int index) => _nativeContext.GetV(index);
|
||||
public V128 GetV(int index) => _nativeContext.GetV(index);
|
||||
public void SetV(int index, V128 value) => _nativeContext.SetV(index, value);
|
||||
|
||||
public bool GetPstateFlag(PState flag) => _nativeContext.GetPstateFlag(flag);
|
||||
public bool GetPstateFlag(PState flag) => _nativeContext.GetPstateFlag(flag);
|
||||
public void SetPstateFlag(PState flag, bool value) => _nativeContext.SetPstateFlag(flag, value);
|
||||
|
||||
public bool GetFPstateFlag(FPState flag) => _nativeContext.GetFPStateFlag(flag);
|
||||
@ -118,7 +108,7 @@ namespace ARMeilleure.State
|
||||
{
|
||||
_interrupted = false;
|
||||
|
||||
Interrupt?.Invoke(this, EventArgs.Empty);
|
||||
_interruptCallback?.Invoke(this);
|
||||
}
|
||||
|
||||
_nativeContext.SetCounter(MinCountForCheck);
|
||||
@ -131,17 +121,17 @@ namespace ARMeilleure.State
|
||||
|
||||
internal void OnBreak(ulong address, int imm)
|
||||
{
|
||||
Break?.Invoke(this, new InstExceptionEventArgs(address, imm));
|
||||
_breakCallback?.Invoke(this, address, imm);
|
||||
}
|
||||
|
||||
internal void OnSupervisorCall(ulong address, int imm)
|
||||
{
|
||||
SupervisorCall?.Invoke(this, new InstExceptionEventArgs(address, imm));
|
||||
_supervisorCallback?.Invoke(this, address, imm);
|
||||
}
|
||||
|
||||
internal void OnUndefined(ulong address, int opCode)
|
||||
{
|
||||
Undefined?.Invoke(this, new InstUndefinedEventArgs(address, opCode));
|
||||
_undefinedCallback?.Invoke(this, address, opCode);
|
||||
}
|
||||
|
||||
public void StopRunning()
|
||||
@ -151,16 +141,6 @@ namespace ARMeilleure.State
|
||||
_nativeContext.SetCounter(0);
|
||||
}
|
||||
|
||||
public static void SuspendCounter()
|
||||
{
|
||||
_tickCounter.Stop();
|
||||
}
|
||||
|
||||
public static void ResumeCounter()
|
||||
{
|
||||
_tickCounter.Start();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_nativeContext.Dispose();
|
||||
|
18
ARMeilleure/State/ICounter.cs
Normal file
18
ARMeilleure/State/ICounter.cs
Normal file
@ -0,0 +1,18 @@
|
||||
namespace ARMeilleure.State
|
||||
{
|
||||
/// <summary>
|
||||
/// CPU Counter interface.
|
||||
/// </summary>
|
||||
public interface ICounter
|
||||
{
|
||||
/// <summary>
|
||||
/// Counter frequency in Hertz.
|
||||
/// </summary>
|
||||
ulong Frequency { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Current counter value.
|
||||
/// </summary>
|
||||
ulong Counter { get; }
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace ARMeilleure.State
|
||||
{
|
||||
public class InstExceptionEventArgs : EventArgs
|
||||
{
|
||||
public ulong Address { get; }
|
||||
public int Id { get; }
|
||||
|
||||
public InstExceptionEventArgs(ulong address, int id)
|
||||
{
|
||||
Address = address;
|
||||
Id = id;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace ARMeilleure.State
|
||||
{
|
||||
public class InstUndefinedEventArgs : EventArgs
|
||||
{
|
||||
public ulong Address { get; }
|
||||
public int OpCode { get; }
|
||||
|
||||
public InstUndefinedEventArgs(ulong address, int opCode)
|
||||
{
|
||||
Address = address;
|
||||
OpCode = opCode;
|
||||
}
|
||||
}
|
||||
}
|
@ -34,6 +34,12 @@ namespace ARMeilleure.State
|
||||
GetStorage().ExclusiveAddress = ulong.MaxValue;
|
||||
}
|
||||
|
||||
public ulong GetPc()
|
||||
{
|
||||
// TODO: More precise tracking of PC value.
|
||||
return GetStorage().DispatchAddress;
|
||||
}
|
||||
|
||||
public unsafe ulong GetX(int index)
|
||||
{
|
||||
if ((uint)index >= RegisterConsts.IntRegsCount)
|
||||
|
@ -115,7 +115,7 @@ namespace ARMeilleure.Translation
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidr)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidr32))); // A32 only.
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl032))); // A32 only.
|
||||
|
@ -27,7 +27,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||
|
||||
private const uint InternalVersion = 3267; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
private const uint InternalVersion = 3362; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
|
||||
private const string ActualDir = "0";
|
||||
private const string BackupDir = "1";
|
||||
|
@ -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>
|
||||
|
@ -523,9 +523,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
private ulong GetSystemTicks()
|
||||
{
|
||||
double ticks = ARMeilleure.State.ExecutionContext.ElapsedTicks * ARMeilleure.State.ExecutionContext.TickFrequency;
|
||||
|
||||
return (ulong)(ticks * Constants.TargetTimerFrequency);
|
||||
return (ulong)(_manager.TickSource.ElapsedSeconds * Constants.TargetTimerFrequency);
|
||||
}
|
||||
|
||||
private uint ComputeVoiceDrop(CommandBuffer commandBuffer, long voicesEstimatedTime, long deltaTimeDsp)
|
||||
|
@ -19,6 +19,7 @@ using Ryujinx.Audio.Integration;
|
||||
using Ryujinx.Audio.Renderer.Dsp;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
@ -77,6 +78,11 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
/// </summary>
|
||||
private IHardwareDeviceDriver _deviceDriver;
|
||||
|
||||
/// <summary>
|
||||
/// Tick source used to measure elapsed time.
|
||||
/// </summary>
|
||||
public ITickSource TickSource { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="AudioProcessor"/> instance associated to this manager.
|
||||
/// </summary>
|
||||
@ -90,9 +96,11 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
/// <summary>
|
||||
/// Create a new <see cref="AudioRendererManager"/>.
|
||||
/// </summary>
|
||||
public AudioRendererManager()
|
||||
/// <param name="tickSource">Tick source used to measure elapsed time.</param>
|
||||
public AudioRendererManager(ITickSource tickSource)
|
||||
{
|
||||
Processor = new AudioProcessor();
|
||||
TickSource = tickSource;
|
||||
_sessionIds = new int[Constants.AudioRendererSessionCountMax];
|
||||
_sessions = new AudioRenderSystem[Constants.AudioRendererSessionCountMax];
|
||||
_activeSessionCount = 0;
|
||||
|
@ -177,7 +177,7 @@ namespace Ryujinx.Ava
|
||||
{
|
||||
if (_renderer != null)
|
||||
{
|
||||
double scale = Program.WindowScaleFactor;
|
||||
double scale = _parent.PlatformImpl.RenderScaling;
|
||||
_renderer.Window.SetSize((int)(size.Width * scale), (int)(size.Height * scale));
|
||||
}
|
||||
}
|
||||
@ -809,7 +809,7 @@ namespace Ryujinx.Ava
|
||||
Width = (int)Renderer.Bounds.Width;
|
||||
Height = (int)Renderer.Bounds.Height;
|
||||
|
||||
_renderer.Window.SetSize((int)(Width * Program.WindowScaleFactor), (int)(Height * Program.WindowScaleFactor));
|
||||
_renderer.Window.SetSize((int)(Width * _parent.PlatformImpl.RenderScaling), (int)(Height * _parent.PlatformImpl.RenderScaling));
|
||||
|
||||
Device.Gpu.Renderer.RunLoop(() =>
|
||||
{
|
||||
|
@ -98,7 +98,7 @@ namespace Ryujinx.Modules
|
||||
string assetState = (string)asset["state"];
|
||||
string downloadURL = (string)asset["browser_download_url"];
|
||||
|
||||
if (assetName.StartsWith("ava-ryujinx") && assetName.EndsWith(_platformExt))
|
||||
if (assetName.StartsWith("test-ava-ryujinx") && assetName.EndsWith(_platformExt))
|
||||
{
|
||||
_buildUrl = downloadURL;
|
||||
|
||||
|
@ -137,7 +137,6 @@ namespace Ryujinx.Ava
|
||||
}
|
||||
|
||||
// Make process DPI aware for proper window sizing on high-res screens.
|
||||
ForceDpiAware.Windows();
|
||||
WindowScaleFactor = ForceDpiAware.GetWindowScaleFactor();
|
||||
|
||||
// Delete backup files after updating.
|
||||
|
@ -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>
|
||||
|
@ -73,10 +73,13 @@ namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
SizeChanged?.Invoke(this, rect.Size);
|
||||
|
||||
RenderSize = rect.Size * Program.WindowScaleFactor;
|
||||
if (!rect.IsEmpty)
|
||||
{
|
||||
RenderSize = rect.Size * VisualRoot.RenderScaling;
|
||||
|
||||
_glDrawOperation?.Dispose();
|
||||
_glDrawOperation = new GlDrawOperation(this);
|
||||
_glDrawOperation?.Dispose();
|
||||
_glDrawOperation = new GlDrawOperation(this);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Render(DrawingContext context)
|
||||
|
@ -123,10 +123,6 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
CheckLaunchState();
|
||||
}
|
||||
|
||||
if (OperatingSystem.IsLinux())
|
||||
{
|
||||
Program.WindowScaleFactor = this.PlatformImpl.RenderScaling;
|
||||
}
|
||||
_rendererWaitEvent = new AutoResetEvent(false);
|
||||
}
|
||||
|
||||
|
64
Ryujinx.Cpu/ExceptionCallbacks.cs
Normal file
64
Ryujinx.Cpu/ExceptionCallbacks.cs
Normal file
@ -0,0 +1,64 @@
|
||||
namespace Ryujinx.Cpu
|
||||
{
|
||||
/// <summary>
|
||||
/// Exception callback without any additional arguments.
|
||||
/// </summary>
|
||||
/// <param name="context">Context for the thread where the exception was triggered</param>
|
||||
public delegate void ExceptionCallbackNoArgs(IExecutionContext context);
|
||||
|
||||
/// <summary>
|
||||
/// Exception callback.
|
||||
/// </summary>
|
||||
/// <param name="context">Context for the thread where the exception was triggered</param>
|
||||
/// <param name="address">Address of the instruction that caused the exception</param>
|
||||
/// <param name="imm">Immediate value of the instruction that caused the exception, or for undefined instruction, the instruction itself</param>
|
||||
public delegate void ExceptionCallback(IExecutionContext context, ulong address, int imm);
|
||||
|
||||
/// <summary>
|
||||
/// Stores handlers for the various CPU exceptions.
|
||||
/// </summary>
|
||||
public struct ExceptionCallbacks
|
||||
{
|
||||
/// <summary>
|
||||
/// Handler for CPU interrupts triggered using <see cref="IExecutionContext.RequestInterrupt"/>.
|
||||
/// </summary>
|
||||
public readonly ExceptionCallbackNoArgs InterruptCallback;
|
||||
|
||||
/// <summary>
|
||||
/// Handler for CPU software interrupts caused by the Arm BRK instruction.
|
||||
/// </summary>
|
||||
public readonly ExceptionCallback BreakCallback;
|
||||
|
||||
/// <summary>
|
||||
/// Handler for CPU software interrupts caused by the Arm SVC instruction.
|
||||
/// </summary>
|
||||
public readonly ExceptionCallback SupervisorCallback;
|
||||
|
||||
/// <summary>
|
||||
/// Handler for CPU software interrupts caused by any undefined Arm instruction.
|
||||
/// </summary>
|
||||
public readonly ExceptionCallback UndefinedCallback;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new exception callbacks structure.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// All handlers are optional, and if null, the CPU will just continue executing as if nothing happened.
|
||||
/// </remarks>
|
||||
/// <param name="interruptCallback">Handler for CPU interrupts triggered using <see cref="IExecutionContext.RequestInterrupt"/></param>
|
||||
/// <param name="breakCallback">Handler for CPU software interrupts caused by the Arm BRK instruction</param>
|
||||
/// <param name="supervisorCallback">Handler for CPU software interrupts caused by the Arm SVC instruction</param>
|
||||
/// <param name="undefinedCallback">Handler for CPU software interrupts caused by any undefined Arm instruction</param>
|
||||
public ExceptionCallbacks(
|
||||
ExceptionCallbackNoArgs interruptCallback = null,
|
||||
ExceptionCallback breakCallback = null,
|
||||
ExceptionCallback supervisorCallback = null,
|
||||
ExceptionCallback undefinedCallback = null)
|
||||
{
|
||||
InterruptCallback = interruptCallback;
|
||||
BreakCallback = breakCallback;
|
||||
SupervisorCallback = supervisorCallback;
|
||||
UndefinedCallback = undefinedCallback;
|
||||
}
|
||||
}
|
||||
}
|
39
Ryujinx.Cpu/ICpuContext.cs
Normal file
39
Ryujinx.Cpu/ICpuContext.cs
Normal file
@ -0,0 +1,39 @@
|
||||
namespace Ryujinx.Cpu
|
||||
{
|
||||
/// <summary>
|
||||
/// CPU context interface.
|
||||
/// </summary>
|
||||
public interface ICpuContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new execution context that will store thread CPU register state when executing guest code.
|
||||
/// </summary>
|
||||
/// <param name="exceptionCallbacks">Optional functions to be called when the CPU receives an interrupt</param>
|
||||
/// <returns>Execution context</returns>
|
||||
IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks);
|
||||
|
||||
/// <summary>
|
||||
/// Starts executing code at a specified entry point address.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This function only returns when the execution is stopped, by calling <see cref="IExecutionContext.StopRunning"/>.
|
||||
/// </remarks>
|
||||
/// <param name="context">Execution context to be used for this run</param>
|
||||
/// <param name="address">Entry point address</param>
|
||||
void Execute(IExecutionContext context, ulong address);
|
||||
|
||||
/// <summary>
|
||||
/// Invalidates the instruction cache for a given memory region.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This should be called if code is modified to make the CPU emulator aware of the modifications,
|
||||
/// otherwise it might run stale code which will lead to errors and crashes.
|
||||
/// Calling this function is not necessary if the code memory was modified by guest code,
|
||||
/// as the expectation is that it will do it on its own using the appropriate cache invalidation instructions,
|
||||
/// except on Arm32 where those instructions can't be used in unprivileged mode.
|
||||
/// </remarks>
|
||||
/// <param name="address">Address of the region to be invalidated</param>
|
||||
/// <param name="size">Size of the region to be invalidated</param>
|
||||
void InvalidateCacheRegion(ulong address, ulong size);
|
||||
}
|
||||
}
|
18
Ryujinx.Cpu/ICpuEngine.cs
Normal file
18
Ryujinx.Cpu/ICpuEngine.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using ARMeilleure.Memory;
|
||||
|
||||
namespace Ryujinx.Cpu
|
||||
{
|
||||
/// <summary>
|
||||
/// CPU execution engine interface.
|
||||
/// </summary>
|
||||
public interface ICpuEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new CPU context that can be used to run code for multiple threads sharing an address space.
|
||||
/// </summary>
|
||||
/// <param name="memoryManager">Memory manager for the address space of the context</param>
|
||||
/// <param name="for64Bit">Indicates if the context will be used to run 64-bit or 32-bit Arm code</param>
|
||||
/// <returns>CPU context</returns>
|
||||
ICpuContext CreateCpuContext(IMemoryManager memoryManager, bool for64Bit);
|
||||
}
|
||||
}
|
112
Ryujinx.Cpu/IExecutionContext.cs
Normal file
112
Ryujinx.Cpu/IExecutionContext.cs
Normal file
@ -0,0 +1,112 @@
|
||||
using ARMeilleure.State;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Cpu
|
||||
{
|
||||
/// <summary>
|
||||
/// CPU register state interface.
|
||||
/// </summary>
|
||||
public interface IExecutionContext : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Current Program Counter.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// In some implementations, this value might not be accurate and might not point to the last instruction executed.
|
||||
/// </remarks>
|
||||
ulong Pc { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Thread ID Register (EL0).
|
||||
/// </summary>
|
||||
long TpidrEl0 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Thread ID Register (read-only) (EL0).
|
||||
/// </summary>
|
||||
long TpidrroEl0 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Processor State register.
|
||||
/// </summary>
|
||||
uint Pstate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Floating-point Control Register.
|
||||
/// </summary>
|
||||
uint Fpcr { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Floating-point Status Register.
|
||||
/// </summary>
|
||||
uint Fpsr { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whenever the CPU is running 64-bit (AArch64 mode) or 32-bit (AArch32 mode) code.
|
||||
/// </summary>
|
||||
bool IsAarch32 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whenever the CPU is still running code.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Even if this is false, the guest code might be still exiting.
|
||||
/// One must not assume that the code is no longer running from this property alone.
|
||||
/// </remarks>
|
||||
bool Running { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of a general purpose register.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The special <paramref name="index"/> of 31 can be used to access the SP (Stack Pointer) register.
|
||||
/// </remarks>
|
||||
/// <param name="index">Index of the register, in the range 0-31 (inclusive)</param>
|
||||
/// <returns>The register value</returns>
|
||||
ulong GetX(int index);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value of a general purpose register.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The special <paramref name="index"/> of 31 can be used to access the SP (Stack Pointer) register.
|
||||
/// </remarks>
|
||||
/// <param name="index">Index of the register, in the range 0-31 (inclusive)</param>
|
||||
/// <param name="value">Value to be set</param>
|
||||
void SetX(int index, ulong value);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of a FP/SIMD register.
|
||||
/// </summary>
|
||||
/// <param name="index">Index of the register, in the range 0-31 (inclusive)</param>
|
||||
/// <returns>The register value</returns>
|
||||
V128 GetV(int index);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value of a FP/SIMD register.
|
||||
/// </summary>
|
||||
/// <param name="index">Index of the register, in the range 0-31 (inclusive)</param>
|
||||
/// <param name="value">Value to be set</param>
|
||||
void SetV(int index, V128 value);
|
||||
|
||||
/// <summary>
|
||||
/// Requests the thread to stop running temporarily and call <see cref="ExceptionCallbacks.InterruptCallback"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The thread might not pause immediately.
|
||||
/// One must not assume that guest code is no longer being executed by the thread after calling this function.
|
||||
/// </remarks>
|
||||
void RequestInterrupt();
|
||||
|
||||
/// <summary>
|
||||
/// Requests the thread to stop running guest code and return as soon as possible.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The thread might not stop immediately.
|
||||
/// One must not assume that guest code is no longer being executed by the thread after calling this function.
|
||||
/// After a thread has been stopped, it can't be restarted with the same <see cref="IExecutionContext"/>.
|
||||
/// If you only need to pause the thread temporarily, use <see cref="RequestInterrupt"/> instead.
|
||||
/// </remarks>
|
||||
void StopRunning();
|
||||
}
|
||||
}
|
31
Ryujinx.Cpu/ITickSource.cs
Normal file
31
Ryujinx.Cpu/ITickSource.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using ARMeilleure.State;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Cpu
|
||||
{
|
||||
/// <summary>
|
||||
/// Tick source interface.
|
||||
/// </summary>
|
||||
public interface ITickSource : ICounter
|
||||
{
|
||||
/// <summary>
|
||||
/// Time elapsed since the counter was created.
|
||||
/// </summary>
|
||||
TimeSpan ElapsedTime { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Time elapsed since the counter was created, in seconds.
|
||||
/// </summary>
|
||||
double ElapsedSeconds { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Stops counting.
|
||||
/// </summary>
|
||||
void Suspend();
|
||||
|
||||
/// <summary>
|
||||
/// Resumes counting after a call to <see cref="Suspend"/>.
|
||||
/// </summary>
|
||||
void Resume();
|
||||
}
|
||||
}
|
41
Ryujinx.Cpu/Jit/JitCpuContext.cs
Normal file
41
Ryujinx.Cpu/Jit/JitCpuContext.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.Translation;
|
||||
|
||||
namespace Ryujinx.Cpu.Jit
|
||||
{
|
||||
class JitCpuContext : ICpuContext
|
||||
{
|
||||
private readonly ITickSource _tickSource;
|
||||
private readonly Translator _translator;
|
||||
|
||||
public JitCpuContext(ITickSource tickSource, IMemoryManager memory, bool for64Bit)
|
||||
{
|
||||
_tickSource = tickSource;
|
||||
_translator = new Translator(new JitMemoryAllocator(), memory, for64Bit);
|
||||
memory.UnmapEvent += UnmapHandler;
|
||||
}
|
||||
|
||||
private void UnmapHandler(ulong address, ulong size)
|
||||
{
|
||||
_translator.InvalidateJitCacheRegion(address, size);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks)
|
||||
{
|
||||
return new JitExecutionContext(new JitMemoryAllocator(), _tickSource, exceptionCallbacks);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Execute(IExecutionContext context, ulong address)
|
||||
{
|
||||
_translator.Execute(((JitExecutionContext)context).Impl, address);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void InvalidateCacheRegion(ulong address, ulong size)
|
||||
{
|
||||
_translator.InvalidateJitCacheRegion(address, size);
|
||||
}
|
||||
}
|
||||
}
|
20
Ryujinx.Cpu/Jit/JitEngine.cs
Normal file
20
Ryujinx.Cpu/Jit/JitEngine.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using ARMeilleure.Memory;
|
||||
|
||||
namespace Ryujinx.Cpu.Jit
|
||||
{
|
||||
public class JitEngine : ICpuEngine
|
||||
{
|
||||
private readonly ITickSource _tickSource;
|
||||
|
||||
public JitEngine(ITickSource tickSource)
|
||||
{
|
||||
_tickSource = tickSource;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ICpuContext CreateCpuContext(IMemoryManager memoryManager, bool for64Bit)
|
||||
{
|
||||
return new JitCpuContext(_tickSource, memoryManager, for64Bit);
|
||||
}
|
||||
}
|
||||
}
|
123
Ryujinx.Cpu/Jit/JitExecutionContext.cs
Normal file
123
Ryujinx.Cpu/Jit/JitExecutionContext.cs
Normal file
@ -0,0 +1,123 @@
|
||||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.State;
|
||||
|
||||
namespace Ryujinx.Cpu.Jit
|
||||
{
|
||||
class JitExecutionContext : IExecutionContext
|
||||
{
|
||||
private readonly ExecutionContext _impl;
|
||||
internal ExecutionContext Impl => _impl;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ulong Pc => _impl.Pc;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public long TpidrEl0
|
||||
{
|
||||
get => _impl.TpidrEl0;
|
||||
set => _impl.TpidrEl0 = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public long TpidrroEl0
|
||||
{
|
||||
get => _impl.TpidrroEl0;
|
||||
set => _impl.TpidrroEl0 = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public uint Pstate
|
||||
{
|
||||
get => _impl.Pstate;
|
||||
set => _impl.Pstate = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public uint Fpcr
|
||||
{
|
||||
get => (uint)_impl.Fpcr;
|
||||
set => _impl.Fpcr = (FPCR)value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public uint Fpsr
|
||||
{
|
||||
get => (uint)_impl.Fpsr;
|
||||
set => _impl.Fpsr = (FPSR)value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsAarch32
|
||||
{
|
||||
get => _impl.IsAarch32;
|
||||
set => _impl.IsAarch32 = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Running => _impl.Running;
|
||||
|
||||
private readonly ExceptionCallbacks _exceptionCallbacks;
|
||||
|
||||
public JitExecutionContext(IJitMemoryAllocator allocator, ICounter counter, ExceptionCallbacks exceptionCallbacks)
|
||||
{
|
||||
_impl = new ExecutionContext(
|
||||
allocator,
|
||||
counter,
|
||||
InterruptHandler,
|
||||
BreakHandler,
|
||||
SupervisorCallHandler,
|
||||
UndefinedHandler);
|
||||
|
||||
_exceptionCallbacks = exceptionCallbacks;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ulong GetX(int index) => _impl.GetX(index);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void SetX(int index, ulong value) => _impl.SetX(index, value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public V128 GetV(int index) => _impl.GetV(index);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void SetV(int index, V128 value) => _impl.SetV(index, value);
|
||||
|
||||
private void InterruptHandler(ExecutionContext context)
|
||||
{
|
||||
_exceptionCallbacks.InterruptCallback?.Invoke(this);
|
||||
}
|
||||
|
||||
private void BreakHandler(ExecutionContext context, ulong address, int imm)
|
||||
{
|
||||
_exceptionCallbacks.BreakCallback?.Invoke(this, address, imm);
|
||||
}
|
||||
|
||||
private void SupervisorCallHandler(ExecutionContext context, ulong address, int imm)
|
||||
{
|
||||
_exceptionCallbacks.SupervisorCallback?.Invoke(this, address, imm);
|
||||
}
|
||||
|
||||
private void UndefinedHandler(ExecutionContext context, ulong address, int opCode)
|
||||
{
|
||||
_exceptionCallbacks.UndefinedCallback?.Invoke(this, address, opCode);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RequestInterrupt()
|
||||
{
|
||||
_impl.RequestInterrupt();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void StopRunning()
|
||||
{
|
||||
_impl.StopRunning();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_impl.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
using ARMeilleure.Memory;
|
||||
using Ryujinx.Memory;
|
||||
|
||||
namespace Ryujinx.Cpu
|
||||
namespace Ryujinx.Cpu.Jit
|
||||
{
|
||||
class JitMemoryAllocator : IJitMemoryAllocator
|
||||
public class JitMemoryAllocator : IJitMemoryAllocator
|
||||
{
|
||||
public IJitMemoryBlock Allocate(ulong size) => new JitMemoryBlock(size, MemoryAllocationFlags.None);
|
||||
public IJitMemoryBlock Reserve(ulong size) => new JitMemoryBlock(size, MemoryAllocationFlags.Reserve);
|
@ -2,9 +2,9 @@
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Cpu
|
||||
namespace Ryujinx.Cpu.Jit
|
||||
{
|
||||
class JitMemoryBlock : IJitMemoryBlock
|
||||
public class JitMemoryBlock : IJitMemoryBlock
|
||||
{
|
||||
private readonly MemoryBlock _impl;
|
||||
|
@ -10,7 +10,7 @@ using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.Cpu
|
||||
namespace Ryujinx.Cpu.Jit
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a CPU memory manager.
|
@ -8,12 +8,12 @@ using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.Cpu
|
||||
namespace Ryujinx.Cpu.Jit
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a CPU memory manager which maps guest virtual memory directly onto a host virtual region.
|
||||
/// </summary>
|
||||
public class MemoryManagerHostMapped : MemoryManagerBase, IMemoryManager, IVirtualMemoryManagerTracked, IWritableBlock
|
||||
public sealed class MemoryManagerHostMapped : MemoryManagerBase, IMemoryManager, IVirtualMemoryManagerTracked, IWritableBlock
|
||||
{
|
||||
public const int PageBits = 12;
|
||||
public const int PageSize = 1 << PageBits;
|
45
Ryujinx.Cpu/TickSource.cs
Normal file
45
Ryujinx.Cpu/TickSource.cs
Normal file
@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Ryujinx.Cpu
|
||||
{
|
||||
public class TickSource : ITickSource
|
||||
{
|
||||
private static Stopwatch _tickCounter;
|
||||
|
||||
private static double _hostTickFreq;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ulong Frequency { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ulong Counter => (ulong)(ElapsedSeconds * Frequency);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public TimeSpan ElapsedTime => _tickCounter.Elapsed;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public double ElapsedSeconds => _tickCounter.ElapsedTicks * _hostTickFreq;
|
||||
|
||||
public TickSource(ulong frequency)
|
||||
{
|
||||
Frequency = frequency;
|
||||
_hostTickFreq = 1.0 / Stopwatch.Frequency;
|
||||
|
||||
_tickCounter = new Stopwatch();
|
||||
_tickCounter.Start();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Suspend()
|
||||
{
|
||||
_tickCounter.Stop();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Resume()
|
||||
{
|
||||
_tickCounter.Start();
|
||||
}
|
||||
}
|
||||
}
|
@ -280,13 +280,6 @@ namespace Ryujinx.HLE.HOS
|
||||
return;
|
||||
}
|
||||
|
||||
if (mainNca == null)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Loader, "Unable to load NSP: Could not find Main NCA");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (mainNca != null)
|
||||
{
|
||||
_device.Configuration.ContentManager.ClearAocData();
|
||||
@ -298,7 +291,7 @@ namespace Ryujinx.HLE.HOS
|
||||
}
|
||||
|
||||
// This is not a normal NSP, it's actually a ExeFS as a NSP
|
||||
LoadExeFs(nsp);
|
||||
LoadExeFs(nsp, null, isHomebrew: true);
|
||||
}
|
||||
|
||||
public void LoadNca(string ncaFile)
|
||||
@ -593,7 +586,7 @@ namespace Ryujinx.HLE.HOS
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadExeFs(IFileSystem codeFs, MetaLoader metaData = null)
|
||||
private void LoadExeFs(IFileSystem codeFs, MetaLoader metaData = null, bool isHomebrew = false)
|
||||
{
|
||||
if (_device.Configuration.VirtualFileSystem.ModLoader.ReplaceExefsPartition(TitleId, ref codeFs))
|
||||
{
|
||||
@ -661,7 +654,7 @@ namespace Ryujinx.HLE.HOS
|
||||
Ptc.Initialize(TitleIdText, DisplayVersion, usePtc, memoryManagerMode);
|
||||
|
||||
// We allow it for nx-hbloader because it can be used to launch homebrew.
|
||||
bool allowCodeMemoryForJit = TitleId == 0x010000000000100DUL;
|
||||
bool allowCodeMemoryForJit = TitleId == 0x010000000000100DUL || isHomebrew;
|
||||
|
||||
metaData.GetNpdm(out Npdm npdm).ThrowIfFailure();
|
||||
ProgramInfo programInfo = new ProgramInfo(in npdm, allowCodeMemoryForJit);
|
||||
|
@ -1,5 +1,4 @@
|
||||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.State;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Graphics.Gpu;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
@ -11,12 +10,12 @@ namespace Ryujinx.HLE.HOS
|
||||
{
|
||||
private readonly ulong _pid;
|
||||
private readonly GpuContext _gpuContext;
|
||||
private readonly CpuContext _cpuContext;
|
||||
private readonly ICpuContext _cpuContext;
|
||||
private T _memoryManager;
|
||||
|
||||
public IVirtualMemoryManager AddressSpace => _memoryManager;
|
||||
|
||||
public ArmProcessContext(ulong pid, GpuContext gpuContext, T memoryManager, bool for64Bit)
|
||||
public ArmProcessContext(ulong pid, ICpuEngine cpuEngine, GpuContext gpuContext, T memoryManager, bool for64Bit)
|
||||
{
|
||||
if (memoryManager is IRefCounted rc)
|
||||
{
|
||||
@ -27,11 +26,16 @@ namespace Ryujinx.HLE.HOS
|
||||
|
||||
_pid = pid;
|
||||
_gpuContext = gpuContext;
|
||||
_cpuContext = new CpuContext(memoryManager, for64Bit);
|
||||
_cpuContext = cpuEngine.CreateCpuContext(memoryManager, for64Bit);
|
||||
_memoryManager = memoryManager;
|
||||
}
|
||||
|
||||
public void Execute(ExecutionContext context, ulong codeAddress)
|
||||
public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks)
|
||||
{
|
||||
return _cpuContext.CreateExecutionContext(exceptionCallbacks);
|
||||
}
|
||||
|
||||
public void Execute(IExecutionContext context, ulong codeAddress)
|
||||
{
|
||||
_cpuContext.Execute(context, codeAddress);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Cpu.Jit;
|
||||
using Ryujinx.Graphics.Gpu;
|
||||
using Ryujinx.HLE.HOS.Kernel;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
@ -10,10 +11,12 @@ namespace Ryujinx.HLE.HOS
|
||||
{
|
||||
class ArmProcessContextFactory : IProcessContextFactory
|
||||
{
|
||||
private readonly ICpuEngine _cpuEngine;
|
||||
private readonly GpuContext _gpu;
|
||||
|
||||
public ArmProcessContextFactory(GpuContext gpu)
|
||||
public ArmProcessContextFactory(ICpuEngine cpuEngine, GpuContext gpu)
|
||||
{
|
||||
_cpuEngine = cpuEngine;
|
||||
_gpu = gpu;
|
||||
}
|
||||
|
||||
@ -29,12 +32,14 @@ namespace Ryujinx.HLE.HOS
|
||||
switch (mode)
|
||||
{
|
||||
case MemoryManagerMode.SoftwarePageTable:
|
||||
return new ArmProcessContext<MemoryManager>(pid, _gpu, new MemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler), for64Bit);
|
||||
var memoryManager = new MemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler);
|
||||
return new ArmProcessContext<MemoryManager>(pid, _cpuEngine, _gpu, memoryManager, for64Bit);
|
||||
|
||||
case MemoryManagerMode.HostMapped:
|
||||
case MemoryManagerMode.HostMappedUnsafe:
|
||||
bool unsafeMode = mode == MemoryManagerMode.HostMappedUnsafe;
|
||||
return new ArmProcessContext<MemoryManagerHostMapped>(pid, _gpu, new MemoryManagerHostMapped(context.Memory, addressSpaceSize, unsafeMode, invalidAccessHandler), for64Bit);
|
||||
var memoryManagerHostMapped = new MemoryManagerHostMapped(context.Memory, addressSpaceSize, unsafeMode, invalidAccessHandler);
|
||||
return new ArmProcessContext<MemoryManagerHostMapped>(pid, _cpuEngine, _gpu, memoryManagerHostMapped, for64Bit);
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
@ -10,6 +10,8 @@ using Ryujinx.Audio.Integration;
|
||||
using Ryujinx.Audio.Output;
|
||||
using Ryujinx.Audio.Renderer.Device;
|
||||
using Ryujinx.Audio.Renderer.Server;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Cpu.Jit;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.HLE.HOS.Kernel;
|
||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||
@ -57,6 +59,9 @@ namespace Ryujinx.HLE.HOS
|
||||
|
||||
internal Switch Device { get; private set; }
|
||||
|
||||
internal ITickSource TickSource { get; }
|
||||
internal ICpuEngine CpuEngine { get; }
|
||||
|
||||
internal SurfaceFlinger SurfaceFlinger { get; private set; }
|
||||
internal AudioManager AudioManager { get; private set; }
|
||||
internal AudioOutputManager AudioOutputManager { get; private set; }
|
||||
@ -121,7 +126,11 @@ namespace Ryujinx.HLE.HOS
|
||||
|
||||
public Horizon(Switch device)
|
||||
{
|
||||
TickSource = new TickSource(KernelConstants.CounterFrequency);
|
||||
CpuEngine = new JitEngine(TickSource);
|
||||
|
||||
KernelContext = new KernelContext(
|
||||
TickSource,
|
||||
device,
|
||||
device.Memory,
|
||||
device.Configuration.MemoryConfiguration.ToKernelMemorySize(),
|
||||
@ -215,40 +224,40 @@ namespace Ryujinx.HLE.HOS
|
||||
internalOffset = new TimeSpanType(-internalOffset.NanoSeconds);
|
||||
|
||||
// First init the standard steady clock
|
||||
TimeServiceManager.Instance.SetupStandardSteadyClock(null, clockSourceId, systemTime, internalOffset, TimeSpanType.Zero, false);
|
||||
TimeServiceManager.Instance.SetupStandardLocalSystemClock(null, new SystemClockContext(), systemTime.ToSeconds());
|
||||
TimeServiceManager.Instance.SetupStandardSteadyClock(TickSource, clockSourceId, systemTime, internalOffset, TimeSpanType.Zero, false);
|
||||
TimeServiceManager.Instance.SetupStandardLocalSystemClock(TickSource, new SystemClockContext(), systemTime.ToSeconds());
|
||||
|
||||
if (NxSettings.Settings.TryGetValue("time!standard_network_clock_sufficient_accuracy_minutes", out object standardNetworkClockSufficientAccuracyMinutes))
|
||||
{
|
||||
TimeSpanType standardNetworkClockSufficientAccuracy = new TimeSpanType((int)standardNetworkClockSufficientAccuracyMinutes * 60000000000);
|
||||
|
||||
// The network system clock needs a valid system clock, as such we setup this system clock using the local system clock.
|
||||
TimeServiceManager.Instance.StandardLocalSystemClock.GetClockContext(null, out SystemClockContext localSytemClockContext);
|
||||
TimeServiceManager.Instance.StandardLocalSystemClock.GetClockContext(TickSource, out SystemClockContext localSytemClockContext);
|
||||
TimeServiceManager.Instance.SetupStandardNetworkSystemClock(localSytemClockContext, standardNetworkClockSufficientAccuracy);
|
||||
}
|
||||
|
||||
TimeServiceManager.Instance.SetupStandardUserSystemClock(null, false, SteadyClockTimePoint.GetRandom());
|
||||
TimeServiceManager.Instance.SetupStandardUserSystemClock(TickSource, false, SteadyClockTimePoint.GetRandom());
|
||||
|
||||
// FIXME: TimeZone should be init here but it's actually done in ContentManager
|
||||
|
||||
TimeServiceManager.Instance.SetupEphemeralNetworkSystemClock();
|
||||
|
||||
DatabaseImpl.Instance.InitializeDatabase(LibHacHorizonManager.SdbClient);
|
||||
DatabaseImpl.Instance.InitializeDatabase(TickSource, LibHacHorizonManager.SdbClient);
|
||||
|
||||
HostSyncpoint = new NvHostSyncpt(device);
|
||||
|
||||
SurfaceFlinger = new SurfaceFlinger(device);
|
||||
|
||||
InitializeAudioRenderer();
|
||||
InitializeAudioRenderer(TickSource);
|
||||
InitializeServices();
|
||||
}
|
||||
|
||||
private void InitializeAudioRenderer()
|
||||
private void InitializeAudioRenderer(ITickSource tickSource)
|
||||
{
|
||||
AudioManager = new AudioManager();
|
||||
AudioOutputManager = new AudioOutputManager();
|
||||
AudioInputManager = new AudioInputManager();
|
||||
AudioRendererManager = new AudioRendererManager();
|
||||
AudioRendererManager = new AudioRendererManager(tickSource);
|
||||
AudioRendererManager.SetVolume(Device.Configuration.AudioVolume);
|
||||
AudioDeviceSessionRegistry = new VirtualDeviceSessionRegistry();
|
||||
|
||||
@ -492,12 +501,12 @@ namespace Ryujinx.HLE.HOS
|
||||
if (pause && !IsPaused)
|
||||
{
|
||||
Device.AudioDeviceDriver.GetPauseEvent().Reset();
|
||||
ARMeilleure.State.ExecutionContext.SuspendCounter();
|
||||
TickSource.Suspend();
|
||||
}
|
||||
else if (!pause && IsPaused)
|
||||
{
|
||||
Device.AudioDeviceDriver.GetPauseEvent().Set();
|
||||
ARMeilleure.State.ExecutionContext.ResumeCounter();
|
||||
TickSource.Resume();
|
||||
}
|
||||
}
|
||||
IsPaused = pause;
|
||||
|
@ -12,5 +12,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
public const ulong UserSlabHeapBase = DramMemoryMap.SlabHeapBase;
|
||||
public const ulong UserSlabHeapItemSize = KPageTableBase.PageSize;
|
||||
public const ulong UserSlabHeapSize = 0x3de000;
|
||||
|
||||
public const ulong CounterFrequency = 19200000;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
using Ryujinx.HLE.HOS.Kernel.SupervisorCall;
|
||||
@ -23,6 +24,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
|
||||
public Switch Device { get; }
|
||||
public MemoryBlock Memory { get; }
|
||||
public ITickSource TickSource { get; }
|
||||
public Syscall Syscall { get; }
|
||||
public SyscallHandler SyscallHandler { get; }
|
||||
|
||||
@ -52,11 +54,13 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
private ulong _threadUid;
|
||||
|
||||
public KernelContext(
|
||||
ITickSource tickSource,
|
||||
Switch device,
|
||||
MemoryBlock memory,
|
||||
MemorySize memorySize,
|
||||
MemoryArrange memoryArrange)
|
||||
{
|
||||
TickSource = tickSource;
|
||||
Device = device;
|
||||
Memory = memory;
|
||||
|
||||
|
@ -115,7 +115,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
|
||||
string GetReg(int x)
|
||||
{
|
||||
var v = x == 32 ? (ulong)thread.LastPc : context.GetX(x);
|
||||
var v = x == 32 ? context.Pc : context.GetX(x);
|
||||
if (!AnalyzePointer(out PointerInfo info, v, thread))
|
||||
{
|
||||
return $"0x{v:x16}";
|
||||
|
@ -1,4 +1,4 @@
|
||||
using ARMeilleure.State;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
|
||||
@ -8,7 +8,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
{
|
||||
IVirtualMemoryManager AddressSpace { get; }
|
||||
|
||||
void Execute(ExecutionContext context, ulong codeAddress);
|
||||
IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks);
|
||||
void Execute(IExecutionContext context, ulong codeAddress);
|
||||
void InvalidateCacheRegion(ulong address, ulong size);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
using ARMeilleure.State;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Cpu;
|
||||
@ -744,14 +743,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
}
|
||||
}
|
||||
|
||||
public void SubscribeThreadEventHandlers(ARMeilleure.State.ExecutionContext context)
|
||||
public IExecutionContext CreateExecutionContext()
|
||||
{
|
||||
context.Interrupt += InterruptHandler;
|
||||
context.SupervisorCall += KernelContext.SyscallHandler.SvcCall;
|
||||
context.Undefined += UndefinedInstructionHandler;
|
||||
return Context?.CreateExecutionContext(new ExceptionCallbacks(
|
||||
InterruptHandler,
|
||||
null,
|
||||
KernelContext.SyscallHandler.SvcCall,
|
||||
UndefinedInstructionHandler));
|
||||
}
|
||||
|
||||
private void InterruptHandler(object sender, EventArgs e)
|
||||
private void InterruptHandler(IExecutionContext context)
|
||||
{
|
||||
KThread currentThread = KernelStatic.GetCurrentThread();
|
||||
|
||||
@ -1093,12 +1094,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
return false;
|
||||
}
|
||||
|
||||
private void UndefinedInstructionHandler(object sender, InstUndefinedEventArgs e)
|
||||
private void UndefinedInstructionHandler(IExecutionContext context, ulong address, int opCode)
|
||||
{
|
||||
KernelStatic.GetCurrentThread().PrintGuestStackTrace();
|
||||
KernelStatic.GetCurrentThread()?.PrintGuestRegisterPrintout();
|
||||
|
||||
throw new UndefinedInstructionException(e.Address, e.OpCode);
|
||||
throw new UndefinedInstructionException(address, opCode);
|
||||
}
|
||||
|
||||
protected override void Destroy() => Context.Dispose();
|
||||
|
@ -1,4 +1,4 @@
|
||||
using ARMeilleure.State;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
|
||||
@ -13,7 +13,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
AddressSpace = asManager;
|
||||
}
|
||||
|
||||
public void Execute(ExecutionContext context, ulong codeAddress)
|
||||
public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks)
|
||||
{
|
||||
return new ProcessExecutionContext();
|
||||
}
|
||||
|
||||
public void Execute(IExecutionContext context, ulong codeAddress)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
44
Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs
Normal file
44
Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs
Normal file
@ -0,0 +1,44 @@
|
||||
using ARMeilleure.State;
|
||||
using Ryujinx.Cpu;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
{
|
||||
class ProcessExecutionContext : IExecutionContext
|
||||
{
|
||||
public ulong Pc => 0UL;
|
||||
|
||||
public ulong CntfrqEl0 { get => 0; set { } }
|
||||
public ulong CntpctEl0 => 0UL;
|
||||
|
||||
public long TpidrEl0 { get => 0; set { } }
|
||||
public long TpidrroEl0 { get => 0; set { } }
|
||||
|
||||
public uint Pstate { get => 0; set { } }
|
||||
|
||||
public uint Fpcr { get => 0; set { } }
|
||||
public uint Fpsr { get => 0; set { } }
|
||||
|
||||
public bool IsAarch32 { get => false; set { } }
|
||||
|
||||
public bool Running { get; private set; } = true;
|
||||
|
||||
public ulong GetX(int index) => 0UL;
|
||||
public void SetX(int index, ulong value) { }
|
||||
|
||||
public V128 GetV(int index) => default;
|
||||
public void SetV(int index, V128 value) { }
|
||||
|
||||
public void RequestInterrupt()
|
||||
{
|
||||
}
|
||||
|
||||
public void StopRunning()
|
||||
{
|
||||
Running = false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||
{
|
||||
class InvalidSvcException : Exception
|
||||
{
|
||||
public InvalidSvcException(string message) : base(message) { }
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
|
||||
class PointerSizedAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
15
Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcAttribute.cs
Normal file
15
Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcAttribute.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
|
||||
class SvcImplAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
@ -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 KernelStatic.GetCurrentThread().Context.CntpctEl0;
|
||||
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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,23 +1,18 @@
|
||||
using ARMeilleure.State;
|
||||
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(object sender, InstExceptionEventArgs e)
|
||||
public void SvcCall(IExecutionContext context, ulong address, int id)
|
||||
{
|
||||
KThread currentThread = KernelStatic.GetCurrentThread();
|
||||
|
||||
@ -34,29 +29,13 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||
_context.CriticalSection.Leave();
|
||||
}
|
||||
|
||||
ExecutionContext context = (ExecutionContext)sender;
|
||||
|
||||
if (context.IsAarch32)
|
||||
{
|
||||
var svcFunc = SyscallTable.SvcTable32[e.Id];
|
||||
|
||||
if (svcFunc == null)
|
||||
{
|
||||
throw new NotImplementedException($"SVC 0x{e.Id:X4} is not implemented.");
|
||||
}
|
||||
|
||||
svcFunc(_syscall32, context);
|
||||
SyscallDispatch.Dispatch32(_context.Syscall, context, id);
|
||||
}
|
||||
else
|
||||
{
|
||||
var svcFunc = SyscallTable.SvcTable64[e.Id];
|
||||
|
||||
if (svcFunc == null)
|
||||
{
|
||||
throw new NotImplementedException($"SVC 0x{e.Id:X4} is not implemented.");
|
||||
}
|
||||
|
||||
svcFunc(_syscall64, context);
|
||||
SyscallDispatch.Dispatch64(_context.Syscall, context, id);
|
||||
}
|
||||
|
||||
currentThread.HandlePostSyscall();
|
||||
|
@ -1,494 +0,0 @@
|
||||
using ARMeilleure.State;
|
||||
using Ryujinx.Common.Logging;
|
||||
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, ExecutionContext>[] SvcTable32 { get; }
|
||||
public static Action<Syscall64, ExecutionContext>[] SvcTable64 { get; }
|
||||
|
||||
static SyscallTable()
|
||||
{
|
||||
SvcTable32 = new Action<Syscall32, ExecutionContext>[SvcMax];
|
||||
SvcTable64 = new Action<Syscall64, ExecutionContext>[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, ExecutionContext> GenerateMethod<T>(string svcName, int registerCleanCount)
|
||||
{
|
||||
Type[] argTypes = new Type[] { typeof(T), typeof(ExecutionContext) };
|
||||
|
||||
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(ExecutionContext).GetMethod(nameof(ExecutionContext.GetX));
|
||||
|
||||
generator.Emit(OpCodes.Call, info);
|
||||
|
||||
generator.Emit(OpCodes.Box, typeof(ulong));
|
||||
|
||||
generator.Emit(OpCodes.Stelem_Ref);
|
||||
}
|
||||
|
||||
argsFormat = argsFormat.Substring(0, argsFormat.Length - 1);
|
||||
|
||||
generator.Emit(OpCodes.Ldstr, argsFormat);
|
||||
}
|
||||
else
|
||||
{
|
||||
generator.Emit(OpCodes.Ldnull);
|
||||
|
||||
generator.Emit(OpCodes.Ldstr, svcName);
|
||||
}
|
||||
|
||||
MethodInfo printArgsMethod = typeof(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(ExecutionContext).GetMethod(nameof(ExecutionContext.GetX));
|
||||
|
||||
generator.Emit(OpCodes.Call, info);
|
||||
|
||||
ConvertToArgType(argType);
|
||||
|
||||
generator.Emit(OpCodes.Stloc, local);
|
||||
}
|
||||
|
||||
generator.Emit(OpCodes.Ldloca, local);
|
||||
}
|
||||
else
|
||||
{
|
||||
generator.Emit(OpCodes.Ldarg_1);
|
||||
generator.Emit(OpCodes.Ldc_I4, registerAttribute.Index);
|
||||
|
||||
MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.GetX));
|
||||
|
||||
generator.Emit(OpCodes.Call, info);
|
||||
|
||||
ConvertToArgType(argType);
|
||||
}
|
||||
}
|
||||
|
||||
generator.Emit(OpCodes.Call, methodInfo);
|
||||
|
||||
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(ExecutionContext).GetMethod(nameof(ExecutionContext.SetX));
|
||||
|
||||
generator.Emit(OpCodes.Call, info);
|
||||
|
||||
registerInUse |= 1u << 0;
|
||||
}
|
||||
|
||||
for (int index = 0; index < locals.Count; index++)
|
||||
{
|
||||
(LocalBuilder local, RAttribute attribute) = locals[index];
|
||||
|
||||
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(ExecutionContext).GetMethod(nameof(ExecutionContext.SetX));
|
||||
|
||||
generator.Emit(OpCodes.Call, 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(ExecutionContext).GetMethod(nameof(ExecutionContext.SetX));
|
||||
|
||||
generator.Emit(OpCodes.Call, info);
|
||||
}
|
||||
|
||||
generator.Emit(OpCodes.Ret);
|
||||
|
||||
return method.CreateDelegate<Action<T, ExecutionContext>>();
|
||||
}
|
||||
|
||||
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}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
|
||||
public Thread HostThread { get; private set; }
|
||||
|
||||
public ARMeilleure.State.ExecutionContext Context { get; private set; }
|
||||
public IExecutionContext Context { get; private set; }
|
||||
|
||||
public KThreadContext ThreadContext { get; private set; }
|
||||
|
||||
@ -115,9 +115,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
|
||||
public bool WaitingInArbitration { get; set; }
|
||||
|
||||
public long LastPc { get; set; }
|
||||
|
||||
private object ActivityOperationLock = new object();
|
||||
private object _activityOperationLock;
|
||||
|
||||
public KThread(KernelContext context) : base(context)
|
||||
{
|
||||
@ -128,6 +126,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
|
||||
_mutexWaiters = new LinkedList<KThread>();
|
||||
_pinnedWaiters = new LinkedList<KThread>();
|
||||
|
||||
_activityOperationLock = new object();
|
||||
}
|
||||
|
||||
public KernelResult Initialize(
|
||||
@ -192,7 +192,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
|
||||
HostThread = new Thread(ThreadStart);
|
||||
|
||||
Context = CpuContext.CreateExecutionContext();
|
||||
Context = owner?.CreateExecutionContext() ?? new ProcessExecutionContext();
|
||||
|
||||
Context.IsAarch32 = !is64Bits;
|
||||
|
||||
@ -208,8 +208,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
Context.SetX(13, (uint)stackTop);
|
||||
}
|
||||
|
||||
Context.CntfrqEl0 = 19200000;
|
||||
Context.Tpidr = (long)_tlsAddress;
|
||||
Context.TpidrroEl0 = (long)_tlsAddress;
|
||||
|
||||
ThreadUid = KernelContext.NewThreadUid();
|
||||
|
||||
@ -221,7 +220,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
|
||||
if (owner != null)
|
||||
{
|
||||
owner.SubscribeThreadEventHandlers(Context);
|
||||
owner.AddThread(this);
|
||||
|
||||
if (owner.IsPaused)
|
||||
@ -538,7 +536,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
|
||||
public KernelResult SetActivity(bool pause)
|
||||
{
|
||||
lock (ActivityOperationLock)
|
||||
lock (_activityOperationLock)
|
||||
{
|
||||
KernelResult result = KernelResult.Success;
|
||||
|
||||
@ -634,7 +632,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
{
|
||||
context = default;
|
||||
|
||||
lock (ActivityOperationLock)
|
||||
lock (_activityOperationLock)
|
||||
{
|
||||
KernelContext.CriticalSection.Enter();
|
||||
|
||||
@ -656,7 +654,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
private static uint GetPsr(ARMeilleure.State.ExecutionContext context)
|
||||
private static uint GetPsr(IExecutionContext context)
|
||||
{
|
||||
return context.Pstate & 0xFF0FFE20;
|
||||
}
|
||||
@ -683,9 +681,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
context.Fp = Context.GetX(29);
|
||||
context.Lr = Context.GetX(30);
|
||||
context.Sp = Context.GetX(31);
|
||||
context.Pc = (ulong)LastPc;
|
||||
context.Pc = Context.Pc;
|
||||
context.Pstate = GetPsr(Context);
|
||||
context.Tpidr = (ulong)Context.Tpidr;
|
||||
context.Tpidr = (ulong)Context.TpidrroEl0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -699,9 +697,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
context.FpuRegisters[i] = Context.GetV(i);
|
||||
}
|
||||
|
||||
context.Pc = (uint)LastPc;
|
||||
context.Pc = (uint)Context.Pc;
|
||||
context.Pstate = GetPsr(Context);
|
||||
context.Tpidr = (uint)Context.Tpidr;
|
||||
context.Tpidr = (uint)Context.TpidrroEl0;
|
||||
}
|
||||
|
||||
context.Fpcr = (uint)Context.Fpcr;
|
||||
@ -743,7 +741,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
|
||||
public KernelResult SetCoreAndAffinityMask(int newCore, ulong newAffinityMask)
|
||||
{
|
||||
lock (ActivityOperationLock)
|
||||
lock (_activityOperationLock)
|
||||
{
|
||||
KernelContext.CriticalSection.Enter();
|
||||
|
||||
|
@ -101,7 +101,7 @@ namespace Ryujinx.HLE.HOS
|
||||
|
||||
KProcess process = new KProcess(context);
|
||||
|
||||
var processContextFactory = new ArmProcessContextFactory(context.Device.Gpu);
|
||||
var processContextFactory = new ArmProcessContextFactory(context.Device.System.CpuEngine, context.Device.Gpu);
|
||||
|
||||
result = process.InitializeKip(
|
||||
creationInfo,
|
||||
@ -264,7 +264,7 @@ namespace Ryujinx.HLE.HOS
|
||||
return false;
|
||||
}
|
||||
|
||||
var processContextFactory = new ArmProcessContextFactory(context.Device.Gpu);
|
||||
var processContextFactory = new ArmProcessContextFactory(context.Device.System.CpuEngine, context.Device.Gpu);
|
||||
|
||||
result = process.Initialize(
|
||||
creationInfo,
|
||||
|
@ -83,7 +83,7 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Error?.Print(LogClass.ServiceAudio, $"Error while processing renderer update: 0x{result}");
|
||||
Logger.Error?.Print(LogClass.ServiceAudio, $"Error while processing renderer update: 0x{(int)result:X}");
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -1,4 +1,5 @@
|
||||
using LibHac;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.HOS.Services.Mii.Types;
|
||||
using System;
|
||||
|
||||
@ -27,7 +28,6 @@ namespace Ryujinx.HLE.HOS.Services.Mii
|
||||
|
||||
public DatabaseImpl()
|
||||
{
|
||||
_utilityImpl = new UtilityImpl();
|
||||
_miiDatabase = new MiiDatabaseManager();
|
||||
}
|
||||
|
||||
@ -148,12 +148,13 @@ namespace Ryujinx.HLE.HOS.Services.Mii
|
||||
return GetDefault(flag, ref count, elements);
|
||||
}
|
||||
|
||||
public ResultCode InitializeDatabase(HorizonClient horizonClient)
|
||||
public ResultCode InitializeDatabase(ITickSource tickSource, HorizonClient horizonClient)
|
||||
{
|
||||
_utilityImpl = new UtilityImpl(tickSource);
|
||||
_miiDatabase.InitializeDatabase(horizonClient);
|
||||
_miiDatabase.LoadFromFile(out _isBroken);
|
||||
|
||||
// Nintendo ignore any error code from before
|
||||
// Nintendo ignores any error code from before.
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Ryujinx.HLE.HOS.Services.Mii.Types;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.HOS.Services.Mii.Types;
|
||||
using Ryujinx.HLE.HOS.Services.Time;
|
||||
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
||||
using System;
|
||||
@ -12,12 +13,12 @@ namespace Ryujinx.HLE.HOS.Services.Mii
|
||||
private uint _z;
|
||||
private uint _w;
|
||||
|
||||
public UtilityImpl()
|
||||
public UtilityImpl(ITickSource tickSource)
|
||||
{
|
||||
_x = 123456789;
|
||||
_y = 362436069;
|
||||
|
||||
TimeSpanType time = TimeManager.Instance.TickBasedSteadyClock.GetCurrentRawTimePoint(null);
|
||||
TimeSpanType time = TimeManager.Instance.TickBasedSteadyClock.GetCurrentRawTimePoint(tickSource);
|
||||
|
||||
_w = (uint)(time.NanoSeconds & uint.MaxValue);
|
||||
_z = (uint)((time.NanoSeconds >> 32) & uint.MaxValue);
|
||||
|
@ -688,7 +688,10 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
||||
{
|
||||
if (context.Device.System.NfpDevices[i].State == NfpDeviceState.TagMounted)
|
||||
{
|
||||
RegisterInfo registerInfo = VirtualAmiibo.GetRegisterInfo(context.Device.System.NfpDevices[i].AmiiboId, context.Device.System.AccountManager.LastOpenedUser.Name);
|
||||
RegisterInfo registerInfo = VirtualAmiibo.GetRegisterInfo(
|
||||
context.Device.System.TickSource,
|
||||
context.Device.System.NfpDevices[i].AmiiboId,
|
||||
context.Device.System.AccountManager.LastOpenedUser.Name);
|
||||
|
||||
context.Memory.Write(outputPosition, registerInfo);
|
||||
|
||||
@ -911,7 +914,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
|
||||
context.ResponseData.Write((uint)context.Device.System.NfpDevices[i].State);
|
||||
|
||||
return ResultCode.Success;
|
||||
|
@ -1,5 +1,6 @@
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.HOS.Services.Mii;
|
||||
using Ryujinx.HLE.HOS.Services.Mii.Types;
|
||||
using Ryujinx.HLE.HOS.Services.Nfc.Nfp.NfpManager;
|
||||
@ -63,11 +64,11 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
||||
};
|
||||
}
|
||||
|
||||
public static RegisterInfo GetRegisterInfo(string amiiboId, string nickname)
|
||||
public static RegisterInfo GetRegisterInfo(ITickSource tickSource, string amiiboId, string nickname)
|
||||
{
|
||||
VirtualAmiiboFile amiiboFile = LoadAmiiboFile(amiiboId);
|
||||
|
||||
UtilityImpl utilityImpl = new UtilityImpl();
|
||||
UtilityImpl utilityImpl = new UtilityImpl(tickSource);
|
||||
CharInfo charInfo = new CharInfo();
|
||||
|
||||
charInfo.SetFromStoreData(StoreData.BuildDefault(utilityImpl, 0));
|
||||
|
@ -6,7 +6,7 @@
|
||||
{
|
||||
BufferQueueCore core = new BufferQueueCore(device, pid);
|
||||
|
||||
producer = new BufferQueueProducer(core);
|
||||
producer = new BufferQueueProducer(core, device.System.TickSource);
|
||||
consumer = new BufferQueueConsumer(core);
|
||||
|
||||
return core;
|
||||
|
@ -1,5 +1,4 @@
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Kernel;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
|
||||
using System;
|
||||
@ -241,7 +240,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||
{
|
||||
BufferSlot slot = Slots[item.Slot];
|
||||
|
||||
// TODO: Check this. On Android, this checks the "handle". I assume NvMapHandle is the handle, but it might not be.
|
||||
// TODO: Check this. On Android, this checks the "handle". I assume NvMapHandle is the handle, but it might not be.
|
||||
return !slot.GraphicBuffer.IsNull && slot.GraphicBuffer.Object.Buffer.Surfaces[0].NvMapHandle == item.GraphicBuffer.Object.Buffer.Surfaces[0].NvMapHandle;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.HLE.HOS.Services.Settings;
|
||||
using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
|
||||
@ -12,6 +13,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||
{
|
||||
public BufferQueueCore Core { get; }
|
||||
|
||||
private readonly ITickSource _tickSource;
|
||||
|
||||
private uint _stickyTransform;
|
||||
|
||||
private uint _nextCallbackTicket;
|
||||
@ -20,9 +23,10 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||
|
||||
private readonly object _callbackLock = new object();
|
||||
|
||||
public BufferQueueProducer(BufferQueueCore core)
|
||||
public BufferQueueProducer(BufferQueueCore core, ITickSource tickSource)
|
||||
{
|
||||
Core = core;
|
||||
_tickSource = tickSource;
|
||||
|
||||
_stickyTransform = 0;
|
||||
_callbackTicket = 0;
|
||||
@ -179,8 +183,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||
GraphicBuffer graphicBuffer = Core.Slots[slot].GraphicBuffer.Object;
|
||||
|
||||
if (Core.Slots[slot].GraphicBuffer.IsNull
|
||||
|| graphicBuffer.Width != width
|
||||
|| graphicBuffer.Height != height
|
||||
|| graphicBuffer.Width != width
|
||||
|| graphicBuffer.Height != height
|
||||
|| graphicBuffer.Format != format
|
||||
|| (graphicBuffer.Usage & usage) != usage)
|
||||
{
|
||||
@ -193,7 +197,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Error?.Print(LogClass.SurfaceFlinger,
|
||||
Logger.Error?.Print(LogClass.SurfaceFlinger,
|
||||
$"Preallocated buffer mismatch - slot {slot}\n" +
|
||||
$"available: Width = {graphicBuffer.Width} Height = {graphicBuffer.Height} Format = {graphicBuffer.Format} Usage = {graphicBuffer.Usage:x} " +
|
||||
$"requested: Width = {width} Height = {height} Format = {format} Usage = {usage:x}");
|
||||
@ -388,7 +392,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||
Core.Slots[slot].BufferState = BufferState.Queued;
|
||||
Core.FrameCounter++;
|
||||
Core.Slots[slot].FrameNumber = Core.FrameCounter;
|
||||
Core.Slots[slot].QueueTime = TimeSpanType.FromTimeSpan(ARMeilleure.State.ExecutionContext.ElapsedTime);
|
||||
Core.Slots[slot].QueueTime = TimeSpanType.FromTimeSpan(_tickSource.ElapsedTime);
|
||||
Core.Slots[slot].PresentationTime = TimeSpanType.Zero;
|
||||
|
||||
item.AcquireCalled = Core.Slots[slot].AcquireCalled;
|
||||
|
@ -1,4 +1,4 @@
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.Cpu;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
{
|
||||
@ -11,14 +11,14 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
_standardNetworkClockSufficientAccuracy = new TimeSpanType(0);
|
||||
}
|
||||
|
||||
public bool IsStandardNetworkSystemClockAccuracySufficient(KThread thread)
|
||||
public bool IsStandardNetworkSystemClockAccuracySufficient(ITickSource tickSource)
|
||||
{
|
||||
SteadyClockCore steadyClockCore = GetSteadyClockCore();
|
||||
SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(thread);
|
||||
SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(tickSource);
|
||||
|
||||
bool isStandardNetworkClockSufficientAccuracy = false;
|
||||
|
||||
ResultCode result = GetClockContext(thread, out SystemClockContext context);
|
||||
ResultCode result = GetClockContext(tickSource, out SystemClockContext context);
|
||||
|
||||
if (result == ResultCode.Success && context.SteadyTimePoint.GetSpanBetween(currentTimePoint, out long outSpan) == ResultCode.Success)
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.Cpu;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
{
|
||||
@ -17,11 +17,11 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
_cachedRawTimePoint = TimeSpanType.Zero;
|
||||
}
|
||||
|
||||
public override SteadyClockTimePoint GetTimePoint(KThread thread)
|
||||
public override SteadyClockTimePoint GetTimePoint(ITickSource tickSource)
|
||||
{
|
||||
SteadyClockTimePoint result = new SteadyClockTimePoint
|
||||
{
|
||||
TimePoint = GetCurrentRawTimePoint(thread).ToSeconds(),
|
||||
TimePoint = GetCurrentRawTimePoint(tickSource).ToSeconds(),
|
||||
ClockSourceId = GetClockSourceId()
|
||||
};
|
||||
|
||||
@ -48,19 +48,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
_internalOffset = internalOffset;
|
||||
}
|
||||
|
||||
public override TimeSpanType GetCurrentRawTimePoint(KThread thread)
|
||||
public override TimeSpanType GetCurrentRawTimePoint(ITickSource tickSource)
|
||||
{
|
||||
TimeSpanType ticksTimeSpan;
|
||||
|
||||
// As this may be called before the guest code, we support passing a null thread to make this api usable.
|
||||
if (thread == null)
|
||||
{
|
||||
ticksTimeSpan = TimeSpanType.FromSeconds(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.CntpctEl0, thread.Context.CntfrqEl0);
|
||||
}
|
||||
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(tickSource.Counter, tickSource.Frequency);
|
||||
|
||||
TimeSpanType rawTimePoint = new TimeSpanType(_setupValue.NanoSeconds + ticksTimeSpan.NanoSeconds);
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
@ -26,15 +27,15 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override ResultCode GetClockContext(KThread thread, out SystemClockContext context)
|
||||
public override ResultCode GetClockContext(ITickSource tickSource, out SystemClockContext context)
|
||||
{
|
||||
ResultCode result = ApplyAutomaticCorrection(thread, false);
|
||||
ResultCode result = ApplyAutomaticCorrection(tickSource, false);
|
||||
|
||||
context = new SystemClockContext();
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
{
|
||||
return _localSystemClockCore.GetClockContext(thread, out context);
|
||||
return _localSystemClockCore.GetClockContext(tickSource, out context);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -45,13 +46,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
return ResultCode.NotImplemented;
|
||||
}
|
||||
|
||||
private ResultCode ApplyAutomaticCorrection(KThread thread, bool autoCorrectionEnabled)
|
||||
private ResultCode ApplyAutomaticCorrection(ITickSource tickSource, bool autoCorrectionEnabled)
|
||||
{
|
||||
ResultCode result = ResultCode.Success;
|
||||
|
||||
if (_autoCorrectionEnabled != autoCorrectionEnabled && _networkSystemClockCore.IsClockSetup(thread))
|
||||
if (_autoCorrectionEnabled != autoCorrectionEnabled && _networkSystemClockCore.IsClockSetup(tickSource))
|
||||
{
|
||||
result = _networkSystemClockCore.GetClockContext(thread, out SystemClockContext context);
|
||||
result = _networkSystemClockCore.GetClockContext(tickSource, out SystemClockContext context);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
{
|
||||
@ -67,9 +68,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
_autoCorrectionEvent = new KEvent(system.KernelContext);
|
||||
}
|
||||
|
||||
public ResultCode SetAutomaticCorrectionEnabled(KThread thread, bool autoCorrectionEnabled)
|
||||
public ResultCode SetAutomaticCorrectionEnabled(ITickSource tickSource, bool autoCorrectionEnabled)
|
||||
{
|
||||
ResultCode result = ApplyAutomaticCorrection(thread, autoCorrectionEnabled);
|
||||
ResultCode result = ApplyAutomaticCorrection(tickSource, autoCorrectionEnabled);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.Utilities;
|
||||
using System;
|
||||
|
||||
@ -63,21 +63,21 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
|
||||
public virtual void SetInternalOffset(TimeSpanType internalOffset) {}
|
||||
|
||||
public virtual SteadyClockTimePoint GetTimePoint(KThread thread)
|
||||
public virtual SteadyClockTimePoint GetTimePoint(ITickSource tickSource)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual TimeSpanType GetCurrentRawTimePoint(KThread thread)
|
||||
public virtual TimeSpanType GetCurrentRawTimePoint(ITickSource tickSource)
|
||||
{
|
||||
SteadyClockTimePoint timePoint = GetTimePoint(thread);
|
||||
SteadyClockTimePoint timePoint = GetTimePoint(tickSource);
|
||||
|
||||
return TimeSpanType.FromSeconds(timePoint.TimePoint);
|
||||
}
|
||||
|
||||
public SteadyClockTimePoint GetCurrentTimePoint(KThread thread)
|
||||
public SteadyClockTimePoint GetCurrentTimePoint(ITickSource tickSource)
|
||||
{
|
||||
SteadyClockTimePoint result = GetTimePoint(thread);
|
||||
SteadyClockTimePoint result = GetTimePoint(tickSource);
|
||||
|
||||
result.TimePoint += GetTestOffset().ToSeconds();
|
||||
result.TimePoint += GetInternalOffset().ToSeconds();
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
@ -25,13 +25,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
return _steadyClockCore;
|
||||
}
|
||||
|
||||
public ResultCode GetCurrentTime(KThread thread, out long posixTime)
|
||||
public ResultCode GetCurrentTime(ITickSource tickSource, out long posixTime)
|
||||
{
|
||||
posixTime = 0;
|
||||
|
||||
SteadyClockTimePoint currentTimePoint = _steadyClockCore.GetCurrentTimePoint(thread);
|
||||
SteadyClockTimePoint currentTimePoint = _steadyClockCore.GetCurrentTimePoint(tickSource);
|
||||
|
||||
ResultCode result = GetClockContext(thread, out SystemClockContext clockContext);
|
||||
ResultCode result = GetClockContext(tickSource, out SystemClockContext clockContext);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
{
|
||||
@ -48,9 +48,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
return result;
|
||||
}
|
||||
|
||||
public ResultCode SetCurrentTime(KThread thread, long posixTime)
|
||||
public ResultCode SetCurrentTime(ITickSource tickSource, long posixTime)
|
||||
{
|
||||
SteadyClockTimePoint currentTimePoint = _steadyClockCore.GetCurrentTimePoint(thread);
|
||||
SteadyClockTimePoint currentTimePoint = _steadyClockCore.GetCurrentTimePoint(tickSource);
|
||||
|
||||
SystemClockContext clockContext = new SystemClockContext()
|
||||
{
|
||||
@ -68,7 +68,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
return result;
|
||||
}
|
||||
|
||||
public virtual ResultCode GetClockContext(KThread thread, out SystemClockContext context)
|
||||
public virtual ResultCode GetClockContext(ITickSource tickSource, out SystemClockContext context)
|
||||
{
|
||||
context = _context;
|
||||
|
||||
@ -127,13 +127,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
_isInitialized = true;
|
||||
}
|
||||
|
||||
public bool IsClockSetup(KThread thread)
|
||||
public bool IsClockSetup(ITickSource tickSource)
|
||||
{
|
||||
ResultCode result = GetClockContext(thread, out SystemClockContext context);
|
||||
ResultCode result = GetClockContext(tickSource, out SystemClockContext context);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
{
|
||||
SteadyClockTimePoint steadyClockTimePoint = _steadyClockCore.GetCurrentTimePoint(thread);
|
||||
SteadyClockTimePoint steadyClockTimePoint = _steadyClockCore.GetCurrentTimePoint(tickSource);
|
||||
|
||||
return steadyClockTimePoint.ClockSourceId == context.SteadyTimePoint.ClockSourceId;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.Cpu;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
{
|
||||
@ -6,7 +6,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
{
|
||||
public TickBasedSteadyClockCore() {}
|
||||
|
||||
public override SteadyClockTimePoint GetTimePoint(KThread thread)
|
||||
public override SteadyClockTimePoint GetTimePoint(ITickSource tickSource)
|
||||
{
|
||||
SteadyClockTimePoint result = new SteadyClockTimePoint
|
||||
{
|
||||
@ -14,17 +14,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
ClockSourceId = GetClockSourceId()
|
||||
};
|
||||
|
||||
TimeSpanType ticksTimeSpan;
|
||||
|
||||
// As this may be called before the guest code, we support passing a null thread to make this api usable.
|
||||
if (thread == null)
|
||||
{
|
||||
ticksTimeSpan = TimeSpanType.FromSeconds(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.CntpctEl0, thread.Context.CntfrqEl0);
|
||||
}
|
||||
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(tickSource.Counter, tickSource.Frequency);
|
||||
|
||||
result.TimePoint = ticksTimeSpan.ToSeconds();
|
||||
|
||||
|
@ -2,7 +2,6 @@ using Ryujinx.Common;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
||||
using Ryujinx.HLE.HOS.Services.Time.StaticService;
|
||||
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
||||
@ -163,13 +162,15 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||
|
||||
bool autoCorrectionEnabled = context.RequestData.ReadBoolean();
|
||||
|
||||
ResultCode result = userClock.SetAutomaticCorrectionEnabled(context.Thread, autoCorrectionEnabled);
|
||||
ITickSource tickSource = context.Device.System.TickSource;
|
||||
|
||||
ResultCode result = userClock.SetAutomaticCorrectionEnabled(tickSource, autoCorrectionEnabled);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
{
|
||||
_timeManager.SharedMemory.SetAutomaticCorrectionEnabled(autoCorrectionEnabled);
|
||||
|
||||
SteadyClockTimePoint currentTimePoint = userClock.GetSteadyClockCore().GetCurrentTimePoint(context.Thread);
|
||||
SteadyClockTimePoint currentTimePoint = userClock.GetSteadyClockCore().GetCurrentTimePoint(tickSource);
|
||||
|
||||
userClock.SetAutomaticCorrectionUpdatedTime(currentTimePoint);
|
||||
userClock.SignalAutomaticCorrectionEvent();
|
||||
@ -190,7 +191,9 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||
// IsStandardNetworkSystemClockAccuracySufficient() -> bool
|
||||
public ResultCode IsStandardNetworkSystemClockAccuracySufficient(ServiceCtx context)
|
||||
{
|
||||
context.ResponseData.Write(_timeManager.StandardNetworkSystemClock.IsStandardNetworkSystemClockAccuracySufficient(context.Thread));
|
||||
ITickSource tickSource = context.Device.System.TickSource;
|
||||
|
||||
context.ResponseData.Write(_timeManager.StandardNetworkSystemClock.IsStandardNetworkSystemClockAccuracySufficient(tickSource));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
@ -222,14 +225,16 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||
return ResultCode.UninitializedClock;
|
||||
}
|
||||
|
||||
ITickSource tickSource = context.Device.System.TickSource;
|
||||
|
||||
SystemClockContext otherContext = context.RequestData.ReadStruct<SystemClockContext>();
|
||||
SteadyClockTimePoint currentTimePoint = steadyClock.GetCurrentTimePoint(context.Thread);
|
||||
SteadyClockTimePoint currentTimePoint = steadyClock.GetCurrentTimePoint(tickSource);
|
||||
|
||||
ResultCode result = ResultCode.TimeMismatch;
|
||||
|
||||
if (currentTimePoint.ClockSourceId == otherContext.SteadyTimePoint.ClockSourceId)
|
||||
{
|
||||
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(context.Thread.Context.CntpctEl0, context.Thread.Context.CntfrqEl0);
|
||||
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(tickSource.Counter, tickSource.Frequency);
|
||||
long baseTimePoint = otherContext.Offset + currentTimePoint.TimePoint - ticksTimeSpan.ToSeconds();
|
||||
|
||||
context.ResponseData.Write(baseTimePoint);
|
||||
@ -248,15 +253,17 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||
|
||||
context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf<ClockSnapshot>());
|
||||
|
||||
ResultCode result = _timeManager.StandardUserSystemClock.GetClockContext(context.Thread, out SystemClockContext userContext);
|
||||
ITickSource tickSource = context.Device.System.TickSource;
|
||||
|
||||
ResultCode result = _timeManager.StandardUserSystemClock.GetClockContext(tickSource, out SystemClockContext userContext);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
{
|
||||
result = _timeManager.StandardNetworkSystemClock.GetClockContext(context.Thread, out SystemClockContext networkContext);
|
||||
result = _timeManager.StandardNetworkSystemClock.GetClockContext(tickSource, out SystemClockContext networkContext);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
{
|
||||
result = GetClockSnapshotFromSystemClockContextInternal(context.Thread, userContext, networkContext, type, out ClockSnapshot clockSnapshot);
|
||||
result = GetClockSnapshotFromSystemClockContextInternal(tickSource, userContext, networkContext, type, out ClockSnapshot clockSnapshot);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
{
|
||||
@ -281,7 +288,9 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||
SystemClockContext userContext = context.RequestData.ReadStruct<SystemClockContext>();
|
||||
SystemClockContext networkContext = context.RequestData.ReadStruct<SystemClockContext>();
|
||||
|
||||
ResultCode result = GetClockSnapshotFromSystemClockContextInternal(context.Thread, userContext, networkContext, type, out ClockSnapshot clockSnapshot);
|
||||
ITickSource tickSource = context.Device.System.TickSource;
|
||||
|
||||
ResultCode result = GetClockSnapshotFromSystemClockContextInternal(tickSource, userContext, networkContext, type, out ClockSnapshot clockSnapshot);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
{
|
||||
@ -344,12 +353,12 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||
return resultCode;
|
||||
}
|
||||
|
||||
private ResultCode GetClockSnapshotFromSystemClockContextInternal(KThread thread, SystemClockContext userContext, SystemClockContext networkContext, byte type, out ClockSnapshot clockSnapshot)
|
||||
private ResultCode GetClockSnapshotFromSystemClockContextInternal(ITickSource tickSource, SystemClockContext userContext, SystemClockContext networkContext, byte type, out ClockSnapshot clockSnapshot)
|
||||
{
|
||||
clockSnapshot = new ClockSnapshot();
|
||||
|
||||
SteadyClockCore steadyClockCore = _timeManager.StandardSteadyClock;
|
||||
SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(thread);
|
||||
SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(tickSource);
|
||||
|
||||
clockSnapshot.IsAutomaticCorrectionEnabled = _timeManager.StandardUserSystemClock.IsAutomaticCorrectionEnabled();
|
||||
clockSnapshot.UserContext = userContext;
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.Exceptions;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
@ -6,7 +7,6 @@ using Ryujinx.HLE.HOS.Services.Time.Clock;
|
||||
using Ryujinx.HLE.Utilities;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time
|
||||
{
|
||||
@ -68,7 +68,9 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||
TimeSpanType testOffset = context.RequestData.ReadStruct<TimeSpanType>();
|
||||
bool isRtcResetDetected = context.RequestData.ReadBoolean();
|
||||
|
||||
_timeManager.SetupStandardSteadyClock(context.Thread, clockSourceId, setupValue, internalOffset, testOffset, isRtcResetDetected);
|
||||
ITickSource tickSource = context.Device.System.TickSource;
|
||||
|
||||
_timeManager.SetupStandardSteadyClock(tickSource, clockSourceId, setupValue, internalOffset, testOffset, isRtcResetDetected);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
@ -80,7 +82,9 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||
SystemClockContext clockContext = context.RequestData.ReadStruct<SystemClockContext>();
|
||||
long posixTime = context.RequestData.ReadInt64();
|
||||
|
||||
_timeManager.SetupStandardLocalSystemClock(context.Thread, clockContext, posixTime);
|
||||
ITickSource tickSource = context.Device.System.TickSource;
|
||||
|
||||
_timeManager.SetupStandardLocalSystemClock(tickSource, clockContext, posixTime);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
@ -107,7 +111,9 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||
|
||||
SteadyClockTimePoint steadyClockTimePoint = context.RequestData.ReadStruct<SteadyClockTimePoint>();
|
||||
|
||||
_timeManager.SetupStandardUserSystemClock(context.Thread, isAutomaticCorrectionEnabled, steadyClockTimePoint);
|
||||
ITickSource tickSource = context.Device.System.TickSource;
|
||||
|
||||
_timeManager.SetupStandardUserSystemClock(tickSource, isAutomaticCorrectionEnabled, steadyClockTimePoint);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
@ -191,7 +197,9 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||
{
|
||||
TimeSpanType rtcOffset = context.RequestData.ReadStruct<TimeSpanType>();
|
||||
|
||||
_timeManager.SetStandardSteadyClockRtcOffset(context.Thread, rtcOffset);
|
||||
ITickSource tickSource = context.Device.System.TickSource;
|
||||
|
||||
_timeManager.SetStandardSteadyClockRtcOffset(tickSource, rtcOffset);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time.StaticService
|
||||
@ -25,7 +26,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
|
||||
return ResultCode.UninitializedClock;
|
||||
}
|
||||
|
||||
SteadyClockTimePoint currentTimePoint = _steadyClock.GetCurrentTimePoint(context.Thread);
|
||||
ITickSource tickSource = context.Device.System.TickSource;
|
||||
|
||||
SteadyClockTimePoint currentTimePoint = _steadyClock.GetCurrentTimePoint(tickSource);
|
||||
|
||||
context.ResponseData.WriteStruct(currentTimePoint);
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
@ -31,7 +32,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
|
||||
return ResultCode.UninitializedClock;
|
||||
}
|
||||
|
||||
ResultCode result = _clockCore.GetCurrentTime(context.Thread, out long posixTime);
|
||||
ITickSource tickSource = context.Device.System.TickSource;
|
||||
|
||||
ResultCode result = _clockCore.GetCurrentTime(tickSource, out long posixTime);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
{
|
||||
@ -57,7 +60,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
|
||||
|
||||
long posixTime = context.RequestData.ReadInt64();
|
||||
|
||||
return _clockCore.SetCurrentTime(context.Thread, posixTime);
|
||||
ITickSource tickSource = context.Device.System.TickSource;
|
||||
|
||||
return _clockCore.SetCurrentTime(tickSource, posixTime);
|
||||
}
|
||||
|
||||
[CommandHipc(2)]
|
||||
@ -69,7 +74,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
|
||||
return ResultCode.UninitializedClock;
|
||||
}
|
||||
|
||||
ResultCode result = _clockCore.GetClockContext(context.Thread, out SystemClockContext clockContext);
|
||||
ITickSource tickSource = context.Device.System.TickSource;
|
||||
|
||||
ResultCode result = _clockCore.GetClockContext(tickSource, out SystemClockContext clockContext);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
{
|
||||
|
@ -7,7 +7,6 @@ using Ryujinx.HLE.Utilities;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time.StaticService
|
||||
{
|
||||
@ -44,7 +43,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
|
||||
{
|
||||
return ResultCode.PermissionDenied;
|
||||
}
|
||||
|
||||
|
||||
return ResultCode.NotImplemented;
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,10 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.Exceptions;
|
||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
||||
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
||||
using Ryujinx.HLE.Utilities;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time
|
||||
{
|
||||
@ -68,14 +67,13 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||
TimeZone.Initialize(this, device);
|
||||
}
|
||||
|
||||
|
||||
public void SetupStandardSteadyClock(KThread thread, UInt128 clockSourceId, TimeSpanType setupValue, TimeSpanType internalOffset, TimeSpanType testOffset, bool isRtcResetDetected)
|
||||
public void SetupStandardSteadyClock(ITickSource tickSource, UInt128 clockSourceId, TimeSpanType setupValue, TimeSpanType internalOffset, TimeSpanType testOffset, bool isRtcResetDetected)
|
||||
{
|
||||
SetupInternalStandardSteadyClock(clockSourceId, setupValue, internalOffset, testOffset, isRtcResetDetected);
|
||||
|
||||
TimeSpanType currentTimePoint = StandardSteadyClock.GetCurrentRawTimePoint(thread);
|
||||
TimeSpanType currentTimePoint = StandardSteadyClock.GetCurrentRawTimePoint(tickSource);
|
||||
|
||||
SharedMemory.SetupStandardSteadyClock(thread, clockSourceId, currentTimePoint);
|
||||
SharedMemory.SetupStandardSteadyClock(tickSource, clockSourceId, currentTimePoint);
|
||||
|
||||
// TODO: propagate IPC late binding of "time:s" and "time:p"
|
||||
}
|
||||
@ -97,18 +95,18 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||
// TODO: propagate IPC late binding of "time:s" and "time:p"
|
||||
}
|
||||
|
||||
public void SetupStandardLocalSystemClock(KThread thread, SystemClockContext clockContext, long posixTime)
|
||||
public void SetupStandardLocalSystemClock(ITickSource tickSource, SystemClockContext clockContext, long posixTime)
|
||||
{
|
||||
StandardLocalSystemClock.SetUpdateCallbackInstance(LocalClockContextWriter);
|
||||
|
||||
SteadyClockTimePoint currentTimePoint = StandardLocalSystemClock.GetSteadyClockCore().GetCurrentTimePoint(thread);
|
||||
SteadyClockTimePoint currentTimePoint = StandardLocalSystemClock.GetSteadyClockCore().GetCurrentTimePoint(tickSource);
|
||||
if (currentTimePoint.ClockSourceId == clockContext.SteadyTimePoint.ClockSourceId)
|
||||
{
|
||||
StandardLocalSystemClock.SetSystemClockContext(clockContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (StandardLocalSystemClock.SetCurrentTime(thread, posixTime) != ResultCode.Success)
|
||||
if (StandardLocalSystemClock.SetCurrentTime(tickSource, posixTime) != ResultCode.Success)
|
||||
{
|
||||
throw new InternalServiceException("Cannot set current local time");
|
||||
}
|
||||
@ -157,9 +155,9 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||
// TODO: propagate IPC late binding of "time:s" and "time:p"
|
||||
}
|
||||
|
||||
public void SetupStandardUserSystemClock(KThread thread, bool isAutomaticCorrectionEnabled, SteadyClockTimePoint steadyClockTimePoint)
|
||||
public void SetupStandardUserSystemClock(ITickSource tickSource, bool isAutomaticCorrectionEnabled, SteadyClockTimePoint steadyClockTimePoint)
|
||||
{
|
||||
if (StandardUserSystemClock.SetAutomaticCorrectionEnabled(thread, isAutomaticCorrectionEnabled) != ResultCode.Success)
|
||||
if (StandardUserSystemClock.SetAutomaticCorrectionEnabled(tickSource, isAutomaticCorrectionEnabled) != ResultCode.Success)
|
||||
{
|
||||
throw new InternalServiceException("Cannot set automatic user time correction state");
|
||||
}
|
||||
@ -172,13 +170,13 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||
// TODO: propagate IPC late binding of "time:s" and "time:p"
|
||||
}
|
||||
|
||||
public void SetStandardSteadyClockRtcOffset(KThread thread, TimeSpanType rtcOffset)
|
||||
public void SetStandardSteadyClockRtcOffset(ITickSource tickSource, TimeSpanType rtcOffset)
|
||||
{
|
||||
StandardSteadyClock.SetSetupValue(rtcOffset);
|
||||
|
||||
TimeSpanType currentTimePoint = StandardSteadyClock.GetCurrentRawTimePoint(thread);
|
||||
TimeSpanType currentTimePoint = StandardSteadyClock.GetCurrentRawTimePoint(tickSource);
|
||||
|
||||
SharedMemory.SetSteadyClockRawTimePoint(thread, currentTimePoint);
|
||||
SharedMemory.SetSteadyClockRawTimePoint(tickSource, currentTimePoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,11 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
||||
using Ryujinx.HLE.HOS.Services.Time.Types;
|
||||
using Ryujinx.HLE.Utilities;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time
|
||||
{
|
||||
@ -38,19 +37,9 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||
return _sharedMemory;
|
||||
}
|
||||
|
||||
public void SetupStandardSteadyClock(KThread thread, UInt128 clockSourceId, TimeSpanType currentTimePoint)
|
||||
public void SetupStandardSteadyClock(ITickSource tickSource, UInt128 clockSourceId, TimeSpanType currentTimePoint)
|
||||
{
|
||||
TimeSpanType ticksTimeSpan;
|
||||
|
||||
// As this may be called before the guest code, we support passing a null thread to make this api usable.
|
||||
if (thread == null)
|
||||
{
|
||||
ticksTimeSpan = TimeSpanType.FromSeconds(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.CntpctEl0, thread.Context.CntfrqEl0);
|
||||
}
|
||||
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(tickSource.Counter, tickSource.Frequency);
|
||||
|
||||
SteadyClockContext context = new SteadyClockContext
|
||||
{
|
||||
@ -67,10 +56,10 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||
WriteObjectToSharedMemory(AutomaticCorrectionEnabledOffset, 0, Convert.ToByte(isAutomaticCorrectionEnabled));
|
||||
}
|
||||
|
||||
public void SetSteadyClockRawTimePoint(KThread thread, TimeSpanType currentTimePoint)
|
||||
public void SetSteadyClockRawTimePoint(ITickSource tickSource, TimeSpanType currentTimePoint)
|
||||
{
|
||||
SteadyClockContext context = ReadObjectFromSharedMemory<SteadyClockContext>(SteadyClockContextOffset, 4);
|
||||
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.CntpctEl0, thread.Context.CntfrqEl0);
|
||||
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(tickSource.Counter, tickSource.Frequency);
|
||||
|
||||
context.InternalOffset = (ulong)(currentTimePoint.NanoSeconds - ticksTimeSpan.NanoSeconds);
|
||||
|
||||
|
@ -7,6 +7,7 @@ using LibHac.Ncm;
|
||||
using LibHac.Tools.FsSystem;
|
||||
using LibHac.Tools.FsSystem.NcaUtils;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.Exceptions;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
||||
@ -63,7 +64,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
|
||||
{
|
||||
InitializeInstance(device.FileSystem, device.System.ContentManager, device.System.FsIntegrityCheckLevel);
|
||||
|
||||
SteadyClockTimePoint timeZoneUpdatedTimePoint = timeManager.StandardSteadyClock.GetCurrentTimePoint(null);
|
||||
ITickSource tickSource = device.System.TickSource;
|
||||
|
||||
SteadyClockTimePoint timeZoneUpdatedTimePoint = timeManager.StandardSteadyClock.GetCurrentTimePoint(tickSource);
|
||||
|
||||
string deviceLocationName = SanityCheckDeviceLocationName(device.Configuration.TimeZone);
|
||||
|
||||
|
@ -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" />
|
||||
|
@ -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>
|
||||
|
58
Ryujinx.Horizon.Generators/CodeGenerator.cs
Normal file
58
Ryujinx.Horizon.Generators/CodeGenerator.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
524
Ryujinx.Horizon.Generators/Kernel/SyscallGenerator.cs
Normal file
524
Ryujinx.Horizon.Generators/Kernel/SyscallGenerator.cs
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
54
Ryujinx.Horizon.Generators/Kernel/SyscallSyntaxReceiver.cs
Normal file
54
Ryujinx.Horizon.Generators/Kernel/SyscallSyntaxReceiver.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
15
Ryujinx.Horizon.Generators/Ryujinx.Horizon.Generators.csproj
Normal file
15
Ryujinx.Horizon.Generators/Ryujinx.Horizon.Generators.csproj
Normal 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>
|
@ -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>
|
||||
|
@ -1,8 +1,10 @@
|
||||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.State;
|
||||
using ARMeilleure.Translation;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Cpu.Jit;
|
||||
|
||||
namespace Ryujinx.Cpu
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
public class CpuContext
|
||||
{
|
||||
@ -21,7 +23,7 @@ namespace Ryujinx.Cpu
|
||||
|
||||
public static ExecutionContext CreateExecutionContext()
|
||||
{
|
||||
return new ExecutionContext(new JitMemoryAllocator());
|
||||
return new ExecutionContext(new JitMemoryAllocator(), new TickSource(19200000));
|
||||
}
|
||||
|
||||
public void Execute(ExecutionContext context, ulong address)
|
@ -2,7 +2,7 @@ using ARMeilleure;
|
||||
using ARMeilleure.State;
|
||||
using ARMeilleure.Translation;
|
||||
using NUnit.Framework;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Cpu.Jit;
|
||||
using Ryujinx.Memory;
|
||||
using Ryujinx.Tests.Unicorn;
|
||||
using System;
|
||||
|
@ -2,7 +2,7 @@
|
||||
using ARMeilleure.State;
|
||||
using ARMeilleure.Translation;
|
||||
using NUnit.Framework;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.Cpu.Jit;
|
||||
using Ryujinx.Memory;
|
||||
using Ryujinx.Tests.Unicorn;
|
||||
using System;
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
||||
<OutputType>Exe</OutputType>
|
||||
<IsPackable>false</IsPackable>
|
||||
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -114,12 +114,12 @@ namespace Ryujinx.Ui
|
||||
|
||||
GL.BlitFramebuffer(0,
|
||||
0,
|
||||
AllocatedWidth,
|
||||
AllocatedHeight,
|
||||
WindowWidth,
|
||||
WindowHeight,
|
||||
0,
|
||||
0,
|
||||
AllocatedWidth,
|
||||
AllocatedHeight,
|
||||
WindowWidth,
|
||||
WindowHeight,
|
||||
ClearBufferMask.ColorBufferBit,
|
||||
BlitFramebufferFilter.Linear);
|
||||
}
|
||||
|
@ -41,6 +41,8 @@ namespace Ryujinx.Ui
|
||||
public IRenderer Renderer { get; private set; }
|
||||
|
||||
public bool ScreenshotRequested { get; set; }
|
||||
protected int WindowWidth { get; private set; }
|
||||
protected int WindowHeight { get; private set; }
|
||||
|
||||
public static event EventHandler<StatusUpdatedEventArgs> StatusUpdatedEvent;
|
||||
|
||||
@ -71,9 +73,6 @@ namespace Ryujinx.Ui
|
||||
private IKeyboard _keyboardInterface;
|
||||
private GraphicsDebugLevel _glLogLevel;
|
||||
private string _gpuVendorName;
|
||||
|
||||
private int _windowHeight;
|
||||
private int _windowWidth;
|
||||
private bool _isMouseInClient;
|
||||
|
||||
public RendererWidgetBase(InputManager inputManager, GraphicsDebugLevel glLogLevel)
|
||||
@ -223,10 +222,10 @@ namespace Ryujinx.Ui
|
||||
|
||||
Gdk.Monitor monitor = Display.GetMonitorAtWindow(Window);
|
||||
|
||||
_windowWidth = evnt.Width * monitor.ScaleFactor;
|
||||
_windowHeight = evnt.Height * monitor.ScaleFactor;
|
||||
WindowWidth = evnt.Width * monitor.ScaleFactor;
|
||||
WindowHeight = evnt.Height * monitor.ScaleFactor;
|
||||
|
||||
Renderer?.Window.SetSize(_windowWidth, _windowHeight);
|
||||
Renderer?.Window.SetSize(WindowWidth, WindowHeight);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -307,7 +306,7 @@ namespace Ryujinx.Ui
|
||||
}
|
||||
|
||||
Renderer = renderer;
|
||||
Renderer?.Window.SetSize(_windowWidth, _windowHeight);
|
||||
Renderer?.Window.SetSize(WindowWidth, WindowHeight);
|
||||
|
||||
if (Renderer != null)
|
||||
{
|
||||
|
@ -112,7 +112,7 @@ namespace Ryujinx.Ui.Windows
|
||||
_amiiboJsonPath = System.IO.Path.Join(AppDataManager.BaseDirPath, "system", "amiibo", "Amiibo.json");
|
||||
_amiiboList = new List<AmiiboApi>();
|
||||
|
||||
_amiiboLogoBytes = EmbeddedResources.Read("Ryujinx/Ui/Resources/Logo_Amiibo.png");
|
||||
_amiiboLogoBytes = EmbeddedResources.Read("Ryujinx.Ui.Common/Resources/Logo_Amiibo.png");
|
||||
_amiiboImage.Pixbuf = new Gdk.Pixbuf(_amiiboLogoBytes);
|
||||
|
||||
_scanButton.Sensitive = false;
|
||||
|
Reference in New Issue
Block a user