forked from Mirror/Ryujinx
Implement many objects, improve logging. (#42)
* Implement many objects, improve logging. Change and rename folders of Services Add Logging of IpcMessage. Add "lm" Log Service. Parse Errors of SetTerminateResult Add Svc Calls. Add many object implementations. * Corrections Forgotten Debug Conf * Corrections 2 * Corrections 3 * Corrections 4
This commit is contained in:
parent
fba0bf8732
commit
e174100474
69 changed files with 660 additions and 27 deletions
|
@ -26,6 +26,10 @@
|
|||
|
||||
Enable the Fatal Logging (Enabled in Debug recommanded).
|
||||
|
||||
- `Logging_Enable_Ipc` *(bool)*
|
||||
|
||||
Enable the Ipc Message Logging.
|
||||
|
||||
- `Logging_Enable_LogFile` *(bool)*
|
||||
|
||||
Enable writing the logging inside a Ryujinx.log file.
|
||||
|
|
|
@ -8,12 +8,13 @@ namespace Ryujinx.Core
|
|||
{
|
||||
public static class Config
|
||||
{
|
||||
public static bool LoggingEnableInfo { get; private set; }
|
||||
public static bool LoggingEnableTrace { get; private set; }
|
||||
public static bool LoggingEnableDebug { get; private set; }
|
||||
public static bool LoggingEnableWarn { get; private set; }
|
||||
public static bool LoggingEnableError { get; private set; }
|
||||
public static bool LoggingEnableFatal { get; private set; }
|
||||
public static bool LoggingEnableInfo { get; private set; }
|
||||
public static bool LoggingEnableTrace { get; private set; }
|
||||
public static bool LoggingEnableDebug { get; private set; }
|
||||
public static bool LoggingEnableWarn { get; private set; }
|
||||
public static bool LoggingEnableError { get; private set; }
|
||||
public static bool LoggingEnableFatal { get; private set; }
|
||||
public static bool LoggingEnableIpc { get; private set; }
|
||||
public static bool LoggingEnableLogFile { get; private set; }
|
||||
|
||||
public static JoyCon FakeJoyCon { get; private set; }
|
||||
|
@ -30,6 +31,7 @@ namespace Ryujinx.Core
|
|||
LoggingEnableWarn = Convert.ToBoolean(Parser.Value("Logging_Enable_Warn"));
|
||||
LoggingEnableError = Convert.ToBoolean(Parser.Value("Logging_Enable_Error"));
|
||||
LoggingEnableFatal = Convert.ToBoolean(Parser.Value("Logging_Enable_Fatal"));
|
||||
LoggingEnableIpc = Convert.ToBoolean(Parser.Value("Logging_Enable_Ipc"));
|
||||
LoggingEnableLogFile = Convert.ToBoolean(Parser.Value("Logging_Enable_LogFile"));
|
||||
|
||||
FakeJoyCon = new JoyCon
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using System;
|
||||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.Core
|
||||
{
|
||||
|
@ -9,13 +11,14 @@ namespace Ryujinx.Core
|
|||
private static Stopwatch ExecutionTime = new Stopwatch();
|
||||
private const string LogFileName = "Ryujinx.log";
|
||||
|
||||
public static bool EnableInfo = Config.LoggingEnableInfo;
|
||||
public static bool EnableTrace = Config.LoggingEnableTrace;
|
||||
public static bool EnableDebug = Config.LoggingEnableDebug;
|
||||
public static bool EnableWarn = Config.LoggingEnableWarn;
|
||||
public static bool EnableError = Config.LoggingEnableError;
|
||||
public static bool EnableFatal = Config.LoggingEnableFatal;
|
||||
public static bool EnableLogFile = Config.LoggingEnableLogFile;
|
||||
private static bool EnableInfo = Config.LoggingEnableInfo;
|
||||
private static bool EnableTrace = Config.LoggingEnableTrace;
|
||||
private static bool EnableDebug = Config.LoggingEnableDebug;
|
||||
private static bool EnableWarn = Config.LoggingEnableWarn;
|
||||
private static bool EnableError = Config.LoggingEnableError;
|
||||
private static bool EnableFatal = Config.LoggingEnableFatal;
|
||||
private static bool EnableIpc = Config.LoggingEnableIpc;
|
||||
private static bool EnableLogFile = Config.LoggingEnableLogFile;
|
||||
|
||||
static Logging()
|
||||
{
|
||||
|
@ -128,5 +131,79 @@ namespace Ryujinx.Core
|
|||
LogFile(Text);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Ipc(byte[] Data, long CmdPtr, bool Domain)
|
||||
{
|
||||
if (EnableIpc)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Cyan;
|
||||
Console.WriteLine(IpcLog.Message(Data, CmdPtr, Domain));
|
||||
Console.ResetColor();
|
||||
}
|
||||
}
|
||||
|
||||
//https://www.codeproject.com/Articles/36747/Quick-and-Dirty-HexDump-of-a-Byte-Array
|
||||
public static string HexDump(byte[] bytes, int bytesPerLine = 16)
|
||||
{
|
||||
if (bytes == null) return "<null>";
|
||||
int bytesLength = bytes.Length;
|
||||
|
||||
char[] HexChars = "0123456789ABCDEF".ToCharArray();
|
||||
|
||||
int firstHexColumn =
|
||||
8 // 8 characters for the address
|
||||
+ 3; // 3 spaces
|
||||
|
||||
int firstCharColumn = firstHexColumn
|
||||
+ bytesPerLine * 3 // - 2 digit for the hexadecimal value and 1 space
|
||||
+ (bytesPerLine - 1) / 8 // - 1 extra space every 8 characters from the 9th
|
||||
+ 2; // 2 spaces
|
||||
|
||||
int lineLength = firstCharColumn
|
||||
+ bytesPerLine // - characters to show the ascii value
|
||||
+ Environment.NewLine.Length; // Carriage return and line feed (should normally be 2)
|
||||
|
||||
char[] line = (new String(' ', lineLength - Environment.NewLine.Length) + Environment.NewLine).ToCharArray();
|
||||
int expectedLines = (bytesLength + bytesPerLine - 1) / bytesPerLine;
|
||||
StringBuilder result = new StringBuilder(expectedLines * lineLength);
|
||||
|
||||
for (int i = 0; i < bytesLength; i += bytesPerLine)
|
||||
{
|
||||
line[0] = HexChars[(i >> 28) & 0xF];
|
||||
line[1] = HexChars[(i >> 24) & 0xF];
|
||||
line[2] = HexChars[(i >> 20) & 0xF];
|
||||
line[3] = HexChars[(i >> 16) & 0xF];
|
||||
line[4] = HexChars[(i >> 12) & 0xF];
|
||||
line[5] = HexChars[(i >> 8) & 0xF];
|
||||
line[6] = HexChars[(i >> 4) & 0xF];
|
||||
line[7] = HexChars[(i >> 0) & 0xF];
|
||||
|
||||
int hexColumn = firstHexColumn;
|
||||
int charColumn = firstCharColumn;
|
||||
|
||||
for (int j = 0; j < bytesPerLine; j++)
|
||||
{
|
||||
if (j > 0 && (j & 7) == 0) hexColumn++;
|
||||
if (i + j >= bytesLength)
|
||||
{
|
||||
line[hexColumn] = ' ';
|
||||
line[hexColumn + 1] = ' ';
|
||||
line[charColumn] = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
byte b = bytes[i + j];
|
||||
line[hexColumn] = HexChars[(b >> 4) & 0xF];
|
||||
line[hexColumn + 1] = HexChars[b & 0xF];
|
||||
line[charColumn] = (b < 32 ? '·' : (char)b);
|
||||
}
|
||||
hexColumn += 3;
|
||||
charColumn++;
|
||||
}
|
||||
|
||||
result.Append(line);
|
||||
}
|
||||
return result.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
public AThread Thread { get; private set; }
|
||||
|
||||
public int ProcessorId { get; private set; }
|
||||
public int Priority { get; private set; }
|
||||
public int Priority { get; set; }
|
||||
|
||||
public int ThreadId => Thread.ThreadId;
|
||||
|
||||
|
|
179
Ryujinx.Core/OsHle/Ipc/IpcLog.cs
Normal file
179
Ryujinx.Core/OsHle/Ipc/IpcLog.cs
Normal file
|
@ -0,0 +1,179 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.Ipc
|
||||
{
|
||||
public static class IpcLog
|
||||
{
|
||||
public static string Message(byte[] Data, long CmdPtr, bool Domain)
|
||||
{
|
||||
string IpcMessage = "";
|
||||
|
||||
using (MemoryStream MS = new MemoryStream(Data))
|
||||
{
|
||||
BinaryReader Reader = new BinaryReader(MS);
|
||||
|
||||
int Word0 = Reader.ReadInt32();
|
||||
int Word1 = Reader.ReadInt32();
|
||||
|
||||
int Type = (Word0 & 0xffff);
|
||||
|
||||
int PtrBuffCount = (Word0 >> 16) & 0xf;
|
||||
int SendBuffCount = (Word0 >> 20) & 0xf;
|
||||
int RecvBuffCount = (Word0 >> 24) & 0xf;
|
||||
int XchgBuffCount = (Word0 >> 28) & 0xf;
|
||||
|
||||
int RawDataSize = (Word1 >> 0) & 0x3ff;
|
||||
int RecvListFlags = (Word1 >> 10) & 0xf;
|
||||
bool HndDescEnable = ((Word1 >> 31) & 0x1) != 0;
|
||||
|
||||
IpcMessage += Environment.NewLine + $" {Logging.GetExecutionTime()} | IpcMessage >" + Environment.NewLine +
|
||||
$" Type: {Enum.GetName(typeof(IpcMessageType), Type)}" + Environment.NewLine +
|
||||
|
||||
$" PtrBuffCount: {PtrBuffCount.ToString()}" + Environment.NewLine +
|
||||
$" SendBuffCount: {SendBuffCount.ToString()}" + Environment.NewLine +
|
||||
$" RecvBuffCount: {RecvBuffCount.ToString()}" + Environment.NewLine +
|
||||
$" XchgBuffCount: {XchgBuffCount.ToString()}" + Environment.NewLine +
|
||||
|
||||
$" RawDataSize: {RawDataSize.ToString()}" + Environment.NewLine +
|
||||
$" RecvListFlags: {RecvListFlags.ToString()}" + Environment.NewLine +
|
||||
$" HndDescEnable: {HndDescEnable.ToString()}" + Environment.NewLine;
|
||||
|
||||
if (HndDescEnable)
|
||||
{
|
||||
int Word = Reader.ReadInt32();
|
||||
|
||||
bool HasPId = (Word & 1) != 0;
|
||||
|
||||
int[] ToCopy = new int[(Word >> 1) & 0xf];
|
||||
int[] ToMove = new int[(Word >> 5) & 0xf];
|
||||
|
||||
long PId = HasPId ? Reader.ReadInt64() : 0;
|
||||
|
||||
for (int Index = 0; Index < ToCopy.Length; Index++)
|
||||
{
|
||||
ToCopy[Index] = Reader.ReadInt32();
|
||||
}
|
||||
|
||||
for (int Index = 0; Index < ToMove.Length; Index++)
|
||||
{
|
||||
ToMove[Index] = Reader.ReadInt32();
|
||||
}
|
||||
|
||||
IpcMessage += Environment.NewLine + " HndDesc:" + Environment.NewLine +
|
||||
$" PId: {PId.ToString()}" + Environment.NewLine +
|
||||
$" ToCopy.Length: {ToCopy.Length.ToString()}" + Environment.NewLine +
|
||||
$" ToMove.Length: {ToMove.Length.ToString()}" + Environment.NewLine;
|
||||
}
|
||||
|
||||
for (int Index = 0; Index < PtrBuffCount; Index++)
|
||||
{
|
||||
long IpcPtrBuffDescWord0 = Reader.ReadUInt32();
|
||||
long IpcPtrBuffDescWord1 = Reader.ReadUInt32();
|
||||
|
||||
long Position = IpcPtrBuffDescWord1;
|
||||
Position |= (IpcPtrBuffDescWord0 << 20) & 0x0f00000000;
|
||||
Position |= (IpcPtrBuffDescWord0 << 30) & 0x7000000000;
|
||||
|
||||
int IpcPtrBuffDescIndex = ((int)IpcPtrBuffDescWord0 >> 0) & 0x03f;
|
||||
IpcPtrBuffDescIndex |= ((int)IpcPtrBuffDescWord0 >> 3) & 0x1c0;
|
||||
|
||||
short Size = (short)(IpcPtrBuffDescWord0 >> 16);
|
||||
|
||||
IpcMessage += Environment.NewLine + $" PtrBuff[{Index}]:" + Environment.NewLine +
|
||||
$" Position: {Position.ToString()}" + Environment.NewLine +
|
||||
$" IpcPtrBuffDescIndex: {IpcPtrBuffDescIndex.ToString()}" + Environment.NewLine +
|
||||
$" Size: {Size.ToString()}" + Environment.NewLine;
|
||||
}
|
||||
|
||||
ReadIpcBuffValues(Reader, SendBuffCount, IpcMessage, "SendBuff");
|
||||
ReadIpcBuffValues(Reader, RecvBuffCount, IpcMessage, "RecvBuff");
|
||||
ReadIpcBuffValues(Reader, XchgBuffCount, IpcMessage, "XchgBuff");
|
||||
|
||||
RawDataSize *= 4;
|
||||
|
||||
long RecvListPos = Reader.BaseStream.Position + RawDataSize;
|
||||
long Pad0 = 0;
|
||||
|
||||
if ((Reader.BaseStream.Position + CmdPtr & 0xf) != 0)
|
||||
{
|
||||
Pad0 = 0x10 - (Reader.BaseStream.Position + CmdPtr & 0xf);
|
||||
}
|
||||
|
||||
Reader.BaseStream.Seek(Pad0, SeekOrigin.Current);
|
||||
|
||||
int RecvListCount = RecvListFlags - 2;
|
||||
|
||||
if (RecvListCount == 0)
|
||||
{
|
||||
RecvListCount = 1;
|
||||
}
|
||||
else if (RecvListCount < 0)
|
||||
{
|
||||
RecvListCount = 0;
|
||||
}
|
||||
|
||||
if (Domain && (IpcMessageType)Type == IpcMessageType.Request)
|
||||
{
|
||||
int DomWord0 = Reader.ReadInt32();
|
||||
|
||||
int DomCmd = (DomWord0 & 0xff);
|
||||
|
||||
RawDataSize = (DomWord0 >> 16) & 0xffff;
|
||||
|
||||
int DomObjId = Reader.ReadInt32();
|
||||
|
||||
Reader.ReadInt64(); //Padding
|
||||
|
||||
IpcMessage += Environment.NewLine + $" Domain:" + Environment.NewLine +
|
||||
$" DomCmd: {Enum.GetName(typeof(IpcDomCmd), DomCmd)}" + Environment.NewLine +
|
||||
$" DomObjId: {DomObjId.ToString()}" + Environment.NewLine;
|
||||
}
|
||||
|
||||
byte[] RawData = Reader.ReadBytes(RawDataSize);
|
||||
|
||||
IpcMessage += Environment.NewLine + $" RawData:" + Environment.NewLine + Logging.HexDump(RawData);
|
||||
|
||||
Reader.BaseStream.Seek(RecvListPos, SeekOrigin.Begin);
|
||||
|
||||
for (int Index = 0; Index < RecvListCount; Index++)
|
||||
{
|
||||
long RecvListBuffValue = Reader.ReadInt64();
|
||||
long RecvListBuffPosition = RecvListBuffValue & 0xffffffffffff;
|
||||
long RecvListBuffSize = (short)(RecvListBuffValue >> 48);
|
||||
|
||||
IpcMessage += Environment.NewLine + $" RecvList[{Index}]:" + Environment.NewLine +
|
||||
$" Value: {RecvListBuffValue.ToString()}" + Environment.NewLine +
|
||||
$" Position: {RecvListBuffPosition.ToString()}" + Environment.NewLine +
|
||||
$" Size: {RecvListBuffSize.ToString()}" + Environment.NewLine;
|
||||
}
|
||||
}
|
||||
|
||||
return IpcMessage;
|
||||
}
|
||||
|
||||
private static void ReadIpcBuffValues(BinaryReader Reader, int Count, string IpcMessage, string BufferName)
|
||||
{
|
||||
for (int Index = 0; Index < Count; Index++)
|
||||
{
|
||||
long Word0 = Reader.ReadUInt32();
|
||||
long Word1 = Reader.ReadUInt32();
|
||||
long Word2 = Reader.ReadUInt32();
|
||||
|
||||
long Position = Word1;
|
||||
Position |= (Word2 << 4) & 0x0f00000000;
|
||||
Position |= (Word2 << 34) & 0x7000000000;
|
||||
|
||||
long Size = Word0;
|
||||
Size |= (Word2 << 8) & 0xf00000000;
|
||||
|
||||
int Flags = (int)Word2 & 3;
|
||||
|
||||
IpcMessage += Environment.NewLine + $" {BufferName}[{Index}]:" + Environment.NewLine +
|
||||
$" Position: {Position.ToString()}" + Environment.NewLine +
|
||||
$" Flags: {Flags.ToString()}" + Environment.NewLine +
|
||||
$" Size: {Size.ToString()}" + Environment.NewLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -41,6 +41,8 @@ namespace Ryujinx.Core.OsHle.Ipc
|
|||
|
||||
public IpcMessage(byte[] Data, long CmdPtr, bool Domain) : this()
|
||||
{
|
||||
Logging.Ipc(Data, CmdPtr, Domain);
|
||||
|
||||
using (MemoryStream MS = new MemoryStream(Data))
|
||||
{
|
||||
BinaryReader Reader = new BinaryReader(MS);
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
namespace Ryujinx.Core.OsHle.IpcServices
|
||||
{
|
||||
enum ErrorModule
|
||||
{
|
||||
Fs = 2,
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
|
@ -19,6 +20,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Am
|
|||
{ 1, PopLaunchParameter },
|
||||
{ 20, EnsureSaveData },
|
||||
{ 21, GetDesiredLanguage },
|
||||
{ 22, SetTerminateResult },
|
||||
{ 40, NotifyRunning }
|
||||
};
|
||||
}
|
||||
|
@ -52,6 +54,18 @@ namespace Ryujinx.Core.OsHle.IpcServices.Am
|
|||
return 0;
|
||||
}
|
||||
|
||||
public long SetTerminateResult(ServiceCtx Context)
|
||||
{
|
||||
int ErrorCode = Context.RequestData.ReadInt32();
|
||||
|
||||
int Module = ErrorCode & 0xFF;
|
||||
int Description = (ErrorCode >> 9) & 0xFFF;
|
||||
|
||||
Logging.Info($"({(ErrorModule)Module}){2000 + Module}-{Description}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long NotifyRunning(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write(1);
|
|
@ -13,14 +13,21 @@ namespace Ryujinx.Core.OsHle.IpcServices.Am
|
|||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 1, Exit },
|
||||
{ 10, SetScreenShotPermission },
|
||||
{ 11, SetOperationModeChangedNotification },
|
||||
{ 12, SetPerformanceModeChangedNotification },
|
||||
{ 13, SetFocusHandlingMode },
|
||||
{ 14, SetRestartMessageEnabled },
|
||||
{ 16, SetOutOfFocusSuspendingEnabled }
|
||||
};
|
||||
}
|
||||
|
||||
public long Exit(ServiceCtx Context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long SetScreenShotPermission(ServiceCtx Context)
|
||||
{
|
||||
bool Enable = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
|
@ -51,6 +58,13 @@ namespace Ryujinx.Core.OsHle.IpcServices.Am
|
|||
return 0;
|
||||
}
|
||||
|
||||
public long SetRestartMessageEnabled(ServiceCtx Context)
|
||||
{
|
||||
bool Enable = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long SetOutOfFocusSuspendingEnabled(ServiceCtx Context)
|
||||
{
|
||||
bool Enable = Context.RequestData.ReadByte() != 0 ? true : false;
|
63
Ryujinx.Core/OsHle/Services/ErrorModule.cs
Normal file
63
Ryujinx.Core/OsHle/Services/ErrorModule.cs
Normal file
|
@ -0,0 +1,63 @@
|
|||
namespace Ryujinx.Core.OsHle.IpcServices
|
||||
{
|
||||
enum ErrorModule
|
||||
{
|
||||
Kernel = 1,
|
||||
Fs = 2,
|
||||
Nvidia_TransferMemory = 3,
|
||||
Ncm = 5,
|
||||
Dd = 6,
|
||||
Lr = 8,
|
||||
Loader = 9,
|
||||
IPC_Command_Interface = 10,
|
||||
IPC = 11,
|
||||
Pm = 15,
|
||||
Ns = 16,
|
||||
Htc = 18,
|
||||
Sm = 21,
|
||||
RO_Userland = 22,
|
||||
SdMmc = 24,
|
||||
Spl = 26,
|
||||
Ethc = 100,
|
||||
I2C = 101,
|
||||
Settings = 105,
|
||||
Nifm = 110,
|
||||
Display = 114,
|
||||
Ntc = 116,
|
||||
Fdm = 117,
|
||||
Pcie = 120,
|
||||
Friends = 121,
|
||||
SSL = 123,
|
||||
Account = 124,
|
||||
Mii = 126,
|
||||
Am = 128,
|
||||
Play_Report = 129,
|
||||
Pcv = 133,
|
||||
Omm = 134,
|
||||
Nim = 137,
|
||||
Psc = 138,
|
||||
Usb = 140,
|
||||
Nsd = 141,
|
||||
Btm = 143,
|
||||
Erpt = 147,
|
||||
Apm = 148,
|
||||
Audio = 153,
|
||||
Npns = 154,
|
||||
Arp = 157,
|
||||
Boot = 158,
|
||||
Nfc = 161,
|
||||
Userland_Assert = 162,
|
||||
Userland_Crash = 168,
|
||||
Hid = 203,
|
||||
Capture = 206,
|
||||
Libnx = 345,
|
||||
Homebrew_ABI = 346,
|
||||
Homebrew_Loader = 347,
|
||||
libnx_Nvidia_Errors = 348,
|
||||
Tc = 651,
|
||||
General_Web_Applet = 800,
|
||||
Wifi_Web_Auth_Applet = 809,
|
||||
Whitelisted_Applet = 810,
|
||||
ShopN = 811
|
||||
}
|
||||
}
|
|
@ -11,7 +11,17 @@ namespace Ryujinx.Core.OsHle.IpcServices.Hid
|
|||
|
||||
public IActiveApplicationDeviceList()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>() { };
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, ActivateVibrationDevice }
|
||||
};
|
||||
}
|
||||
|
||||
public long ActivateVibrationDevice(ServiceCtx Context)
|
||||
{
|
||||
int VibrationDeviceHandle = Context.RequestData.ReadInt32();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ namespace Ryujinx.Core.OsHle.IpcServices.Hid
|
|||
{ 103, ActivateNpad },
|
||||
{ 120, SetNpadJoyHoldType },
|
||||
{ 121, GetNpadJoyHoldType },
|
||||
{ 200, GetVibrationDeviceInfo },
|
||||
{ 203, CreateActiveVibrationDeviceList },
|
||||
};
|
||||
}
|
||||
|
@ -88,6 +89,15 @@ namespace Ryujinx.Core.OsHle.IpcServices.Hid
|
|||
return 0;
|
||||
}
|
||||
|
||||
public long GetVibrationDeviceInfo(ServiceCtx Context)
|
||||
{
|
||||
int VibrationDeviceHandle = Context.RequestData.ReadInt32();
|
||||
|
||||
Context.ResponseData.Write(0L); //VibrationDeviceInfoForIpc
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long CreateActiveVibrationDeviceList(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new IActiveApplicationDeviceList());
|
143
Ryujinx.Core/OsHle/Services/Lm/ILogger.cs
Normal file
143
Ryujinx.Core/OsHle/Services/Lm/ILogger.cs
Normal file
|
@ -0,0 +1,143 @@
|
|||
using ChocolArm64.Memory;
|
||||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Lm
|
||||
{
|
||||
class ILogger : IIpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ILogger()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, Log }
|
||||
};
|
||||
}
|
||||
|
||||
enum Flags
|
||||
{
|
||||
Padding,
|
||||
IsHead,
|
||||
IsTail
|
||||
}
|
||||
|
||||
enum Severity
|
||||
{
|
||||
Trace,
|
||||
Info,
|
||||
Warning,
|
||||
Error,
|
||||
Critical
|
||||
}
|
||||
|
||||
enum Field
|
||||
{
|
||||
Padding,
|
||||
Skip,
|
||||
Message,
|
||||
Line,
|
||||
Filename,
|
||||
Function,
|
||||
Module,
|
||||
Thread
|
||||
}
|
||||
|
||||
public long Log(ServiceCtx Context)
|
||||
{
|
||||
long BufferPosition = Context.Request.PtrBuff[0].Position;
|
||||
long BufferLen = Context.Request.PtrBuff[0].Size;
|
||||
|
||||
byte[] LogBuffer = AMemoryHelper.ReadBytes(Context.Memory, BufferPosition, (int)BufferLen);
|
||||
|
||||
MemoryStream LogMessage = new MemoryStream(LogBuffer);
|
||||
BinaryReader bReader = new BinaryReader(LogMessage);
|
||||
|
||||
//Header reading.
|
||||
long Pid = bReader.ReadInt64();
|
||||
long ThreadCxt = bReader.ReadInt64();
|
||||
int Infos = bReader.ReadInt32();
|
||||
int PayloadLen = bReader.ReadInt32();
|
||||
|
||||
int iFlags = Infos & 0xFFFF;
|
||||
int iSeverity = (Infos >> 17) & 0x7F;
|
||||
int iVerbosity = (Infos >> 25) & 0x7F;
|
||||
|
||||
//ToDo: For now we don't care about Head or Tail Log.
|
||||
bool IsHeadLog = Convert.ToBoolean(iFlags & (int)Flags.IsHead);
|
||||
bool IsTailLog = Convert.ToBoolean(iFlags & (int)Flags.IsTail);
|
||||
|
||||
string LogString = "nn::diag::detail::LogImpl()" + Environment.NewLine + Environment.NewLine +
|
||||
"Header:" + Environment.NewLine +
|
||||
$" Pid: {Pid}" + Environment.NewLine +
|
||||
$" ThreadContext: {ThreadCxt}" + Environment.NewLine +
|
||||
$" Flags: {IsHeadLog}/{IsTailLog}" + Environment.NewLine +
|
||||
$" Severity: {Enum.GetName(typeof(Severity), iSeverity)}" + Environment.NewLine +
|
||||
$" Verbosity: {iVerbosity}";
|
||||
|
||||
LogString += Environment.NewLine + Environment.NewLine + "Message:" + Environment.NewLine;
|
||||
|
||||
string StrMessage = "", StrLine = "", StrFilename = "", StrFunction = "",
|
||||
StrModule = "", StrThread = "";
|
||||
|
||||
do
|
||||
{
|
||||
byte FieldType = bReader.ReadByte();
|
||||
byte FieldSize = bReader.ReadByte();
|
||||
|
||||
if ((Field)FieldType != Field.Skip || FieldSize != 0)
|
||||
{
|
||||
byte[] Message = bReader.ReadBytes(FieldSize);
|
||||
switch ((Field)FieldType)
|
||||
{
|
||||
case Field.Message:
|
||||
StrMessage = Encoding.UTF8.GetString(Message);
|
||||
break;
|
||||
|
||||
case Field.Line:
|
||||
StrLine = BitConverter.ToInt32(Message, 0).ToString();
|
||||
break;
|
||||
|
||||
case Field.Filename:
|
||||
StrFilename = Encoding.UTF8.GetString(Message);
|
||||
break;
|
||||
|
||||
case Field.Function:
|
||||
StrFunction = Encoding.UTF8.GetString(Message);
|
||||
break;
|
||||
|
||||
case Field.Module:
|
||||
StrModule = Encoding.UTF8.GetString(Message);
|
||||
break;
|
||||
|
||||
case Field.Thread:
|
||||
StrThread = Encoding.UTF8.GetString(Message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
while (LogMessage.Position != PayloadLen + 0x18); // 0x18 - Size of Header LogMessage.
|
||||
|
||||
LogString += StrModule + " > " + StrThread + ": " + StrFilename + "@" + StrFunction + "(" + StrLine + ") '" + StrMessage + "'" + Environment.NewLine;
|
||||
|
||||
switch((Severity)iSeverity)
|
||||
{
|
||||
case Severity.Trace: Logging.Trace(LogString); break;
|
||||
case Severity.Info: Logging.Info(LogString); break;
|
||||
case Severity.Warning: Logging.Warn(LogString); break;
|
||||
case Severity.Error: Logging.Error(LogString); break;
|
||||
case Severity.Critical: Logging.Fatal(LogString); break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using static Ryujinx.Core.OsHle.IpcServices.ObjHelper;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Lm
|
||||
{
|
||||
class ServiceLm : IIpcService
|
||||
|
@ -21,6 +23,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Lm
|
|||
{
|
||||
Context.Session.Initialize();
|
||||
|
||||
MakeObject(Context, new ILogger());
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -1,19 +1,19 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Time
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Ns
|
||||
{
|
||||
class ITimeZoneService : IIpcService
|
||||
class ServiceNs : IIpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ITimeZoneService()
|
||||
public ServiceNs()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
//...
|
||||
//{ 1, Function }
|
||||
};
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ using Ryujinx.Core.OsHle.IpcServices.Friend;
|
|||
using Ryujinx.Core.OsHle.IpcServices.FspSrv;
|
||||
using Ryujinx.Core.OsHle.IpcServices.Hid;
|
||||
using Ryujinx.Core.OsHle.IpcServices.Lm;
|
||||
using Ryujinx.Core.OsHle.IpcServices.Ns;
|
||||
using Ryujinx.Core.OsHle.IpcServices.NvServices;
|
||||
using Ryujinx.Core.OsHle.IpcServices.Pctl;
|
||||
using Ryujinx.Core.OsHle.IpcServices.Pl;
|
||||
|
@ -24,6 +25,7 @@ namespace Ryujinx.Core.OsHle.IpcServices
|
|||
switch (Name)
|
||||
{
|
||||
case "acc:u0": return new ServiceAcc();
|
||||
case "aoc:u": return new ServiceNs();
|
||||
case "apm": return new ServiceApm();
|
||||
case "apm:p": return new ServiceApm();
|
||||
case "appletOE": return new ServiceAppletOE();
|
||||
|
@ -42,6 +44,8 @@ namespace Ryujinx.Core.OsHle.IpcServices
|
|||
case "time:s": return new ServiceTime();
|
||||
case "time:u": return new ServiceTime();
|
||||
case "vi:m": return new ServiceVi();
|
||||
case "vi:s": return new ServiceVi();
|
||||
case "vi:u": return new ServiceVi();
|
||||
}
|
||||
|
||||
throw new NotImplementedException(Name);
|
69
Ryujinx.Core/OsHle/Services/Time/ITimeZoneService.cs
Normal file
69
Ryujinx.Core/OsHle/Services/Time/ITimeZoneService.cs
Normal file
|
@ -0,0 +1,69 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.IpcServices.Time
|
||||
{
|
||||
class ITimeZoneService : IIpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local);
|
||||
|
||||
public ITimeZoneService()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 101, ToCalendarTimeWithMyRule }
|
||||
};
|
||||
}
|
||||
|
||||
//(nn::time::PosixTime)-> (nn::time::CalendarTime, nn::time::sf::CalendarAdditionalInfo)
|
||||
public long ToCalendarTimeWithMyRule(ServiceCtx Context)
|
||||
{
|
||||
long PosixTime = Context.RequestData.ReadInt64();
|
||||
|
||||
Epoch = Epoch.AddSeconds(PosixTime).ToLocalTime();
|
||||
|
||||
/*
|
||||
struct CalendarTime {
|
||||
u16_le year;
|
||||
u8 month; // Starts at 1
|
||||
u8 day; // Starts at 1
|
||||
u8 hour;
|
||||
u8 minute;
|
||||
u8 second;
|
||||
INSERT_PADDING_BYTES(1);
|
||||
};
|
||||
*/
|
||||
Context.ResponseData.Write((short)Epoch.Year);
|
||||
Context.ResponseData.Write((byte)Epoch.Month);
|
||||
Context.ResponseData.Write((byte)Epoch.Day);
|
||||
Context.ResponseData.Write((byte)Epoch.Hour);
|
||||
Context.ResponseData.Write((byte)Epoch.Minute);
|
||||
Context.ResponseData.Write((byte)Epoch.Second);
|
||||
Context.ResponseData.Write((byte)0);
|
||||
|
||||
/* Thanks to TuxSH
|
||||
struct CalendarAdditionalInfo {
|
||||
u32 tm_wday; //day of week [0,6] (Sunday = 0)
|
||||
s32 tm_yday; //day of year [0,365]
|
||||
struct timezone {
|
||||
char[8] tz_name;
|
||||
bool isDaylightSavingTime;
|
||||
s32 utcOffsetSeconds;
|
||||
};
|
||||
};
|
||||
*/
|
||||
Context.ResponseData.Write((int)Epoch.DayOfWeek);
|
||||
Context.ResponseData.Write(Epoch.DayOfYear);
|
||||
Context.ResponseData.Write(new byte[8]);
|
||||
Context.ResponseData.Write(Convert.ToByte(Epoch.IsDaylightSavingTime()));
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,6 +30,8 @@ namespace Ryujinx.Core.OsHle.Svc
|
|||
{ 0x09, SvcStartThread },
|
||||
{ 0x0b, SvcSleepThread },
|
||||
{ 0x0c, SvcGetThreadPriority },
|
||||
{ 0x0d, SvcSetThreadPriority },
|
||||
{ 0x0f, SvcSetThreadCoreMask },
|
||||
{ 0x13, SvcMapSharedMemory },
|
||||
{ 0x14, SvcUnmapSharedMemory },
|
||||
{ 0x15, SvcCreateTransferMemory },
|
||||
|
@ -44,6 +46,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
|||
{ 0x1f, SvcConnectToNamedPort },
|
||||
{ 0x21, SvcSendSyncRequest },
|
||||
{ 0x22, SvcSendSyncRequestWithUserBuffer },
|
||||
{ 0x25, SvcGetThreadId },
|
||||
{ 0x26, SvcBreak },
|
||||
{ 0x27, SvcOutputDebugString },
|
||||
{ 0x29, SvcGetInfo }
|
||||
|
|
|
@ -81,5 +81,44 @@ namespace Ryujinx.Core.OsHle.Svc
|
|||
|
||||
//TODO: Error codes.
|
||||
}
|
||||
|
||||
private void SvcSetThreadPriority(AThreadState ThreadState)
|
||||
{
|
||||
int Handle = (int)ThreadState.X1;
|
||||
int Prio = (int)ThreadState.X0;
|
||||
|
||||
HThread Thread = Ns.Os.Handles.GetData<HThread>(Handle);
|
||||
|
||||
if (Thread != null)
|
||||
{
|
||||
Thread.Priority = Prio;
|
||||
|
||||
ThreadState.X0 = (int)SvcResult.Success;
|
||||
}
|
||||
|
||||
//TODO: Error codes.
|
||||
}
|
||||
|
||||
private void SvcSetThreadCoreMask(AThreadState ThreadState)
|
||||
{
|
||||
ThreadState.X0 = (int)SvcResult.Success;
|
||||
|
||||
//TODO: Error codes.
|
||||
}
|
||||
|
||||
private void SvcGetThreadId(AThreadState ThreadState)
|
||||
{
|
||||
int Handle = (int)ThreadState.X0;
|
||||
|
||||
HThread Thread = Ns.Os.Handles.GetData<HThread>(Handle);
|
||||
|
||||
if (Thread != null)
|
||||
{
|
||||
ThreadState.X1 = (ulong)Thread.ThreadId;
|
||||
ThreadState.X0 = (int)SvcResult.Success;
|
||||
}
|
||||
|
||||
//TODO: Error codes.
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,6 +16,9 @@ Logging_Enable_Error = true
|
|||
#Enabled print fatal logs
|
||||
Logging_Enable_Fatal = true
|
||||
|
||||
#Enabled print Ipc logs
|
||||
Logging_Enable_Ipc = false
|
||||
|
||||
#Saved logs into Ryujinx.log
|
||||
Logging_Enable_LogFile = false
|
||||
|
||||
|
|
Loading…
Reference in a new issue