0
0
Fork 0
mirror of https://github.com/ryujinx-mirror/ryujinx.git synced 2024-12-23 14:05:46 +00:00

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.
This commit is contained in:
Ac_K 2023-01-18 14:50:42 +01:00 committed by GitHub
parent 410be95ab6
commit f449895e6d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 61 additions and 24 deletions

View file

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

View file

@ -76,11 +76,6 @@ namespace Ryujinx.HLE.HOS
public void LoadCart(string exeFsDir, string romFsFile = null) public void LoadCart(string exeFsDir, string romFsFile = null)
{ {
if (romFsFile != null)
{
_device.Configuration.VirtualFileSystem.LoadRomFs(romFsFile);
}
LocalFileSystem codeFs = new LocalFileSystem(exeFsDir); LocalFileSystem codeFs = new LocalFileSystem(exeFsDir);
MetaLoader metaData = ReadNpdm(codeFs); MetaLoader metaData = ReadNpdm(codeFs);
@ -95,7 +90,12 @@ namespace Ryujinx.HLE.HOS
EnsureSaveData(new ApplicationId(TitleId)); 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) 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; _displayVersion = displayVersion;
ulong pid = LoadExeFs(codeFs, displayVersion, metaData);
if (dataStorage == null) if (dataStorage == null)
{ {
Logger.Warning?.Print(LogClass.Loader, "No RomFS found in NCA"); 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); 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. // Don't create save data for system programs.
@ -510,8 +512,6 @@ namespace Ryujinx.HLE.HOS
EnsureSaveData(new ApplicationId(TitleId & ~0xFul)); 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")}]"); 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)) if (_device.Configuration.VirtualFileSystem.ModLoader.ReplaceExefsPartition(TitleId, ref codeFs))
{ {
@ -654,6 +654,8 @@ namespace Ryujinx.HLE.HOS
DiskCacheLoadState = result.DiskCacheLoadState; DiskCacheLoadState = result.DiskCacheLoadState;
_device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, result.TamperInfo, _device.TamperMachine); _device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, result.TamperInfo, _device.TamperMachine);
return result.ProcessId;
} }
public void LoadProgram(string filePath) public void LoadProgram(string filePath)
@ -665,6 +667,7 @@ namespace Ryujinx.HLE.HOS
bool isNro = Path.GetExtension(filePath).ToLower() == ".nro"; bool isNro = Path.GetExtension(filePath).ToLower() == ".nro";
IExecutable executable; IExecutable executable;
Stream romfsStream = null;
if (isNro) if (isNro)
{ {
@ -697,7 +700,7 @@ namespace Ryujinx.HLE.HOS
if (romfsSize != 0) 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) if (nacpSize != 0)
@ -758,6 +761,11 @@ namespace Ryujinx.HLE.HOS
ProgramLoadResult result = ProgramLoader.LoadNsos(_device.System.KernelContext, metaData, programInfo, executables: executable); ProgramLoadResult result = ProgramLoader.LoadNsos(_device.System.KernelContext, metaData, programInfo, executables: executable);
if (romfsStream != null)
{
_device.Configuration.VirtualFileSystem.SetRomFs(result.ProcessId, romfsStream);
}
DiskCacheLoadState = result.DiskCacheLoadState; DiskCacheLoadState = result.DiskCacheLoadState;
_device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, result.TamperInfo, _device.TamperMachine); _device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, result.TamperInfo, _device.TamperMachine);

View file

@ -41,17 +41,19 @@ namespace Ryujinx.HLE.HOS
struct ProgramLoadResult 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 bool Success;
public readonly ProcessTamperInfo TamperInfo; public readonly ProcessTamperInfo TamperInfo;
public readonly IDiskCacheLoadState DiskCacheLoadState; 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; Success = success;
TamperInfo = tamperInfo; TamperInfo = tamperInfo;
DiskCacheLoadState = diskCacheLoadState; DiskCacheLoadState = diskCacheLoadState;
ProcessId = pid;
} }
} }
@ -366,7 +368,7 @@ namespace Ryujinx.HLE.HOS
process.MemoryManager.AliasRegionStart, process.MemoryManager.AliasRegionStart,
process.MemoryManager.CodeRegionStart); 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) private static Result LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress)

View file

@ -27,6 +27,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
class IFileSystemProxy : DisposableIpcService class IFileSystemProxy : DisposableIpcService
{ {
private SharedRef<LibHac.FsSrv.Sf.IFileSystemProxy> _baseFileSystemProxy; private SharedRef<LibHac.FsSrv.Sf.IFileSystemProxy> _baseFileSystemProxy;
private ulong _pid;
public IFileSystemProxy(ServiceCtx context) : base(context.Device.System.FsServer) public IFileSystemProxy(ServiceCtx context) : base(context.Device.System.FsServer)
{ {
@ -38,6 +39,8 @@ namespace Ryujinx.HLE.HOS.Services.Fs
// SetCurrentProcess(u64, pid) // SetCurrentProcess(u64, pid)
public ResultCode SetCurrentProcess(ServiceCtx context) public ResultCode SetCurrentProcess(ServiceCtx context)
{ {
_pid = context.Request.HandleDesc.PId;
return ResultCode.Success; return ResultCode.Success;
} }
@ -702,7 +705,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
// OpenDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage> dataStorage // OpenDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage> dataStorage
public ResultCode OpenDataStorageByCurrentProcess(ServiceCtx context) 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 sharedStorage = new SharedRef<LibHac.Fs.IStorage>(storage);
using var sfStorage = new SharedRef<IStorage>(new StorageInterfaceAdapter(ref sharedStorage.Ref())); 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> // OpenPatchDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage>
public ResultCode OpenPatchDataStorageByCurrentProcess(ServiceCtx context) 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 sharedStorage = new SharedRef<LibHac.Fs.IStorage>(storage);
using var sfStorage = new SharedRef<IStorage>(new StorageInterfaceAdapter(ref sharedStorage.Ref())); 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})."); 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 sharedStorage = new SharedRef<LibHac.Fs.IStorage>(storage);
using var sfStorage = new SharedRef<IStorage>(new StorageInterfaceAdapter(ref sharedStorage.Ref())); using var sfStorage = new SharedRef<IStorage>(new StorageInterfaceAdapter(ref sharedStorage.Ref()));