Просмотр исходного кода

HOS: Load RomFs by pid (#4301)

We currently loading only one RomFs at a time, which could be wrong if one day we want to load more than one guest at time.
This PR fixes that by loading romfs by pid.
Ac_K 3 лет назад
Родитель
Сommit
f449895e6d

+ 31 - 7
Ryujinx.HLE/FileSystem/VirtualFileSystem.cs

@@ -16,6 +16,7 @@ using Ryujinx.Common.Logging;
 using Ryujinx.HLE.HOS;
 using System;
 using System.Buffers.Text;
+using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.IO;
 using System.Runtime.CompilerServices;
@@ -35,7 +36,8 @@ namespace Ryujinx.HLE.FileSystem
         public EmulatedGameCard GameCard  { get; private set; }
         public EmulatedSdCard   SdCard    { get; private set; }
         public ModLoader        ModLoader { get; private set; }
-        public Stream           RomFs     { get; private set; }
+
+        private readonly ConcurrentDictionary<ulong, Stream> _romFsByPid;
 
         private static bool _isInitialized = false;
 
@@ -55,17 +57,34 @@ namespace Ryujinx.HLE.FileSystem
         {
             ReloadKeySet();
             ModLoader = new ModLoader(); // Should only be created once
+            _romFsByPid = new ConcurrentDictionary<ulong, Stream>();
+        }
+
+        public void LoadRomFs(ulong pid, string fileName)
+        {
+            var romfsStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
+
+            _romFsByPid.AddOrUpdate(pid, romfsStream, (pid, oldStream) =>
+            {
+                oldStream.Close();
+
+                return romfsStream;
+            });
         }
 
-        public void LoadRomFs(string fileName)
+        public void SetRomFs(ulong pid, Stream romfsStream)
         {
-            RomFs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
+            _romFsByPid.AddOrUpdate(pid, romfsStream, (pid, oldStream) =>
+            {
+                oldStream.Close();
+
+                return romfsStream;
+            });
         }
 
-        public void SetRomFs(Stream romfsStream)
+        public Stream GetRomFs(ulong pid)
         {
-            RomFs?.Close();
-            RomFs = romfsStream;
+            return _romFsByPid[pid];
         }
 
         public string GetFullPath(string basePath, string fileName)
@@ -583,7 +602,12 @@ namespace Ryujinx.HLE.FileSystem
         {
             if (disposing)
             {
-                RomFs?.Dispose();
+                foreach (var stream in _romFsByPid.Values)
+                {
+                    stream.Close();
+                }
+
+                _romFsByPid.Clear();
             }
         }
     }

+ 19 - 11
Ryujinx.HLE/HOS/ApplicationLoader.cs

@@ -76,11 +76,6 @@ namespace Ryujinx.HLE.HOS
 
         public void LoadCart(string exeFsDir, string romFsFile = null)
         {
-            if (romFsFile != null)
-            {
-                _device.Configuration.VirtualFileSystem.LoadRomFs(romFsFile);
-            }
-
             LocalFileSystem codeFs = new LocalFileSystem(exeFsDir);
 
             MetaLoader metaData = ReadNpdm(codeFs);
@@ -95,7 +90,12 @@ namespace Ryujinx.HLE.HOS
                 EnsureSaveData(new ApplicationId(TitleId));
             }
 
-            LoadExeFs(codeFs, string.Empty, metaData);
+            ulong pid = LoadExeFs(codeFs, string.Empty, metaData);
+
+            if (romFsFile != null)
+            {
+                _device.Configuration.VirtualFileSystem.LoadRomFs(pid, romFsFile);
+            }
         }
 
         public static (Nca main, Nca patch, Nca control) GetGameData(VirtualFileSystem fileSystem, PartitionFileSystem pfs, int programIndex)
@@ -491,6 +491,8 @@ namespace Ryujinx.HLE.HOS
 
             _displayVersion = displayVersion;
 
+            ulong pid = LoadExeFs(codeFs, displayVersion, metaData);
+
             if (dataStorage == null)
             {
                 Logger.Warning?.Print(LogClass.Loader, "No RomFS found in NCA");
@@ -499,7 +501,7 @@ namespace Ryujinx.HLE.HOS
             {
                 IStorage newStorage = _device.Configuration.VirtualFileSystem.ModLoader.ApplyRomFsMods(TitleId, dataStorage);
 
-                _device.Configuration.VirtualFileSystem.SetRomFs(newStorage.AsStream(FileAccess.Read));
+                _device.Configuration.VirtualFileSystem.SetRomFs(pid, newStorage.AsStream(FileAccess.Read));
             }
 
             // Don't create save data for system programs.
@@ -510,8 +512,6 @@ namespace Ryujinx.HLE.HOS
                 EnsureSaveData(new ApplicationId(TitleId & ~0xFul));
             }
 
-            LoadExeFs(codeFs, displayVersion, metaData);
-
             Logger.Info?.Print(LogClass.Loader, $"Application Loaded: {TitleName} v{DisplayVersion} [{TitleIdText}] [{(TitleIs64Bit ? "64-bit" : "32-bit")}]");
         }
 
@@ -579,7 +579,7 @@ namespace Ryujinx.HLE.HOS
             }
         }
 
-        private void LoadExeFs(IFileSystem codeFs, string displayVersion, MetaLoader metaData = null, bool isHomebrew = false)
+        private ulong LoadExeFs(IFileSystem codeFs, string displayVersion, MetaLoader metaData = null, bool isHomebrew = false)
         {
             if (_device.Configuration.VirtualFileSystem.ModLoader.ReplaceExefsPartition(TitleId, ref codeFs))
             {
@@ -654,6 +654,8 @@ namespace Ryujinx.HLE.HOS
             DiskCacheLoadState = result.DiskCacheLoadState;
 
             _device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, result.TamperInfo, _device.TamperMachine);
+
+            return result.ProcessId;
         }
 
         public void LoadProgram(string filePath)
@@ -665,6 +667,7 @@ namespace Ryujinx.HLE.HOS
             bool isNro = Path.GetExtension(filePath).ToLower() == ".nro";
 
             IExecutable executable;
+            Stream romfsStream = null;
 
             if (isNro)
             {
@@ -697,7 +700,7 @@ namespace Ryujinx.HLE.HOS
 
                             if (romfsSize != 0)
                             {
-                                _device.Configuration.VirtualFileSystem.SetRomFs(new HomebrewRomFsStream(input, obj.FileSize + (long)romfsOffset));
+                                romfsStream = new HomebrewRomFsStream(input, obj.FileSize + (long)romfsOffset);
                             }
 
                             if (nacpSize != 0)
@@ -758,6 +761,11 @@ namespace Ryujinx.HLE.HOS
 
             ProgramLoadResult result = ProgramLoader.LoadNsos(_device.System.KernelContext, metaData, programInfo, executables: executable);
 
+            if (romfsStream != null)
+            {
+                _device.Configuration.VirtualFileSystem.SetRomFs(result.ProcessId, romfsStream);
+            }
+
             DiskCacheLoadState = result.DiskCacheLoadState;
 
             _device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, result.TamperInfo, _device.TamperMachine);

+ 5 - 3
Ryujinx.HLE/HOS/ProgramLoader.cs

@@ -41,17 +41,19 @@ namespace Ryujinx.HLE.HOS
 
     struct ProgramLoadResult
     {
-        public static ProgramLoadResult Failed => new ProgramLoadResult(false, null, null);
+        public static ProgramLoadResult Failed => new ProgramLoadResult(false, null, null, 0);
 
         public readonly bool Success;
         public readonly ProcessTamperInfo TamperInfo;
         public readonly IDiskCacheLoadState DiskCacheLoadState;
+        public readonly ulong ProcessId;
 
-        public ProgramLoadResult(bool success, ProcessTamperInfo tamperInfo, IDiskCacheLoadState diskCacheLoadState)
+        public ProgramLoadResult(bool success, ProcessTamperInfo tamperInfo, IDiskCacheLoadState diskCacheLoadState, ulong pid)
         {
             Success = success;
             TamperInfo = tamperInfo;
             DiskCacheLoadState = diskCacheLoadState;
+            ProcessId = pid;
         }
     }
 
@@ -366,7 +368,7 @@ namespace Ryujinx.HLE.HOS
                 process.MemoryManager.AliasRegionStart,
                 process.MemoryManager.CodeRegionStart);
 
-            return new ProgramLoadResult(true, tamperInfo, processContextFactory.DiskCacheLoadState);
+            return new ProgramLoadResult(true, tamperInfo, processContextFactory.DiskCacheLoadState, process.Pid);
         }
 
         private static Result LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress)

+ 6 - 3
Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs

@@ -27,6 +27,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
     class IFileSystemProxy : DisposableIpcService
     {
         private SharedRef<LibHac.FsSrv.Sf.IFileSystemProxy> _baseFileSystemProxy;
+        private ulong _pid;
 
         public IFileSystemProxy(ServiceCtx context) : base(context.Device.System.FsServer)
         {
@@ -38,6 +39,8 @@ namespace Ryujinx.HLE.HOS.Services.Fs
         // SetCurrentProcess(u64, pid)
         public ResultCode SetCurrentProcess(ServiceCtx context)
         {
+            _pid = context.Request.HandleDesc.PId;
+
             return ResultCode.Success;
         }
 
@@ -702,7 +705,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
         // OpenDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage> dataStorage
         public ResultCode OpenDataStorageByCurrentProcess(ServiceCtx context)
         {
-            var storage = context.Device.FileSystem.RomFs.AsStorage(true);
+            var storage = context.Device.FileSystem.GetRomFs(_pid).AsStorage(true);
             using var sharedStorage = new SharedRef<LibHac.Fs.IStorage>(storage);
             using var sfStorage = new SharedRef<IStorage>(new StorageInterfaceAdapter(ref sharedStorage.Ref()));
 
@@ -791,7 +794,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
         // OpenPatchDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage>
         public ResultCode OpenPatchDataStorageByCurrentProcess(ServiceCtx context)
         {
-            var storage = context.Device.FileSystem.RomFs.AsStorage(true);
+            var storage = context.Device.FileSystem.GetRomFs(_pid).AsStorage(true);
             using var sharedStorage = new SharedRef<LibHac.Fs.IStorage>(storage);
             using var sfStorage = new SharedRef<IStorage>(new StorageInterfaceAdapter(ref sharedStorage.Ref()));
 
@@ -811,7 +814,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
                 throw new NotImplementedException($"Accessing storage from other programs is not supported (program index = {programIndex}).");
             }
 
-            var storage = context.Device.FileSystem.RomFs.AsStorage(true);
+            var storage = context.Device.FileSystem.GetRomFs(_pid).AsStorage(true);
             using var sharedStorage = new SharedRef<LibHac.Fs.IStorage>(storage);
             using var sfStorage = new SharedRef<IStorage>(new StorageInterfaceAdapter(ref sharedStorage.Ref()));