From 556be08c4e9ad9f508dc2647ef70d3b89c2c242c Mon Sep 17 00:00:00 2001 From: gdkchan Date: Tue, 3 May 2022 18:28:32 -0300 Subject: [PATCH] Implement PM GetProcessInfo atmosphere extension (partially) (#2966) --- Ryujinx.HLE/HOS/ApplicationLoader.cs | 16 +++++++----- Ryujinx.HLE/HOS/Kernel/KernelStatic.cs | 10 ++++++++ Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs | 6 ++++- .../HOS/Kernel/SupervisorCall/Syscall.cs | 7 +++--- Ryujinx.HLE/HOS/ProgramLoader.cs | 14 ++++++++--- .../HOS/Services/Pm/IDebugMonitorInterface.cs | 25 ++++++++++++++++++- 6 files changed, 63 insertions(+), 15 deletions(-) diff --git a/Ryujinx.HLE/HOS/ApplicationLoader.cs b/Ryujinx.HLE/HOS/ApplicationLoader.cs index 80d609b66..b3d23ea7b 100644 --- a/Ryujinx.HLE/HOS/ApplicationLoader.cs +++ b/Ryujinx.HLE/HOS/ApplicationLoader.cs @@ -86,8 +86,8 @@ namespace Ryujinx.HLE.HOS MetaLoader metaData = ReadNpdm(codeFs); _device.Configuration.VirtualFileSystem.ModLoader.CollectMods( - new[] { TitleId }, - _device.Configuration.VirtualFileSystem.ModLoader.GetModsBasePath(), + new[] { TitleId }, + _device.Configuration.VirtualFileSystem.ModLoader.GetModsBasePath(), _device.Configuration.VirtualFileSystem.ModLoader.GetSdModsBasePath()); if (TitleId != 0) @@ -393,8 +393,8 @@ namespace Ryujinx.HLE.HOS MetaLoader metaData = ReadNpdm(codeFs); _device.Configuration.VirtualFileSystem.ModLoader.CollectMods( - _device.Configuration.ContentManager.GetAocTitleIds().Prepend(TitleId), - _device.Configuration.VirtualFileSystem.ModLoader.GetModsBasePath(), + _device.Configuration.ContentManager.GetAocTitleIds().Prepend(TitleId), + _device.Configuration.VirtualFileSystem.ModLoader.GetModsBasePath(), _device.Configuration.VirtualFileSystem.ModLoader.GetSdModsBasePath()); if (controlNca != null) @@ -571,8 +571,12 @@ namespace Ryujinx.HLE.HOS Ptc.Initialize(TitleIdText, DisplayVersion, usePtc, memoryManagerMode); + // We allow it for nx-hbloader because it can be used to launch homebrew. + bool allowCodeMemoryForJit = TitleId == 0x010000000000100DUL; + metaData.GetNpdm(out Npdm npdm).ThrowIfFailure(); - ProgramLoader.LoadNsos(_device.System.KernelContext, out ProcessTamperInfo tamperInfo, metaData, new ProgramInfo(in npdm), executables: programs); + ProgramInfo programInfo = new ProgramInfo(in npdm, allowCodeMemoryForJit); + ProgramLoader.LoadNsos(_device.System.KernelContext, out ProcessTamperInfo tamperInfo, metaData, programInfo, executables: programs); _device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, tamperInfo, _device.TamperMachine); } @@ -581,7 +585,7 @@ namespace Ryujinx.HLE.HOS { MetaLoader metaData = GetDefaultNpdm(); metaData.GetNpdm(out Npdm npdm).ThrowIfFailure(); - ProgramInfo programInfo = new ProgramInfo(in npdm); + ProgramInfo programInfo = new ProgramInfo(in npdm, allowCodeMemoryForJit: true); bool isNro = Path.GetExtension(filePath).ToLower() == ".nro"; diff --git a/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs b/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs index 2446ace4b..625a007dd 100644 --- a/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs +++ b/Ryujinx.HLE/HOS/Kernel/KernelStatic.cs @@ -59,5 +59,15 @@ namespace Ryujinx.HLE.HOS.Kernel { return GetCurrentThread().Owner; } + + internal static KProcess GetProcessByPid(ulong pid) + { + if (Context.Processes.TryGetValue(pid, out KProcess process)) + { + return process; + } + + return null; + } } } diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs index 93ecf2973..b10737b43 100644 --- a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs +++ b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs @@ -60,6 +60,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process public KProcessCapabilities Capabilities { get; private set; } + public bool AllowCodeMemoryForJit { get; private set; } + public ulong TitleId { get; private set; } public bool IsApplication { get; private set; } public ulong Pid { get; private set; } @@ -90,7 +92,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process public HleProcessDebugger Debugger { get; private set; } - public KProcess(KernelContext context) : base(context) + public KProcess(KernelContext context, bool allowCodeMemoryForJit = false) : base(context) { _processLock = new object(); _threadingLock = new object(); @@ -102,6 +104,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process Capabilities = new KProcessCapabilities(); + AllowCodeMemoryForJit = allowCodeMemoryForJit; + RandomEntropy = new ulong[KScheduler.CpuCoresCount]; PinnedThreads = new KThread[KScheduler.CpuCoresCount]; diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs index 0c111bc44..d9d492a52 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs @@ -7,7 +7,6 @@ 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.Memory; using System; using System.Threading; @@ -1363,10 +1362,10 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall KCodeMemory codeMemory = currentProcess.HandleTable.GetObject(handle); - // Newer versions of the return also returns an error here if the owner and process + // Newer versions of the kernel also returns an error here if the owner and process // where the operation will happen are the same. We do not return an error here - // because some homebrew requires this to be patched out to work (for JIT). - if (codeMemory == null /* || codeMemory.Owner == currentProcess */) + // for homebrew because some of them requires this to be patched out to work (for JIT). + if (codeMemory == null || (!currentProcess.AllowCodeMemoryForJit && codeMemory.Owner == currentProcess)) { return KernelResult.InvalidHandle; } diff --git a/Ryujinx.HLE/HOS/ProgramLoader.cs b/Ryujinx.HLE/HOS/ProgramLoader.cs index 403e0227c..294ca5b82 100644 --- a/Ryujinx.HLE/HOS/ProgramLoader.cs +++ b/Ryujinx.HLE/HOS/ProgramLoader.cs @@ -20,11 +20,13 @@ namespace Ryujinx.HLE.HOS { public string Name; public ulong ProgramId; + public bool AllowCodeMemoryForJit; - public ProgramInfo(in Npdm npdm) + public ProgramInfo(in Npdm npdm, bool allowCodeMemoryForJit) { Name = StringUtils.Utf8ZToString(npdm.Meta.Value.ProgramName); ProgramId = npdm.Aci.Value.ProgramId.Value; + AllowCodeMemoryForJit = allowCodeMemoryForJit; } } @@ -141,7 +143,13 @@ namespace Ryujinx.HLE.HOS return true; } - public static bool LoadNsos(KernelContext context, out ProcessTamperInfo tamperInfo, MetaLoader metaData, ProgramInfo programInfo, byte[] arguments = null, params IExecutable[] executables) + public static bool LoadNsos( + KernelContext context, + out ProcessTamperInfo tamperInfo, + MetaLoader metaData, + ProgramInfo programInfo, + byte[] arguments = null, + params IExecutable[] executables) { LibHac.Result rc = metaData.GetNpdm(out var npdm); @@ -243,7 +251,7 @@ namespace Ryujinx.HLE.HOS return false; } - KProcess process = new KProcess(context); + KProcess process = new KProcess(context, programInfo.AllowCodeMemoryForJit); MemoryRegion memoryRegion = (MemoryRegion)((npdm.Acid.Value.Flags >> 2) & 0xf); diff --git a/Ryujinx.HLE/HOS/Services/Pm/IDebugMonitorInterface.cs b/Ryujinx.HLE/HOS/Services/Pm/IDebugMonitorInterface.cs index 06c119436..4b0df9b7b 100644 --- a/Ryujinx.HLE/HOS/Services/Pm/IDebugMonitorInterface.cs +++ b/Ryujinx.HLE/HOS/Services/Pm/IDebugMonitorInterface.cs @@ -1,8 +1,31 @@ -namespace Ryujinx.HLE.HOS.Services.Pm +using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel; +using Ryujinx.HLE.HOS.Kernel.Common; +using Ryujinx.HLE.HOS.Kernel.Process; + +namespace Ryujinx.HLE.HOS.Services.Pm { [Service("pm:dmnt")] class IDebugMonitorInterface : IpcService { public IDebugMonitorInterface(ServiceCtx context) { } + + [CommandHipc(65000)] + // AtmosphereGetProcessInfo(os::ProcessId process_id) -> sf::OutCopyHandle out_process_handle, sf::Out out_loc, sf::Out out_status + public ResultCode GetProcessInfo(ServiceCtx context) + { + ulong pid = context.RequestData.ReadUInt64(); + + KProcess process = KernelStatic.GetProcessByPid(pid); + + if (context.Process.HandleTable.GenerateHandle(process, out int processHandle) != KernelResult.Success) + { + throw new System.Exception("Out of handles!"); + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(processHandle); + + return ResultCode.Success; + } } } \ No newline at end of file