Răsfoiți Sursa

Implement OutputAccessLogToSdCard and expose an FS access log option (#700)

* Add OutputAccessLogToSdCard

* Add config options for the FS access log
Alex Barney 6 ani în urmă
părinte
comite
350a3667f7

+ 3 - 1
Ryujinx.Common/Logging/LogLevel.cs

@@ -6,6 +6,8 @@ namespace Ryujinx.Common.Logging
         Stub,
         Info,
         Warning,
-        Error
+        Error,
+        Guest,
+        AccessLog
     }
 }

+ 16 - 4
Ryujinx.Common/Logging/Logger.cs

@@ -22,10 +22,12 @@ namespace Ryujinx.Common.Logging
             m_EnabledLevels  = new bool[Enum.GetNames(typeof(LogLevel)).Length];
             m_EnabledClasses = new bool[Enum.GetNames(typeof(LogClass)).Length];
 
-            m_EnabledLevels[(int)LogLevel.Stub]    = true;
-            m_EnabledLevels[(int)LogLevel.Info]    = true;
-            m_EnabledLevels[(int)LogLevel.Warning] = true;
-            m_EnabledLevels[(int)LogLevel.Error]   = true;
+            m_EnabledLevels[(int)LogLevel.Stub]      = true;
+            m_EnabledLevels[(int)LogLevel.Info]      = true;
+            m_EnabledLevels[(int)LogLevel.Warning]   = true;
+            m_EnabledLevels[(int)LogLevel.Error]     = true;
+            m_EnabledLevels[(int)LogLevel.Guest]     = true;
+            m_EnabledLevels[(int)LogLevel.AccessLog] = true;
 
             for (int index = 0; index < m_EnabledClasses.Length; index++)
             {
@@ -101,6 +103,16 @@ namespace Ryujinx.Common.Logging
             Print(LogLevel.Stub, logClass, GetFormattedMessage(logClass, "Stubbed. " + message, caller), obj);
         }
 
+        public static void PrintGuest(LogClass logClass, string message, [CallerMemberName] string caller = "")
+        {
+            Print(LogLevel.Guest, logClass, GetFormattedMessage(logClass, message, caller));
+        }
+
+        public static void PrintAccessLog(LogClass logClass, string message)
+        {
+            Print(LogLevel.AccessLog, logClass, message);
+        }
+
         private static void Print(LogLevel logLevel, LogClass logClass, string message)
         {
             if (m_EnabledLevels[(int)logLevel] && m_EnabledClasses[(int)logClass])

+ 2 - 0
Ryujinx.HLE/HOS/Horizon.cs

@@ -105,6 +105,8 @@ namespace Ryujinx.HLE.HOS
 
         public IntegrityCheckLevel FsIntegrityCheckLevel { get; set; }
 
+        public int GlobalAccessLogMode { get; set; }
+
         internal long HidBaseAddress { get; private set; }
 
         public Horizon(Switch device)

+ 17 - 2
Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs

@@ -1,6 +1,7 @@
 using LibHac;
 using LibHac.Fs;
 using LibHac.Fs.NcaUtils;
+using Ryujinx.Common.Logging;
 using Ryujinx.HLE.FileSystem;
 using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.Utilities;
@@ -32,7 +33,8 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
                 { 200,  OpenDataStorageByCurrentProcess          },
                 { 202,  OpenDataStorageByDataId                  },
                 { 203,  OpenPatchDataStorageByCurrentProcess     },
-                { 1005, GetGlobalAccessLogMode                   }
+                { 1005, GetGlobalAccessLogMode                   },
+                { 1006, OutputAccessLogToSdCard                  }
             };
         }
 
@@ -208,7 +210,20 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
         // GetGlobalAccessLogMode() -> u32 logMode
         public long GetGlobalAccessLogMode(ServiceCtx context)
         {
-            context.ResponseData.Write(0);
+            int mode = context.Device.System.GlobalAccessLogMode;
+
+            context.ResponseData.Write(mode);
+
+            return 0;
+        }
+
+        // OutputAccessLogToSdCard(buffer<bytes, 5> log_text)
+        public long OutputAccessLogToSdCard(ServiceCtx context)
+        {
+            string message = ReadUtf8StringSend(context);
+
+            // FS ends each line with a newline. Remove it because Ryujinx logging adds its own newline
+            Logger.PrintAccessLog(LogClass.ServiceFs, message.TrimEnd('\n'));
 
             return 0;
         }

+ 3 - 8
Ryujinx.HLE/HOS/Services/Lm/ILogger.cs

@@ -41,6 +41,8 @@ namespace Ryujinx.HLE.HOS.Services.Lm
 
                 sb.AppendLine("Guest log:");
 
+                sb.AppendLine($" Log level: {(LmLogLevel)level}");
+
                 while (ms.Position < ms.Length)
                 {
                     byte type = reader.ReadByte();
@@ -86,14 +88,7 @@ namespace Ryujinx.HLE.HOS.Services.Lm
 
                 string text = sb.ToString();
 
-                switch((LmLogLevel)level)
-                {
-                    case LmLogLevel.Trace:    Logger.PrintDebug  (LogClass.ServiceLm, text); break;
-                    case LmLogLevel.Info:     Logger.PrintInfo   (LogClass.ServiceLm, text); break;
-                    case LmLogLevel.Warning:  Logger.PrintWarning(LogClass.ServiceLm, text); break;
-                    case LmLogLevel.Error:    Logger.PrintError  (LogClass.ServiceLm, text); break;
-                    case LmLogLevel.Critical: Logger.PrintError  (LogClass.ServiceLm, text); break;
-                }
+                Logger.PrintGuest(LogClass.ServiceLm, text);
             }
 
             return 0;

+ 23 - 0
Ryujinx.HLE/Utilities/StringUtils.cs

@@ -72,5 +72,28 @@ namespace Ryujinx.HLE.Utilities
                 return Encoding.UTF8.GetString(ms.ToArray());
             }
         }
+
+        public static string ReadUtf8StringSend(ServiceCtx context, int index = 0)
+        {
+            long position = context.Request.SendBuff[index].Position;
+            long size     = context.Request.SendBuff[index].Size;
+
+            using (MemoryStream ms = new MemoryStream())
+            {
+                while (size-- > 0)
+                {
+                    byte value = context.Memory.ReadByte(position++);
+
+                    if (value == 0)
+                    {
+                        break;
+                    }
+
+                    ms.WriteByte(value);
+                }
+
+                return Encoding.UTF8.GetString(ms.ToArray());
+            }
+        }
     }
 }

+ 9 - 0
Ryujinx/Config.jsonc

@@ -19,6 +19,12 @@
     // Enable print error logs
     "logging_enable_error": true,
 
+    // Enable printing guest logs
+    "logging_enable_guest": true,
+    
+    // Enable printing FS access logs. fs_global_access_log_mode must be 2 or 3
+    "logging_enable_fs_access_log": false,
+
     // Filtered log classes, in a JSON array, eg. `[ "Loader", "ServiceFs" ]`
     "logging_filtered_classes": [ ],
 
@@ -44,6 +50,9 @@
     // Enable integrity checks on Switch content files
     "enable_fs_integrity_checks": true,
 
+    // Sets the "GlobalAccessLogMode". Possible modes are 0-3
+    "fs_global_access_log_mode": 0,
+
     // Enable or disable aggressive CPU optimizations
     "enable_aggressive_cpu_opts": true,
 

+ 24 - 5
Ryujinx/Configuration.cs

@@ -52,6 +52,16 @@ namespace Ryujinx
         /// </summary>
         public bool LoggingEnableError { get; private set; }
 
+        /// <summary>
+        /// Enables printing guest log messages
+        /// </summary>
+        public bool LoggingEnableGuest { get; private set; }
+
+        /// <summary>
+        /// Enables printing FS access log messages
+        /// </summary>
+        public bool LoggingEnableFsAccessLog { get; private set; }
+
         /// <summary>
         /// Controls which log messages are written to the log targets
         /// </summary>
@@ -92,6 +102,11 @@ namespace Ryujinx
         /// </summary>
         public bool EnableFsIntegrityChecks { get; private set; }
 
+        /// <summary>
+        /// Enables FS access log output to the console. Possible modes are 0-3
+        /// </summary>
+        public int FsGlobalAccessLogMode { get; private set; }
+
         /// <summary>
         /// Enable or Disable aggressive CPU optimizations
         /// </summary>
@@ -184,11 +199,13 @@ namespace Ryujinx
                 ));
             }
 
-            Logger.SetEnable(LogLevel.Debug,   Instance.LoggingEnableDebug);
-            Logger.SetEnable(LogLevel.Stub,    Instance.LoggingEnableStub);
-            Logger.SetEnable(LogLevel.Info,    Instance.LoggingEnableInfo);
-            Logger.SetEnable(LogLevel.Warning, Instance.LoggingEnableWarn);
-            Logger.SetEnable(LogLevel.Error,   Instance.LoggingEnableError);
+            Logger.SetEnable(LogLevel.Debug,     Instance.LoggingEnableDebug);
+            Logger.SetEnable(LogLevel.Stub,      Instance.LoggingEnableStub);
+            Logger.SetEnable(LogLevel.Info,      Instance.LoggingEnableInfo);
+            Logger.SetEnable(LogLevel.Warning,   Instance.LoggingEnableWarn);
+            Logger.SetEnable(LogLevel.Error,     Instance.LoggingEnableError);
+            Logger.SetEnable(LogLevel.Guest,     Instance.LoggingEnableGuest);
+            Logger.SetEnable(LogLevel.AccessLog, Instance.LoggingEnableFsAccessLog);
 
             if (Instance.LoggingFilteredClasses.Length > 0)
             {
@@ -220,6 +237,8 @@ namespace Ryujinx
                 ? IntegrityCheckLevel.ErrorOnInvalid
                 : IntegrityCheckLevel.None;
 
+            device.System.GlobalAccessLogMode = Instance.FsGlobalAccessLogMode;
+
             if (Instance.EnableAggressiveCpuOpts)
             {
                 Optimizations.AssumeStrictAbiCompliance = true;

+ 39 - 0
Ryujinx/_schema.json

@@ -10,6 +10,8 @@
     "logging_enable_info",
     "logging_enable_warn",
     "logging_enable_error",
+    "logging_enable_guest",
+    "logging_enable_fs_access_log",
     "logging_filtered_classes",
     "enable_file_log",
     "system_language",
@@ -17,6 +19,7 @@
     "enable_vsync",
     "enable_multicore_scheduling",
     "enable_fs_integrity_checks",
+    "fs_global_access_log_mode",
     "enable_aggressive_cpu_opts",
     "controller_type",
     "enable_keyboard",
@@ -265,6 +268,28 @@
         false
       ]
     },
+    "logging_enable_guest": {
+      "$id": "#/properties/logging_enable_guest",
+      "type": "boolean",
+      "title": "Logging Enable Guest",
+      "description": "Enables printing guest log messages",
+      "default": true,
+      "examples": [
+        true,
+        false
+      ]
+    },
+    "logging_enable_fs_access": {
+      "$id": "#/properties/logging_enable_fs_access_log",
+      "type": "boolean",
+      "title": "Logging Enable FS Access Log",
+      "description": "Enables printing FS access log messages",
+      "default": true,
+      "examples": [
+        true,
+        false
+      ]
+    },
     "logging_filtered_classes": {
       "$id": "#/properties/logging_filtered_classes",
       "type": "array",
@@ -412,6 +437,20 @@
         false
       ]
     },
+    "fs_global_access_log_mode": {
+      "$id": "#/properties/fs_global_access_log_mode",
+      "type": "integer",
+      "title": "Enable FS access log",
+      "description": "Enables FS access log output. Possible modes are 0-3. Modes 2 and 3 output to the console.",
+      "default": 0,
+      "minimum": 0,
+      "examples": [
+        0,
+        1,
+        2,
+        3
+      ]
+    },
     "enable_aggressive_cpu_opts": {
       "$id": "#/properties/enable_aggressive_cpu_opts",
       "type": "boolean",