From 550747eac6c0f6da14070c8b6d208bde6f1d1eb9 Mon Sep 17 00:00:00 2001 From: Ac_K Date: Sun, 8 Jan 2023 13:13:39 +0100 Subject: Horizon: Impl Prepo, Fixes bugs, Clean things (#4220) * Horizon: Impl Prepo, Fixes bugs, Clean things * remove ToArray() * resultCode > status * Remove old services * Addresses gdkchan's comments and more cleanup * Addresses Gdkchan's feedback 2 * Reorganize services, make sure service are loaded before guest Co-Authored-By: gdkchan <5624669+gdkchan@users.noreply.github.com> * Create interfaces for lm and sm Co-authored-by: gdkchan <5624669+gdkchan@users.noreply.github.com> --- Ryujinx.Horizon/LogManager/Ipc/LmLogger.cs | 136 +++++++++++++++++++++++++++ Ryujinx.Horizon/LogManager/Ipc/LogService.cs | 20 ++++ 2 files changed, 156 insertions(+) create mode 100644 Ryujinx.Horizon/LogManager/Ipc/LmLogger.cs create mode 100644 Ryujinx.Horizon/LogManager/Ipc/LogService.cs (limited to 'Ryujinx.Horizon/LogManager/Ipc') diff --git a/Ryujinx.Horizon/LogManager/Ipc/LmLogger.cs b/Ryujinx.Horizon/LogManager/Ipc/LmLogger.cs new file mode 100644 index 00000000..002a5982 --- /dev/null +++ b/Ryujinx.Horizon/LogManager/Ipc/LmLogger.cs @@ -0,0 +1,136 @@ +using Ryujinx.Common.Logging; +using Ryujinx.Common.Memory; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Lm; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; + +namespace Ryujinx.Horizon.LogManager.Ipc +{ + partial class LmLogger : ILmLogger + { + private readonly LogService _log; + private readonly ulong _pid; + + public LmLogger(LogService log, ulong pid) + { + _log = log; + _pid = pid; + } + + [CmifCommand(0)] + public Result Log([Buffer(HipcBufferFlags.In | HipcBufferFlags.AutoSelect)] Span message) + { + if (!SetProcessId(message, _pid)) + { + return Result.Success; + } + + Logger.Guest?.Print(LogClass.ServiceLm, LogImpl(message)); + + return Result.Success; + } + + [CmifCommand(1)] // 3.0.0+ + public Result SetDestination(LogDestination destination) + { + _log.LogDestination = destination; + + return Result.Success; + } + + private static bool SetProcessId(Span message, ulong processId) + { + ref LogPacketHeader header = ref MemoryMarshal.Cast(message)[0]; + + uint expectedMessageSize = (uint)Unsafe.SizeOf() + header.PayloadSize; + if (expectedMessageSize != (uint)message.Length) + { + Logger.Warning?.Print(LogClass.ServiceLm, $"Invalid message size (expected 0x{expectedMessageSize:X} but got 0x{message.Length:X})."); + + return false; + } + + header.ProcessId = processId; + + return true; + } + + private static string LogImpl(ReadOnlySpan message) + { + SpanReader reader = new(message); + LogPacketHeader header = reader.Read(); + StringBuilder builder = new(); + + builder.AppendLine($"Guest Log:\n Log level: {header.Severity}"); + + while (reader.Length > 0) + { + int type = ReadUleb128(ref reader); + int size = ReadUleb128(ref reader); + + LogDataChunkKey field = (LogDataChunkKey)type; + + string fieldStr; + + if (field == LogDataChunkKey.Start) + { + reader.Skip(size); + + continue; + } + else if (field == LogDataChunkKey.Stop) + { + break; + } + else if (field == LogDataChunkKey.Line) + { + fieldStr = $"{field}: {reader.Read()}"; + } + else if (field == LogDataChunkKey.DropCount) + { + fieldStr = $"{field}: {reader.Read()}"; + } + else if (field == LogDataChunkKey.Time) + { + fieldStr = $"{field}: {reader.Read()}s"; + } + else if (field < LogDataChunkKey.Count) + { + fieldStr = $"{field}: '{Encoding.UTF8.GetString(reader.GetSpan(size)).TrimEnd()}'"; + } + else + { + fieldStr = $"Field{field}: '{Encoding.UTF8.GetString(reader.GetSpan(size)).TrimEnd()}'"; + } + + builder.AppendLine($" {fieldStr}"); + } + + return builder.ToString(); + } + + private static int ReadUleb128(ref SpanReader reader) + { + int result = 0; + int count = 0; + + byte encoded; + + do + { + encoded = reader.Read(); + + result += (encoded & 0x7F) << (7 * count); + + count++; + } while ((encoded & 0x80) != 0); + + return result; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Horizon/LogManager/Ipc/LogService.cs b/Ryujinx.Horizon/LogManager/Ipc/LogService.cs new file mode 100644 index 00000000..6899739e --- /dev/null +++ b/Ryujinx.Horizon/LogManager/Ipc/LogService.cs @@ -0,0 +1,20 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Lm; +using Ryujinx.Horizon.Sdk.Sf; + +namespace Ryujinx.Horizon.LogManager.Ipc +{ + partial class LogService : ILogService + { + public LogDestination LogDestination { get; set; } = LogDestination.TargetManager; + + [CmifCommand(0)] + public Result OpenLogger(out LmLogger logger, [ClientProcessId] ulong pid) + { + // NOTE: Internal name is Logger, but we rename it LmLogger to avoid name clash with Ryujinx.Common.Logging logger. + logger = new LmLogger(this, pid); + + return Result.Success; + } + } +} \ No newline at end of file -- cgit v1.2.3