aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.HLE/Loaders/Processes/Extensions/FileSystemExtensions.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.HLE/Loaders/Processes/Extensions/FileSystemExtensions.cs')
-rw-r--r--src/Ryujinx.HLE/Loaders/Processes/Extensions/FileSystemExtensions.cs133
1 files changed, 133 insertions, 0 deletions
diff --git a/src/Ryujinx.HLE/Loaders/Processes/Extensions/FileSystemExtensions.cs b/src/Ryujinx.HLE/Loaders/Processes/Extensions/FileSystemExtensions.cs
new file mode 100644
index 00000000..58759ddb
--- /dev/null
+++ b/src/Ryujinx.HLE/Loaders/Processes/Extensions/FileSystemExtensions.cs
@@ -0,0 +1,133 @@
+using LibHac.Common;
+using LibHac.Fs;
+using LibHac.Fs.Fsa;
+using LibHac.Loader;
+using LibHac.Ns;
+using LibHac.Tools.FsSystem;
+using Ryujinx.Common.Configuration;
+using Ryujinx.Common.Logging;
+using Ryujinx.HLE.Loaders.Executables;
+using Ryujinx.Memory;
+using System.Linq;
+using static Ryujinx.HLE.HOS.ModLoader;
+
+namespace Ryujinx.HLE.Loaders.Processes.Extensions
+{
+ static class FileSystemExtensions
+ {
+ public static MetaLoader GetNpdm(this IFileSystem fileSystem)
+ {
+ MetaLoader metaLoader = new();
+
+ if (fileSystem == null || !fileSystem.FileExists(ProcessConst.MainNpdmPath))
+ {
+ Logger.Warning?.Print(LogClass.Loader, "NPDM file not found, using default values!");
+
+ metaLoader.LoadDefault();
+ }
+ else
+ {
+ metaLoader.LoadFromFile(fileSystem);
+ }
+
+ return metaLoader;
+ }
+
+ public static ProcessResult Load(this IFileSystem exeFs, Switch device, BlitStruct<ApplicationControlProperty> nacpData, MetaLoader metaLoader, bool isHomebrew = false)
+ {
+ ulong programId = metaLoader.GetProgramId();
+
+ // Replace the whole ExeFs partition by the modded one.
+ if (device.Configuration.VirtualFileSystem.ModLoader.ReplaceExefsPartition(programId, ref exeFs))
+ {
+ metaLoader = null;
+ }
+
+ // Reload the MetaLoader in case of ExeFs partition replacement.
+ metaLoader ??= exeFs.GetNpdm();
+
+ NsoExecutable[] nsoExecutables = new NsoExecutable[ProcessConst.ExeFsPrefixes.Length];
+
+ for (int i = 0; i < nsoExecutables.Length; i++)
+ {
+ string name = ProcessConst.ExeFsPrefixes[i];
+
+ if (!exeFs.FileExists($"/{name}"))
+ {
+ continue; // File doesn't exist, skip.
+ }
+
+ Logger.Info?.Print(LogClass.Loader, $"Loading {name}...");
+
+ using var nsoFile = new UniqueRef<IFile>();
+
+ exeFs.OpenFile(ref nsoFile.Ref, $"/{name}".ToU8Span(), OpenMode.Read).ThrowIfFailure();
+
+ nsoExecutables[i] = new NsoExecutable(nsoFile.Release().AsStorage(), name);
+ }
+
+ // ExeFs file replacements.
+ ModLoadResult modLoadResult = device.Configuration.VirtualFileSystem.ModLoader.ApplyExefsMods(programId, nsoExecutables);
+
+ // Take the Npdm from mods if present.
+ if (modLoadResult.Npdm != null)
+ {
+ metaLoader = modLoadResult.Npdm;
+ }
+
+ // Collect the Nsos, ignoring ones that aren't used.
+ nsoExecutables = nsoExecutables.Where(x => x != null).ToArray();
+
+ // Apply Nsos patches.
+ device.Configuration.VirtualFileSystem.ModLoader.ApplyNsoPatches(programId, nsoExecutables);
+
+ // Don't use PTC if ExeFS files have been replaced.
+ bool enablePtc = device.System.EnablePtc && !modLoadResult.Modified;
+ if (!enablePtc)
+ {
+ Logger.Warning?.Print(LogClass.Ptc, $"Detected unsupported ExeFs modifications. PTC disabled.");
+ }
+
+ // We allow it for nx-hbloader because it can be used to launch homebrew.
+ bool allowCodeMemoryForJit = programId == 0x010000000000100DUL || isHomebrew;
+
+ string programName = "";
+
+ if (!isHomebrew && programId > 0x010000000000FFFF)
+ {
+ programName = nacpData.Value.Title[(int)device.System.State.DesiredTitleLanguage].NameString.ToString();
+
+ if (string.IsNullOrWhiteSpace(programName))
+ {
+ programName = nacpData.Value.Title.ItemsRo.ToArray().FirstOrDefault(x => x.Name[0] != 0).NameString.ToString();
+ }
+ }
+
+ // Initialize GPU.
+ Graphics.Gpu.GraphicsConfig.TitleId = $"{programId:x16}";
+ device.Gpu.HostInitalized.Set();
+
+ if (!MemoryBlock.SupportsFlags(MemoryAllocationFlags.ViewCompatible))
+ {
+ device.Configuration.MemoryManagerMode = MemoryManagerMode.SoftwarePageTable;
+ }
+
+ ProcessResult processResult = ProcessLoaderHelper.LoadNsos(
+ device,
+ device.System.KernelContext,
+ metaLoader,
+ nacpData.Value,
+ enablePtc,
+ allowCodeMemoryForJit,
+ programName,
+ metaLoader.GetProgramId(),
+ null,
+ nsoExecutables);
+
+ // TODO: This should be stored using ProcessId instead.
+ device.System.LibHacHorizonManager.ArpIReader.ApplicationId = new LibHac.ApplicationId(metaLoader.GetProgramId());
+
+ return processResult;
+ }
+ }
+} \ No newline at end of file