Merge remote-tracking branch 'ryu/master' into feature3

This commit is contained in:
John Clemis 2018-12-18 00:26:21 -06:00
commit 5731c58332
114 changed files with 2066 additions and 2166 deletions

View file

@ -116,6 +116,56 @@
Controls_Right_JoyConController_Button_ZR (String) Controls_Right_JoyConController_Button_ZR (String)
``` ```
- Default Mapping
- Controller
- Left Joycon:
- Analog Stick = Left Analog Stick
- DPad Up = DPad Up
- DPad Down = DPad Down
- DPad Left = DPad Left
- DPad Right = DPad Right
- Minus = Select / Back / Share
- L = Left Shoulder Button
- ZL = Left Trigger
- Right Joycon:
- Analog Stick = Right Analog Stick
- A = B / Circle
- B = A / Cross
- X = Y / Triangle
- Y = X / Square
- Plus = Start / Options
- R = Right Shoulder Button
- ZR = Right Trigger
- Keyboard
- Left Joycon:
- Stick Up = W
- Stick Down = S
- Stick Left = A
- Stick Right = D
- Stick Button = F
- DPad Up = Up
- DPad Down = Down
- DPad Left = Left
- DPad Right = Right
- Minus = -
- L = E
- ZL = Q
- Right Joycon:
- Stick Up = I
- Stick Down = K
- Stick Left = J
- Stick Right = L
- Stick Button = H
- A = Z
- B = X
- X = C
- Y = V
- Plus = +
- R = U
- ZR = O
- Valid Button Mappings - Valid Button Mappings
- A = The A / Cross Button - A = The A / Cross Button
- B = The B / Circle Button - B = The B / Circle Button

View file

@ -1380,6 +1380,22 @@ namespace ChocolArm64.Instructions
}); });
} }
public static void Frintz_S(ILEmitterCtx context)
{
EmitScalarUnaryOpF(context, () =>
{
EmitUnaryMathCall(context, nameof(Math.Truncate));
});
}
public static void Frintz_V(ILEmitterCtx context)
{
EmitVectorUnaryOpF(context, () =>
{
EmitUnaryMathCall(context, nameof(Math.Truncate));
});
}
public static void Frsqrte_S(ILEmitterCtx context) public static void Frsqrte_S(ILEmitterCtx context)
{ {
EmitScalarUnaryOpF(context, () => EmitScalarUnaryOpF(context, () =>

View file

@ -329,6 +329,8 @@ namespace ChocolArm64
SetA64("0>0011101<100001100010xxxxxxxxxx", InstEmit.Frintp_V, typeof(OpCodeSimd64)); SetA64("0>0011101<100001100010xxxxxxxxxx", InstEmit.Frintp_V, typeof(OpCodeSimd64));
SetA64("000111100x100111010000xxxxxxxxxx", InstEmit.Frintx_S, typeof(OpCodeSimd64)); SetA64("000111100x100111010000xxxxxxxxxx", InstEmit.Frintx_S, typeof(OpCodeSimd64));
SetA64("0>1011100<100001100110xxxxxxxxxx", InstEmit.Frintx_V, typeof(OpCodeSimd64)); SetA64("0>1011100<100001100110xxxxxxxxxx", InstEmit.Frintx_V, typeof(OpCodeSimd64));
SetA64("000111100x100101110000xxxxxxxxxx", InstEmit.Frintz_S, typeof(OpCodeSimd64));
SetA64("0>0011101<100001100110xxxxxxxxxx", InstEmit.Frintz_V, typeof(OpCodeSimd64));
SetA64("011111101x100001110110xxxxxxxxxx", InstEmit.Frsqrte_S, typeof(OpCodeSimd64)); SetA64("011111101x100001110110xxxxxxxxxx", InstEmit.Frsqrte_S, typeof(OpCodeSimd64));
SetA64("0>1011101<100001110110xxxxxxxxxx", InstEmit.Frsqrte_V, typeof(OpCodeSimd64)); SetA64("0>1011101<100001110110xxxxxxxxxx", InstEmit.Frsqrte_V, typeof(OpCodeSimd64));
SetA64("010111101x1xxxxx111111xxxxxxxxxx", InstEmit.Frsqrts_S, typeof(OpCodeSimdReg64)); SetA64("010111101x1xxxxx111111xxxxxxxxxx", InstEmit.Frsqrts_S, typeof(OpCodeSimdReg64));

View file

@ -3,98 +3,45 @@
Experimental Switch emulator written in C# Experimental Switch emulator written in C#
Don't expect much from this. Some homebrew apps work, Puyo Puyo Tetris shows the intro logo (sometimes), and a handful of games boot / work; but that's about it for now. Many games boot, only a handful are playable, see the compatiblity list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues).
Contributions are always welcome.
**Building** **Building**
To build this emulator, you will need the .NET Core 2.1 (RC1) (or higher) SDK. https://www.microsoft.com/net/download/ To build this emulator, you will need the [.NET Core 2.1 (or higher) SDK](https://www.microsoft.com/net/download/)
In release builds, memory checks are disabled to improve performances. or just drag'n'drop the homebrew *.NRO / *.NSO or the game *.NSP / *.XCI on the executable if you have a pre-built version.
Or just drag'n'drop the *.NRO / *.NSO or the game folder on the executable if you have a pre-build version.
**Features** **Features**
- Audio is partially supported (glitched) on Windows but you need to install the OpenAL Core SDK. - Audio is partially supported.
https://openal.org/downloads/OpenAL11CoreSDK.zip
- Keyboard Input is partially supported: - Keyboard Input is supported, see [CONFIG.md](CONFIG.md)
- Left Joycon:
- Stick Up = W
- Stick Down = S
- Stick Left = A
- Stick Right = D
- Stick Button = F
- DPad Up = Up
- DPad Down = Down
- DPad Left = Left
- DPad Right = Right
- Minus = -
- L = E
- ZL = Q
- Right Joycon: - Controller Input is supported, see [CONFIG.md](CONFIG.md)
- Stick Up = I
- Stick Down = K
- Stick Left = J
- Stick Right = L
- Stick Button = H
- A = Z
- B = X
- X = C
- Y = V
- Plus = +
- R = U
- ZR = O
- For more information on how to configure these buttons see [CONFIG.md](CONFIG.md)
- Controller Input is partially supported:
- Left Joycon:
- Analog Stick = Left Analog Stick
- DPad Up = DPad Up
- DPad Down = DPad Down
- DPad Left = DPad Left
- DPad Right = DPad Right
- Minus = Select / Back / Share
- L = Left Shoulder Button
- ZL = Left Trigger
- Right Joycon:
- Analog Stick = Right Analog Stick
- A = B / Circle
- B = A / Cross
- X = Y / Triangle
- Y = X / Square
- Plus = Start / Options
- R = Right Shoulder Button
- ZR = Right Trigger
- For more information on how to configure these buttons see [CONFIG.md](CONFIG.md)
- Config File: `Ryujinx.conf` should be present in executable folder. - Config File: `Ryujinx.conf` should be present in executable folder.
For more information [you can go here](CONFIG.md). For more information [you can go here](CONFIG.md).
**Help** **Help**
If you have some homebrew that currently doesn't work within the emulator, you can contact us through our Discord with the compiled NRO/NSO (and source code if possible) and then we'll make changes in order to make the requested app / game work. If you have some homebrew that currently doesn't work within the emulator, you can contact us through our Discord with the compiled *.NRO / *.NSO (and source code if possible) and then we'll keep whatever is making app / game not work on the watch list and fix it at a later date.
**Contact** **Contact**
For help, support, suggestions, or if you just want to get in touch with the team; join our Discord server! For help, support, suggestions, or if you just want to get in touch with the team; join our [Discord server](https://discord.gg/N2FmfVc)!
https://discord.gg/VkQYXAZ
For donation support, please take a look at our Patreon: https://www.patreon.com/ryujinx For donation support, please take a look at our [Patreon](https://www.patreon.com/ryujinx).
**Running** **Running**
To run this emulator, you need the .NET Core 2.1 (or higher) SDK *and* the OpenAL 11 Core SDK. To run this emulator, you need the .NET Core 2.1 (or higher) SDK.
Run `dotnet run -c Release -- path\to\homebrew.nro` inside the Ryujinx solution folder to run homebrew apps. Run `dotnet run -c Release -- path\to\homebrew.nro` inside the Ryujinx project folder to run homebrew apps.
Run `dotnet run -c Release -- path\to\game_exefs_and_romfs_folder` to run official games (they need to be decrypted and extracted first!) Run `dotnet run -c Release -- path\to\game.nsp/xci` to run official games.
**Compatibility** **Compatibility**
You can check out the compatibility list within the Wiki. Only a handful of games actually work. You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues).
**Latest build** **Latest build**
These builds are compiled automatically for each commit on the master branch. They may be unstable or might not work at all. These builds are compiled automatically for each commit on the master branch. They may be unstable or might not work at all.
The latest automatic build for Windows (64-bit) can be found on the [official website](https://ryujinx.org/#/Build). The latest automatic build for Windows, Mac, and Linux can be found on the [official website](https://ryujinx.org/#/Build).

View file

@ -59,7 +59,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{ {
GlslProgram Program; GlslProgram Program;
GlslDecompiler Decompiler = new GlslDecompiler(); GlslDecompiler Decompiler = new GlslDecompiler(OGLLimit.MaxUboSize);
int ShaderDumpIndex = ShaderDumper.DumpIndex; int ShaderDumpIndex = ShaderDumper.DumpIndex;

View file

@ -1,4 +1,3 @@
using Ryujinx.Graphics.Gal.OpenGL;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -51,8 +50,6 @@ namespace Ryujinx.Graphics.Gal.Shader
public const string SsyStackName = "ssy_stack"; public const string SsyStackName = "ssy_stack";
public const string SsyCursorName = "ssy_cursor"; public const string SsyCursorName = "ssy_cursor";
public static int MaxUboSize => OGLLimit.MaxUboSize / 16;
private string[] StagePrefixes = new string[] { "vp", "tcp", "tep", "gp", "fp" }; private string[] StagePrefixes = new string[] { "vp", "tcp", "tep", "gp", "fp" };
private string StagePrefix; private string StagePrefix;

View file

@ -31,7 +31,9 @@ namespace Ryujinx.Graphics.Gal.Shader
private StringBuilder SB; private StringBuilder SB;
public GlslDecompiler() public int MaxUboSize { get; }
public GlslDecompiler(int MaxUboSize)
{ {
InstsExpr = new Dictionary<ShaderIrInst, GetInstExpr>() InstsExpr = new Dictionary<ShaderIrInst, GetInstExpr>()
{ {
@ -106,6 +108,8 @@ namespace Ryujinx.Graphics.Gal.Shader
{ ShaderIrInst.Utof, GetUtofExpr }, { ShaderIrInst.Utof, GetUtofExpr },
{ ShaderIrInst.Xor, GetXorExpr } { ShaderIrInst.Xor, GetXorExpr }
}; };
this.MaxUboSize = MaxUboSize / 16;
} }
public GlslProgram Decompile( public GlslProgram Decompile(
@ -259,7 +263,7 @@ namespace Ryujinx.Graphics.Gal.Shader
{ {
SB.AppendLine($"layout (std140) uniform {GlslDecl.GmemUniformBlockName} {{"); SB.AppendLine($"layout (std140) uniform {GlslDecl.GmemUniformBlockName} {{");
SB.AppendLine($"{IndentationStr}vec4 {GlslDecl.GmemUniformBlockName}_data[{GlslDecl.MaxUboSize}];"); SB.AppendLine($"{IndentationStr}vec4 {GlslDecl.GmemUniformBlockName}_data[{MaxUboSize}];");
SB.AppendLine("};"); SB.AppendLine("};");
SB.AppendLine(); SB.AppendLine();
@ -269,7 +273,7 @@ namespace Ryujinx.Graphics.Gal.Shader
{ {
SB.AppendLine($"layout (std140) uniform {DeclInfo.Name} {{"); SB.AppendLine($"layout (std140) uniform {DeclInfo.Name} {{");
SB.AppendLine($"{IndentationStr}vec4 {DeclInfo.Name}_data[{GlslDecl.MaxUboSize}];"); SB.AppendLine($"{IndentationStr}vec4 {DeclInfo.Name}_data[{MaxUboSize}];");
SB.AppendLine("};"); SB.AppendLine("};");
} }

View file

@ -1,4 +1,4 @@
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Process;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;

View file

@ -2,7 +2,10 @@ using LibHac;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem.Content; using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS.Font; using Ryujinx.HLE.HOS.Font;
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.HOS.SystemState;
using Ryujinx.HLE.Loaders.Executables; using Ryujinx.HLE.Loaders.Executables;
using Ryujinx.HLE.Loaders.Npdm; using Ryujinx.HLE.Loaders.Npdm;

View file

@ -1,5 +1,7 @@
using ChocolArm64.Memory; using ChocolArm64.Memory;
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Ipc;
using Ryujinx.HLE.HOS.Kernel.Process;
using System; using System;
using System.IO; using System.IO;
@ -7,7 +9,7 @@ namespace Ryujinx.HLE.HOS.Ipc
{ {
static class IpcHandler static class IpcHandler
{ {
public static long IpcCall( public static KernelResult IpcCall(
Switch device, Switch device,
KProcess process, KProcess process,
MemoryManager memory, MemoryManager memory,
@ -100,7 +102,7 @@ namespace Ryujinx.HLE.HOS.Ipc
memory.WriteBytes(cmdPtr, response.GetBytes(cmdPtr)); memory.WriteBytes(cmdPtr, response.GetBytes(cmdPtr));
} }
return 0; return KernelResult.Success;
} }
private static IpcMessage FillResponse(IpcMessage response, long result, params int[] values) private static IpcMessage FillResponse(IpcMessage response, long result, params int[] values)

View file

@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Common
{ {
interface IKFutureSchedulerObject interface IKFutureSchedulerObject
{ {

View file

@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Common
{ {
class KAutoObject class KAutoObject
{ {

View file

@ -1,7 +1,8 @@
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using System.Collections.Generic; using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Common
{ {
class KResourceLimit class KResourceLimit
{ {

View file

@ -1,6 +1,7 @@
using Ryujinx.HLE.HOS.Kernel.Threading;
using System.Collections.Generic; using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Common
{ {
class KSynchronizationObject : KAutoObject class KSynchronizationObject : KAutoObject
{ {

View file

@ -4,7 +4,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Common
{ {
class KTimeManager : IDisposable class KTimeManager : IDisposable
{ {

View file

@ -1,6 +1,7 @@
using Ryujinx.HLE.HOS.Kernel.Memory;
using System; using System;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Common
{ {
static class KernelInit static class KernelInit
{ {

View file

@ -1,9 +1,10 @@
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Common
{ {
enum KernelResult enum KernelResult
{ {
Success = 0, Success = 0,
InvalidCapability = 0x1c01, InvalidCapability = 0x1c01,
ThreadNotStarted = 0x7201,
ThreadTerminating = 0x7601, ThreadTerminating = 0x7601,
InvalidSize = 0xca01, InvalidSize = 0xca01,
InvalidAddress = 0xcc01, InvalidAddress = 0xcc01,

View file

@ -0,0 +1,72 @@
using Ryujinx.HLE.HOS.Kernel.Process;
using ChocolArm64.Memory;
namespace Ryujinx.HLE.HOS.Kernel.Common
{
static class KernelTransfer
{
public static bool UserToKernelInt32(Horizon system, ulong address, out int value)
{
KProcess currentProcess = system.Scheduler.GetCurrentProcess();
if (currentProcess.CpuMemory.IsMapped((long)address) &&
currentProcess.CpuMemory.IsMapped((long)address + 3))
{
value = currentProcess.CpuMemory.ReadInt32((long)address);
return true;
}
value = 0;
return false;
}
public static bool UserToKernelString(Horizon system, ulong address, int size, out string value)
{
KProcess currentProcess = system.Scheduler.GetCurrentProcess();
if (currentProcess.CpuMemory.IsMapped((long)address) &&
currentProcess.CpuMemory.IsMapped((long)address + size - 1))
{
value = MemoryHelper.ReadAsciiString(currentProcess.CpuMemory, (long)address, size);
return true;
}
value = null;
return false;
}
public static bool KernelToUserInt32(Horizon system, ulong address, int value)
{
KProcess currentProcess = system.Scheduler.GetCurrentProcess();
if (currentProcess.CpuMemory.IsMapped((long)address) &&
currentProcess.CpuMemory.IsMapped((long)address + 3))
{
currentProcess.CpuMemory.WriteInt32ToSharedAddr((long)address, value);
return true;
}
return false;
}
public static bool KernelToUserInt64(Horizon system, ulong address, long value)
{
KProcess currentProcess = system.Scheduler.GetCurrentProcess();
if (currentProcess.CpuMemory.IsMapped((long)address) &&
currentProcess.CpuMemory.IsMapped((long)address + 7))
{
currentProcess.CpuMemory.WriteInt64((long)address, value);
return true;
}
return false;
}
}
}

View file

@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Common
{ {
enum LimitableResource : byte enum LimitableResource : byte
{ {

View file

@ -1,6 +1,6 @@
using Ryujinx.Common; using Ryujinx.Common;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Common
{ {
class MersenneTwister class MersenneTwister
{ {

View file

@ -1,4 +1,6 @@
namespace Ryujinx.HLE.HOS.Kernel using Ryujinx.HLE.HOS.Kernel.Common;
namespace Ryujinx.HLE.HOS.Kernel.Ipc
{ {
class KClientPort : KSynchronizationObject class KClientPort : KSynchronizationObject
{ {

View file

@ -1,4 +1,6 @@
namespace Ryujinx.HLE.HOS.Kernel using Ryujinx.HLE.HOS.Kernel.Common;
namespace Ryujinx.HLE.HOS.Kernel.Ipc
{ {
class KPort : KAutoObject class KPort : KAutoObject
{ {

View file

@ -1,4 +1,6 @@
namespace Ryujinx.HLE.HOS.Kernel using Ryujinx.HLE.HOS.Kernel.Common;
namespace Ryujinx.HLE.HOS.Kernel.Ipc
{ {
class KServerPort : KSynchronizationObject class KServerPort : KSynchronizationObject
{ {

View file

@ -1,7 +1,7 @@
using Ryujinx.HLE.HOS.Services; using Ryujinx.HLE.HOS.Services;
using System; using System;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Ipc
{ {
class KSession : IDisposable class KSession : IDisposable
{ {

View file

@ -1,24 +0,0 @@
namespace Ryujinx.HLE.HOS.Kernel
{
static class KernelErr
{
public const int ThreadTerminating = 59;
public const int InvalidSize = 101;
public const int InvalidAddress = 102;
public const int OutOfMemory = 104;
public const int HandleTableFull = 105;
public const int NoAccessPerm = 106;
public const int InvalidPermission = 108;
public const int InvalidMemRange = 110;
public const int InvalidPriority = 112;
public const int InvalidCoreId = 113;
public const int InvalidHandle = 114;
public const int InvalidMaskValue = 116;
public const int Timeout = 117;
public const int Cancelled = 118;
public const int CountOutOfRange = 119;
public const int InvalidEnumValue = 120;
public const int InvalidThread = 122;
public const int InvalidState = 125;
}
}

View file

@ -1,71 +0,0 @@
using ChocolArm64.Memory;
namespace Ryujinx.HLE.HOS.Kernel
{
static class KernelTransfer
{
public static bool UserToKernelInt32(Horizon system, long address, out int value)
{
KProcess currentProcess = system.Scheduler.GetCurrentProcess();
if (currentProcess.CpuMemory.IsMapped(address) &&
currentProcess.CpuMemory.IsMapped(address + 3))
{
value = currentProcess.CpuMemory.ReadInt32(address);
return true;
}
value = 0;
return false;
}
public static bool UserToKernelString(Horizon system, long address, int size, out string value)
{
KProcess currentProcess = system.Scheduler.GetCurrentProcess();
if (currentProcess.CpuMemory.IsMapped(address) &&
currentProcess.CpuMemory.IsMapped(address + size - 1))
{
value = MemoryHelper.ReadAsciiString(currentProcess.CpuMemory, address, size);
return true;
}
value = null;
return false;
}
public static bool KernelToUserInt32(Horizon system, long address, int value)
{
KProcess currentProcess = system.Scheduler.GetCurrentProcess();
if (currentProcess.CpuMemory.IsMapped(address) &&
currentProcess.CpuMemory.IsMapped(address + 3))
{
currentProcess.CpuMemory.WriteInt32ToSharedAddr(address, value);
return true;
}
return false;
}
public static bool KernelToUserInt64(Horizon system, long address, long value)
{
KProcess currentProcess = system.Scheduler.GetCurrentProcess();
if (currentProcess.CpuMemory.IsMapped(address) &&
currentProcess.CpuMemory.IsMapped(address + 7))
{
currentProcess.CpuMemory.WriteInt64(address, value);
return true;
}
return false;
}
}
}

View file

@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
enum AddressSpaceType enum AddressSpaceType
{ {

View file

@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
static class DramMemoryMap static class DramMemoryMap
{ {

View file

@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
class KMemoryArrange class KMemoryArrange
{ {

View file

@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
struct KMemoryArrangeRegion struct KMemoryArrangeRegion
{ {

View file

@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
class KMemoryBlock class KMemoryBlock
{ {

View file

@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
class KMemoryBlockAllocator class KMemoryBlockAllocator
{ {

View file

@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
class KMemoryInfo class KMemoryInfo
{ {

View file

@ -1,9 +1,11 @@
using ChocolArm64.Memory; using ChocolArm64.Memory;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Process;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
class KMemoryManager class KMemoryManager
{ {

View file

@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
class KMemoryRegionBlock class KMemoryRegionBlock
{ {

View file

@ -1,6 +1,7 @@
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.HLE.HOS.Kernel.Common;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
class KMemoryRegionManager class KMemoryRegionManager
{ {

View file

@ -1,7 +1,8 @@
using Ryujinx.HLE.HOS.Kernel.Common;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
class KPageList : IEnumerable<KPageNode> class KPageList : IEnumerable<KPageNode>
{ {

View file

@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
struct KPageNode struct KPageNode
{ {

View file

@ -1,6 +1,8 @@
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Process;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
class KSharedMemory class KSharedMemory
{ {

View file

@ -1,6 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
class KSlabHeap class KSlabHeap
{ {

View file

@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
class KTransferMemory class KTransferMemory
{ {

View file

@ -1,6 +1,6 @@
using System; using System;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
[Flags] [Flags]
enum MemoryAttribute : byte enum MemoryAttribute : byte

View file

@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
enum MemoryOperation enum MemoryOperation
{ {

View file

@ -1,6 +1,6 @@
using System; using System;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
[Flags] [Flags]
enum MemoryPermission : byte enum MemoryPermission : byte

View file

@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
enum MemoryRegion enum MemoryRegion
{ {

View file

@ -1,6 +1,6 @@
using System; using System;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Memory
{ {
[Flags] [Flags]
enum MemoryState : uint enum MemoryState : uint

View file

@ -2,13 +2,14 @@ using ChocolArm64.Memory;
using ChocolArm64.State; using ChocolArm64.State;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Diagnostics.Demangler; using Ryujinx.HLE.HOS.Diagnostics.Demangler;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.Loaders.Elf; using Ryujinx.HLE.Loaders.Elf;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Process
{ {
class HleProcessDebugger class HleProcessDebugger
{ {

View file

@ -1,7 +1,7 @@
using Ryujinx.Common; using Ryujinx.Common;
using System; using System;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Process
{ {
class KContextIdManager class KContextIdManager
{ {

View file

@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Process
{ {
class KHandleEntry class KHandleEntry
{ {

View file

@ -1,6 +1,8 @@
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using System; using System;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Process
{ {
class KHandleTable class KHandleTable
{ {

View file

@ -3,12 +3,16 @@ using ChocolArm64.Events;
using ChocolArm64.Memory; using ChocolArm64.Memory;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.SupervisorCall;
using Ryujinx.HLE.HOS.Kernel.Threading;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Process
{ {
class KProcess : KSynchronizationObject class KProcess : KSynchronizationObject
{ {

View file

@ -1,6 +1,9 @@
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Threading;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Process
{ {
class KProcessCapabilities class KProcessCapabilities
{ {

View file

@ -1,4 +1,6 @@
namespace Ryujinx.HLE.HOS.Kernel using Ryujinx.HLE.HOS.Kernel.Memory;
namespace Ryujinx.HLE.HOS.Kernel.Process
{ {
class KTlsPageInfo class KTlsPageInfo
{ {

View file

@ -1,6 +1,7 @@
using Ryujinx.HLE.HOS.Kernel.Memory;
using System; using System;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Process
{ {
class KTlsPageManager class KTlsPageManager
{ {

View file

@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Process
{ {
struct ProcessCreationInfo struct ProcessCreationInfo
{ {

View file

@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Process
{ {
enum ProcessState : byte enum ProcessState : byte
{ {

View file

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

View file

@ -0,0 +1,61 @@
using ChocolArm64.Events;
using ChocolArm64.Memory;
using ChocolArm64.State;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel.Ipc;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading;
using System;
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
partial class SvcHandler
{
private Switch _device;
private KProcess _process;
private Horizon _system;
private MemoryManager _memory;
private struct HleIpcMessage
{
public KThread Thread { get; private set; }
public KSession Session { get; private set; }
public IpcMessage Message { get; private set; }
public long MessagePtr { get; private set; }
public HleIpcMessage(
KThread thread,
KSession session,
IpcMessage message,
long messagePtr)
{
Thread = thread;
Session = session;
Message = message;
MessagePtr = messagePtr;
}
}
public SvcHandler(Switch device, KProcess process)
{
_device = device;
_process = process;
_system = device.System;
_memory = process.CpuMemory;
}
public void SvcCall(object sender, InstExceptionEventArgs e)
{
Action<SvcHandler, CpuThreadState> svcFunc = SvcTable.GetSvcFunc(e.Id);
if (svcFunc == null)
{
throw new NotImplementedException($"SVC 0x{e.Id:X4} is not implemented.");
}
CpuThreadState threadState = (CpuThreadState)sender;
svcFunc(this, threadState);
}
}
}

View file

@ -0,0 +1,394 @@
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Process;
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
partial class SvcHandler
{
public KernelResult SetHeapSize64(ulong size, out ulong position)
{
return SetHeapSize(size, out position);
}
private KernelResult SetHeapSize(ulong size, out ulong position)
{
if ((size & 0xfffffffe001fffff) != 0)
{
position = 0;
return KernelResult.InvalidSize;
}
return _process.MemoryManager.SetHeapSize(size, out position);
}
public KernelResult SetMemoryAttribute64(
ulong position,
ulong size,
MemoryAttribute attributeMask,
MemoryAttribute attributeValue)
{
return SetMemoryAttribute(position, size, attributeMask, attributeValue);
}
private KernelResult SetMemoryAttribute(
ulong position,
ulong size,
MemoryAttribute attributeMask,
MemoryAttribute attributeValue)
{
if (!PageAligned(position))
{
return KernelResult.InvalidAddress;
}
if (!PageAligned(size) || size == 0)
{
return KernelResult.InvalidSize;
}
MemoryAttribute attributes = attributeMask | attributeValue;
if (attributes != attributeMask ||
(attributes | MemoryAttribute.Uncached) != MemoryAttribute.Uncached)
{
return KernelResult.InvalidCombination;
}
KernelResult result = _process.MemoryManager.SetMemoryAttribute(
position,
size,
attributeMask,
attributeValue);
if (result == KernelResult.Success)
{
_memory.StopObservingRegion((long)position, (long)size);
}
return result;
}
public KernelResult MapMemory64(ulong dst, ulong src, ulong size)
{
return MapMemory(dst, src, size);
}
private KernelResult MapMemory(ulong dst, ulong src, ulong size)
{
if (!PageAligned(src | dst))
{
return KernelResult.InvalidAddress;
}
if (!PageAligned(size) || size == 0)
{
return KernelResult.InvalidSize;
}
if (src + size <= src || dst + size <= dst)
{
return KernelResult.InvalidMemState;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
if (!currentProcess.MemoryManager.InsideAddrSpace(src, size))
{
return KernelResult.InvalidMemState;
}
if (currentProcess.MemoryManager.OutsideStackRegion(dst, size) ||
currentProcess.MemoryManager.InsideHeapRegion (dst, size) ||
currentProcess.MemoryManager.InsideAliasRegion (dst, size))
{
return KernelResult.InvalidMemRange;
}
return _process.MemoryManager.Map(dst, src, size);
}
public KernelResult UnmapMemory64(ulong dst, ulong src, ulong size)
{
return UnmapMemory(dst, src, size);
}
private KernelResult UnmapMemory(ulong dst, ulong src, ulong size)
{
if (!PageAligned(src | dst))
{
return KernelResult.InvalidAddress;
}
if (!PageAligned(size) || size == 0)
{
return KernelResult.InvalidSize;
}
if (src + size <= src || dst + size <= dst)
{
return KernelResult.InvalidMemState;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
if (!currentProcess.MemoryManager.InsideAddrSpace(src, size))
{
return KernelResult.InvalidMemState;
}
if (currentProcess.MemoryManager.OutsideStackRegion(dst, size) ||
currentProcess.MemoryManager.InsideHeapRegion (dst, size) ||
currentProcess.MemoryManager.InsideAliasRegion (dst, size))
{
return KernelResult.InvalidMemRange;
}
return _process.MemoryManager.Unmap(dst, src, size);
}
public KernelResult QueryMemory64(ulong infoPtr, ulong x1, ulong position)
{
return QueryMemory(infoPtr, position);
}
private KernelResult QueryMemory(ulong infoPtr, ulong position)
{
KMemoryInfo blkInfo = _process.MemoryManager.QueryMemory(position);
_memory.WriteUInt64((long)infoPtr + 0x00, blkInfo.Address);
_memory.WriteUInt64((long)infoPtr + 0x08, blkInfo.Size);
_memory.WriteInt32 ((long)infoPtr + 0x10, (int)blkInfo.State & 0xff);
_memory.WriteInt32 ((long)infoPtr + 0x14, (int)blkInfo.Attribute);
_memory.WriteInt32 ((long)infoPtr + 0x18, (int)blkInfo.Permission);
_memory.WriteInt32 ((long)infoPtr + 0x1c, blkInfo.IpcRefCount);
_memory.WriteInt32 ((long)infoPtr + 0x20, blkInfo.DeviceRefCount);
_memory.WriteInt32 ((long)infoPtr + 0x24, 0);
return KernelResult.Success;
}
public KernelResult MapSharedMemory64(int handle, ulong address, ulong size, MemoryPermission permission)
{
return MapSharedMemory(handle, address, size, permission);
}
private KernelResult MapSharedMemory(int handle, ulong address, ulong size, MemoryPermission permission)
{
if (!PageAligned(address))
{
return KernelResult.InvalidAddress;
}
if (!PageAligned(size) || size == 0)
{
return KernelResult.InvalidSize;
}
if (address + size <= address)
{
return KernelResult.InvalidMemState;
}
if ((permission | MemoryPermission.Write) != MemoryPermission.ReadAndWrite)
{
return KernelResult.InvalidPermission;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KSharedMemory sharedMemory = currentProcess.HandleTable.GetObject<KSharedMemory>(handle);
if (sharedMemory == null)
{
return KernelResult.InvalidHandle;
}
if (currentProcess.MemoryManager.IsInvalidRegion (address, size) ||
currentProcess.MemoryManager.InsideHeapRegion (address, size) ||
currentProcess.MemoryManager.InsideAliasRegion(address, size))
{
return KernelResult.InvalidMemRange;
}
return sharedMemory.MapIntoProcess(
currentProcess.MemoryManager,
address,
size,
currentProcess,
permission);
}
public KernelResult UnmapSharedMemory64(int handle, ulong address, ulong size)
{
return UnmapSharedMemory(handle, address, size);
}
private KernelResult UnmapSharedMemory(int handle, ulong address, ulong size)
{
if (!PageAligned(address))
{
return KernelResult.InvalidAddress;
}
if (!PageAligned(size) || size == 0)
{
return KernelResult.InvalidSize;
}
if (address + size <= address)
{
return KernelResult.InvalidMemState;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KSharedMemory sharedMemory = currentProcess.HandleTable.GetObject<KSharedMemory>(handle);
if (sharedMemory == null)
{
return KernelResult.InvalidHandle;
}
if (currentProcess.MemoryManager.IsInvalidRegion (address, size) ||
currentProcess.MemoryManager.InsideHeapRegion (address, size) ||
currentProcess.MemoryManager.InsideAliasRegion(address, size))
{
return KernelResult.InvalidMemRange;
}
return sharedMemory.UnmapFromProcess(
currentProcess.MemoryManager,
address,
size,
currentProcess);
}
public KernelResult CreateTransferMemory64(
ulong address,
ulong size,
MemoryPermission permission,
out int handle)
{
return CreateTransferMemory(address, size, permission, out handle);
}
private KernelResult CreateTransferMemory(ulong address, ulong size, MemoryPermission permission, out int handle)
{
handle = 0;
if (!PageAligned(address))
{
return KernelResult.InvalidAddress;
}
if (!PageAligned(size) || size == 0)
{
return KernelResult.InvalidSize;
}
if (address + size <= address)
{
return KernelResult.InvalidMemState;
}
if (permission > MemoryPermission.ReadAndWrite || permission == MemoryPermission.Write)
{
return KernelResult.InvalidPermission;
}
KernelResult result = _process.MemoryManager.ReserveTransferMemory(address, size, permission);
if (result != KernelResult.Success)
{
return result;
}
KTransferMemory transferMemory = new KTransferMemory(address, size);
return _process.HandleTable.GenerateHandle(transferMemory, out handle);
}
public KernelResult MapPhysicalMemory64(ulong address, ulong size)
{
return MapPhysicalMemory(address, size);
}
private KernelResult MapPhysicalMemory(ulong address, ulong size)
{
if (!PageAligned(address))
{
return KernelResult.InvalidAddress;
}
if (!PageAligned(size) || size == 0)
{
return KernelResult.InvalidSize;
}
if (address + size <= address)
{
return KernelResult.InvalidMemRange;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
if ((currentProcess.PersonalMmHeapPagesCount & 0xfffffffffffff) == 0)
{
return KernelResult.InvalidState;
}
if (!currentProcess.MemoryManager.InsideAddrSpace (address, size) ||
currentProcess.MemoryManager.OutsideAliasRegion(address, size))
{
return KernelResult.InvalidMemRange;
}
return _process.MemoryManager.MapPhysicalMemory(address, size);
}
public KernelResult UnmapPhysicalMemory64(ulong address, ulong size)
{
return MapPhysicalMemory(address, size);
}
private KernelResult UnmapPhysicalMemory(ulong address, ulong size)
{
if (!PageAligned(address))
{
return KernelResult.InvalidAddress;
}
if (!PageAligned(size) || size == 0)
{
return KernelResult.InvalidSize;
}
if (address + size <= address)
{
return KernelResult.InvalidMemRange;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
if ((currentProcess.PersonalMmHeapPagesCount & 0xfffffffffffff) == 0)
{
return KernelResult.InvalidState;
}
if (!currentProcess.MemoryManager.InsideAddrSpace (address, size) ||
currentProcess.MemoryManager.OutsideAliasRegion(address, size))
{
return KernelResult.InvalidMemRange;
}
return _process.MemoryManager.UnmapPhysicalMemory(address, size);
}
private static bool PageAligned(ulong position)
{
return (position & (KMemoryManager.PageSize - 1)) == 0;
}
}
}

View file

@ -1,27 +1,33 @@
using ChocolArm64.Memory; using ChocolArm64.Memory;
using ChocolArm64.State;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Ipc;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services; using Ryujinx.HLE.HOS.Services;
using System;
using System.Threading; using System.Threading;
using static Ryujinx.HLE.HOS.ErrorCode; namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
namespace Ryujinx.HLE.HOS.Kernel
{ {
partial class SvcHandler partial class SvcHandler
{ {
private void SvcExitProcess(CpuThreadState threadState) public void ExitProcess64()
{
ExitProcess();
}
private void ExitProcess()
{ {
_system.Scheduler.GetCurrentProcess().Terminate(); _system.Scheduler.GetCurrentProcess().Terminate();
} }
private void SignalEvent64(CpuThreadState threadState) public KernelResult SignalEvent64(int handle)
{ {
threadState.X0 = (ulong)SignalEvent((int)threadState.X0); return SignalEvent(handle);
} }
private KernelResult SignalEvent(int handle) private KernelResult SignalEvent(int handle)
@ -41,17 +47,12 @@ namespace Ryujinx.HLE.HOS.Kernel
result = KernelResult.InvalidHandle; result = KernelResult.InvalidHandle;
} }
if (result != KernelResult.Success)
{
Logger.PrintWarning(LogClass.KernelSvc, "Operation failed with error: " + result + "!");
}
return result; return result;
} }
private void ClearEvent64(CpuThreadState threadState) public KernelResult ClearEvent64(int handle)
{ {
threadState.X0 = (ulong)ClearEvent((int)threadState.X0); return ClearEvent(handle);
} }
private KernelResult ClearEvent(int handle) private KernelResult ClearEvent(int handle)
@ -71,29 +72,23 @@ namespace Ryujinx.HLE.HOS.Kernel
result = writableEvent.Clear(); result = writableEvent.Clear();
} }
if (result != KernelResult.Success)
{
Logger.PrintWarning(LogClass.KernelSvc, "Operation failed with error: " + result + "!");
}
return result; return result;
} }
private void SvcCloseHandle(CpuThreadState threadState) public KernelResult CloseHandle64(int handle)
{ {
int handle = (int)threadState.X0; return CloseHandle(handle);
}
private KernelResult CloseHandle(int handle)
{
object obj = _process.HandleTable.GetObject<object>(handle); object obj = _process.HandleTable.GetObject<object>(handle);
_process.HandleTable.CloseHandle(handle); _process.HandleTable.CloseHandle(handle);
if (obj == null) if (obj == null)
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid handle 0x{handle:x8}!"); return KernelResult.InvalidHandle;
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
return;
} }
if (obj is KSession session) if (obj is KSession session)
@ -107,12 +102,12 @@ namespace Ryujinx.HLE.HOS.Kernel
transferMemory.Size); transferMemory.Size);
} }
threadState.X0 = 0; return KernelResult.Success;
} }
private void ResetSignal64(CpuThreadState threadState) public KernelResult ResetSignal64(int handle)
{ {
threadState.X0 = (ulong)ResetSignal((int)threadState.X0); return ResetSignal(handle);
} }
private KernelResult ResetSignal(int handle) private KernelResult ResetSignal(int handle)
@ -141,60 +136,43 @@ namespace Ryujinx.HLE.HOS.Kernel
} }
} }
if (result == KernelResult.InvalidState)
{
Logger.PrintDebug(LogClass.KernelSvc, "Operation failed with error: " + result + "!");
}
else if (result != KernelResult.Success)
{
Logger.PrintWarning(LogClass.KernelSvc, "Operation failed with error: " + result + "!");
}
return result; return result;
} }
private void SvcGetSystemTick(CpuThreadState threadState) public ulong GetSystemTick64()
{ {
threadState.X0 = threadState.CntpctEl0; return _system.Scheduler.GetCurrentThread().Context.ThreadState.CntpctEl0;
} }
private void SvcConnectToNamedPort(CpuThreadState threadState) public KernelResult ConnectToNamedPort64(ulong namePtr, out int handle)
{ {
long stackPtr = (long)threadState.X0; return ConnectToNamedPort(namePtr, out handle);
long namePtr = (long)threadState.X1; }
string name = MemoryHelper.ReadAsciiString(_memory, namePtr, 8); private KernelResult ConnectToNamedPort(ulong namePtr, out int handle)
{
string name = MemoryHelper.ReadAsciiString(_memory, (long)namePtr, 8);
//TODO: Validate that app has perms to access the service, and that the service //TODO: Validate that app has perms to access the service, and that the service
//actually exists, return error codes otherwise. //actually exists, return error codes otherwise.
KSession session = new KSession(ServiceFactory.MakeService(_system, name), name); KSession session = new KSession(ServiceFactory.MakeService(_system, name), name);
if (_process.HandleTable.GenerateHandle(session, out int handle) != KernelResult.Success) return _process.HandleTable.GenerateHandle(session, out handle);
{
throw new InvalidOperationException("Out of handles!");
}
threadState.X0 = 0;
threadState.X1 = (uint)handle;
} }
private void SvcSendSyncRequest(CpuThreadState threadState) public KernelResult SendSyncRequest64(int handle)
{ {
SendSyncRequest(threadState, threadState.Tpidr, 0x100, (int)threadState.X0); return SendSyncRequest((ulong)_system.Scheduler.GetCurrentThread().Context.ThreadState.Tpidr, 0x100, handle);
} }
private void SvcSendSyncRequestWithUserBuffer(CpuThreadState threadState) public KernelResult SendSyncRequestWithUserBuffer64(ulong messagePtr, ulong size, int handle)
{ {
SendSyncRequest( return SendSyncRequest(messagePtr, size, handle);
threadState,
(long)threadState.X0,
(long)threadState.X1,
(int)threadState.X2);
} }
private void SendSyncRequest(CpuThreadState threadState, long messagePtr, long size, int handle) private KernelResult SendSyncRequest(ulong messagePtr, ulong size, int handle)
{ {
byte[] messageData = _memory.ReadBytes(messagePtr, size); byte[] messageData = _memory.ReadBytes((long)messagePtr, (long)size);
KSession session = _process.HandleTable.GetObject<KSession>(handle); KSession session = _process.HandleTable.GetObject<KSession>(handle);
@ -205,29 +183,29 @@ namespace Ryujinx.HLE.HOS.Kernel
KThread currentThread = _system.Scheduler.GetCurrentThread(); KThread currentThread = _system.Scheduler.GetCurrentThread();
currentThread.SignaledObj = null; currentThread.SignaledObj = null;
currentThread.ObjSyncResult = 0; currentThread.ObjSyncResult = KernelResult.Success;
currentThread.Reschedule(ThreadSchedState.Paused); currentThread.Reschedule(ThreadSchedState.Paused);
IpcMessage message = new IpcMessage(messageData, messagePtr); IpcMessage message = new IpcMessage(messageData, (long)messagePtr);
ThreadPool.QueueUserWorkItem(ProcessIpcRequest, new HleIpcMessage( ThreadPool.QueueUserWorkItem(ProcessIpcRequest, new HleIpcMessage(
currentThread, currentThread,
session, session,
message, message,
messagePtr)); (long)messagePtr));
_system.ThreadCounter.AddCount(); _system.ThreadCounter.AddCount();
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
threadState.X0 = (ulong)currentThread.ObjSyncResult; return currentThread.ObjSyncResult;
} }
else else
{ {
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid session handle 0x{handle:x8}!"); Logger.PrintWarning(LogClass.KernelSvc, $"Invalid session handle 0x{handle:x8}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); return KernelResult.InvalidHandle;
} }
} }
@ -235,7 +213,7 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
HleIpcMessage ipcMessage = (HleIpcMessage)state; HleIpcMessage ipcMessage = (HleIpcMessage)state;
ipcMessage.Thread.ObjSyncResult = (int)IpcHandler.IpcCall( ipcMessage.Thread.ObjSyncResult = IpcHandler.IpcCall(
_device, _device,
_process, _process,
_memory, _memory,
@ -248,14 +226,9 @@ namespace Ryujinx.HLE.HOS.Kernel
ipcMessage.Thread.Reschedule(ThreadSchedState.Running); ipcMessage.Thread.Reschedule(ThreadSchedState.Running);
} }
private void GetProcessId64(CpuThreadState threadState) public KernelResult GetProcessId64(int handle, out long pid)
{ {
int handle = (int)threadState.X1; return GetProcessId(handle, out pid);
KernelResult result = GetProcessId(handle, out long pid);
threadState.X0 = (ulong)result;
threadState.X1 = (ulong)pid;
} }
private KernelResult GetProcessId(int handle, out long pid) private KernelResult GetProcessId(int handle, out long pid)
@ -283,15 +256,16 @@ namespace Ryujinx.HLE.HOS.Kernel
: KernelResult.InvalidHandle; : KernelResult.InvalidHandle;
} }
private void SvcBreak(CpuThreadState threadState) public void Break64(ulong reason, ulong x1, ulong info)
{ {
long reason = (long)threadState.X0; Break(reason);
long unknown = (long)threadState.X1; }
long info = (long)threadState.X2;
private void Break(ulong reason)
{
KThread currentThread = _system.Scheduler.GetCurrentThread(); KThread currentThread = _system.Scheduler.GetCurrentThread();
if ((reason & (1 << 31)) == 0) if ((reason & (1UL << 31)) == 0)
{ {
currentThread.PrintGuestStackTrace(); currentThread.PrintGuestStackTrace();
@ -305,29 +279,21 @@ namespace Ryujinx.HLE.HOS.Kernel
} }
} }
private void SvcOutputDebugString(CpuThreadState threadState) public void OutputDebugString64(ulong strPtr, ulong size)
{ {
long position = (long)threadState.X0; OutputDebugString(strPtr, size);
long size = (long)threadState.X1;
string str = MemoryHelper.ReadAsciiString(_memory, position, size);
Logger.PrintWarning(LogClass.KernelSvc, str);
threadState.X0 = 0;
} }
private void GetInfo64(CpuThreadState threadState) private void OutputDebugString(ulong strPtr, ulong size)
{ {
long stackPtr = (long)threadState.X0; string str = MemoryHelper.ReadAsciiString(_memory, (long)strPtr, (long)size);
uint id = (uint)threadState.X1;
int handle = (int)threadState.X2;
long subId = (long)threadState.X3;
KernelResult result = GetInfo(id, handle, subId, out long value); Logger.PrintWarning(LogClass.KernelSvc, str);
}
threadState.X0 = (ulong)result; public KernelResult GetInfo64(uint id, int handle, long subId, out long value)
threadState.X1 = (ulong)value; {
return GetInfo(id, handle, subId, out value);
} }
private KernelResult GetInfo(uint id, int handle, long subId, out long value) private KernelResult GetInfo(uint id, int handle, long subId, out long value)
@ -556,13 +522,9 @@ namespace Ryujinx.HLE.HOS.Kernel
return KernelResult.Success; return KernelResult.Success;
} }
private void CreateEvent64(CpuThreadState state) public KernelResult CreateEvent64(out int wEventHandle, out int rEventHandle)
{ {
KernelResult result = CreateEvent(out int wEventHandle, out int rEventHandle); return CreateEvent(out wEventHandle, out rEventHandle);
state.X0 = (ulong)result;
state.X1 = (ulong)wEventHandle;
state.X2 = (ulong)rEventHandle;
} }
private KernelResult CreateEvent(out int wEventHandle, out int rEventHandle) private KernelResult CreateEvent(out int wEventHandle, out int rEventHandle)
@ -588,15 +550,9 @@ namespace Ryujinx.HLE.HOS.Kernel
return result; return result;
} }
private void GetProcessList64(CpuThreadState state) public KernelResult GetProcessList64(ulong address, int maxCount, out int count)
{ {
ulong address = state.X1; return GetProcessList(address, maxCount, out count);
int maxOut = (int)state.X2;
KernelResult result = GetProcessList(address, maxOut, out int count);
state.X0 = (ulong)result;
state.X1 = (ulong)count;
} }
private KernelResult GetProcessList(ulong address, int maxCount, out int count) private KernelResult GetProcessList(ulong address, int maxCount, out int count)
@ -633,7 +589,7 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
if (copyCount < maxCount) if (copyCount < maxCount)
{ {
if (!KernelTransfer.KernelToUserInt64(_system, (long)address + copyCount * 8, process.Pid)) if (!KernelTransfer.KernelToUserInt64(_system, address + (ulong)copyCount * 8, process.Pid))
{ {
return KernelResult.UserCopyFailed; return KernelResult.UserCopyFailed;
} }
@ -648,16 +604,9 @@ namespace Ryujinx.HLE.HOS.Kernel
return KernelResult.Success; return KernelResult.Success;
} }
private void GetSystemInfo64(CpuThreadState state) public KernelResult GetSystemInfo64(uint id, int handle, long subId, out long value)
{ {
uint id = (uint)state.X1; return GetSystemInfo(id, handle, subId, out value);
int handle = (int)state.X2;
long subId = (long)state.X3;
KernelResult result = GetSystemInfo(id, handle, subId, out long value);
state.X0 = (ulong)result;
state.X1 = (ulong)value;
} }
private KernelResult GetSystemInfo(uint id, int handle, long subId, out long value) private KernelResult GetSystemInfo(uint id, int handle, long subId, out long value)
@ -716,28 +665,20 @@ namespace Ryujinx.HLE.HOS.Kernel
return KernelResult.Success; return KernelResult.Success;
} }
private void CreatePort64(CpuThreadState state) public KernelResult CreatePort64(
int maxSessions,
bool isLight,
ulong namePtr,
out int serverPortHandle,
out int clientPortHandle)
{ {
int maxSessions = (int)state.X2; return CreatePort(maxSessions, isLight, namePtr, out serverPortHandle, out clientPortHandle);
bool isLight = (state.X3 & 1) != 0;
long nameAddress = (long)state.X4;
KernelResult result = CreatePort(
maxSessions,
isLight,
nameAddress,
out int serverPortHandle,
out int clientPortHandle);
state.X0 = (ulong)result;
state.X1 = (ulong)serverPortHandle;
state.X2 = (ulong)clientPortHandle;
} }
private KernelResult CreatePort( private KernelResult CreatePort(
int maxSessions, int maxSessions,
bool isLight, bool isLight,
long nameAddress, ulong namePtr,
out int serverPortHandle, out int serverPortHandle,
out int clientPortHandle) out int clientPortHandle)
{ {
@ -750,7 +691,7 @@ namespace Ryujinx.HLE.HOS.Kernel
KPort port = new KPort(_system); KPort port = new KPort(_system);
port.Initialize(maxSessions, isLight, nameAddress); port.Initialize(maxSessions, isLight, (long)namePtr);
KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
@ -771,22 +712,16 @@ namespace Ryujinx.HLE.HOS.Kernel
return result; return result;
} }
private void ManageNamedPort64(CpuThreadState state) public KernelResult ManageNamedPort64(ulong namePtr, int maxSessions, out int handle)
{ {
long nameAddress = (long)state.X1; return ManageNamedPort(namePtr, maxSessions, out handle);
int maxSessions = (int)state.X2;
KernelResult result = ManageNamedPort(nameAddress, maxSessions, out int handle);
state.X0 = (ulong)result;
state.X1 = (ulong)handle;
} }
private KernelResult ManageNamedPort(long nameAddress, int maxSessions, out int handle) private KernelResult ManageNamedPort(ulong namePtr, int maxSessions, out int handle)
{ {
handle = 0; handle = 0;
if (!KernelTransfer.UserToKernelString(_system, nameAddress, 12, out string name)) if (!KernelTransfer.UserToKernelString(_system, namePtr, 12, out string name))
{ {
return KernelResult.UserCopyFailed; return KernelResult.UserCopyFailed;
} }

View file

@ -0,0 +1,340 @@
using ChocolArm64.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 SvcTable
{
private const int SvcFuncMaxArguments = 8;
private static Dictionary<int, string> _svcFuncs64;
private static Action<SvcHandler, CpuThreadState>[] _svcTable64;
static SvcTable()
{
_svcFuncs64 = new Dictionary<int, string>
{
{ 0x01, nameof(SvcHandler.SetHeapSize64) },
{ 0x03, nameof(SvcHandler.SetMemoryAttribute64) },
{ 0x04, nameof(SvcHandler.MapMemory64) },
{ 0x05, nameof(SvcHandler.UnmapMemory64) },
{ 0x06, nameof(SvcHandler.QueryMemory64) },
{ 0x07, nameof(SvcHandler.ExitProcess64) },
{ 0x08, nameof(SvcHandler.CreateThread64) },
{ 0x09, nameof(SvcHandler.StartThread64) },
{ 0x0a, nameof(SvcHandler.ExitThread64) },
{ 0x0b, nameof(SvcHandler.SleepThread64) },
{ 0x0c, nameof(SvcHandler.GetThreadPriority64) },
{ 0x0d, nameof(SvcHandler.SetThreadPriority64) },
{ 0x0e, nameof(SvcHandler.GetThreadCoreMask64) },
{ 0x0f, nameof(SvcHandler.SetThreadCoreMask64) },
{ 0x10, nameof(SvcHandler.GetCurrentProcessorNumber64) },
{ 0x11, nameof(SvcHandler.SignalEvent64) },
{ 0x12, nameof(SvcHandler.ClearEvent64) },
{ 0x13, nameof(SvcHandler.MapSharedMemory64) },
{ 0x14, nameof(SvcHandler.UnmapSharedMemory64) },
{ 0x15, nameof(SvcHandler.CreateTransferMemory64) },
{ 0x16, nameof(SvcHandler.CloseHandle64) },
{ 0x17, nameof(SvcHandler.ResetSignal64) },
{ 0x18, nameof(SvcHandler.WaitSynchronization64) },
{ 0x19, nameof(SvcHandler.CancelSynchronization64) },
{ 0x1a, nameof(SvcHandler.ArbitrateLock64) },
{ 0x1b, nameof(SvcHandler.ArbitrateUnlock64) },
{ 0x1c, nameof(SvcHandler.WaitProcessWideKeyAtomic64) },
{ 0x1d, nameof(SvcHandler.SignalProcessWideKey64) },
{ 0x1e, nameof(SvcHandler.GetSystemTick64) },
{ 0x1f, nameof(SvcHandler.ConnectToNamedPort64) },
{ 0x21, nameof(SvcHandler.SendSyncRequest64) },
{ 0x22, nameof(SvcHandler.SendSyncRequestWithUserBuffer64) },
{ 0x24, nameof(SvcHandler.GetProcessId64) },
{ 0x25, nameof(SvcHandler.GetThreadId64) },
{ 0x26, nameof(SvcHandler.Break64) },
{ 0x27, nameof(SvcHandler.OutputDebugString64) },
{ 0x29, nameof(SvcHandler.GetInfo64) },
{ 0x2c, nameof(SvcHandler.MapPhysicalMemory64) },
{ 0x2d, nameof(SvcHandler.UnmapPhysicalMemory64) },
{ 0x32, nameof(SvcHandler.SetThreadActivity64) },
{ 0x33, nameof(SvcHandler.GetThreadContext364) },
{ 0x34, nameof(SvcHandler.WaitForAddress64) },
{ 0x35, nameof(SvcHandler.SignalToAddress64) },
{ 0x45, nameof(SvcHandler.CreateEvent64) },
{ 0x65, nameof(SvcHandler.GetProcessList64) },
{ 0x6f, nameof(SvcHandler.GetSystemInfo64) },
{ 0x70, nameof(SvcHandler.CreatePort64) },
{ 0x71, nameof(SvcHandler.ManageNamedPort64) }
};
_svcTable64 = new Action<SvcHandler, CpuThreadState>[0x80];
}
public static Action<SvcHandler, CpuThreadState> GetSvcFunc(int svcId)
{
if (_svcTable64[svcId] != null)
{
return _svcTable64[svcId];
}
if (_svcFuncs64.TryGetValue(svcId, out string svcName))
{
return _svcTable64[svcId] = GenerateMethod(svcName);
}
return null;
}
private static Action<SvcHandler, CpuThreadState> GenerateMethod(string svcName)
{
Type[] argTypes = new Type[] { typeof(SvcHandler), typeof(CpuThreadState) };
DynamicMethod method = new DynamicMethod(svcName, null, argTypes);
MethodInfo methodInfo = typeof(SvcHandler).GetMethod(svcName);
ParameterInfo[] methodArgs = methodInfo.GetParameters();
if (methodArgs.Length > SvcFuncMaxArguments)
{
throw new InvalidOperationException($"Method \"{svcName}\" has too many arguments, max is 8.");
}
ILGenerator generator = method.GetILGenerator();
void ConvertToArgType(Type sourceType)
{
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;
}
}
//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++;
}
}
//Print all the arguments for debugging purposes.
int inputArgsCount = methodArgs.Length - byRefArgsCount;
generator.Emit(OpCodes.Ldc_I4_S, inputArgsCount);
generator.Emit(OpCodes.Newarr, typeof(object));
string argsFormat = svcName;
for (int index = 0; index < inputArgsCount; index++)
{
argsFormat += $" {methodArgs[index].Name}: 0x{{{index}:X8}},";
generator.Emit(OpCodes.Dup);
generator.Emit(OpCodes.Ldc_I4_S, index);
generator.Emit(OpCodes.Conv_I);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldfld, GetStateFieldX(byRefArgsCount + index));
generator.Emit(OpCodes.Box, typeof(ulong));
generator.Emit(OpCodes.Stelem_Ref);
}
argsFormat = argsFormat.Substring(0, argsFormat.Length - 1);
generator.Emit(OpCodes.Ldstr, argsFormat);
BindingFlags staticNonPublic = BindingFlags.NonPublic | BindingFlags.Static;
MethodInfo printArgsMethod = typeof(SvcTable).GetMethod(nameof(PrintArguments), staticNonPublic);
generator.Emit(OpCodes.Call, printArgsMethod);
//Call the SVC function handler.
generator.Emit(OpCodes.Ldarg_0);
List<LocalBuilder> locals = new List<LocalBuilder>();
for (int index = 0; index < methodArgs.Length; index++)
{
Type argType = methodArgs[index].ParameterType;
if (argType.IsByRef)
{
argType = argType.GetElementType();
LocalBuilder local = generator.DeclareLocal(argType);
locals.Add(local);
if (!methodArgs[index].IsOut)
{
throw new InvalidOperationException($"Method \"{svcName}\" has a invalid ref type \"{argType.Name}\".");
}
generator.Emit(OpCodes.Ldloca_S, (byte)local.LocalIndex);
}
else
{
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldfld, GetStateFieldX(byRefArgsCount + index));
ConvertToArgType(argType);
}
}
generator.Emit(OpCodes.Call, methodInfo);
int outRegIndex = 0;
Type retType = methodInfo.ReturnType;
//Print result code.
if (retType == typeof(KernelResult))
{
MethodInfo printResultMethod = typeof(SvcTable).GetMethod(nameof(PrintResult), staticNonPublic);
generator.Emit(OpCodes.Dup);
generator.Emit(OpCodes.Ldstr, svcName);
generator.Emit(OpCodes.Call, printResultMethod);
}
//Save return value into register X0 (when the method has a return value).
if (retType != typeof(void))
{
CheckIfTypeIsSupported(retType, svcName);
LocalBuilder tempLocal = generator.DeclareLocal(retType);
generator.Emit(OpCodes.Stloc, tempLocal);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldloc, tempLocal);
ConvertToFieldType(retType);
generator.Emit(OpCodes.Stfld, GetStateFieldX(outRegIndex++));
}
for (int index = 0; index < locals.Count; index++)
{
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldloc, locals[index]);
ConvertToFieldType(locals[index].LocalType);
generator.Emit(OpCodes.Stfld, GetStateFieldX(outRegIndex++));
}
//Zero out the remaining unused registers.
while (outRegIndex < SvcFuncMaxArguments)
{
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Ldc_I8, 0L);
generator.Emit(OpCodes.Stfld, GetStateFieldX(outRegIndex++));
}
generator.Emit(OpCodes.Ret);
return (Action<SvcHandler, CpuThreadState>)method.CreateDelegate(typeof(Action<SvcHandler, CpuThreadState>));
}
private static FieldInfo GetStateFieldX(int index)
{
switch (index)
{
case 0: return typeof(CpuThreadState).GetField(nameof(CpuThreadState.X0));
case 1: return typeof(CpuThreadState).GetField(nameof(CpuThreadState.X1));
case 2: return typeof(CpuThreadState).GetField(nameof(CpuThreadState.X2));
case 3: return typeof(CpuThreadState).GetField(nameof(CpuThreadState.X3));
case 4: return typeof(CpuThreadState).GetField(nameof(CpuThreadState.X4));
case 5: return typeof(CpuThreadState).GetField(nameof(CpuThreadState.X5));
case 6: return typeof(CpuThreadState).GetField(nameof(CpuThreadState.X6));
case 7: return typeof(CpuThreadState).GetField(nameof(CpuThreadState.X7));
}
throw new ArgumentOutOfRangeException(nameof(index));
}
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 PrintResult(KernelResult result, string svcName)
{
if (result != KernelResult.Success &&
result != KernelResult.TimedOut &&
result != KernelResult.Cancelled &&
result != KernelResult.InvalidState)
{
Logger.PrintWarning(LogClass.KernelSvc, $"{svcName} returned error {result}.");
}
else
{
Logger.PrintDebug(LogClass.KernelSvc, $"{svcName} returned result {result}.");
}
}
private static void PrintArguments(object[] argValues, string format)
{
Logger.PrintDebug(LogClass.KernelSvc, string.Format(format, argValues));
}
}
}

View file

@ -0,0 +1,420 @@
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading;
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
partial class SvcHandler
{
public KernelResult CreateThread64(
ulong entrypoint,
ulong argsPtr,
ulong stackTop,
int priority,
int cpuCore,
out int handle)
{
return CreateThread(entrypoint, argsPtr, stackTop, priority, cpuCore, out handle);
}
private KernelResult CreateThread(
ulong entrypoint,
ulong argsPtr,
ulong stackTop,
int priority,
int cpuCore,
out int handle)
{
handle = 0;
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
if (cpuCore == -2)
{
cpuCore = currentProcess.DefaultCpuCore;
}
if ((uint)cpuCore >= KScheduler.CpuCoresCount || !currentProcess.IsCpuCoreAllowed(cpuCore))
{
return KernelResult.InvalidCpuCore;
}
if ((uint)priority >= KScheduler.PrioritiesCount || !currentProcess.IsPriorityAllowed(priority))
{
return KernelResult.InvalidPriority;
}
long timeout = KTimeManager.ConvertMillisecondsToNanoseconds(100);
if (currentProcess.ResourceLimit != null &&
!currentProcess.ResourceLimit.Reserve(LimitableResource.Thread, 1, timeout))
{
return KernelResult.ResLimitExceeded;
}
KThread thread = new KThread(_system);
KernelResult result = currentProcess.InitializeThread(
thread,
entrypoint,
argsPtr,
stackTop,
priority,
cpuCore);
if (result != KernelResult.Success)
{
currentProcess.ResourceLimit?.Release(LimitableResource.Thread, 1);
return result;
}
result = _process.HandleTable.GenerateHandle(thread, out handle);
if (result != KernelResult.Success)
{
thread.Terminate();
currentProcess.ResourceLimit?.Release(LimitableResource.Thread, 1);
}
return result;
}
public KernelResult StartThread64(int handle)
{
return StartThread(handle);
}
private KernelResult StartThread(int handle)
{
KThread thread = _process.HandleTable.GetObject<KThread>(handle);
if (thread != null)
{
return thread.Start();
}
else
{
return KernelResult.InvalidHandle;
}
}
public void ExitThread64()
{
ExitThread();
}
private void ExitThread()
{
KThread currentThread = _system.Scheduler.GetCurrentThread();
_system.Scheduler.ExitThread(currentThread);
currentThread.Exit();
}
public void SleepThread64(long timeout)
{
SleepThread(timeout);
}
private void SleepThread(long timeout)
{
KThread currentThread = _system.Scheduler.GetCurrentThread();
if (timeout < 1)
{
switch (timeout)
{
case 0: currentThread.Yield(); break;
case -1: currentThread.YieldWithLoadBalancing(); break;
case -2: currentThread.YieldAndWaitForLoadBalancing(); break;
}
}
else
{
currentThread.Sleep(timeout);
}
}
public KernelResult GetThreadPriority64(int handle, out int priority)
{
return GetThreadPriority(handle, out priority);
}
private KernelResult GetThreadPriority(int handle, out int priority)
{
KThread thread = _process.HandleTable.GetKThread(handle);
if (thread != null)
{
priority = thread.DynamicPriority;
return KernelResult.Success;
}
else
{
priority = 0;
return KernelResult.InvalidHandle;
}
}
public KernelResult SetThreadPriority64(int handle, int priority)
{
return SetThreadPriority(handle, priority);
}
public KernelResult SetThreadPriority(int handle, int priority)
{
//TODO: NPDM check.
KThread thread = _process.HandleTable.GetKThread(handle);
if (thread == null)
{
return KernelResult.InvalidHandle;
}
thread.SetPriority(priority);
return KernelResult.Success;
}
public KernelResult GetThreadCoreMask64(int handle, out int preferredCore, out long affinityMask)
{
return GetThreadCoreMask(handle, out preferredCore, out affinityMask);
}
private KernelResult GetThreadCoreMask(int handle, out int preferredCore, out long affinityMask)
{
KThread thread = _process.HandleTable.GetKThread(handle);
if (thread != null)
{
preferredCore = thread.PreferredCore;
affinityMask = thread.AffinityMask;
return KernelResult.Success;
}
else
{
preferredCore = 0;
affinityMask = 0;
return KernelResult.InvalidHandle;
}
}
public KernelResult SetThreadCoreMask64(int handle, int preferredCore, long affinityMask)
{
return SetThreadCoreMask(handle, preferredCore, affinityMask);
}
private KernelResult SetThreadCoreMask(int handle, int preferredCore, long affinityMask)
{
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
if (preferredCore == -2)
{
preferredCore = currentProcess.DefaultCpuCore;
affinityMask = 1 << preferredCore;
}
else
{
if ((currentProcess.Capabilities.AllowedCpuCoresMask | affinityMask) !=
currentProcess.Capabilities.AllowedCpuCoresMask)
{
return KernelResult.InvalidCpuCore;
}
if (affinityMask == 0)
{
return KernelResult.InvalidCombination;
}
if ((uint)preferredCore > 3)
{
if ((preferredCore | 2) != -1)
{
return KernelResult.InvalidCpuCore;
}
}
else if ((affinityMask & (1 << preferredCore)) == 0)
{
return KernelResult.InvalidCombination;
}
}
KThread thread = _process.HandleTable.GetKThread(handle);
if (thread == null)
{
return KernelResult.InvalidHandle;
}
return thread.SetCoreAndAffinityMask(preferredCore, affinityMask);
}
public int GetCurrentProcessorNumber64()
{
return _system.Scheduler.GetCurrentThread().CurrentCore;
}
public KernelResult GetThreadId64(int handle, out long threadUid)
{
return GetThreadId(handle, out threadUid);
}
private KernelResult GetThreadId(int handle, out long threadUid)
{
KThread thread = _process.HandleTable.GetKThread(handle);
if (thread != null)
{
threadUid = thread.ThreadUid;
return KernelResult.Success;
}
else
{
threadUid = 0;
return KernelResult.InvalidHandle;
}
}
public KernelResult SetThreadActivity64(int handle, bool pause)
{
return SetThreadActivity(handle, pause);
}
private KernelResult SetThreadActivity(int handle, bool pause)
{
KThread thread = _process.HandleTable.GetObject<KThread>(handle);
if (thread == null)
{
return KernelResult.InvalidHandle;
}
if (thread.Owner != _system.Scheduler.GetCurrentProcess())
{
return KernelResult.InvalidHandle;
}
if (thread == _system.Scheduler.GetCurrentThread())
{
return KernelResult.InvalidThread;
}
return thread.SetActivity(pause);
}
public KernelResult GetThreadContext364(ulong address, int handle)
{
return GetThreadContext3(address, handle);
}
private KernelResult GetThreadContext3(ulong address, int handle)
{
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KThread currentThread = _system.Scheduler.GetCurrentThread();
KThread thread = _process.HandleTable.GetObject<KThread>(handle);
if (thread == null)
{
return KernelResult.InvalidHandle;
}
if (thread.Owner != currentProcess)
{
return KernelResult.InvalidHandle;
}
if (currentThread == thread)
{
return KernelResult.InvalidThread;
}
_memory.WriteUInt64((long)address + 0x0, thread.Context.ThreadState.X0);
_memory.WriteUInt64((long)address + 0x8, thread.Context.ThreadState.X1);
_memory.WriteUInt64((long)address + 0x10, thread.Context.ThreadState.X2);
_memory.WriteUInt64((long)address + 0x18, thread.Context.ThreadState.X3);
_memory.WriteUInt64((long)address + 0x20, thread.Context.ThreadState.X4);
_memory.WriteUInt64((long)address + 0x28, thread.Context.ThreadState.X5);
_memory.WriteUInt64((long)address + 0x30, thread.Context.ThreadState.X6);
_memory.WriteUInt64((long)address + 0x38, thread.Context.ThreadState.X7);
_memory.WriteUInt64((long)address + 0x40, thread.Context.ThreadState.X8);
_memory.WriteUInt64((long)address + 0x48, thread.Context.ThreadState.X9);
_memory.WriteUInt64((long)address + 0x50, thread.Context.ThreadState.X10);
_memory.WriteUInt64((long)address + 0x58, thread.Context.ThreadState.X11);
_memory.WriteUInt64((long)address + 0x60, thread.Context.ThreadState.X12);
_memory.WriteUInt64((long)address + 0x68, thread.Context.ThreadState.X13);
_memory.WriteUInt64((long)address + 0x70, thread.Context.ThreadState.X14);
_memory.WriteUInt64((long)address + 0x78, thread.Context.ThreadState.X15);
_memory.WriteUInt64((long)address + 0x80, thread.Context.ThreadState.X16);
_memory.WriteUInt64((long)address + 0x88, thread.Context.ThreadState.X17);
_memory.WriteUInt64((long)address + 0x90, thread.Context.ThreadState.X18);
_memory.WriteUInt64((long)address + 0x98, thread.Context.ThreadState.X19);
_memory.WriteUInt64((long)address + 0xa0, thread.Context.ThreadState.X20);
_memory.WriteUInt64((long)address + 0xa8, thread.Context.ThreadState.X21);
_memory.WriteUInt64((long)address + 0xb0, thread.Context.ThreadState.X22);
_memory.WriteUInt64((long)address + 0xb8, thread.Context.ThreadState.X23);
_memory.WriteUInt64((long)address + 0xc0, thread.Context.ThreadState.X24);
_memory.WriteUInt64((long)address + 0xc8, thread.Context.ThreadState.X25);
_memory.WriteUInt64((long)address + 0xd0, thread.Context.ThreadState.X26);
_memory.WriteUInt64((long)address + 0xd8, thread.Context.ThreadState.X27);
_memory.WriteUInt64((long)address + 0xe0, thread.Context.ThreadState.X28);
_memory.WriteUInt64((long)address + 0xe8, thread.Context.ThreadState.X29);
_memory.WriteUInt64((long)address + 0xf0, thread.Context.ThreadState.X30);
_memory.WriteUInt64((long)address + 0xf8, thread.Context.ThreadState.X31);
_memory.WriteInt64((long)address + 0x100, thread.LastPc);
_memory.WriteUInt64((long)address + 0x108, (ulong)thread.Context.ThreadState.Psr);
_memory.WriteVector128((long)address + 0x110, thread.Context.ThreadState.V0);
_memory.WriteVector128((long)address + 0x120, thread.Context.ThreadState.V1);
_memory.WriteVector128((long)address + 0x130, thread.Context.ThreadState.V2);
_memory.WriteVector128((long)address + 0x140, thread.Context.ThreadState.V3);
_memory.WriteVector128((long)address + 0x150, thread.Context.ThreadState.V4);
_memory.WriteVector128((long)address + 0x160, thread.Context.ThreadState.V5);
_memory.WriteVector128((long)address + 0x170, thread.Context.ThreadState.V6);
_memory.WriteVector128((long)address + 0x180, thread.Context.ThreadState.V7);
_memory.WriteVector128((long)address + 0x190, thread.Context.ThreadState.V8);
_memory.WriteVector128((long)address + 0x1a0, thread.Context.ThreadState.V9);
_memory.WriteVector128((long)address + 0x1b0, thread.Context.ThreadState.V10);
_memory.WriteVector128((long)address + 0x1c0, thread.Context.ThreadState.V11);
_memory.WriteVector128((long)address + 0x1d0, thread.Context.ThreadState.V12);
_memory.WriteVector128((long)address + 0x1e0, thread.Context.ThreadState.V13);
_memory.WriteVector128((long)address + 0x1f0, thread.Context.ThreadState.V14);
_memory.WriteVector128((long)address + 0x200, thread.Context.ThreadState.V15);
_memory.WriteVector128((long)address + 0x210, thread.Context.ThreadState.V16);
_memory.WriteVector128((long)address + 0x220, thread.Context.ThreadState.V17);
_memory.WriteVector128((long)address + 0x230, thread.Context.ThreadState.V18);
_memory.WriteVector128((long)address + 0x240, thread.Context.ThreadState.V19);
_memory.WriteVector128((long)address + 0x250, thread.Context.ThreadState.V20);
_memory.WriteVector128((long)address + 0x260, thread.Context.ThreadState.V21);
_memory.WriteVector128((long)address + 0x270, thread.Context.ThreadState.V22);
_memory.WriteVector128((long)address + 0x280, thread.Context.ThreadState.V23);
_memory.WriteVector128((long)address + 0x290, thread.Context.ThreadState.V24);
_memory.WriteVector128((long)address + 0x2a0, thread.Context.ThreadState.V25);
_memory.WriteVector128((long)address + 0x2b0, thread.Context.ThreadState.V26);
_memory.WriteVector128((long)address + 0x2c0, thread.Context.ThreadState.V27);
_memory.WriteVector128((long)address + 0x2d0, thread.Context.ThreadState.V28);
_memory.WriteVector128((long)address + 0x2e0, thread.Context.ThreadState.V29);
_memory.WriteVector128((long)address + 0x2f0, thread.Context.ThreadState.V30);
_memory.WriteVector128((long)address + 0x300, thread.Context.ThreadState.V31);
_memory.WriteInt32((long)address + 0x310, thread.Context.ThreadState.Fpcr);
_memory.WriteInt32((long)address + 0x314, thread.Context.ThreadState.Fpsr);
_memory.WriteInt64((long)address + 0x318, thread.Context.ThreadState.Tpidr);
return KernelResult.Success;
}
}
}

View file

@ -0,0 +1,250 @@
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.HOS.Kernel.Threading;
using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
{
partial class SvcHandler
{
public KernelResult WaitSynchronization64(ulong handlesPtr, int handlesCount, long timeout, out int handleIndex)
{
return WaitSynchronization(handlesPtr, handlesCount, timeout, out handleIndex);
}
private KernelResult WaitSynchronization(ulong handlesPtr, int handlesCount, long timeout, out int handleIndex)
{
handleIndex = 0;
if ((uint)handlesCount > 0x40)
{
return KernelResult.MaximumExceeded;
}
List<KSynchronizationObject> syncObjs = new List<KSynchronizationObject>();
for (int index = 0; index < handlesCount; index++)
{
int handle = _memory.ReadInt32((long)handlesPtr + index * 4);
KSynchronizationObject syncObj = _process.HandleTable.GetObject<KSynchronizationObject>(handle);
if (syncObj == null)
{
break;
}
syncObjs.Add(syncObj);
}
return _system.Synchronization.WaitFor(syncObjs.ToArray(), timeout, out handleIndex);
}
public KernelResult CancelSynchronization64(int handle)
{
return CancelSynchronization(handle);
}
private KernelResult CancelSynchronization(int handle)
{
KThread thread = _process.HandleTable.GetKThread(handle);
if (thread == null)
{
return KernelResult.InvalidHandle;
}
thread.CancelSynchronization();
return KernelResult.Success;
}
public KernelResult ArbitrateLock64(int ownerHandle, ulong mutexAddress, int requesterHandle)
{
return ArbitrateLock(ownerHandle, mutexAddress, requesterHandle);
}
private KernelResult ArbitrateLock(int ownerHandle, ulong mutexAddress, int requesterHandle)
{
if (IsPointingInsideKernel(mutexAddress))
{
return KernelResult.InvalidMemState;
}
if (IsAddressNotWordAligned(mutexAddress))
{
return KernelResult.InvalidAddress;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
return currentProcess.AddressArbiter.ArbitrateLock(ownerHandle, mutexAddress, requesterHandle);
}
public KernelResult ArbitrateUnlock64(ulong mutexAddress)
{
return ArbitrateUnlock(mutexAddress);
}
private KernelResult ArbitrateUnlock(ulong mutexAddress)
{
if (IsPointingInsideKernel(mutexAddress))
{
return KernelResult.InvalidMemState;
}
if (IsAddressNotWordAligned(mutexAddress))
{
return KernelResult.InvalidAddress;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
return currentProcess.AddressArbiter.ArbitrateUnlock(mutexAddress);
}
public KernelResult WaitProcessWideKeyAtomic64(
ulong mutexAddress,
ulong condVarAddress,
int handle,
long timeout)
{
return WaitProcessWideKeyAtomic(mutexAddress, condVarAddress, handle, timeout);
}
private KernelResult WaitProcessWideKeyAtomic(
ulong mutexAddress,
ulong condVarAddress,
int handle,
long timeout)
{
if (IsPointingInsideKernel(mutexAddress))
{
return KernelResult.InvalidMemState;
}
if (IsAddressNotWordAligned(mutexAddress))
{
return KernelResult.InvalidAddress;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
return currentProcess.AddressArbiter.WaitProcessWideKeyAtomic(
mutexAddress,
condVarAddress,
handle,
timeout);
}
public KernelResult SignalProcessWideKey64(ulong address, int count)
{
return SignalProcessWideKey(address, count);
}
private KernelResult SignalProcessWideKey(ulong address, int count)
{
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
currentProcess.AddressArbiter.SignalProcessWideKey(address, count);
return KernelResult.Success;
}
public KernelResult WaitForAddress64(ulong address, ArbitrationType type, int value, long timeout)
{
return WaitForAddress(address, type, value, timeout);
}
private KernelResult WaitForAddress(ulong address, ArbitrationType type, int value, long timeout)
{
if (IsPointingInsideKernel(address))
{
return KernelResult.InvalidMemState;
}
if (IsAddressNotWordAligned(address))
{
return KernelResult.InvalidAddress;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KernelResult result;
switch (type)
{
case ArbitrationType.WaitIfLessThan:
result = currentProcess.AddressArbiter.WaitForAddressIfLessThan(address, value, false, timeout);
break;
case ArbitrationType.DecrementAndWaitIfLessThan:
result = currentProcess.AddressArbiter.WaitForAddressIfLessThan(address, value, true, timeout);
break;
case ArbitrationType.WaitIfEqual:
result = currentProcess.AddressArbiter.WaitForAddressIfEqual(address, value, timeout);
break;
default:
result = KernelResult.InvalidEnumValue;
break;
}
return result;
}
public KernelResult SignalToAddress64(ulong address, SignalType type, int value, int count)
{
return SignalToAddress(address, type, value, count);
}
private KernelResult SignalToAddress(ulong address, SignalType type, int value, int count)
{
if (IsPointingInsideKernel(address))
{
return KernelResult.InvalidMemState;
}
if (IsAddressNotWordAligned(address))
{
return KernelResult.InvalidAddress;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KernelResult result;
switch (type)
{
case SignalType.Signal:
result = currentProcess.AddressArbiter.Signal(address, count);
break;
case SignalType.SignalAndIncrementIfEqual:
result = currentProcess.AddressArbiter.SignalAndIncrementIfEqual(address, value, count);
break;
case SignalType.SignalAndModifyIfEqual:
result = currentProcess.AddressArbiter.SignalAndModifyIfEqual(address, value, count);
break;
default:
result = KernelResult.InvalidEnumValue;
break;
}
return result;
}
private bool IsPointingInsideKernel(ulong address)
{
return (address + 0x1000000000) < 0xffffff000;
}
private bool IsAddressNotWordAligned(ulong address)
{
return (address & 3) != 0;
}
}
}

View file

@ -1,122 +0,0 @@
using ChocolArm64.Events;
using ChocolArm64.Memory;
using ChocolArm64.State;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.Common.Logging;
using System;
using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Kernel
{
partial class SvcHandler
{
private delegate void SvcFunc(CpuThreadState threadState);
private Dictionary<int, SvcFunc> _svcFuncs;
private Switch _device;
private KProcess _process;
private Horizon _system;
private MemoryManager _memory;
private struct HleIpcMessage
{
public KThread Thread { get; private set; }
public KSession Session { get; private set; }
public IpcMessage Message { get; private set; }
public long MessagePtr { get; private set; }
public HleIpcMessage(
KThread thread,
KSession session,
IpcMessage message,
long messagePtr)
{
Thread = thread;
Session = session;
Message = message;
MessagePtr = messagePtr;
}
}
public SvcHandler(Switch device, KProcess process)
{
_svcFuncs = new Dictionary<int, SvcFunc>
{
{ 0x01, SvcSetHeapSize },
{ 0x03, SvcSetMemoryAttribute },
{ 0x04, SvcMapMemory },
{ 0x05, SvcUnmapMemory },
{ 0x06, SvcQueryMemory },
{ 0x07, SvcExitProcess },
{ 0x08, CreateThread64 },
{ 0x09, SvcStartThread },
{ 0x0a, SvcExitThread },
{ 0x0b, SvcSleepThread },
{ 0x0c, SvcGetThreadPriority },
{ 0x0d, SvcSetThreadPriority },
{ 0x0e, SvcGetThreadCoreMask },
{ 0x0f, SetThreadCoreMask64 },
{ 0x10, SvcGetCurrentProcessorNumber },
{ 0x11, SignalEvent64 },
{ 0x12, ClearEvent64 },
{ 0x13, SvcMapSharedMemory },
{ 0x14, SvcUnmapSharedMemory },
{ 0x15, SvcCreateTransferMemory },
{ 0x16, SvcCloseHandle },
{ 0x17, ResetSignal64 },
{ 0x18, SvcWaitSynchronization },
{ 0x19, SvcCancelSynchronization },
{ 0x1a, SvcArbitrateLock },
{ 0x1b, SvcArbitrateUnlock },
{ 0x1c, SvcWaitProcessWideKeyAtomic },
{ 0x1d, SvcSignalProcessWideKey },
{ 0x1e, SvcGetSystemTick },
{ 0x1f, SvcConnectToNamedPort },
{ 0x21, SvcSendSyncRequest },
{ 0x22, SvcSendSyncRequestWithUserBuffer },
{ 0x24, GetProcessId64 },
{ 0x25, SvcGetThreadId },
{ 0x26, SvcBreak },
{ 0x27, SvcOutputDebugString },
{ 0x29, GetInfo64 },
{ 0x2c, SvcMapPhysicalMemory },
{ 0x2d, SvcUnmapPhysicalMemory },
{ 0x32, SvcSetThreadActivity },
{ 0x33, SvcGetThreadContext3 },
{ 0x34, SvcWaitForAddress },
{ 0x35, SvcSignalToAddress },
{ 0x45, CreateEvent64 },
{ 0x65, GetProcessList64 },
{ 0x6f, GetSystemInfo64 },
{ 0x70, CreatePort64 },
{ 0x71, ManageNamedPort64 }
};
_device = device;
_process = process;
_system = device.System;
_memory = process.CpuMemory;
}
public void SvcCall(object sender, InstExceptionEventArgs e)
{
CpuThreadState threadState = (CpuThreadState)sender;
if (_svcFuncs.TryGetValue(e.Id, out SvcFunc func))
{
Logger.PrintDebug(LogClass.KernelSvc, $"{func.Method.Name} called.");
func(threadState);
Logger.PrintDebug(LogClass.KernelSvc, $"{func.Method.Name} ended.");
}
else
{
//Process.PrintStackTrace(ThreadState);
throw new NotImplementedException($"0x{e.Id:x4}");
}
}
}
}

View file

@ -1,581 +0,0 @@
using ChocolArm64.State;
using Ryujinx.Common.Logging;
using static Ryujinx.HLE.HOS.ErrorCode;
namespace Ryujinx.HLE.HOS.Kernel
{
partial class SvcHandler
{
private void SvcSetHeapSize(CpuThreadState threadState)
{
ulong size = threadState.X1;
if ((size & 0xfffffffe001fffff) != 0)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Heap size 0x{size:x16} is not aligned!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
return;
}
KernelResult result = _process.MemoryManager.SetHeapSize(size, out ulong position);
threadState.X0 = (ulong)result;
if (result == KernelResult.Success)
{
threadState.X1 = position;
}
else
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{result}\".");
}
}
private void SvcSetMemoryAttribute(CpuThreadState threadState)
{
ulong position = threadState.X0;
ulong size = threadState.X1;
if (!PageAligned(position))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{position:x16} is not page aligned!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
}
if (!PageAligned(size) || size == 0)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{size:x16} is not page aligned or is zero!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
return;
}
MemoryAttribute attributeMask = (MemoryAttribute)threadState.X2;
MemoryAttribute attributeValue = (MemoryAttribute)threadState.X3;
MemoryAttribute attributes = attributeMask | attributeValue;
if (attributes != attributeMask ||
(attributes | MemoryAttribute.Uncached) != MemoryAttribute.Uncached)
{
Logger.PrintWarning(LogClass.KernelSvc, "Invalid memory attributes!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMaskValue);
return;
}
KernelResult result = _process.MemoryManager.SetMemoryAttribute(
position,
size,
attributeMask,
attributeValue);
if (result != KernelResult.Success)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{result}\".");
}
else
{
_memory.StopObservingRegion((long)position, (long)size);
}
threadState.X0 = (ulong)result;
}
private void SvcMapMemory(CpuThreadState threadState)
{
ulong dst = threadState.X0;
ulong src = threadState.X1;
ulong size = threadState.X2;
if (!PageAligned(src | dst))
{
Logger.PrintWarning(LogClass.KernelSvc, "Addresses are not page aligned!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
}
if (!PageAligned(size) || size == 0)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{size:x16} is not page aligned or is zero!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
return;
}
if (src + size <= src || dst + size <= dst)
{
Logger.PrintWarning(LogClass.KernelSvc, "Addresses outside of range!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
if (!currentProcess.MemoryManager.InsideAddrSpace(src, size))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Src address 0x{src:x16} out of range!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
}
if (currentProcess.MemoryManager.OutsideStackRegion(dst, size) ||
currentProcess.MemoryManager.InsideHeapRegion (dst, size) ||
currentProcess.MemoryManager.InsideAliasRegion (dst, size))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Dst address 0x{dst:x16} out of range!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
return;
}
KernelResult result = _process.MemoryManager.Map(dst, src, size);
if (result != KernelResult.Success)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
threadState.X0 = (ulong)result;
}
private void SvcUnmapMemory(CpuThreadState threadState)
{
ulong dst = threadState.X0;
ulong src = threadState.X1;
ulong size = threadState.X2;
if (!PageAligned(src | dst))
{
Logger.PrintWarning(LogClass.KernelSvc, "Addresses are not page aligned!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
}
if (!PageAligned(size) || size == 0)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{size:x16} is not page aligned or is zero!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
return;
}
if (src + size <= src || dst + size <= dst)
{
Logger.PrintWarning(LogClass.KernelSvc, "Addresses outside of range!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
if (!currentProcess.MemoryManager.InsideAddrSpace(src, size))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Src address 0x{src:x16} out of range!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
}
if (currentProcess.MemoryManager.OutsideStackRegion(dst, size) ||
currentProcess.MemoryManager.InsideHeapRegion (dst, size) ||
currentProcess.MemoryManager.InsideAliasRegion (dst, size))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Dst address 0x{dst:x16} out of range!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
return;
}
KernelResult result = _process.MemoryManager.Unmap(dst, src, size);
if (result != KernelResult.Success)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
threadState.X0 = (ulong)result;
}
private void SvcQueryMemory(CpuThreadState threadState)
{
long infoPtr = (long)threadState.X0;
ulong position = threadState.X2;
KMemoryInfo blkInfo = _process.MemoryManager.QueryMemory(position);
_memory.WriteUInt64(infoPtr + 0x00, blkInfo.Address);
_memory.WriteUInt64(infoPtr + 0x08, blkInfo.Size);
_memory.WriteInt32 (infoPtr + 0x10, (int)blkInfo.State & 0xff);
_memory.WriteInt32 (infoPtr + 0x14, (int)blkInfo.Attribute);
_memory.WriteInt32 (infoPtr + 0x18, (int)blkInfo.Permission);
_memory.WriteInt32 (infoPtr + 0x1c, blkInfo.IpcRefCount);
_memory.WriteInt32 (infoPtr + 0x20, blkInfo.DeviceRefCount);
_memory.WriteInt32 (infoPtr + 0x24, 0);
threadState.X0 = 0;
threadState.X1 = 0;
}
private void SvcMapSharedMemory(CpuThreadState threadState)
{
int handle = (int)threadState.X0;
ulong address = threadState.X1;
ulong size = threadState.X2;
if (!PageAligned(address))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{address:x16} is not page aligned!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
}
if (!PageAligned(size) || size == 0)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{size:x16} is not page aligned or is zero!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
return;
}
if (address + size <= address)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{address:x16} / size 0x{size:x16}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
}
MemoryPermission permission = (MemoryPermission)threadState.X3;
if ((permission | MemoryPermission.Write) != MemoryPermission.ReadAndWrite)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid permission {permission}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidPermission);
return;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KSharedMemory sharedMemory = currentProcess.HandleTable.GetObject<KSharedMemory>(handle);
if (sharedMemory == null)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid shared memory handle 0x{handle:x8}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
return;
}
if (currentProcess.MemoryManager.IsInvalidRegion (address, size) ||
currentProcess.MemoryManager.InsideHeapRegion (address, size) ||
currentProcess.MemoryManager.InsideAliasRegion(address, size))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{address:x16} out of range!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
}
KernelResult result = sharedMemory.MapIntoProcess(
currentProcess.MemoryManager,
address,
size,
currentProcess,
permission);
if (result != KernelResult.Success)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{result}\".");
}
threadState.X0 = (ulong)result;
}
private void SvcUnmapSharedMemory(CpuThreadState threadState)
{
int handle = (int)threadState.X0;
ulong address = threadState.X1;
ulong size = threadState.X2;
if (!PageAligned(address))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{address:x16} is not page aligned!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
}
if (!PageAligned(size) || size == 0)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{size:x16} is not page aligned or is zero!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
return;
}
if (address + size <= address)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{address:x16} / size 0x{size:x16}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KSharedMemory sharedMemory = currentProcess.HandleTable.GetObject<KSharedMemory>(handle);
if (sharedMemory == null)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid shared memory handle 0x{handle:x8}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
return;
}
if (currentProcess.MemoryManager.IsInvalidRegion (address, size) ||
currentProcess.MemoryManager.InsideHeapRegion (address, size) ||
currentProcess.MemoryManager.InsideAliasRegion(address, size))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{address:x16} out of range!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
}
KernelResult result = sharedMemory.UnmapFromProcess(
currentProcess.MemoryManager,
address,
size,
currentProcess);
if (result != KernelResult.Success)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{result}\".");
}
threadState.X0 = (ulong)result;
}
private void SvcCreateTransferMemory(CpuThreadState threadState)
{
ulong address = threadState.X1;
ulong size = threadState.X2;
if (!PageAligned(address))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{address:x16} is not page aligned!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
}
if (!PageAligned(size) || size == 0)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{size:x16} is not page aligned or is zero!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
}
if (address + size <= address)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{address:x16} / size 0x{size:x16}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
}
MemoryPermission permission = (MemoryPermission)threadState.X3;
if (permission > MemoryPermission.ReadAndWrite || permission == MemoryPermission.Write)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid permission {permission}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidPermission);
return;
}
_process.MemoryManager.ReserveTransferMemory(address, size, permission);
KTransferMemory transferMemory = new KTransferMemory(address, size);
KernelResult result = _process.HandleTable.GenerateHandle(transferMemory, out int handle);
threadState.X0 = (uint)result;
threadState.X1 = (ulong)handle;
}
private void SvcMapPhysicalMemory(CpuThreadState threadState)
{
ulong address = threadState.X0;
ulong size = threadState.X1;
if (!PageAligned(address))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{address:x16} is not page aligned!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
}
if (!PageAligned(size) || size == 0)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{size:x16} is not page aligned or is zero!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
return;
}
if (address + size <= address)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{address:x16} / size 0x{size:x16}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
if ((currentProcess.PersonalMmHeapPagesCount & 0xfffffffffffff) == 0)
{
Logger.PrintWarning(LogClass.KernelSvc, $"System resource size is zero.");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidState);
return;
}
if (!currentProcess.MemoryManager.InsideAddrSpace (address, size) ||
currentProcess.MemoryManager.OutsideAliasRegion(address, size))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid address {address:x16}.");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
}
KernelResult result = _process.MemoryManager.MapPhysicalMemory(address, size);
if (result != KernelResult.Success)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
threadState.X0 = (ulong)result;
}
private void SvcUnmapPhysicalMemory(CpuThreadState threadState)
{
ulong address = threadState.X0;
ulong size = threadState.X1;
if (!PageAligned(address))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{address:x16} is not page aligned!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
}
if (!PageAligned(size) || size == 0)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{size:x16} is not page aligned or is zero!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
return;
}
if (address + size <= address)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{address:x16} / size 0x{size:x16}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
if ((currentProcess.PersonalMmHeapPagesCount & 0xfffffffffffff) == 0)
{
Logger.PrintWarning(LogClass.KernelSvc, $"System resource size is zero.");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidState);
return;
}
if (!currentProcess.MemoryManager.InsideAddrSpace (address, size) ||
currentProcess.MemoryManager.OutsideAliasRegion(address, size))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid address {address:x16}.");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
}
KernelResult result = _process.MemoryManager.UnmapPhysicalMemory(address, size);
if (result != KernelResult.Success)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
threadState.X0 = (ulong)result;
}
private static bool PageAligned(ulong position)
{
return (position & (KMemoryManager.PageSize - 1)) == 0;
}
}
}

View file

@ -1,464 +0,0 @@
using ChocolArm64.State;
using Ryujinx.Common.Logging;
using static Ryujinx.HLE.HOS.ErrorCode;
namespace Ryujinx.HLE.HOS.Kernel
{
partial class SvcHandler
{
private void CreateThread64(CpuThreadState threadState)
{
ulong entrypoint = threadState.X1;
ulong argsPtr = threadState.X2;
ulong stackTop = threadState.X3;
int priority = (int)threadState.X4;
int cpuCore = (int)threadState.X5;
KernelResult result = CreateThread(entrypoint, argsPtr, stackTop, priority, cpuCore, out int handle);
threadState.X0 = (ulong)result;
threadState.X1 = (ulong)handle;
}
private KernelResult CreateThread(
ulong entrypoint,
ulong argsPtr,
ulong stackTop,
int priority,
int cpuCore,
out int handle)
{
handle = 0;
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
if (cpuCore == -2)
{
cpuCore = currentProcess.DefaultCpuCore;
}
if ((uint)cpuCore >= KScheduler.CpuCoresCount || !currentProcess.IsCpuCoreAllowed(cpuCore))
{
return KernelResult.InvalidCpuCore;
}
if ((uint)priority >= KScheduler.PrioritiesCount || !currentProcess.IsPriorityAllowed(priority))
{
return KernelResult.InvalidPriority;
}
long timeout = KTimeManager.ConvertMillisecondsToNanoseconds(100);
if (currentProcess.ResourceLimit != null &&
!currentProcess.ResourceLimit.Reserve(LimitableResource.Thread, 1, timeout))
{
return KernelResult.ResLimitExceeded;
}
KThread thread = new KThread(_system);
KernelResult result = currentProcess.InitializeThread(
thread,
entrypoint,
argsPtr,
stackTop,
priority,
cpuCore);
if (result != KernelResult.Success)
{
currentProcess.ResourceLimit?.Release(LimitableResource.Thread, 1);
return result;
}
result = _process.HandleTable.GenerateHandle(thread, out handle);
if (result != KernelResult.Success)
{
thread.Terminate();
currentProcess.ResourceLimit?.Release(LimitableResource.Thread, 1);
}
return result;
}
private void SvcStartThread(CpuThreadState threadState)
{
int handle = (int)threadState.X0;
KThread thread = _process.HandleTable.GetObject<KThread>(handle);
if (thread != null)
{
KernelResult result = thread.Start();
if (result != KernelResult.Success)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{result}\".");
}
threadState.X0 = (ulong)result;
}
else
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
}
}
private void SvcExitThread(CpuThreadState threadState)
{
KThread currentThread = _system.Scheduler.GetCurrentThread();
_system.Scheduler.ExitThread(currentThread);
currentThread.Exit();
}
private void SvcSleepThread(CpuThreadState threadState)
{
long timeout = (long)threadState.X0;
Logger.PrintDebug(LogClass.KernelSvc, "Timeout = 0x" + timeout.ToString("x16"));
KThread currentThread = _system.Scheduler.GetCurrentThread();
if (timeout < 1)
{
switch (timeout)
{
case 0: currentThread.Yield(); break;
case -1: currentThread.YieldWithLoadBalancing(); break;
case -2: currentThread.YieldAndWaitForLoadBalancing(); break;
}
}
else
{
currentThread.Sleep(timeout);
threadState.X0 = 0;
}
}
private void SvcGetThreadPriority(CpuThreadState threadState)
{
int handle = (int)threadState.X1;
KThread thread = _process.HandleTable.GetKThread(handle);
if (thread != null)
{
threadState.X0 = 0;
threadState.X1 = (ulong)thread.DynamicPriority;
}
else
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
}
}
private void SvcSetThreadPriority(CpuThreadState threadState)
{
int handle = (int)threadState.X0;
int priority = (int)threadState.X1;
Logger.PrintDebug(LogClass.KernelSvc,
"Handle = 0x" + handle .ToString("x8") + ", " +
"Priority = 0x" + priority.ToString("x8"));
//TODO: NPDM check.
KThread thread = _process.HandleTable.GetKThread(handle);
if (thread == null)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
return;
}
thread.SetPriority(priority);
threadState.X0 = 0;
}
private void SvcGetThreadCoreMask(CpuThreadState threadState)
{
int handle = (int)threadState.X2;
Logger.PrintDebug(LogClass.KernelSvc, "Handle = 0x" + handle.ToString("x8"));
KThread thread = _process.HandleTable.GetKThread(handle);
if (thread != null)
{
threadState.X0 = 0;
threadState.X1 = (ulong)thread.PreferredCore;
threadState.X2 = (ulong)thread.AffinityMask;
}
else
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
}
}
private void SetThreadCoreMask64(CpuThreadState threadState)
{
int handle = (int)threadState.X0;
int preferredCore = (int)threadState.X1;
long affinityMask = (long)threadState.X2;
Logger.PrintDebug(LogClass.KernelSvc,
"Handle = 0x" + handle .ToString("x8") + ", " +
"PreferredCore = 0x" + preferredCore.ToString("x8") + ", " +
"AffinityMask = 0x" + affinityMask .ToString("x16"));
KernelResult result = SetThreadCoreMask(handle, preferredCore, affinityMask);
if (result != KernelResult.Success)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error \"{result}\".");
}
threadState.X0 = (ulong)result;
}
private KernelResult SetThreadCoreMask(int handle, int preferredCore, long affinityMask)
{
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
if (preferredCore == -2)
{
preferredCore = currentProcess.DefaultCpuCore;
affinityMask = 1 << preferredCore;
}
else
{
if ((currentProcess.Capabilities.AllowedCpuCoresMask | affinityMask) !=
currentProcess.Capabilities.AllowedCpuCoresMask)
{
return KernelResult.InvalidCpuCore;
}
if (affinityMask == 0)
{
return KernelResult.InvalidCombination;
}
if ((uint)preferredCore > 3)
{
if ((preferredCore | 2) != -1)
{
return KernelResult.InvalidCpuCore;
}
}
else if ((affinityMask & (1 << preferredCore)) == 0)
{
return KernelResult.InvalidCombination;
}
}
KThread thread = _process.HandleTable.GetKThread(handle);
if (thread == null)
{
return KernelResult.InvalidHandle;
}
return thread.SetCoreAndAffinityMask(preferredCore, affinityMask);
}
private void SvcGetCurrentProcessorNumber(CpuThreadState threadState)
{
threadState.X0 = (ulong)_system.Scheduler.GetCurrentThread().CurrentCore;
}
private void SvcGetThreadId(CpuThreadState threadState)
{
int handle = (int)threadState.X1;
KThread thread = _process.HandleTable.GetKThread(handle);
if (thread != null)
{
threadState.X0 = 0;
threadState.X1 = (ulong)thread.ThreadUid;
}
else
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
}
}
private void SvcSetThreadActivity(CpuThreadState threadState)
{
int handle = (int)threadState.X0;
bool pause = (int)threadState.X1 == 1;
KThread thread = _process.HandleTable.GetObject<KThread>(handle);
if (thread == null)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
return;
}
if (thread.Owner != _system.Scheduler.GetCurrentProcess())
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread, it belongs to another process.");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
return;
}
if (thread == _system.Scheduler.GetCurrentThread())
{
Logger.PrintWarning(LogClass.KernelSvc, "Invalid thread, current thread is not accepted.");
threadState.X0 = (ulong)KernelResult.InvalidThread;
return;
}
long result = thread.SetActivity(pause);
if (result != 0)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
threadState.X0 = (ulong)result;
}
private void SvcGetThreadContext3(CpuThreadState threadState)
{
long position = (long)threadState.X0;
int handle = (int)threadState.X1;
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
KThread currentThread = _system.Scheduler.GetCurrentThread();
KThread thread = _process.HandleTable.GetObject<KThread>(handle);
if (thread == null)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{handle:x8}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
return;
}
if (thread.Owner != currentProcess)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread, it belongs to another process.");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
return;
}
if (currentThread == thread)
{
Logger.PrintWarning(LogClass.KernelSvc, "Invalid thread, current thread is not accepted.");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidThread);
return;
}
_memory.WriteUInt64(position + 0x0, thread.Context.ThreadState.X0);
_memory.WriteUInt64(position + 0x8, thread.Context.ThreadState.X1);
_memory.WriteUInt64(position + 0x10, thread.Context.ThreadState.X2);
_memory.WriteUInt64(position + 0x18, thread.Context.ThreadState.X3);
_memory.WriteUInt64(position + 0x20, thread.Context.ThreadState.X4);
_memory.WriteUInt64(position + 0x28, thread.Context.ThreadState.X5);
_memory.WriteUInt64(position + 0x30, thread.Context.ThreadState.X6);
_memory.WriteUInt64(position + 0x38, thread.Context.ThreadState.X7);
_memory.WriteUInt64(position + 0x40, thread.Context.ThreadState.X8);
_memory.WriteUInt64(position + 0x48, thread.Context.ThreadState.X9);
_memory.WriteUInt64(position + 0x50, thread.Context.ThreadState.X10);
_memory.WriteUInt64(position + 0x58, thread.Context.ThreadState.X11);
_memory.WriteUInt64(position + 0x60, thread.Context.ThreadState.X12);
_memory.WriteUInt64(position + 0x68, thread.Context.ThreadState.X13);
_memory.WriteUInt64(position + 0x70, thread.Context.ThreadState.X14);
_memory.WriteUInt64(position + 0x78, thread.Context.ThreadState.X15);
_memory.WriteUInt64(position + 0x80, thread.Context.ThreadState.X16);
_memory.WriteUInt64(position + 0x88, thread.Context.ThreadState.X17);
_memory.WriteUInt64(position + 0x90, thread.Context.ThreadState.X18);
_memory.WriteUInt64(position + 0x98, thread.Context.ThreadState.X19);
_memory.WriteUInt64(position + 0xa0, thread.Context.ThreadState.X20);
_memory.WriteUInt64(position + 0xa8, thread.Context.ThreadState.X21);
_memory.WriteUInt64(position + 0xb0, thread.Context.ThreadState.X22);
_memory.WriteUInt64(position + 0xb8, thread.Context.ThreadState.X23);
_memory.WriteUInt64(position + 0xc0, thread.Context.ThreadState.X24);
_memory.WriteUInt64(position + 0xc8, thread.Context.ThreadState.X25);
_memory.WriteUInt64(position + 0xd0, thread.Context.ThreadState.X26);
_memory.WriteUInt64(position + 0xd8, thread.Context.ThreadState.X27);
_memory.WriteUInt64(position + 0xe0, thread.Context.ThreadState.X28);
_memory.WriteUInt64(position + 0xe8, thread.Context.ThreadState.X29);
_memory.WriteUInt64(position + 0xf0, thread.Context.ThreadState.X30);
_memory.WriteUInt64(position + 0xf8, thread.Context.ThreadState.X31);
_memory.WriteInt64(position + 0x100, thread.LastPc);
_memory.WriteUInt64(position + 0x108, (ulong)thread.Context.ThreadState.Psr);
_memory.WriteVector128(position + 0x110, thread.Context.ThreadState.V0);
_memory.WriteVector128(position + 0x120, thread.Context.ThreadState.V1);
_memory.WriteVector128(position + 0x130, thread.Context.ThreadState.V2);
_memory.WriteVector128(position + 0x140, thread.Context.ThreadState.V3);
_memory.WriteVector128(position + 0x150, thread.Context.ThreadState.V4);
_memory.WriteVector128(position + 0x160, thread.Context.ThreadState.V5);
_memory.WriteVector128(position + 0x170, thread.Context.ThreadState.V6);
_memory.WriteVector128(position + 0x180, thread.Context.ThreadState.V7);
_memory.WriteVector128(position + 0x190, thread.Context.ThreadState.V8);
_memory.WriteVector128(position + 0x1a0, thread.Context.ThreadState.V9);
_memory.WriteVector128(position + 0x1b0, thread.Context.ThreadState.V10);
_memory.WriteVector128(position + 0x1c0, thread.Context.ThreadState.V11);
_memory.WriteVector128(position + 0x1d0, thread.Context.ThreadState.V12);
_memory.WriteVector128(position + 0x1e0, thread.Context.ThreadState.V13);
_memory.WriteVector128(position + 0x1f0, thread.Context.ThreadState.V14);
_memory.WriteVector128(position + 0x200, thread.Context.ThreadState.V15);
_memory.WriteVector128(position + 0x210, thread.Context.ThreadState.V16);
_memory.WriteVector128(position + 0x220, thread.Context.ThreadState.V17);
_memory.WriteVector128(position + 0x230, thread.Context.ThreadState.V18);
_memory.WriteVector128(position + 0x240, thread.Context.ThreadState.V19);
_memory.WriteVector128(position + 0x250, thread.Context.ThreadState.V20);
_memory.WriteVector128(position + 0x260, thread.Context.ThreadState.V21);
_memory.WriteVector128(position + 0x270, thread.Context.ThreadState.V22);
_memory.WriteVector128(position + 0x280, thread.Context.ThreadState.V23);
_memory.WriteVector128(position + 0x290, thread.Context.ThreadState.V24);
_memory.WriteVector128(position + 0x2a0, thread.Context.ThreadState.V25);
_memory.WriteVector128(position + 0x2b0, thread.Context.ThreadState.V26);
_memory.WriteVector128(position + 0x2c0, thread.Context.ThreadState.V27);
_memory.WriteVector128(position + 0x2d0, thread.Context.ThreadState.V28);
_memory.WriteVector128(position + 0x2e0, thread.Context.ThreadState.V29);
_memory.WriteVector128(position + 0x2f0, thread.Context.ThreadState.V30);
_memory.WriteVector128(position + 0x300, thread.Context.ThreadState.V31);
_memory.WriteInt32(position + 0x310, thread.Context.ThreadState.Fpcr);
_memory.WriteInt32(position + 0x314, thread.Context.ThreadState.Fpsr);
_memory.WriteInt64(position + 0x318, thread.Context.ThreadState.Tpidr);
threadState.X0 = 0;
}
}
}

View file

@ -1,373 +0,0 @@
using ChocolArm64.State;
using Ryujinx.Common.Logging;
using System.Collections.Generic;
using static Ryujinx.HLE.HOS.ErrorCode;
namespace Ryujinx.HLE.HOS.Kernel
{
partial class SvcHandler
{
private void SvcWaitSynchronization(CpuThreadState threadState)
{
long handlesPtr = (long)threadState.X1;
int handlesCount = (int)threadState.X2;
long timeout = (long)threadState.X3;
Logger.PrintDebug(LogClass.KernelSvc,
"HandlesPtr = 0x" + handlesPtr .ToString("x16") + ", " +
"HandlesCount = 0x" + handlesCount.ToString("x8") + ", " +
"Timeout = 0x" + timeout .ToString("x16"));
if ((uint)handlesCount > 0x40)
{
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.CountOutOfRange);
return;
}
List<KSynchronizationObject> syncObjs = new List<KSynchronizationObject>();
for (int index = 0; index < handlesCount; index++)
{
int handle = _memory.ReadInt32(handlesPtr + index * 4);
Logger.PrintDebug(LogClass.KernelSvc, $"Sync handle 0x{handle:x8}");
KSynchronizationObject syncObj = _process.HandleTable.GetObject<KSynchronizationObject>(handle);
if (syncObj == null)
{
break;
}
syncObjs.Add(syncObj);
}
int hndIndex = (int)threadState.X1;
ulong high = threadState.X1 & (0xffffffffUL << 32);
long result = _system.Synchronization.WaitFor(syncObjs.ToArray(), timeout, ref hndIndex);
if (result != 0)
{
if (result == MakeError(ErrorModule.Kernel, KernelErr.Timeout) ||
result == MakeError(ErrorModule.Kernel, KernelErr.Cancelled))
{
Logger.PrintDebug(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
else
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
}
threadState.X0 = (ulong)result;
threadState.X1 = (uint)hndIndex | high;
}
private void SvcCancelSynchronization(CpuThreadState threadState)
{
int threadHandle = (int)threadState.X0;
Logger.PrintDebug(LogClass.KernelSvc, "ThreadHandle = 0x" + threadHandle.ToString("x8"));
KThread thread = _process.HandleTable.GetKThread(threadHandle);
if (thread == null)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{threadHandle:x8}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
return;
}
thread.CancelSynchronization();
threadState.X0 = 0;
}
private void SvcArbitrateLock(CpuThreadState threadState)
{
int ownerHandle = (int)threadState.X0;
long mutexAddress = (long)threadState.X1;
int requesterHandle = (int)threadState.X2;
Logger.PrintDebug(LogClass.KernelSvc,
"OwnerHandle = 0x" + ownerHandle .ToString("x8") + ", " +
"MutexAddress = 0x" + mutexAddress .ToString("x16") + ", " +
"RequesterHandle = 0x" + requesterHandle.ToString("x8"));
if (IsPointingInsideKernel(mutexAddress))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{mutexAddress:x16}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
}
if (IsAddressNotWordAligned(mutexAddress))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{mutexAddress:x16}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
long result = currentProcess.AddressArbiter.ArbitrateLock(ownerHandle, mutexAddress, requesterHandle);
if (result != 0)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
threadState.X0 = (ulong)result;
}
private void SvcArbitrateUnlock(CpuThreadState threadState)
{
long mutexAddress = (long)threadState.X0;
Logger.PrintDebug(LogClass.KernelSvc, "MutexAddress = 0x" + mutexAddress.ToString("x16"));
if (IsPointingInsideKernel(mutexAddress))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{mutexAddress:x16}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
}
if (IsAddressNotWordAligned(mutexAddress))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{mutexAddress:x16}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
long result = currentProcess.AddressArbiter.ArbitrateUnlock(mutexAddress);
if (result != 0)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
threadState.X0 = (ulong)result;
}
private void SvcWaitProcessWideKeyAtomic(CpuThreadState threadState)
{
long mutexAddress = (long)threadState.X0;
long condVarAddress = (long)threadState.X1;
int threadHandle = (int)threadState.X2;
long timeout = (long)threadState.X3;
Logger.PrintDebug(LogClass.KernelSvc,
"MutexAddress = 0x" + mutexAddress .ToString("x16") + ", " +
"CondVarAddress = 0x" + condVarAddress.ToString("x16") + ", " +
"ThreadHandle = 0x" + threadHandle .ToString("x8") + ", " +
"Timeout = 0x" + timeout .ToString("x16"));
if (IsPointingInsideKernel(mutexAddress))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{mutexAddress:x16}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
}
if (IsAddressNotWordAligned(mutexAddress))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{mutexAddress:x16}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
long result = currentProcess.AddressArbiter.WaitProcessWideKeyAtomic(
mutexAddress,
condVarAddress,
threadHandle,
timeout);
if (result != 0)
{
if (result == MakeError(ErrorModule.Kernel, KernelErr.Timeout))
{
Logger.PrintDebug(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
else
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
}
threadState.X0 = (ulong)result;
}
private void SvcSignalProcessWideKey(CpuThreadState threadState)
{
long address = (long)threadState.X0;
int count = (int)threadState.X1;
Logger.PrintDebug(LogClass.KernelSvc,
"Address = 0x" + address.ToString("x16") + ", " +
"Count = 0x" + count .ToString("x8"));
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
currentProcess.AddressArbiter.SignalProcessWideKey(address, count);
threadState.X0 = 0;
}
private void SvcWaitForAddress(CpuThreadState threadState)
{
long address = (long)threadState.X0;
ArbitrationType type = (ArbitrationType)threadState.X1;
int value = (int)threadState.X2;
long timeout = (long)threadState.X3;
Logger.PrintDebug(LogClass.KernelSvc,
"Address = 0x" + address.ToString("x16") + ", " +
"Type = " + type .ToString() + ", " +
"Value = 0x" + value .ToString("x8") + ", " +
"Timeout = 0x" + timeout.ToString("x16"));
if (IsPointingInsideKernel(address))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid address 0x{address:x16}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
}
if (IsAddressNotWordAligned(address))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Unaligned address 0x{address:x16}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
long result;
switch (type)
{
case ArbitrationType.WaitIfLessThan:
result = currentProcess.AddressArbiter.WaitForAddressIfLessThan(address, value, false, timeout);
break;
case ArbitrationType.DecrementAndWaitIfLessThan:
result = currentProcess.AddressArbiter.WaitForAddressIfLessThan(address, value, true, timeout);
break;
case ArbitrationType.WaitIfEqual:
result = currentProcess.AddressArbiter.WaitForAddressIfEqual(address, value, timeout);
break;
default:
result = MakeError(ErrorModule.Kernel, KernelErr.InvalidEnumValue);
break;
}
if (result != 0)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
threadState.X0 = (ulong)result;
}
private void SvcSignalToAddress(CpuThreadState threadState)
{
long address = (long)threadState.X0;
SignalType type = (SignalType)threadState.X1;
int value = (int)threadState.X2;
int count = (int)threadState.X3;
Logger.PrintDebug(LogClass.KernelSvc,
"Address = 0x" + address.ToString("x16") + ", " +
"Type = " + type .ToString() + ", " +
"Value = 0x" + value .ToString("x8") + ", " +
"Count = 0x" + count .ToString("x8"));
if (IsPointingInsideKernel(address))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid address 0x{address:x16}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
return;
}
if (IsAddressNotWordAligned(address))
{
Logger.PrintWarning(LogClass.KernelSvc, $"Unaligned address 0x{address:x16}!");
threadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
return;
}
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
long result;
switch (type)
{
case SignalType.Signal:
result = currentProcess.AddressArbiter.Signal(address, count);
break;
case SignalType.SignalAndIncrementIfEqual:
result = currentProcess.AddressArbiter.SignalAndIncrementIfEqual(address, value, count);
break;
case SignalType.SignalAndModifyIfEqual:
result = currentProcess.AddressArbiter.SignalAndModifyIfEqual(address, value, count);
break;
default:
result = MakeError(ErrorModule.Kernel, KernelErr.InvalidEnumValue);
break;
}
if (result != 0)
{
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{result:x}!");
}
threadState.X0 = (ulong)result;
}
private bool IsPointingInsideKernel(long address)
{
return ((ulong)address + 0x1000000000) < 0xffffff000;
}
private bool IsAddressNotWordAligned(long address)
{
return (address & 3) != 0;
}
}
}

View file

@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Threading
{ {
enum ArbitrationType enum ArbitrationType
{ {

View file

@ -1,7 +1,7 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Threading; using System.Threading;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Threading
{ {
class HleCoreManager class HleCoreManager
{ {

View file

@ -1,7 +1,7 @@
using System; using System;
using System.Threading; using System.Threading;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Threading
{ {
partial class KScheduler partial class KScheduler
{ {

View file

@ -1,9 +1,9 @@
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Process;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using static Ryujinx.HLE.HOS.ErrorCode; namespace Ryujinx.HLE.HOS.Kernel.Threading
namespace Ryujinx.HLE.HOS.Kernel
{ {
class KAddressArbiter class KAddressArbiter
{ {
@ -22,14 +22,14 @@ namespace Ryujinx.HLE.HOS.Kernel
ArbiterThreads = new List<KThread>(); ArbiterThreads = new List<KThread>();
} }
public long ArbitrateLock(int ownerHandle, long mutexAddress, int requesterHandle) public KernelResult ArbitrateLock(int ownerHandle, ulong mutexAddress, int requesterHandle)
{ {
KThread currentThread = _system.Scheduler.GetCurrentThread(); KThread currentThread = _system.Scheduler.GetCurrentThread();
_system.CriticalSection.Enter(); _system.CriticalSection.Enter();
currentThread.SignaledObj = null; currentThread.SignaledObj = null;
currentThread.ObjSyncResult = 0; currentThread.ObjSyncResult = KernelResult.Success;
KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
@ -37,7 +37,7 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); return KernelResult.InvalidMemState;
} }
if (mutexValue != (ownerHandle | HasListenersMask)) if (mutexValue != (ownerHandle | HasListenersMask))
@ -53,7 +53,7 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); return KernelResult.InvalidHandle;
} }
currentThread.MutexAddress = mutexAddress; currentThread.MutexAddress = mutexAddress;
@ -73,21 +73,21 @@ namespace Ryujinx.HLE.HOS.Kernel
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return (uint)currentThread.ObjSyncResult; return (KernelResult)currentThread.ObjSyncResult;
} }
public long ArbitrateUnlock(long mutexAddress) public KernelResult ArbitrateUnlock(ulong mutexAddress)
{ {
_system.CriticalSection.Enter(); _system.CriticalSection.Enter();
KThread currentThread = _system.Scheduler.GetCurrentThread(); KThread currentThread = _system.Scheduler.GetCurrentThread();
(long result, KThread newOwnerThread) = MutexUnlock(currentThread, mutexAddress); (KernelResult result, KThread newOwnerThread) = MutexUnlock(currentThread, mutexAddress);
if (result != 0 && newOwnerThread != null) if (result != KernelResult.Success && newOwnerThread != null)
{ {
newOwnerThread.SignaledObj = null; newOwnerThread.SignaledObj = null;
newOwnerThread.ObjSyncResult = (int)result; newOwnerThread.ObjSyncResult = result;
} }
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
@ -95,30 +95,30 @@ namespace Ryujinx.HLE.HOS.Kernel
return result; return result;
} }
public long WaitProcessWideKeyAtomic( public KernelResult WaitProcessWideKeyAtomic(
long mutexAddress, ulong mutexAddress,
long condVarAddress, ulong condVarAddress,
int threadHandle, int threadHandle,
long timeout) long timeout)
{ {
_system.CriticalSection.Enter(); _system.CriticalSection.Enter();
KThread currentThread = _system.Scheduler.GetCurrentThread(); KThread currentThread = _system.Scheduler.GetCurrentThread();
currentThread.SignaledObj = null; currentThread.SignaledObj = null;
currentThread.ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.Timeout); currentThread.ObjSyncResult = KernelResult.TimedOut;
if (currentThread.ShallBeTerminated || if (currentThread.ShallBeTerminated ||
currentThread.SchedFlags == ThreadSchedState.TerminationPending) currentThread.SchedFlags == ThreadSchedState.TerminationPending)
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.ThreadTerminating); return KernelResult.ThreadTerminating;
} }
(long result, _) = MutexUnlock(currentThread, mutexAddress); (KernelResult result, _) = MutexUnlock(currentThread, mutexAddress);
if (result != 0) if (result != KernelResult.Success)
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
@ -159,10 +159,10 @@ namespace Ryujinx.HLE.HOS.Kernel
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return (uint)currentThread.ObjSyncResult; return (KernelResult)currentThread.ObjSyncResult;
} }
private (long, KThread) MutexUnlock(KThread currentThread, long mutexAddress) private (KernelResult, KThread) MutexUnlock(KThread currentThread, ulong mutexAddress)
{ {
KThread newOwnerThread = currentThread.RelinquishMutex(mutexAddress, out int count); KThread newOwnerThread = currentThread.RelinquishMutex(mutexAddress, out int count);
@ -178,22 +178,22 @@ namespace Ryujinx.HLE.HOS.Kernel
} }
newOwnerThread.SignaledObj = null; newOwnerThread.SignaledObj = null;
newOwnerThread.ObjSyncResult = 0; newOwnerThread.ObjSyncResult = KernelResult.Success;
newOwnerThread.ReleaseAndResume(); newOwnerThread.ReleaseAndResume();
} }
long result = 0; KernelResult result = KernelResult.Success;
if (!KernelTransfer.KernelToUserInt32(_system, mutexAddress, mutexValue)) if (!KernelTransfer.KernelToUserInt32(_system, mutexAddress, mutexValue))
{ {
result = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); result = KernelResult.InvalidMemState;
} }
return (result, newOwnerThread); return (result, newOwnerThread);
} }
public void SignalProcessWideKey(long address, int count) public void SignalProcessWideKey(ulong address, int count)
{ {
Queue<KThread> signaledThreads = new Queue<KThread>(); Queue<KThread> signaledThreads = new Queue<KThread>();
@ -224,11 +224,11 @@ namespace Ryujinx.HLE.HOS.Kernel
private KThread TryAcquireMutex(KThread requester) private KThread TryAcquireMutex(KThread requester)
{ {
long address = requester.MutexAddress; ulong address = requester.MutexAddress;
KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
currentProcess.CpuMemory.SetExclusive(0, address); currentProcess.CpuMemory.SetExclusive(0, (long)address);
if (!KernelTransfer.UserToKernelInt32(_system, address, out int mutexValue)) if (!KernelTransfer.UserToKernelInt32(_system, address, out int mutexValue))
{ {
@ -236,24 +236,24 @@ namespace Ryujinx.HLE.HOS.Kernel
currentProcess.CpuMemory.ClearExclusive(0); currentProcess.CpuMemory.ClearExclusive(0);
requester.SignaledObj = null; requester.SignaledObj = null;
requester.ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); requester.ObjSyncResult = KernelResult.InvalidMemState;
return null; return null;
} }
while (true) while (true)
{ {
if (currentProcess.CpuMemory.TestExclusive(0, address)) if (currentProcess.CpuMemory.TestExclusive(0, (long)address))
{ {
if (mutexValue != 0) if (mutexValue != 0)
{ {
//Update value to indicate there is a mutex waiter now. //Update value to indicate there is a mutex waiter now.
currentProcess.CpuMemory.WriteInt32(address, mutexValue | HasListenersMask); currentProcess.CpuMemory.WriteInt32((long)address, mutexValue | HasListenersMask);
} }
else else
{ {
//No thread owning the mutex, assign to requesting thread. //No thread owning the mutex, assign to requesting thread.
currentProcess.CpuMemory.WriteInt32(address, requester.ThreadHandleForUserMutex); currentProcess.CpuMemory.WriteInt32((long)address, requester.ThreadHandleForUserMutex);
} }
currentProcess.CpuMemory.ClearExclusiveForStore(0); currentProcess.CpuMemory.ClearExclusiveForStore(0);
@ -261,16 +261,16 @@ namespace Ryujinx.HLE.HOS.Kernel
break; break;
} }
currentProcess.CpuMemory.SetExclusive(0, address); currentProcess.CpuMemory.SetExclusive(0, (long)address);
mutexValue = currentProcess.CpuMemory.ReadInt32(address); mutexValue = currentProcess.CpuMemory.ReadInt32((long)address);
} }
if (mutexValue == 0) if (mutexValue == 0)
{ {
//We now own the mutex. //We now own the mutex.
requester.SignaledObj = null; requester.SignaledObj = null;
requester.ObjSyncResult = 0; requester.ObjSyncResult = KernelResult.Success;
requester.ReleaseAndResume(); requester.ReleaseAndResume();
@ -290,7 +290,7 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
//Invalid mutex owner. //Invalid mutex owner.
requester.SignaledObj = null; requester.SignaledObj = null;
requester.ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); requester.ObjSyncResult = KernelResult.InvalidHandle;
requester.ReleaseAndResume(); requester.ReleaseAndResume();
} }
@ -298,7 +298,7 @@ namespace Ryujinx.HLE.HOS.Kernel
return mutexOwner; return mutexOwner;
} }
public long WaitForAddressIfEqual(long address, int value, long timeout) public KernelResult WaitForAddressIfEqual(ulong address, int value, long timeout)
{ {
KThread currentThread = _system.Scheduler.GetCurrentThread(); KThread currentThread = _system.Scheduler.GetCurrentThread();
@ -309,17 +309,17 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.ThreadTerminating); return KernelResult.ThreadTerminating;
} }
currentThread.SignaledObj = null; currentThread.SignaledObj = null;
currentThread.ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.Timeout); currentThread.ObjSyncResult = KernelResult.TimedOut;
if (!KernelTransfer.UserToKernelInt32(_system, address, out int currentValue)) if (!KernelTransfer.UserToKernelInt32(_system, address, out int currentValue))
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); return KernelResult.InvalidMemState;
} }
if (currentValue == value) if (currentValue == value)
@ -328,7 +328,7 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.Timeout); return KernelResult.TimedOut;
} }
currentThread.MutexAddress = address; currentThread.MutexAddress = address;
@ -361,15 +361,19 @@ namespace Ryujinx.HLE.HOS.Kernel
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return currentThread.ObjSyncResult; return (KernelResult)currentThread.ObjSyncResult;
} }
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.InvalidState); return KernelResult.InvalidState;
} }
public long WaitForAddressIfLessThan(long address, int value, bool shouldDecrement, long timeout) public KernelResult WaitForAddressIfLessThan(
ulong address,
int value,
bool shouldDecrement,
long timeout)
{ {
KThread currentThread = _system.Scheduler.GetCurrentThread(); KThread currentThread = _system.Scheduler.GetCurrentThread();
@ -380,40 +384,40 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.ThreadTerminating); return KernelResult.ThreadTerminating;
} }
currentThread.SignaledObj = null; currentThread.SignaledObj = null;
currentThread.ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.Timeout); currentThread.ObjSyncResult = KernelResult.TimedOut;
KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
//If ShouldDecrement is true, do atomic decrement of the value at Address. //If ShouldDecrement is true, do atomic decrement of the value at Address.
currentProcess.CpuMemory.SetExclusive(0, address); currentProcess.CpuMemory.SetExclusive(0, (long)address);
if (!KernelTransfer.UserToKernelInt32(_system, address, out int currentValue)) if (!KernelTransfer.UserToKernelInt32(_system, address, out int currentValue))
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); return KernelResult.InvalidMemState;
} }
if (shouldDecrement) if (shouldDecrement)
{ {
while (currentValue < value) while (currentValue < value)
{ {
if (currentProcess.CpuMemory.TestExclusive(0, address)) if (currentProcess.CpuMemory.TestExclusive(0, (long)address))
{ {
currentProcess.CpuMemory.WriteInt32(address, currentValue - 1); currentProcess.CpuMemory.WriteInt32((long)address, currentValue - 1);
currentProcess.CpuMemory.ClearExclusiveForStore(0); currentProcess.CpuMemory.ClearExclusiveForStore(0);
break; break;
} }
currentProcess.CpuMemory.SetExclusive(0, address); currentProcess.CpuMemory.SetExclusive(0, (long)address);
currentValue = currentProcess.CpuMemory.ReadInt32(address); currentValue = currentProcess.CpuMemory.ReadInt32((long)address);
} }
} }
@ -425,7 +429,7 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.Timeout); return KernelResult.TimedOut;
} }
currentThread.MutexAddress = address; currentThread.MutexAddress = address;
@ -458,12 +462,12 @@ namespace Ryujinx.HLE.HOS.Kernel
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return currentThread.ObjSyncResult; return (KernelResult)currentThread.ObjSyncResult;
} }
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.InvalidState); return KernelResult.InvalidState;
} }
private void InsertSortedByPriority(List<KThread> threads, KThread thread) private void InsertSortedByPriority(List<KThread> threads, KThread thread)
@ -490,7 +494,7 @@ namespace Ryujinx.HLE.HOS.Kernel
} }
} }
public long Signal(long address, int count) public KernelResult Signal(ulong address, int count)
{ {
_system.CriticalSection.Enter(); _system.CriticalSection.Enter();
@ -498,38 +502,38 @@ namespace Ryujinx.HLE.HOS.Kernel
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return 0; return KernelResult.Success;
} }
public long SignalAndIncrementIfEqual(long address, int value, int count) public KernelResult SignalAndIncrementIfEqual(ulong address, int value, int count)
{ {
_system.CriticalSection.Enter(); _system.CriticalSection.Enter();
KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
currentProcess.CpuMemory.SetExclusive(0, address); currentProcess.CpuMemory.SetExclusive(0, (long)address);
if (!KernelTransfer.UserToKernelInt32(_system, address, out int currentValue)) if (!KernelTransfer.UserToKernelInt32(_system, address, out int currentValue))
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); return KernelResult.InvalidMemState;
} }
while (currentValue == value) while (currentValue == value)
{ {
if (currentProcess.CpuMemory.TestExclusive(0, address)) if (currentProcess.CpuMemory.TestExclusive(0, (long)address))
{ {
currentProcess.CpuMemory.WriteInt32(address, currentValue + 1); currentProcess.CpuMemory.WriteInt32((long)address, currentValue + 1);
currentProcess.CpuMemory.ClearExclusiveForStore(0); currentProcess.CpuMemory.ClearExclusiveForStore(0);
break; break;
} }
currentProcess.CpuMemory.SetExclusive(0, address); currentProcess.CpuMemory.SetExclusive(0, (long)address);
currentValue = currentProcess.CpuMemory.ReadInt32(address); currentValue = currentProcess.CpuMemory.ReadInt32((long)address);
} }
currentProcess.CpuMemory.ClearExclusive(0); currentProcess.CpuMemory.ClearExclusive(0);
@ -538,17 +542,17 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.InvalidState); return KernelResult.InvalidState;
} }
WakeArbiterThreads(address, count); WakeArbiterThreads(address, count);
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return 0; return KernelResult.Success;
} }
public long SignalAndModifyIfEqual(long address, int value, int count) public KernelResult SignalAndModifyIfEqual(ulong address, int value, int count)
{ {
_system.CriticalSection.Enter(); _system.CriticalSection.Enter();
@ -578,29 +582,29 @@ namespace Ryujinx.HLE.HOS.Kernel
KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
currentProcess.CpuMemory.SetExclusive(0, address); currentProcess.CpuMemory.SetExclusive(0, (long)address);
if (!KernelTransfer.UserToKernelInt32(_system, address, out int currentValue)) if (!KernelTransfer.UserToKernelInt32(_system, address, out int currentValue))
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm); return KernelResult.InvalidMemState;
} }
while (currentValue == value) while (currentValue == value)
{ {
if (currentProcess.CpuMemory.TestExclusive(0, address)) if (currentProcess.CpuMemory.TestExclusive(0, (long)address))
{ {
currentProcess.CpuMemory.WriteInt32(address, currentValue + offset); currentProcess.CpuMemory.WriteInt32((long)address, currentValue + offset);
currentProcess.CpuMemory.ClearExclusiveForStore(0); currentProcess.CpuMemory.ClearExclusiveForStore(0);
break; break;
} }
currentProcess.CpuMemory.SetExclusive(0, address); currentProcess.CpuMemory.SetExclusive(0, (long)address);
currentValue = currentProcess.CpuMemory.ReadInt32(address); currentValue = currentProcess.CpuMemory.ReadInt32((long)address);
} }
currentProcess.CpuMemory.ClearExclusive(0); currentProcess.CpuMemory.ClearExclusive(0);
@ -609,17 +613,17 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.InvalidState); return KernelResult.InvalidState;
} }
WakeArbiterThreads(address, count); WakeArbiterThreads(address, count);
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
return 0; return KernelResult.Success;
} }
private void WakeArbiterThreads(long address, int count) private void WakeArbiterThreads(ulong address, int count)
{ {
Queue<KThread> signaledThreads = new Queue<KThread>(); Queue<KThread> signaledThreads = new Queue<KThread>();
@ -637,7 +641,7 @@ namespace Ryujinx.HLE.HOS.Kernel
while (signaledThreads.TryDequeue(out KThread thread)) while (signaledThreads.TryDequeue(out KThread thread))
{ {
thread.SignaledObj = null; thread.SignaledObj = null;
thread.ObjSyncResult = 0; thread.ObjSyncResult = KernelResult.Success;
thread.ReleaseAndResume(); thread.ReleaseAndResume();

View file

@ -1,7 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Threading
{ {
static class KConditionVariable static class KConditionVariable
{ {

View file

@ -1,6 +1,6 @@
using Ryujinx.Common; using Ryujinx.Common;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Threading
{ {
class KCoreContext class KCoreContext
{ {

View file

@ -1,7 +1,7 @@
using ChocolArm64; using ChocolArm64;
using System.Threading; using System.Threading;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Threading
{ {
class KCriticalSection class KCriticalSection
{ {

View file

@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Threading
{ {
class KEvent class KEvent
{ {

View file

@ -1,4 +1,6 @@
namespace Ryujinx.HLE.HOS.Kernel using Ryujinx.HLE.HOS.Kernel.Common;
namespace Ryujinx.HLE.HOS.Kernel.Threading
{ {
class KReadableEvent : KSynchronizationObject class KReadableEvent : KSynchronizationObject
{ {

View file

@ -1,8 +1,9 @@
using Ryujinx.HLE.HOS.Kernel.Process;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Threading
{ {
partial class KScheduler : IDisposable partial class KScheduler : IDisposable
{ {

View file

@ -1,6 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Threading
{ {
class KSchedulingData class KSchedulingData
{ {

View file

@ -1,8 +1,7 @@
using Ryujinx.HLE.HOS.Kernel.Common;
using System.Collections.Generic; using System.Collections.Generic;
using static Ryujinx.HLE.HOS.ErrorCode; namespace Ryujinx.HLE.HOS.Kernel.Threading
namespace Ryujinx.HLE.HOS.Kernel
{ {
class KSynchronization class KSynchronization
{ {
@ -13,9 +12,11 @@ namespace Ryujinx.HLE.HOS.Kernel
_system = system; _system = system;
} }
public long WaitFor(KSynchronizationObject[] syncObjs, long timeout, ref int hndIndex) public KernelResult WaitFor(KSynchronizationObject[] syncObjs, long timeout, out int handleIndex)
{ {
long result = MakeError(ErrorModule.Kernel, KernelErr.Timeout); handleIndex = 0;
KernelResult result = KernelResult.TimedOut;
_system.CriticalSection.Enter(); _system.CriticalSection.Enter();
@ -27,7 +28,7 @@ namespace Ryujinx.HLE.HOS.Kernel
continue; continue;
} }
hndIndex = index; handleIndex = index;
_system.CriticalSection.Leave(); _system.CriticalSection.Leave();
@ -46,13 +47,13 @@ namespace Ryujinx.HLE.HOS.Kernel
if (currentThread.ShallBeTerminated || if (currentThread.ShallBeTerminated ||
currentThread.SchedFlags == ThreadSchedState.TerminationPending) currentThread.SchedFlags == ThreadSchedState.TerminationPending)
{ {
result = MakeError(ErrorModule.Kernel, KernelErr.ThreadTerminating); result = KernelResult.ThreadTerminating;
} }
else if (currentThread.SyncCancelled) else if (currentThread.SyncCancelled)
{ {
currentThread.SyncCancelled = false; currentThread.SyncCancelled = false;
result = MakeError(ErrorModule.Kernel, KernelErr.Cancelled); result = KernelResult.Cancelled;
} }
else else
{ {
@ -65,7 +66,7 @@ namespace Ryujinx.HLE.HOS.Kernel
currentThread.WaitingSync = true; currentThread.WaitingSync = true;
currentThread.SignaledObj = null; currentThread.SignaledObj = null;
currentThread.ObjSyncResult = (int)result; currentThread.ObjSyncResult = result;
currentThread.Reschedule(ThreadSchedState.Paused); currentThread.Reschedule(ThreadSchedState.Paused);
@ -85,9 +86,9 @@ namespace Ryujinx.HLE.HOS.Kernel
_system.CriticalSection.Enter(); _system.CriticalSection.Enter();
result = (uint)currentThread.ObjSyncResult; result = currentThread.ObjSyncResult;
hndIndex = -1; handleIndex = -1;
for (int index = 0; index < syncObjs.Length; index++) for (int index = 0; index < syncObjs.Length; index++)
{ {
@ -95,7 +96,7 @@ namespace Ryujinx.HLE.HOS.Kernel
if (syncObjs[index] == currentThread.SignaledObj) if (syncObjs[index] == currentThread.SignaledObj)
{ {
hndIndex = index; handleIndex = index;
} }
} }
} }
@ -120,7 +121,7 @@ namespace Ryujinx.HLE.HOS.Kernel
if ((thread.SchedFlags & ThreadSchedState.LowMask) == ThreadSchedState.Paused) if ((thread.SchedFlags & ThreadSchedState.LowMask) == ThreadSchedState.Paused)
{ {
thread.SignaledObj = syncObj; thread.SignaledObj = syncObj;
thread.ObjSyncResult = 0; thread.ObjSyncResult = KernelResult.Success;
thread.Reschedule(ThreadSchedState.Running); thread.Reschedule(ThreadSchedState.Running);
} }

View file

@ -1,12 +1,12 @@
using ChocolArm64; using ChocolArm64;
using ChocolArm64.Memory; using ChocolArm64.Memory;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Process;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using static Ryujinx.HLE.HOS.ErrorCode; namespace Ryujinx.HLE.HOS.Kernel.Threading
namespace Ryujinx.HLE.HOS.Kernel
{ {
class KThread : KSynchronizationObject, IKFutureSchedulerObject class KThread : KSynchronizationObject, IKFutureSchedulerObject
{ {
@ -20,11 +20,11 @@ namespace Ryujinx.HLE.HOS.Kernel
public KSynchronizationObject SignaledObj { get; set; } public KSynchronizationObject SignaledObj { get; set; }
public long CondVarAddress { get; set; } public ulong CondVarAddress { get; set; }
private ulong _entrypoint; private ulong _entrypoint;
public long MutexAddress { get; set; } public ulong MutexAddress { get; set; }
public KProcess Owner { get; private set; } public KProcess Owner { get; private set; }
@ -48,7 +48,7 @@ namespace Ryujinx.HLE.HOS.Kernel
private ThreadSchedState _forcePauseFlags; private ThreadSchedState _forcePauseFlags;
public int ObjSyncResult { get; set; } public KernelResult ObjSyncResult { get; set; }
public int DynamicPriority { get; set; } public int DynamicPriority { get; set; }
public int CurrentCore { get; set; } public int CurrentCore { get; set; }
@ -113,7 +113,7 @@ namespace Ryujinx.HLE.HOS.Kernel
DynamicPriority = priority; DynamicPriority = priority;
BasePriority = priority; BasePriority = priority;
ObjSyncResult = 0x7201; ObjSyncResult = KernelResult.ThreadNotStarted;
_entrypoint = entrypoint; _entrypoint = entrypoint;
@ -274,7 +274,7 @@ namespace Ryujinx.HLE.HOS.Kernel
System.CriticalSection.Leave(); System.CriticalSection.Leave();
} }
public long Sleep(long timeout) public KernelResult Sleep(long timeout)
{ {
System.CriticalSection.Enter(); System.CriticalSection.Enter();
@ -282,7 +282,7 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
System.CriticalSection.Leave(); System.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.ThreadTerminating); return KernelResult.ThreadTerminating;
} }
SetNewSchedFlags(ThreadSchedState.Paused); SetNewSchedFlags(ThreadSchedState.Paused);
@ -468,9 +468,9 @@ namespace Ryujinx.HLE.HOS.Kernel
System.CriticalSection.Leave(); System.CriticalSection.Leave();
} }
public long SetActivity(bool pause) public KernelResult SetActivity(bool pause)
{ {
long result = 0; KernelResult result = KernelResult.Success;
System.CriticalSection.Enter(); System.CriticalSection.Enter();
@ -480,7 +480,7 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
System.CriticalSection.Leave(); System.CriticalSection.Leave();
return MakeError(ErrorModule.Kernel, KernelErr.InvalidState); return KernelResult.InvalidState;
} }
System.CriticalSection.Enter(); System.CriticalSection.Enter();
@ -498,7 +498,7 @@ namespace Ryujinx.HLE.HOS.Kernel
} }
else else
{ {
result = MakeError(ErrorModule.Kernel, KernelErr.InvalidState); result = KernelResult.InvalidState;
} }
} }
else else
@ -521,7 +521,7 @@ namespace Ryujinx.HLE.HOS.Kernel
} }
else else
{ {
result = MakeError(ErrorModule.Kernel, KernelErr.InvalidState); result = KernelResult.InvalidState;
} }
} }
} }
@ -553,7 +553,7 @@ namespace Ryujinx.HLE.HOS.Kernel
else else
{ {
SignaledObj = null; SignaledObj = null;
ObjSyncResult = (int)MakeError(ErrorModule.Kernel, KernelErr.Cancelled); ObjSyncResult = KernelResult.Cancelled;
SetNewSchedFlags(ThreadSchedState.Running); SetNewSchedFlags(ThreadSchedState.Running);
@ -716,7 +716,7 @@ namespace Ryujinx.HLE.HOS.Kernel
UpdatePriorityInheritance(); UpdatePriorityInheritance();
} }
public KThread RelinquishMutex(long mutexAddress, out int count) public KThread RelinquishMutex(ulong mutexAddress, out int count)
{ {
count = 0; count = 0;
@ -1017,7 +1017,7 @@ namespace Ryujinx.HLE.HOS.Kernel
{ {
thread.MutexOwner = null; thread.MutexOwner = null;
thread._preferredCoreOverride = 0; thread._preferredCoreOverride = 0;
thread.ObjSyncResult = 0xfa01; thread.ObjSyncResult = KernelResult.InvalidState;
thread.ReleaseAndResume(); thread.ReleaseAndResume();
} }

View file

@ -1,4 +1,6 @@
namespace Ryujinx.HLE.HOS.Kernel using Ryujinx.HLE.HOS.Kernel.Common;
namespace Ryujinx.HLE.HOS.Kernel.Threading
{ {
class KWritableEvent class KWritableEvent
{ {

View file

@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Threading
{ {
enum SignalType enum SignalType
{ {

View file

@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Threading
{ {
enum ThreadSchedState : ushort enum ThreadSchedState : ushort
{ {

View file

@ -1,4 +1,4 @@
namespace Ryujinx.HLE.HOS.Kernel namespace Ryujinx.HLE.HOS.Kernel.Threading
{ {
enum ThreadType enum ThreadType
{ {

View file

@ -1,7 +1,9 @@
using ChocolArm64.Memory; using ChocolArm64.Memory;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.Loaders.Executables; using Ryujinx.HLE.Loaders.Executables;
using Ryujinx.HLE.Loaders.Npdm; using Ryujinx.HLE.Loaders.Npdm;

View file

@ -1,6 +1,7 @@
using ChocolArm64.Memory; using ChocolArm64.Memory;
using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Ipc;
using Ryujinx.HLE.HOS.Kernel.Process;
using System.IO; using System.IO;
namespace Ryujinx.HLE.HOS namespace Ryujinx.HLE.HOS

View file

@ -1,6 +1,7 @@
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;

View file

@ -1,6 +1,7 @@
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;

View file

@ -1,6 +1,7 @@
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;

View file

@ -1,6 +1,7 @@
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;

View file

@ -1,7 +1,8 @@
using ChocolArm64.Memory; using ChocolArm64.Memory;
using Ryujinx.Audio; using Ryujinx.Audio;
using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;

View file

@ -3,7 +3,8 @@ using Ryujinx.Audio;
using Ryujinx.Audio.Adpcm; using Ryujinx.Audio.Adpcm;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.Utilities; using Ryujinx.HLE.Utilities;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;

View file

@ -1,6 +1,7 @@
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.HOS.SystemState;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;

View file

@ -2,7 +2,7 @@ using ChocolArm64.Memory;
using Ryujinx.Audio; using Ryujinx.Audio;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Aud.AudioOut; using Ryujinx.HLE.HOS.Services.Aud.AudioOut;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;

View file

@ -1,5 +1,6 @@
using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;

View file

@ -1,6 +1,7 @@
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.Input; using Ryujinx.HLE.Input;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;

View file

@ -1,6 +1,7 @@
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Ipc;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;

View file

@ -1,7 +1,9 @@
using ChocolArm64.Memory; using ChocolArm64.Memory;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.Loaders.Executables; using Ryujinx.HLE.Loaders.Executables;
using Ryujinx.HLE.Utilities; using Ryujinx.HLE.Utilities;
using System.Collections.Generic; using System.Collections.Generic;

View file

@ -1,6 +1,7 @@
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.Input; using Ryujinx.HLE.Input;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;

View file

@ -1,6 +1,7 @@
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;

Some files were not shown because too many files have changed in this diff Show more