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:
parent
410be95ab6
commit
f449895e6d
4 changed files with 61 additions and 24 deletions
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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()));
|
||||||
|
|
||||||
|
|
Reference in a new issue