FileSystemExtensions.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. using LibHac.Common;
  2. using LibHac.Fs;
  3. using LibHac.Fs.Fsa;
  4. using LibHac.Loader;
  5. using LibHac.Ns;
  6. using LibHac.Tools.FsSystem;
  7. using Ryujinx.Common.Configuration;
  8. using Ryujinx.Common.Logging;
  9. using Ryujinx.Graphics.Gpu;
  10. using Ryujinx.HLE.Loaders.Executables;
  11. using Ryujinx.Memory;
  12. using System;
  13. using System.Linq;
  14. using static Ryujinx.HLE.HOS.ModLoader;
  15. namespace Ryujinx.HLE.Loaders.Processes.Extensions
  16. {
  17. static class FileSystemExtensions
  18. {
  19. public static MetaLoader GetNpdm(this IFileSystem fileSystem)
  20. {
  21. MetaLoader metaLoader = new();
  22. if (fileSystem == null || !fileSystem.FileExists(ProcessConst.MainNpdmPath))
  23. {
  24. Logger.Warning?.Print(LogClass.Loader, "NPDM file not found, using default values!");
  25. metaLoader.LoadDefault();
  26. }
  27. else
  28. {
  29. metaLoader.LoadFromFile(fileSystem);
  30. }
  31. return metaLoader;
  32. }
  33. public static ProcessResult Load(this IFileSystem exeFs, Switch device, BlitStruct<ApplicationControlProperty> nacpData, MetaLoader metaLoader, byte programIndex, bool isHomebrew = false)
  34. {
  35. ulong programId = metaLoader.GetProgramId();
  36. // Replace the whole ExeFs partition by the modded one.
  37. if (device.Configuration.VirtualFileSystem.ModLoader.ReplaceExefsPartition(programId, ref exeFs))
  38. {
  39. metaLoader = null;
  40. }
  41. // Reload the MetaLoader in case of ExeFs partition replacement.
  42. metaLoader ??= exeFs.GetNpdm();
  43. NsoExecutable[] nsoExecutables = new NsoExecutable[ProcessConst.ExeFsPrefixes.Length];
  44. for (int i = 0; i < nsoExecutables.Length; i++)
  45. {
  46. string name = ProcessConst.ExeFsPrefixes[i];
  47. if (!exeFs.FileExists($"/{name}"))
  48. {
  49. continue; // File doesn't exist, skip.
  50. }
  51. Logger.Info?.Print(LogClass.Loader, $"Loading {name}...");
  52. using UniqueRef<IFile> nsoFile = new();
  53. exeFs.OpenFile(ref nsoFile.Ref, $"/{name}".ToU8Span(), OpenMode.Read).ThrowIfFailure();
  54. nsoExecutables[i] = new NsoExecutable(nsoFile.Release().AsStorage(), name);
  55. }
  56. // ExeFs file replacements.
  57. ModLoadResult modLoadResult = device.Configuration.VirtualFileSystem.ModLoader.ApplyExefsMods(programId, nsoExecutables);
  58. // Take the Npdm from mods if present.
  59. if (modLoadResult.Npdm != null)
  60. {
  61. metaLoader = modLoadResult.Npdm;
  62. }
  63. // Collect the Nsos, ignoring ones that aren't used.
  64. nsoExecutables = nsoExecutables.Where(x => x != null).ToArray();
  65. // Apply Nsos patches.
  66. device.Configuration.VirtualFileSystem.ModLoader.ApplyNsoPatches(programId, nsoExecutables);
  67. string programName = string.Empty;
  68. if (!isHomebrew && programId > 0x010000000000FFFF)
  69. {
  70. programName = nacpData.Value.Title[(int)device.System.State.DesiredTitleLanguage].NameString.ToString();
  71. if (string.IsNullOrWhiteSpace(programName))
  72. {
  73. programName = Array.Find(nacpData.Value.Title.ItemsRo.ToArray(), x => x.Name[0] != 0).NameString.ToString();
  74. }
  75. }
  76. // Initialize GPU.
  77. GraphicsConfig.TitleId = programId.ToString("X16");
  78. device.Gpu.HostInitalized.Set();
  79. if (!MemoryBlock.SupportsFlags(MemoryAllocationFlags.ViewCompatible))
  80. {
  81. device.Configuration.MemoryManagerMode = MemoryManagerMode.SoftwarePageTable;
  82. }
  83. ProcessResult processResult = ProcessLoaderHelper.LoadNsos(
  84. device,
  85. device.System.KernelContext,
  86. metaLoader,
  87. nacpData,
  88. device.System.EnablePtc,
  89. modLoadResult.Hash,
  90. true,
  91. programName,
  92. metaLoader.GetProgramId(),
  93. programIndex,
  94. null,
  95. nsoExecutables);
  96. // TODO: This should be stored using ProcessId instead.
  97. device.System.LibHacHorizonManager.ArpIReader.ApplicationId = new LibHac.ApplicationId(metaLoader.GetProgramId());
  98. return processResult;
  99. }
  100. }
  101. }