Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
45ce540b9b | ||
|
96bf7f8522 | ||
|
33e673ceb8 |
@@ -113,6 +113,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||
Add(X86Instruction.Divps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex));
|
||||
Add(X86Instruction.Divsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||
Add(X86Instruction.Divss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||
Add(X86Instruction.Gf2p8affineqb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3ace, InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Haddpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f7c, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Haddps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f7c, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||
Add(X86Instruction.Idiv, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x070000f7, InstructionFlags.None));
|
||||
|
@@ -20,8 +20,9 @@ namespace ARMeilleure.CodeGen.X86
|
||||
|
||||
if (maxNum >= 7)
|
||||
{
|
||||
(_, int ebx7, _, _) = X86Base.CpuId(0x00000007, 0x00000000);
|
||||
(_, int ebx7, int ecx7, _) = X86Base.CpuId(0x00000007, 0x00000000);
|
||||
FeatureInfo7Ebx = (FeatureFlags7Ebx)ebx7;
|
||||
FeatureInfo7Ecx = (FeatureFlags7Ecx)ecx7;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,9 +55,16 @@ namespace ARMeilleure.CodeGen.X86
|
||||
Sha = 1 << 29
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum FeatureFlags7Ecx
|
||||
{
|
||||
Gfni = 1 << 8,
|
||||
}
|
||||
|
||||
public static FeatureFlags1Edx FeatureInfo1Edx { get; }
|
||||
public static FeatureFlags1Ecx FeatureInfo1Ecx { get; }
|
||||
public static FeatureFlags7Ebx FeatureInfo7Ebx { get; } = 0;
|
||||
public static FeatureFlags7Ecx FeatureInfo7Ecx { get; } = 0;
|
||||
|
||||
public static bool SupportsSse => FeatureInfo1Edx.HasFlag(FeatureFlags1Edx.Sse);
|
||||
public static bool SupportsSse2 => FeatureInfo1Edx.HasFlag(FeatureFlags1Edx.Sse2);
|
||||
@@ -72,6 +80,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||
public static bool SupportsAvx2 => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx2) && SupportsAvx;
|
||||
public static bool SupportsF16c => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.F16c);
|
||||
public static bool SupportsSha => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Sha);
|
||||
public static bool SupportsGfni => FeatureInfo7Ecx.HasFlag(FeatureFlags7Ecx.Gfni);
|
||||
|
||||
public static bool ForceLegacySse { get; set; }
|
||||
|
||||
|
@@ -58,6 +58,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||
Add(Intrinsic.X86Divps, new IntrinsicInfo(X86Instruction.Divps, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Divsd, new IntrinsicInfo(X86Instruction.Divsd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Divss, new IntrinsicInfo(X86Instruction.Divss, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Gf2p8affineqb, new IntrinsicInfo(X86Instruction.Gf2p8affineqb, IntrinsicType.TernaryImm));
|
||||
Add(Intrinsic.X86Haddpd, new IntrinsicInfo(X86Instruction.Haddpd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Haddps, new IntrinsicInfo(X86Instruction.Haddps, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Insertps, new IntrinsicInfo(X86Instruction.Insertps, IntrinsicType.TernaryImm));
|
||||
|
@@ -54,6 +54,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||
Divps,
|
||||
Divsd,
|
||||
Divss,
|
||||
Gf2p8affineqb,
|
||||
Haddpd,
|
||||
Haddps,
|
||||
Idiv,
|
||||
|
@@ -243,6 +243,21 @@ namespace ARMeilleure.Instructions
|
||||
throw new ArgumentException($"Invalid rounding mode \"{roundMode}\".");
|
||||
}
|
||||
|
||||
public static ulong X86GetGf2p8LogicalShiftLeft(int shift)
|
||||
{
|
||||
ulong identity =
|
||||
(0b00000001UL << 56) |
|
||||
(0b00000010UL << 48) |
|
||||
(0b00000100UL << 40) |
|
||||
(0b00001000UL << 32) |
|
||||
(0b00010000UL << 24) |
|
||||
(0b00100000UL << 16) |
|
||||
(0b01000000UL << 8) |
|
||||
(0b10000000UL << 0);
|
||||
|
||||
return shift >= 0 ? identity >> (shift * 8) : identity << (-shift * 8);
|
||||
}
|
||||
|
||||
public static Operand EmitCountSetBits8(ArmEmitterContext context, Operand op) // "size" is 8 (SIMD&FP Inst.).
|
||||
{
|
||||
Debug.Assert(op.Type == OperandType.I32 || op.Type == OperandType.I64);
|
||||
|
@@ -336,8 +336,32 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
Operand res = context.VectorZero();
|
||||
if (Optimizations.UseGfni)
|
||||
{
|
||||
const long bitMatrix =
|
||||
(0b10000000L << 56) |
|
||||
(0b01000000L << 48) |
|
||||
(0b00100000L << 40) |
|
||||
(0b00010000L << 32) |
|
||||
(0b00001000L << 24) |
|
||||
(0b00000100L << 16) |
|
||||
(0b00000010L << 8) |
|
||||
(0b00000001L << 0);
|
||||
|
||||
Operand vBitMatrix = X86GetAllElements(context, bitMatrix);
|
||||
|
||||
Operand res = context.AddIntrinsic(Intrinsic.X86Gf2p8affineqb, GetVec(op.Rn), vBitMatrix, Const(0));
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd64)
|
||||
{
|
||||
res = context.VectorZeroUpper64(res);
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), res);
|
||||
}
|
||||
else
|
||||
{
|
||||
Operand res = context.VectorZero();
|
||||
int elems = op.RegisterSize == RegisterSize.Simd128 ? 16 : 8;
|
||||
|
||||
for (int index = 0; index < elems; index++)
|
||||
@@ -351,6 +375,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
context.Copy(GetVec(op.Rd), res);
|
||||
}
|
||||
}
|
||||
|
||||
private static Operand EmitReverseBits8Op(ArmEmitterContext context, Operand op)
|
||||
{
|
||||
|
@@ -88,8 +88,35 @@ namespace ARMeilleure.Instructions
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShl(op);
|
||||
int eSize = 8 << op.Size;
|
||||
|
||||
if (Optimizations.UseSse2 && op.Size > 0)
|
||||
if (shift >= eSize)
|
||||
{
|
||||
if ((op.RegisterSize == RegisterSize.Simd64))
|
||||
{
|
||||
Operand res = context.VectorZeroUpper64(GetVec(op.Rd));
|
||||
|
||||
context.Copy(GetVec(op.Rd), res);
|
||||
}
|
||||
}
|
||||
else if (Optimizations.UseGfni && op.Size == 0)
|
||||
{
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
ulong bitMatrix = X86GetGf2p8LogicalShiftLeft(shift);
|
||||
|
||||
Operand vBitMatrix = X86GetElements(context, bitMatrix, bitMatrix);
|
||||
|
||||
Operand res = context.AddIntrinsic(Intrinsic.X86Gf2p8affineqb, n, vBitMatrix, Const(0));
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd64)
|
||||
{
|
||||
res = context.VectorZeroUpper64(res);
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), res);
|
||||
}
|
||||
else if (Optimizations.UseSse2 && op.Size > 0)
|
||||
{
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
@@ -396,10 +423,40 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
if (Optimizations.UseSse2 && op.Size > 0 && op.Size < 3)
|
||||
{
|
||||
int shift = GetImmShr(op);
|
||||
|
||||
if (Optimizations.UseGfni && op.Size == 0)
|
||||
{
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
ulong bitMatrix;
|
||||
|
||||
if (shift < 8)
|
||||
{
|
||||
bitMatrix = X86GetGf2p8LogicalShiftLeft(-shift);
|
||||
|
||||
// Extend sign-bit
|
||||
bitMatrix |= 0x8080808080808080UL >> (64 - shift * 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Replicate sign-bit into all bits
|
||||
bitMatrix = 0x8080808080808080UL;
|
||||
}
|
||||
|
||||
Operand vBitMatrix = X86GetElements(context, bitMatrix, bitMatrix);
|
||||
|
||||
Operand res = context.AddIntrinsic(Intrinsic.X86Gf2p8affineqb, n, vBitMatrix, Const(0));
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Simd64)
|
||||
{
|
||||
res = context.VectorZeroUpper64(res);
|
||||
}
|
||||
|
||||
context.Copy(GetVec(op.Rd), res);
|
||||
}
|
||||
else if (Optimizations.UseSse2 && op.Size > 0 && op.Size < 3)
|
||||
{
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
Intrinsic sraInst = X86PsraInstruction[op.Size];
|
||||
@@ -929,10 +986,44 @@ namespace ARMeilleure.Instructions
|
||||
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||
|
||||
int shift = GetImmShl(op);
|
||||
int eSize = 8 << op.Size;
|
||||
|
||||
ulong mask = shift != 0 ? ulong.MaxValue >> (64 - shift) : 0UL;
|
||||
|
||||
if (Optimizations.UseSse2 && op.Size > 0)
|
||||
if (shift >= eSize)
|
||||
{
|
||||
if ((op.RegisterSize == RegisterSize.Simd64) || scalar)
|
||||
{
|
||||
Operand res = context.VectorZeroUpper64(GetVec(op.Rd));
|
||||
|
||||
context.Copy(GetVec(op.Rd), res);
|
||||
}
|
||||
}
|
||||
else if (Optimizations.UseGfni && op.Size == 0)
|
||||
{
|
||||
Operand d = GetVec(op.Rd);
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
ulong bitMatrix = X86GetGf2p8LogicalShiftLeft(shift);
|
||||
|
||||
Operand vBitMatrix = X86GetElements(context, bitMatrix, bitMatrix);
|
||||
|
||||
Operand nShifted = context.AddIntrinsic(Intrinsic.X86Gf2p8affineqb, n, vBitMatrix, Const(0));
|
||||
|
||||
Operand dMask = X86GetAllElements(context, (long)mask * _masks_SliSri[op.Size]);
|
||||
|
||||
Operand dMasked = context.AddIntrinsic(Intrinsic.X86Pand, d, dMask);
|
||||
|
||||
Operand res = context.AddIntrinsic(Intrinsic.X86Por, nShifted, dMasked);
|
||||
|
||||
if ((op.RegisterSize == RegisterSize.Simd64) || scalar)
|
||||
{
|
||||
res = context.VectorZeroUpper64(res);
|
||||
}
|
||||
|
||||
context.Copy(d, res);
|
||||
}
|
||||
else if (Optimizations.UseSse2 && op.Size > 0)
|
||||
{
|
||||
Operand d = GetVec(op.Rd);
|
||||
Operand n = GetVec(op.Rn);
|
||||
@@ -988,7 +1079,40 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
ulong mask = (ulong.MaxValue << (eSize - shift)) & (ulong.MaxValue >> (64 - eSize));
|
||||
|
||||
if (Optimizations.UseSse2 && op.Size > 0)
|
||||
if (shift >= eSize)
|
||||
{
|
||||
if ((op.RegisterSize == RegisterSize.Simd64) || scalar)
|
||||
{
|
||||
Operand res = context.VectorZeroUpper64(GetVec(op.Rd));
|
||||
|
||||
context.Copy(GetVec(op.Rd), res);
|
||||
}
|
||||
}
|
||||
else if (Optimizations.UseGfni && op.Size == 0)
|
||||
{
|
||||
Operand d = GetVec(op.Rd);
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
ulong bitMatrix = X86GetGf2p8LogicalShiftLeft(-shift);
|
||||
|
||||
Operand vBitMatrix = X86GetElements(context, bitMatrix, bitMatrix);
|
||||
|
||||
Operand nShifted = context.AddIntrinsic(Intrinsic.X86Gf2p8affineqb, n, vBitMatrix, Const(0));
|
||||
|
||||
Operand dMask = X86GetAllElements(context, (long)mask * _masks_SliSri[op.Size]);
|
||||
|
||||
Operand dMasked = context.AddIntrinsic(Intrinsic.X86Pand, d, dMask);
|
||||
|
||||
Operand res = context.AddIntrinsic(Intrinsic.X86Por, nShifted, dMasked);
|
||||
|
||||
if ((op.RegisterSize == RegisterSize.Simd64) || scalar)
|
||||
{
|
||||
res = context.VectorZeroUpper64(res);
|
||||
}
|
||||
|
||||
context.Copy(d, res);
|
||||
}
|
||||
else if (Optimizations.UseSse2 && op.Size > 0)
|
||||
{
|
||||
Operand d = GetVec(op.Rd);
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
@@ -47,6 +47,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||
X86Divps,
|
||||
X86Divsd,
|
||||
X86Divss,
|
||||
X86Gf2p8affineqb,
|
||||
X86Haddpd,
|
||||
X86Haddps,
|
||||
X86Insertps,
|
||||
|
@@ -22,6 +22,7 @@ namespace ARMeilleure
|
||||
public static bool UseAesniIfAvailable { get; set; } = true;
|
||||
public static bool UsePclmulqdqIfAvailable { get; set; } = true;
|
||||
public static bool UseShaIfAvailable { get; set; } = true;
|
||||
public static bool UseGfniIfAvailable { get; set; } = true;
|
||||
|
||||
public static bool ForceLegacySse
|
||||
{
|
||||
@@ -42,5 +43,6 @@ namespace ARMeilleure
|
||||
internal static bool UseAesni => UseAesniIfAvailable && HardwareCapabilities.SupportsAesni;
|
||||
internal static bool UsePclmulqdq => UsePclmulqdqIfAvailable && HardwareCapabilities.SupportsPclmulqdq;
|
||||
internal static bool UseSha => UseShaIfAvailable && HardwareCapabilities.SupportsSha;
|
||||
internal static bool UseGfni => UseGfniIfAvailable && HardwareCapabilities.SupportsGfni;
|
||||
}
|
||||
}
|
@@ -27,7 +27,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||
|
||||
private const uint InternalVersion = 3703; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
private const uint InternalVersion = 3710; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
|
||||
private const string ActualDir = "0";
|
||||
private const string BackupDir = "1";
|
||||
@@ -951,7 +951,8 @@ namespace ARMeilleure.Translation.PTC
|
||||
return new FeatureInfo(
|
||||
(uint)HardwareCapabilities.FeatureInfo1Ecx,
|
||||
(uint)HardwareCapabilities.FeatureInfo1Edx,
|
||||
(uint)HardwareCapabilities.FeatureInfo7Ebx);
|
||||
(uint)HardwareCapabilities.FeatureInfo7Ebx,
|
||||
(uint)HardwareCapabilities.FeatureInfo7Ecx);
|
||||
}
|
||||
|
||||
private static byte GetMemoryManagerMode()
|
||||
@@ -971,7 +972,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
return osPlatform;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 54*/)]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 58*/)]
|
||||
private struct OuterHeader
|
||||
{
|
||||
public ulong Magic;
|
||||
@@ -1002,8 +1003,8 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 12*/)]
|
||||
private record struct FeatureInfo(uint FeatureInfo0, uint FeatureInfo1, uint FeatureInfo2);
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 16*/)]
|
||||
private record struct FeatureInfo(uint FeatureInfo0, uint FeatureInfo1, uint FeatureInfo2, uint FeatureInfo3);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 128*/)]
|
||||
private struct InnerHeader
|
||||
|
@@ -30,6 +30,7 @@ namespace Ryujinx.Common.Logging
|
||||
ServiceBsd,
|
||||
ServiceBtm,
|
||||
ServiceCaps,
|
||||
ServiceFatal,
|
||||
ServiceFriend,
|
||||
ServiceFs,
|
||||
ServiceHid,
|
||||
|
@@ -9,17 +9,19 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
class Shader
|
||||
class Shader : IDisposable
|
||||
{
|
||||
// The shaderc.net dependency's Options constructor and dispose are not thread safe.
|
||||
// Take this lock when using them.
|
||||
private static object _shaderOptionsLock = new object();
|
||||
|
||||
private static readonly IntPtr _ptrMainEntryPointName = Marshal.StringToHGlobalAnsi("main");
|
||||
|
||||
private readonly Vk _api;
|
||||
private readonly Device _device;
|
||||
private readonly ShaderStageFlags _stage;
|
||||
|
||||
private IntPtr _entryPointName;
|
||||
private bool _disposed;
|
||||
private ShaderModule _module;
|
||||
|
||||
public ShaderStageFlags StageFlags => _stage;
|
||||
@@ -39,7 +41,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
CompileStatus = ProgramLinkStatus.Incomplete;
|
||||
|
||||
_stage = shaderSource.Stage.Convert();
|
||||
_entryPointName = Marshal.StringToHGlobalAnsi("main");
|
||||
|
||||
CompileTask = Task.Run(() =>
|
||||
{
|
||||
@@ -145,7 +146,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
SType = StructureType.PipelineShaderStageCreateInfo,
|
||||
Stage = _stage,
|
||||
Module = _module,
|
||||
PName = (byte*)_entryPointName
|
||||
PName = (byte*)_ptrMainEntryPointName
|
||||
};
|
||||
}
|
||||
|
||||
@@ -156,11 +157,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
public unsafe void Dispose()
|
||||
{
|
||||
if (_entryPointName != IntPtr.Zero)
|
||||
if (!_disposed)
|
||||
{
|
||||
_api.DestroyShaderModule(_device, _module, null);
|
||||
Marshal.FreeHGlobal(_entryPointName);
|
||||
_entryPointName = IntPtr.Zero;
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,8 +1,147 @@
|
||||
namespace Ryujinx.HLE.HOS.Services.Fatal
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Services.Fatal.Types;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Fatal
|
||||
{
|
||||
[Service("fatal:u")]
|
||||
class IService : IpcService
|
||||
{
|
||||
public IService(ServiceCtx context) { }
|
||||
|
||||
[CommandHipc(0)]
|
||||
// ThrowFatal(u64 result_code, u64 pid)
|
||||
public ResultCode ThrowFatal(ServiceCtx context)
|
||||
{
|
||||
ResultCode resultCode = (ResultCode)context.RequestData.ReadUInt64();
|
||||
ulong pid = context.Request.HandleDesc.PId;
|
||||
|
||||
return ThrowFatalWithCpuContextImpl(context, resultCode, pid, FatalPolicy.ErrorReportAndErrorScreen, null);
|
||||
}
|
||||
|
||||
[CommandHipc(1)]
|
||||
// ThrowFatalWithPolicy(u64 result_code, u32 fatal_policy, u64 pid)
|
||||
public ResultCode ThrowFatalWithPolicy(ServiceCtx context)
|
||||
{
|
||||
ResultCode resultCode = (ResultCode)context.RequestData.ReadUInt64();
|
||||
FatalPolicy fatalPolicy = (FatalPolicy)context.RequestData.ReadUInt32();
|
||||
ulong pid = context.Request.HandleDesc.PId;
|
||||
|
||||
return ThrowFatalWithCpuContextImpl(context, resultCode, pid, fatalPolicy, null);
|
||||
}
|
||||
|
||||
[CommandHipc(2)]
|
||||
// ThrowFatalWithCpuContext(u64 result_code, u32 fatal_policy, u64 pid, buffer<bytes, 0x15> cpu_context)
|
||||
public ResultCode ThrowFatalWithCpuContext(ServiceCtx context)
|
||||
{
|
||||
ResultCode resultCode = (ResultCode)context.RequestData.ReadUInt64();
|
||||
FatalPolicy fatalPolicy = (FatalPolicy)context.RequestData.ReadUInt32();
|
||||
ulong pid = context.Request.HandleDesc.PId;
|
||||
|
||||
ulong cpuContextPosition = context.Request.SendBuff[0].Position;
|
||||
ulong cpuContextSize = context.Request.SendBuff[0].Size;
|
||||
|
||||
ReadOnlySpan<byte> cpuContextData = context.Memory.GetSpan(cpuContextPosition, (int)cpuContextSize);
|
||||
|
||||
return ThrowFatalWithCpuContextImpl(context, resultCode, pid, fatalPolicy, cpuContextData);
|
||||
}
|
||||
|
||||
private ResultCode ThrowFatalWithCpuContextImpl(ServiceCtx context, ResultCode resultCode, ulong pid, FatalPolicy fatalPolicy, ReadOnlySpan<byte> cpuContext)
|
||||
{
|
||||
StringBuilder errorReport = new StringBuilder();
|
||||
|
||||
errorReport.AppendLine();
|
||||
errorReport.AppendLine("ErrorReport log:");
|
||||
|
||||
errorReport.AppendLine($"\tTitleId: {context.Device.Application.TitleId:x16}");
|
||||
errorReport.AppendLine($"\tPid: {pid}");
|
||||
errorReport.AppendLine($"\tResultCode: {((int)resultCode & 0x1FF) + 2000}-{((int)resultCode >> 9) & 0x3FFF:d4}");
|
||||
errorReport.AppendLine($"\tFatalPolicy: {fatalPolicy}");
|
||||
|
||||
if (cpuContext != null)
|
||||
{
|
||||
errorReport.AppendLine("CPU Context:");
|
||||
|
||||
if (context.Device.Application.TitleIs64Bit)
|
||||
{
|
||||
CpuContext64 cpuContext64 = MemoryMarshal.Cast<byte, CpuContext64>(cpuContext)[0];
|
||||
|
||||
errorReport.AppendLine($"\tStartAddress: 0x{cpuContext64.StartAddress:x16}");
|
||||
errorReport.AppendLine($"\tRegisterSetFlags: {cpuContext64.RegisterSetFlags}");
|
||||
|
||||
if (cpuContext64.StackTraceSize > 0)
|
||||
{
|
||||
errorReport.AppendLine("\tStackTrace:");
|
||||
|
||||
for (int i = 0; i < cpuContext64.StackTraceSize; i++)
|
||||
{
|
||||
errorReport.AppendLine($"\t\t0x{cpuContext64.StackTrace[i]:x16}");
|
||||
}
|
||||
}
|
||||
|
||||
errorReport.AppendLine("\tRegisters:");
|
||||
|
||||
for (int i = 0; i < cpuContext64.X.Length; i++)
|
||||
{
|
||||
errorReport.AppendLine($"\t\tX[{i:d2}]:\t0x{cpuContext64.X[i]:x16}");
|
||||
}
|
||||
|
||||
errorReport.AppendLine();
|
||||
errorReport.AppendLine($"\t\tFP:\t0x{cpuContext64.FP:x16}");
|
||||
errorReport.AppendLine($"\t\tLR:\t0x{cpuContext64.LR:x16}");
|
||||
errorReport.AppendLine($"\t\tSP:\t0x{cpuContext64.SP:x16}");
|
||||
errorReport.AppendLine($"\t\tPC:\t0x{cpuContext64.PC:x16}");
|
||||
errorReport.AppendLine($"\t\tPState:\t0x{cpuContext64.PState:x16}");
|
||||
errorReport.AppendLine($"\t\tAfsr0:\t0x{cpuContext64.Afsr0:x16}");
|
||||
errorReport.AppendLine($"\t\tAfsr1:\t0x{cpuContext64.Afsr1:x16}");
|
||||
errorReport.AppendLine($"\t\tEsr:\t0x{cpuContext64.Esr:x16}");
|
||||
errorReport.AppendLine($"\t\tFar:\t0x{cpuContext64.Far:x16}");
|
||||
}
|
||||
else
|
||||
{
|
||||
CpuContext32 cpuContext32 = MemoryMarshal.Cast<byte, CpuContext32>(cpuContext)[0];
|
||||
|
||||
errorReport.AppendLine($"\tStartAddress: 0x{cpuContext32.StartAddress:16}");
|
||||
errorReport.AppendLine($"\tRegisterSetFlags: {cpuContext32.RegisterSetFlags}");
|
||||
|
||||
if (cpuContext32.StackTraceSize > 0)
|
||||
{
|
||||
errorReport.AppendLine("\tStackTrace:");
|
||||
|
||||
for (int i = 0; i < cpuContext32.StackTraceSize; i++)
|
||||
{
|
||||
errorReport.AppendLine($"\t\t0x{cpuContext32.StackTrace[i]:x16}");
|
||||
}
|
||||
}
|
||||
|
||||
errorReport.AppendLine("\tRegisters:");
|
||||
|
||||
for (int i = 0; i < cpuContext32.X.Length; i++)
|
||||
{
|
||||
errorReport.AppendLine($"\t\tX[{i:d2}]:\t0x{cpuContext32.X[i]:x16}");
|
||||
}
|
||||
|
||||
errorReport.AppendLine();
|
||||
errorReport.AppendLine($"\t\tFP:\t0x{cpuContext32.FP:x16}");
|
||||
errorReport.AppendLine($"\t\tFP:\t0x{cpuContext32.IP:x16}");
|
||||
errorReport.AppendLine($"\t\tSP:\t0x{cpuContext32.SP:x16}");
|
||||
errorReport.AppendLine($"\t\tLR:\t0x{cpuContext32.LR:x16}");
|
||||
errorReport.AppendLine($"\t\tPC:\t0x{cpuContext32.PC:x16}");
|
||||
errorReport.AppendLine($"\t\tPState:\t0x{cpuContext32.PState:x16}");
|
||||
errorReport.AppendLine($"\t\tAfsr0:\t0x{cpuContext32.Afsr0:x16}");
|
||||
errorReport.AppendLine($"\t\tAfsr1:\t0x{cpuContext32.Afsr1:x16}");
|
||||
errorReport.AppendLine($"\t\tEsr:\t0x{cpuContext32.Esr:x16}");
|
||||
errorReport.AppendLine($"\t\tFar:\t0x{cpuContext32.Far:x16}");
|
||||
}
|
||||
}
|
||||
|
||||
Logger.Info?.Print(LogClass.ServiceFatal, errorReport.ToString());
|
||||
|
||||
context.Device.System.KernelContext.Syscall.Break((ulong)resultCode);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
25
Ryujinx.HLE/HOS/Services/Fatal/Types/CpuContext32.cs
Normal file
25
Ryujinx.HLE/HOS/Services/Fatal/Types/CpuContext32.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Fatal.Types
|
||||
{
|
||||
public struct CpuContext32
|
||||
{
|
||||
public Array11<uint> X;
|
||||
public uint FP;
|
||||
public uint IP;
|
||||
public uint SP;
|
||||
public uint LR;
|
||||
public uint PC;
|
||||
|
||||
public uint PState;
|
||||
public uint Afsr0;
|
||||
public uint Afsr1;
|
||||
public uint Esr;
|
||||
public uint Far;
|
||||
|
||||
public Array32<uint> StackTrace;
|
||||
public uint StackTraceSize;
|
||||
public uint StartAddress;
|
||||
public uint RegisterSetFlags;
|
||||
}
|
||||
}
|
24
Ryujinx.HLE/HOS/Services/Fatal/Types/CpuContext64.cs
Normal file
24
Ryujinx.HLE/HOS/Services/Fatal/Types/CpuContext64.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Fatal.Types
|
||||
{
|
||||
public struct CpuContext64
|
||||
{
|
||||
public Array29<ulong> X;
|
||||
public ulong FP;
|
||||
public ulong LR;
|
||||
public ulong SP;
|
||||
public ulong PC;
|
||||
|
||||
public ulong PState;
|
||||
public ulong Afsr0;
|
||||
public ulong Afsr1;
|
||||
public ulong Esr;
|
||||
public ulong Far;
|
||||
|
||||
public Array32<ulong> StackTrace;
|
||||
public ulong StartAddress;
|
||||
public ulong RegisterSetFlags;
|
||||
public uint StackTraceSize;
|
||||
}
|
||||
}
|
9
Ryujinx.HLE/HOS/Services/Fatal/Types/FatalPolicy.cs
Normal file
9
Ryujinx.HLE/HOS/Services/Fatal/Types/FatalPolicy.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Ryujinx.HLE.HOS.Services.Fatal.Types
|
||||
{
|
||||
enum FatalPolicy
|
||||
{
|
||||
ErrorReportAndErrorScreen,
|
||||
ErrorReport,
|
||||
ErrorScreen
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user