aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/ApplicationLoader.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.HLE/HOS/ApplicationLoader.cs')
-rw-r--r--Ryujinx.HLE/HOS/ApplicationLoader.cs116
1 files changed, 74 insertions, 42 deletions
diff --git a/Ryujinx.HLE/HOS/ApplicationLoader.cs b/Ryujinx.HLE/HOS/ApplicationLoader.cs
index bc7016bd..994d0f25 100644
--- a/Ryujinx.HLE/HOS/ApplicationLoader.cs
+++ b/Ryujinx.HLE/HOS/ApplicationLoader.cs
@@ -43,7 +43,8 @@ namespace Ryujinx.HLE.HOS
public bool EnablePtc => _device.System.EnablePtc;
- public IntegrityCheckLevel FsIntegrityCheckLevel => _device.System.FsIntegrityCheckLevel;
+ // Binaries from exefs are loaded into mem in this order. Do not change.
+ private static readonly string[] ExeFsPrefixes = { "rtld", "main", "subsdk*", "sdk" };
public ApplicationLoader(Switch device, VirtualFileSystem fileSystem, ContentManager contentManager)
{
@@ -52,6 +53,9 @@ namespace Ryujinx.HLE.HOS
_fileSystem = fileSystem;
ControlData = new BlitStruct<ApplicationControlProperty>(1);
+
+ // Clear Mods cache
+ _fileSystem.ModLoader.Clear();
}
public void LoadCart(string exeFsDir, string romFsFile = null)
@@ -63,12 +67,14 @@ namespace Ryujinx.HLE.HOS
LocalFileSystem codeFs = new LocalFileSystem(exeFsDir);
- LoadExeFs(codeFs, out _);
+ Npdm metaData = ReadNpdm(codeFs);
if (TitleId != 0)
{
EnsureSaveData(new TitleId(TitleId));
}
+
+ LoadExeFs(codeFs, metaData);
}
private (Nca main, Nca patch, Nca control) GetGameData(PartitionFileSystem pfs)
@@ -191,7 +197,7 @@ namespace Ryujinx.HLE.HOS
}
// This is not a normal NSP, it's actually a ExeFS as a NSP
- LoadExeFs(nsp, out _);
+ LoadExeFs(nsp);
}
public void LoadNca(string ncaFile)
@@ -272,24 +278,24 @@ namespace Ryujinx.HLE.HOS
{
if (mainNca.CanOpenSection(NcaSectionType.Data))
{
- dataStorage = mainNca.OpenStorage(NcaSectionType.Data, FsIntegrityCheckLevel);
+ dataStorage = mainNca.OpenStorage(NcaSectionType.Data, _device.System.FsIntegrityCheckLevel);
}
if (mainNca.CanOpenSection(NcaSectionType.Code))
{
- codeFs = mainNca.OpenFileSystem(NcaSectionType.Code, FsIntegrityCheckLevel);
+ codeFs = mainNca.OpenFileSystem(NcaSectionType.Code, _device.System.FsIntegrityCheckLevel);
}
}
else
{
if (patchNca.CanOpenSection(NcaSectionType.Data))
{
- dataStorage = mainNca.OpenStorageWithPatch(patchNca, NcaSectionType.Data, FsIntegrityCheckLevel);
+ dataStorage = mainNca.OpenStorageWithPatch(patchNca, NcaSectionType.Data, _device.System.FsIntegrityCheckLevel);
}
if (patchNca.CanOpenSection(NcaSectionType.Code))
{
- codeFs = mainNca.OpenFileSystemWithPatch(patchNca, NcaSectionType.Code, FsIntegrityCheckLevel);
+ codeFs = mainNca.OpenFileSystemWithPatch(patchNca, NcaSectionType.Code, _device.System.FsIntegrityCheckLevel);
}
}
@@ -300,37 +306,65 @@ namespace Ryujinx.HLE.HOS
return;
}
- if (dataStorage == null)
+ Npdm metaData = ReadNpdm(codeFs);
+
+ _fileSystem.ModLoader.CollectMods(TitleId, _fileSystem.GetBaseModsPath());
+
+ if (controlNca != null)
{
- Logger.PrintWarning(LogClass.Loader, "No RomFS found in NCA");
+ ReadControlData(controlNca);
}
else
{
- _fileSystem.SetRomFs(dataStorage.AsStream(FileAccess.Read));
+ ControlData.ByteSpan.Clear();
}
- if (controlNca != null)
+ if (dataStorage == null)
{
- ReadControlData(controlNca);
+ Logger.PrintWarning(LogClass.Loader, "No RomFS found in NCA");
}
else
{
- ControlData.ByteSpan.Clear();
+ IStorage newStorage = _fileSystem.ModLoader.ApplyRomFsMods(TitleId, dataStorage);
+ _fileSystem.SetRomFs(newStorage.AsStream(FileAccess.Read));
}
- LoadExeFs(codeFs, out _);
-
if (TitleId != 0)
{
EnsureSaveData(new TitleId(TitleId));
}
+ LoadExeFs(codeFs, metaData);
+
Logger.PrintInfo(LogClass.Loader, $"Application Loaded: {TitleName} v{DisplayVersion} [{TitleIdText}] [{(TitleIs64Bit ? "64-bit" : "32-bit")}]");
}
- public void ReadControlData(Nca controlNca)
+ // Sets TitleId, so be sure to call before using it
+ private Npdm ReadNpdm(IFileSystem fs)
+ {
+ Result result = fs.OpenFile(out IFile npdmFile, "/main.npdm".ToU8Span(), OpenMode.Read);
+ Npdm metaData;
+
+ if (ResultFs.PathNotFound.Includes(result))
+ {
+ Logger.PrintWarning(LogClass.Loader, "NPDM file not found, using default values!");
+
+ metaData = GetDefaultNpdm();
+ }
+ else
+ {
+ metaData = new Npdm(npdmFile.AsStream());
+ }
+
+ TitleId = metaData.Aci0.TitleId;
+ TitleIs64Bit = metaData.Is64Bit;
+
+ return metaData;
+ }
+
+ private void ReadControlData(Nca controlNca)
{
- IFileSystem controlFs = controlNca.OpenFileSystem(NcaSectionType.Data, FsIntegrityCheckLevel);
+ IFileSystem controlFs = controlNca.OpenFileSystem(NcaSectionType.Data, _device.System.FsIntegrityCheckLevel);
Result result = controlFs.OpenFile(out IFile controlFile, "/control.nacp".ToU8Span(), OpenMode.Read);
@@ -358,26 +392,20 @@ namespace Ryujinx.HLE.HOS
}
}
- private void LoadExeFs(IFileSystem codeFs, out Npdm metaData)
+ private void LoadExeFs(IFileSystem codeFs, Npdm metaData = null)
{
- Result result = codeFs.OpenFile(out IFile npdmFile, "/main.npdm".ToU8Span(), OpenMode.Read);
-
- if (ResultFs.PathNotFound.Includes(result))
+ if (_fileSystem.ModLoader.ReplaceExefsPartition(TitleId, ref codeFs))
{
- Logger.PrintWarning(LogClass.Loader, "NPDM file not found, using default values!");
-
- metaData = GetDefaultNpdm();
- }
- else
- {
- metaData = new Npdm(npdmFile.AsStream());
+ metaData = null; //TODO: Check if we should retain old npdm
}
- List<IExecutable> nsos = new List<IExecutable>();
+ metaData ??= ReadNpdm(codeFs);
+
+ List<NsoExecutable> nsos = new List<NsoExecutable>();
- void LoadNso(string filename)
+ foreach (string exePrefix in ExeFsPrefixes) // Load binaries with standard prefixes
{
- foreach (DirectoryEntryEx file in codeFs.EnumerateEntries("/", $"{filename}*"))
+ foreach (DirectoryEntryEx file in codeFs.EnumerateEntries("/", exePrefix))
{
if (Path.GetExtension(file.Name) != string.Empty)
{
@@ -388,25 +416,29 @@ namespace Ryujinx.HLE.HOS
codeFs.OpenFile(out IFile nsoFile, file.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
- NsoExecutable nso = new NsoExecutable(nsoFile.AsStorage());
+ NsoExecutable nso = new NsoExecutable(nsoFile.AsStorage(), file.Name);
nsos.Add(nso);
}
}
- TitleId = metaData.Aci0.TitleId;
- TitleIs64Bit = metaData.Is64Bit;
+ // ExeFs file replacements
+ bool modified = _fileSystem.ModLoader.ApplyExefsMods(TitleId, nsos);
+
+ var programs = nsos.ToArray();
- LoadNso("rtld");
- LoadNso("main");
- LoadNso("subsdk");
- LoadNso("sdk");
+ modified |= _fileSystem.ModLoader.ApplyNsoPatches(TitleId, programs);
_contentManager.LoadEntries(_device);
- Ptc.Initialize(TitleIdText, DisplayVersion, EnablePtc);
+ if (EnablePtc && modified)
+ {
+ Logger.PrintWarning(LogClass.Ptc, $"Detected exefs modifications. PPTC disabled.");
+ }
+
+ Ptc.Initialize(TitleIdText, DisplayVersion, EnablePtc && !modified);
- ProgramLoader.LoadNsos(_device.System.KernelContext, metaData, executables: nsos.ToArray());
+ ProgramLoader.LoadNsos(_device.System.KernelContext, metaData, executables: programs);
}
public void LoadProgram(string filePath)
@@ -420,7 +452,7 @@ namespace Ryujinx.HLE.HOS
if (isNro)
{
FileStream input = new FileStream(filePath, FileMode.Open);
- NroExecutable obj = new NroExecutable(input);
+ NroExecutable obj = new NroExecutable(input.AsStorage());
executable = obj;
// homebrew NRO can actually have some data after the actual NRO
@@ -493,7 +525,7 @@ namespace Ryujinx.HLE.HOS
}
else
{
- executable = new NsoExecutable(new LocalStorage(filePath, FileAccess.Read));
+ executable = new NsoExecutable(new LocalStorage(filePath, FileAccess.Read), Path.GetFileNameWithoutExtension(filePath));
}
_contentManager.LoadEntries(_device);