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