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.pull/4310/head 1.1.571
parent
410be95ab6
commit
f449895e6d
|
|
@ -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(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();
|
||||
RomFs = romfsStream;
|
||||
_romFsByPid.AddOrUpdate(pid, romfsStream, (pid, oldStream) =>
|
||||
{
|
||||
oldStream.Close();
|
||||
|
||||
return romfsStream;
|
||||
});
|
||||
}
|
||||
|
||||
public Stream GetRomFs(ulong pid)
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue