FileSystemExtensions.cs 4.8 KB

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