aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.HLE/HOS')
-rw-r--r--Ryujinx.HLE/HOS/ApplicationLoader.cs908
-rw-r--r--Ryujinx.HLE/HOS/Horizon.cs5
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/ProcessTamperInfo.cs2
-rw-r--r--Ryujinx.HLE/HOS/ModLoader.cs9
-rw-r--r--Ryujinx.HLE/HOS/ProgramLoader.cs423
-rw-r--r--Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForApplication.cs2
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/ILibraryAppletSelfAccessor.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs35
-rw-r--r--Ryujinx.HLE/HOS/Services/Arp/ApplicationLaunchProperty.cs2
-rw-r--r--Ryujinx.HLE/HOS/Services/Caps/IScreenShotApplicationService.cs6
-rw-r--r--Ryujinx.HLE/HOS/Services/Fatal/IService.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs2
-rw-r--r--Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs2
-rw-r--r--Ryujinx.HLE/HOS/Services/Ns/Aoc/IAddOnContentManager.cs14
-rw-r--r--Ryujinx.HLE/HOS/Services/Ns/IApplicationManagerInterface.cs10
-rw-r--r--Ryujinx.HLE/HOS/Services/Ns/IReadOnlyApplicationControlDataInterface.cs9
-rw-r--r--Ryujinx.HLE/HOS/Services/Pctl/ParentalControlServiceFactory/IParentalControlService.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Sdb/Pdm/QueryService/QueryPlayStatisticsManager.cs7
18 files changed, 53 insertions, 1395 deletions
diff --git a/Ryujinx.HLE/HOS/ApplicationLoader.cs b/Ryujinx.HLE/HOS/ApplicationLoader.cs
deleted file mode 100644
index 82bd9b31..00000000
--- a/Ryujinx.HLE/HOS/ApplicationLoader.cs
+++ /dev/null
@@ -1,908 +0,0 @@
-using LibHac;
-using LibHac.Account;
-using LibHac.Common;
-using LibHac.Fs;
-using LibHac.Fs.Fsa;
-using LibHac.Fs.Shim;
-using LibHac.FsSystem;
-using LibHac.Loader;
-using LibHac.Ncm;
-using LibHac.Ns;
-using LibHac.Tools.Fs;
-using LibHac.Tools.FsSystem;
-using LibHac.Tools.FsSystem.NcaUtils;
-using Ryujinx.Common.Configuration;
-using Ryujinx.Common.Logging;
-using Ryujinx.Cpu;
-using Ryujinx.HLE.FileSystem;
-using Ryujinx.HLE.Loaders.Executables;
-using Ryujinx.Memory;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Text;
-using static Ryujinx.HLE.HOS.ModLoader;
-using ApplicationId = LibHac.Ncm.ApplicationId;
-using Path = System.IO.Path;
-
-namespace Ryujinx.HLE.HOS
-{
- using JsonHelper = Common.Utilities.JsonHelper;
-
- public class ApplicationLoader
- {
- // Binaries from exefs are loaded into mem in this order. Do not change.
- internal static readonly string[] ExeFsPrefixes =
- {
- "rtld",
- "main",
- "subsdk0",
- "subsdk1",
- "subsdk2",
- "subsdk3",
- "subsdk4",
- "subsdk5",
- "subsdk6",
- "subsdk7",
- "subsdk8",
- "subsdk9",
- "sdk"
- };
-
- private readonly Switch _device;
- private string _titleName;
- private string _displayVersion;
- private BlitStruct<ApplicationControlProperty> _controlData;
-
- public BlitStruct<ApplicationControlProperty> ControlData => _controlData;
- public string TitleName => _titleName;
- public string DisplayVersion => _displayVersion;
-
- public ulong TitleId { get; private set; }
- public bool TitleIs64Bit { get; private set; }
-
- public string TitleIdText => TitleId.ToString("x16");
-
- public IDiskCacheLoadState DiskCacheLoadState { get; private set; }
-
- public ApplicationLoader(Switch device)
- {
- _device = device;
- _controlData = new BlitStruct<ApplicationControlProperty>(1);
- }
-
- public void LoadCart(string exeFsDir, string romFsFile = null)
- {
- LocalFileSystem codeFs = new LocalFileSystem(exeFsDir);
-
- MetaLoader metaData = ReadNpdm(codeFs);
-
- _device.Configuration.VirtualFileSystem.ModLoader.CollectMods(
- new[] { TitleId },
- _device.Configuration.VirtualFileSystem.ModLoader.GetModsBasePath(),
- _device.Configuration.VirtualFileSystem.ModLoader.GetSdModsBasePath());
-
- if (TitleId != 0)
- {
- EnsureSaveData(new ApplicationId(TitleId));
- }
-
- ulong pid = LoadExeFs(codeFs, string.Empty, metaData);
-
- if (romFsFile != null)
- {
- _device.Configuration.VirtualFileSystem.LoadRomFs(pid, romFsFile);
- }
- }
-
- public static (Nca main, Nca patch, Nca control) GetGameData(VirtualFileSystem fileSystem, PartitionFileSystem pfs, int programIndex)
- {
- Nca mainNca = null;
- Nca patchNca = null;
- Nca controlNca = null;
-
- fileSystem.ImportTickets(pfs);
-
- foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
- {
- using var ncaFile = new UniqueRef<IFile>();
-
- pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
-
- Nca nca = new Nca(fileSystem.KeySet, ncaFile.Release().AsStorage());
-
- int ncaProgramIndex = (int)(nca.Header.TitleId & 0xF);
-
- if (ncaProgramIndex != programIndex)
- {
- continue;
- }
-
- if (nca.Header.ContentType == NcaContentType.Program)
- {
- int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program);
-
- if (nca.SectionExists(NcaSectionType.Data) && nca.Header.GetFsHeader(dataIndex).IsPatchSection())
- {
- patchNca = nca;
- }
- else
- {
- mainNca = nca;
- }
- }
- else if (nca.Header.ContentType == NcaContentType.Control)
- {
- controlNca = nca;
- }
- }
-
- return (mainNca, patchNca, controlNca);
- }
-
- public static (Nca patch, Nca control) GetGameUpdateDataFromPartition(VirtualFileSystem fileSystem, PartitionFileSystem pfs, string titleId, int programIndex)
- {
- Nca patchNca = null;
- Nca controlNca = null;
-
- fileSystem.ImportTickets(pfs);
-
- foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
- {
- using var ncaFile = new UniqueRef<IFile>();
-
- pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
-
- Nca nca = new Nca(fileSystem.KeySet, ncaFile.Release().AsStorage());
-
- int ncaProgramIndex = (int)(nca.Header.TitleId & 0xF);
-
- if (ncaProgramIndex != programIndex)
- {
- continue;
- }
-
- if ($"{nca.Header.TitleId.ToString("x16")[..^3]}000" != titleId)
- {
- break;
- }
-
- if (nca.Header.ContentType == NcaContentType.Program)
- {
- patchNca = nca;
- }
- else if (nca.Header.ContentType == NcaContentType.Control)
- {
- controlNca = nca;
- }
- }
-
- return (patchNca, controlNca);
- }
-
- public static (Nca patch, Nca control) GetGameUpdateData(VirtualFileSystem fileSystem, string titleId, int programIndex, out string updatePath)
- {
- updatePath = null;
-
- if (ulong.TryParse(titleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdBase))
- {
- // Clear the program index part.
- titleIdBase &= 0xFFFFFFFFFFFFFFF0;
-
- // Load update informations if existing.
- string titleUpdateMetadataPath = Path.Combine(AppDataManager.GamesDirPath, titleIdBase.ToString("x16"), "updates.json");
-
- if (File.Exists(titleUpdateMetadataPath))
- {
- updatePath = JsonHelper.DeserializeFromFile<TitleUpdateMetadata>(titleUpdateMetadataPath).Selected;
-
- if (File.Exists(updatePath))
- {
- FileStream file = new FileStream(updatePath, FileMode.Open, FileAccess.Read);
- PartitionFileSystem nsp = new PartitionFileSystem(file.AsStorage());
-
- return GetGameUpdateDataFromPartition(fileSystem, nsp, titleIdBase.ToString("x16"), programIndex);
- }
- }
- }
-
- return (null, null);
- }
-
- public void LoadXci(string xciFile)
- {
- FileStream file = new FileStream(xciFile, FileMode.Open, FileAccess.Read);
- Xci xci = new Xci(_device.Configuration.VirtualFileSystem.KeySet, file.AsStorage());
-
- if (!xci.HasPartition(XciPartitionType.Secure))
- {
- Logger.Error?.Print(LogClass.Loader, "Unable to load XCI: Could not find XCI secure partition");
-
- return;
- }
-
- PartitionFileSystem securePartition = xci.OpenPartition(XciPartitionType.Secure);
-
- Nca mainNca;
- Nca patchNca;
- Nca controlNca;
-
- try
- {
- (mainNca, patchNca, controlNca) = GetGameData(_device.Configuration.VirtualFileSystem, securePartition, _device.Configuration.UserChannelPersistence.Index);
-
- RegisterProgramMapInfo(securePartition).ThrowIfFailure();
- }
- catch (Exception e)
- {
- Logger.Error?.Print(LogClass.Loader, $"Unable to load XCI: {e.Message}");
-
- return;
- }
-
- if (mainNca == null)
- {
- Logger.Error?.Print(LogClass.Loader, "Unable to load XCI: Could not find Main NCA");
-
- return;
- }
-
- _device.Configuration.ContentManager.LoadEntries(_device);
- _device.Configuration.ContentManager.ClearAocData();
- _device.Configuration.ContentManager.AddAocData(securePartition, xciFile, mainNca.Header.TitleId, _device.Configuration.FsIntegrityCheckLevel);
-
- LoadNca(mainNca, patchNca, controlNca);
- }
-
- public void LoadNsp(string nspFile)
- {
- FileStream file = new FileStream(nspFile, FileMode.Open, FileAccess.Read);
- PartitionFileSystem nsp = new PartitionFileSystem(file.AsStorage());
-
- Nca mainNca;
- Nca patchNca;
- Nca controlNca;
-
- try
- {
- (mainNca, patchNca, controlNca) = GetGameData(_device.Configuration.VirtualFileSystem, nsp, _device.Configuration.UserChannelPersistence.Index);
-
- RegisterProgramMapInfo(nsp).ThrowIfFailure();
- }
- catch (Exception e)
- {
- Logger.Error?.Print(LogClass.Loader, $"Unable to load NSP: {e.Message}");
-
- return;
- }
-
- if (mainNca != null)
- {
- _device.Configuration.ContentManager.ClearAocData();
- _device.Configuration.ContentManager.AddAocData(nsp, nspFile, mainNca.Header.TitleId, _device.Configuration.FsIntegrityCheckLevel);
-
- LoadNca(mainNca, patchNca, controlNca);
-
- return;
- }
-
- // This is not a normal NSP, it's actually a ExeFS as a NSP
- LoadExeFs(nsp, null, isHomebrew: true);
- }
-
- public void LoadNca(string ncaFile)
- {
- FileStream file = new FileStream(ncaFile, FileMode.Open, FileAccess.Read);
- Nca nca = new Nca(_device.Configuration.VirtualFileSystem.KeySet, file.AsStorage(false));
-
- LoadNca(nca, null, null);
- }
-
- public void LoadServiceNca(string ncaFile)
- {
- FileStream file = new FileStream(ncaFile, FileMode.Open, FileAccess.Read);
- Nca mainNca = new Nca(_device.Configuration.VirtualFileSystem.KeySet, file.AsStorage(false));
-
- if (mainNca.Header.ContentType != NcaContentType.Program)
- {
- Logger.Error?.Print(LogClass.Loader, "Selected NCA is not a \"Program\" NCA");
-
- return;
- }
-
- IFileSystem codeFs = null;
-
- if (mainNca.CanOpenSection(NcaSectionType.Code))
- {
- codeFs = mainNca.OpenFileSystem(NcaSectionType.Code, _device.System.FsIntegrityCheckLevel);
- }
-
- if (codeFs == null)
- {
- Logger.Error?.Print(LogClass.Loader, "No ExeFS found in NCA");
-
- return;
- }
-
- using var npdmFile = new UniqueRef<IFile>();
-
- Result result = codeFs.OpenFile(ref npdmFile.Ref, "/main.npdm".ToU8Span(), OpenMode.Read);
-
- MetaLoader metaData;
-
- npdmFile.Get.GetSize(out long fileSize).ThrowIfFailure();
-
- var npdmBuffer = new byte[fileSize];
- npdmFile.Get.Read(out _, 0, npdmBuffer).ThrowIfFailure();
-
- metaData = new MetaLoader();
- metaData.Load(npdmBuffer).ThrowIfFailure();
-
- NsoExecutable[] nsos = new NsoExecutable[ExeFsPrefixes.Length];
-
- for (int i = 0; i < nsos.Length; i++)
- {
- string name = ExeFsPrefixes[i];
-
- if (!codeFs.FileExists($"/{name}"))
- {
- continue; // File doesn't exist, skip.
- }
-
- Logger.Info?.Print(LogClass.Loader, $"Loading {name}...");
-
- using var nsoFile = new UniqueRef<IFile>();
-
- codeFs.OpenFile(ref nsoFile.Ref, $"/{name}".ToU8Span(), OpenMode.Read).ThrowIfFailure();
-
- nsos[i] = new NsoExecutable(nsoFile.Release().AsStorage(), name);
- }
-
- // Collect the nsos, ignoring ones that aren't used.
- NsoExecutable[] programs = nsos.Where(x => x != null).ToArray();
-
- string displayVersion = _device.System.ContentManager.GetCurrentFirmwareVersion().VersionString;
- bool usePtc = _device.System.EnablePtc;
-
- metaData.GetNpdm(out Npdm npdm).ThrowIfFailure();
- ProgramInfo programInfo = new ProgramInfo(in npdm, displayVersion, usePtc, allowCodeMemoryForJit: false);
- ProgramLoader.LoadNsos(_device.System.KernelContext, metaData, programInfo, executables: programs);
-
- string titleIdText = npdm.Aci.ProgramId.Value.ToString("x16");
- bool titleIs64Bit = (npdm.Meta.Flags & 1) != 0;
-
- string programName = Encoding.ASCII.GetString(npdm.Meta.ProgramName).TrimEnd('\0');
-
- Logger.Info?.Print(LogClass.Loader, $"Service Loaded: {programName} [{titleIdText}] [{(titleIs64Bit ? "64-bit" : "32-bit")}]");
- }
-
- private void LoadNca(Nca mainNca, Nca patchNca, Nca controlNca)
- {
- if (mainNca.Header.ContentType != NcaContentType.Program)
- {
- Logger.Error?.Print(LogClass.Loader, "Selected NCA is not a \"Program\" NCA");
-
- return;
- }
-
- IStorage dataStorage = null;
- IFileSystem codeFs = null;
-
- (Nca updatePatchNca, Nca updateControlNca) = GetGameUpdateData(_device.Configuration.VirtualFileSystem, mainNca.Header.TitleId.ToString("x16"), _device.Configuration.UserChannelPersistence.Index, out _);
-
- if (updatePatchNca != null)
- {
- patchNca = updatePatchNca;
- }
-
- if (updateControlNca != null)
- {
- controlNca = updateControlNca;
- }
-
- // Load program 0 control NCA as we are going to need it for display version.
- (_, Nca updateProgram0ControlNca) = GetGameUpdateData(_device.Configuration.VirtualFileSystem, mainNca.Header.TitleId.ToString("x16"), 0, out _);
-
- // Load Aoc
- string titleAocMetadataPath = Path.Combine(AppDataManager.GamesDirPath, mainNca.Header.TitleId.ToString("x16"), "dlc.json");
-
- if (File.Exists(titleAocMetadataPath))
- {
- List<DownloadableContentContainer> dlcContainerList = JsonHelper.DeserializeFromFile<List<DownloadableContentContainer>>(titleAocMetadataPath);
-
- foreach (DownloadableContentContainer downloadableContentContainer in dlcContainerList)
- {
- foreach (DownloadableContentNca downloadableContentNca in downloadableContentContainer.DownloadableContentNcaList)
- {
- if (File.Exists(downloadableContentContainer.ContainerPath) && downloadableContentNca.Enabled)
- {
- _device.Configuration.ContentManager.AddAocItem(downloadableContentNca.TitleId, downloadableContentContainer.ContainerPath, downloadableContentNca.FullPath);
- }
- else
- {
- Logger.Warning?.Print(LogClass.Application, $"Cannot find AddOnContent file {downloadableContentContainer.ContainerPath}. It may have been moved or renamed.");
- }
- }
- }
- }
-
- if (patchNca == null)
- {
- if (mainNca.CanOpenSection(NcaSectionType.Data))
- {
- dataStorage = mainNca.OpenStorage(NcaSectionType.Data, _device.System.FsIntegrityCheckLevel);
- }
-
- if (mainNca.CanOpenSection(NcaSectionType.Code))
- {
- codeFs = mainNca.OpenFileSystem(NcaSectionType.Code, _device.System.FsIntegrityCheckLevel);
- }
- }
- else
- {
- if (patchNca.CanOpenSection(NcaSectionType.Data))
- {
- dataStorage = mainNca.OpenStorageWithPatch(patchNca, NcaSectionType.Data, _device.System.FsIntegrityCheckLevel);
- }
-
- if (patchNca.CanOpenSection(NcaSectionType.Code))
- {
- codeFs = mainNca.OpenFileSystemWithPatch(patchNca, NcaSectionType.Code, _device.System.FsIntegrityCheckLevel);
- }
- }
-
- if (codeFs == null)
- {
- Logger.Error?.Print(LogClass.Loader, "No ExeFS found in NCA");
-
- return;
- }
-
- MetaLoader metaData = ReadNpdm(codeFs);
-
- _device.Configuration.VirtualFileSystem.ModLoader.CollectMods(
- _device.Configuration.ContentManager.GetAocTitleIds().Prepend(TitleId),
- _device.Configuration.VirtualFileSystem.ModLoader.GetModsBasePath(),
- _device.Configuration.VirtualFileSystem.ModLoader.GetSdModsBasePath());
-
- string displayVersion = string.Empty;
-
- if (controlNca != null)
- {
- ReadControlData(_device, controlNca, ref _controlData, ref _titleName, ref displayVersion);
- }
- else
- {
- ControlData.ByteSpan.Clear();
- }
-
- // NOTE: Nintendo doesn't guarantee that the display version will be updated on sub programs when updating a multi program application.
- // BODY: As such, to avoid PTC cache confusion, we only trust the the program 0 display version when launching a sub program.
- if (updateProgram0ControlNca != null && _device.Configuration.UserChannelPersistence.Index != 0)
- {
- string dummyTitleName = "";
- BlitStruct<ApplicationControlProperty> dummyControl = new BlitStruct<ApplicationControlProperty>(1);
-
- ReadControlData(_device, updateProgram0ControlNca, ref dummyControl, ref dummyTitleName, ref displayVersion);
- }
-
- _displayVersion = displayVersion;
-
- ulong pid = LoadExeFs(codeFs, displayVersion, metaData);
-
- if (dataStorage == null)
- {
- Logger.Warning?.Print(LogClass.Loader, "No RomFS found in NCA");
- }
- else
- {
- IStorage newStorage = _device.Configuration.VirtualFileSystem.ModLoader.ApplyRomFsMods(TitleId, dataStorage);
-
- _device.Configuration.VirtualFileSystem.SetRomFs(pid, newStorage.AsStream(FileAccess.Read));
- }
-
- // Don't create save data for system programs.
- if (TitleId != 0 && (TitleId < SystemProgramId.Start.Value || TitleId > SystemAppletId.End.Value))
- {
- // Multi-program applications can technically use any program ID for the main program, but in practice they always use 0 in the low nibble.
- // We'll know if this changes in the future because stuff will get errors when trying to mount the correct save.
- EnsureSaveData(new ApplicationId(TitleId & ~0xFul));
- }
-
- Logger.Info?.Print(LogClass.Loader, $"Application Loaded: {TitleName} v{DisplayVersion} [{TitleIdText}] [{(TitleIs64Bit ? "64-bit" : "32-bit")}]");
- }
-
- // Sets TitleId, so be sure to call before using it
- private MetaLoader ReadNpdm(IFileSystem fs)
- {
- using var npdmFile = new UniqueRef<IFile>();
-
- Result result = fs.OpenFile(ref npdmFile.Ref, "/main.npdm".ToU8Span(), OpenMode.Read);
-
- MetaLoader metaData;
-
- if (ResultFs.PathNotFound.Includes(result))
- {
- Logger.Warning?.Print(LogClass.Loader, "NPDM file not found, using default values!");
-
- metaData = GetDefaultNpdm();
- }
- else
- {
- npdmFile.Get.GetSize(out long fileSize).ThrowIfFailure();
-
- var npdmBuffer = new byte[fileSize];
- npdmFile.Get.Read(out _, 0, npdmBuffer).ThrowIfFailure();
-
- metaData = new MetaLoader();
- metaData.Load(npdmBuffer).ThrowIfFailure();
- }
-
- metaData.GetNpdm(out var npdm).ThrowIfFailure();
-
- TitleId = npdm.Aci.ProgramId.Value;
- TitleIs64Bit = (npdm.Meta.Flags & 1) != 0;
- _device.System.LibHacHorizonManager.ArpIReader.ApplicationId = new LibHac.ApplicationId(TitleId);
-
- return metaData;
- }
-
- private static void ReadControlData(Switch device, Nca controlNca, ref BlitStruct<ApplicationControlProperty> controlData, ref string titleName, ref string displayVersion)
- {
- using var controlFile = new UniqueRef<IFile>();
-
- IFileSystem controlFs = controlNca.OpenFileSystem(NcaSectionType.Data, device.System.FsIntegrityCheckLevel);
- Result result = controlFs.OpenFile(ref controlFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read);
-
- if (result.IsSuccess())
- {
- result = controlFile.Get.Read(out long bytesRead, 0, controlData.ByteSpan, ReadOption.None);
-
- if (result.IsSuccess() && bytesRead == controlData.ByteSpan.Length)
- {
- titleName = controlData.Value.Title[(int)device.System.State.DesiredTitleLanguage].NameString.ToString();
-
- if (string.IsNullOrWhiteSpace(titleName))
- {
- titleName = controlData.Value.Title.ItemsRo.ToArray().FirstOrDefault(x => x.Name[0] != 0).NameString.ToString();
- }
-
- displayVersion = controlData.Value.DisplayVersionString.ToString();
- }
- }
- else
- {
- controlData.ByteSpan.Clear();
- }
- }
-
- private ulong LoadExeFs(IFileSystem codeFs, string displayVersion, MetaLoader metaData = null, bool isHomebrew = false)
- {
- if (_device.Configuration.VirtualFileSystem.ModLoader.ReplaceExefsPartition(TitleId, ref codeFs))
- {
- metaData = null; // TODO: Check if we should retain old npdm.
- }
-
- metaData ??= ReadNpdm(codeFs);
-
- NsoExecutable[] nsos = new NsoExecutable[ExeFsPrefixes.Length];
-
- for (int i = 0; i < nsos.Length; i++)
- {
- string name = ExeFsPrefixes[i];
-
- if (!codeFs.FileExists($"/{name}"))
- {
- continue; // File doesn't exist, skip.
- }
-
- Logger.Info?.Print(LogClass.Loader, $"Loading {name}...");
-
- using var nsoFile = new UniqueRef<IFile>();
-
- codeFs.OpenFile(ref nsoFile.Ref, $"/{name}".ToU8Span(), OpenMode.Read).ThrowIfFailure();
-
- nsos[i] = new NsoExecutable(nsoFile.Release().AsStorage(), name);
- }
-
- // ExeFs file replacements.
- ModLoadResult modLoadResult = _device.Configuration.VirtualFileSystem.ModLoader.ApplyExefsMods(TitleId, nsos);
-
- // Collect the nsos, ignoring ones that aren't used.
- NsoExecutable[] programs = nsos.Where(x => x != null).ToArray();
-
- // Take the npdm from mods if present.
- if (modLoadResult.Npdm != null)
- {
- metaData = modLoadResult.Npdm;
- }
-
- _device.Configuration.VirtualFileSystem.ModLoader.ApplyNsoPatches(TitleId, programs);
-
- _device.Configuration.ContentManager.LoadEntries(_device);
-
- bool usePtc = _device.System.EnablePtc;
-
- // Don't use PPTC if ExeFs files have been replaced.
- usePtc &= !modLoadResult.Modified;
-
- if (_device.System.EnablePtc && !usePtc)
- {
- Logger.Warning?.Print(LogClass.Ptc, $"Detected unsupported ExeFs modifications. PPTC disabled.");
- }
-
- Graphics.Gpu.GraphicsConfig.TitleId = TitleIdText;
- _device.Gpu.HostInitalized.Set();
-
- MemoryManagerMode memoryManagerMode = _device.Configuration.MemoryManagerMode;
-
- if (!MemoryBlock.SupportsFlags(MemoryAllocationFlags.ViewCompatible))
- {
- memoryManagerMode = MemoryManagerMode.SoftwarePageTable;
- }
-
- // We allow it for nx-hbloader because it can be used to launch homebrew.
- bool allowCodeMemoryForJit = TitleId == 0x010000000000100DUL || isHomebrew;
-
- metaData.GetNpdm(out Npdm npdm).ThrowIfFailure();
- ProgramInfo programInfo = new ProgramInfo(in npdm, displayVersion, usePtc, allowCodeMemoryForJit);
- ProgramLoadResult result = ProgramLoader.LoadNsos(_device.System.KernelContext, metaData, programInfo, executables: programs);
-
- DiskCacheLoadState = result.DiskCacheLoadState;
-
- _device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, result.TamperInfo, _device.TamperMachine);
-
- return result.ProcessId;
- }
-
- public void LoadProgram(string filePath)
- {
- MetaLoader metaData = GetDefaultNpdm();
- metaData.GetNpdm(out Npdm npdm).ThrowIfFailure();
- ProgramInfo programInfo = new ProgramInfo(in npdm, string.Empty, diskCacheEnabled: false, allowCodeMemoryForJit: true);
-
- bool isNro = Path.GetExtension(filePath).ToLower() == ".nro";
-
- IExecutable executable;
- Stream romfsStream = null;
-
- if (isNro)
- {
- FileStream input = new FileStream(filePath, FileMode.Open);
- NroExecutable obj = new NroExecutable(input.AsStorage());
-
- executable = obj;
-
- // Homebrew NRO can actually have some data after the actual NRO.
- if (input.Length > obj.FileSize)
- {
- input.Position = obj.FileSize;
-
- BinaryReader reader = new BinaryReader(input);
-
- uint asetMagic = reader.ReadUInt32();
- if (asetMagic == 0x54455341)
- {
- uint asetVersion = reader.ReadUInt32();
- if (asetVersion == 0)
- {
- ulong iconOffset = reader.ReadUInt64();
- ulong iconSize = reader.ReadUInt64();
-
- ulong nacpOffset = reader.ReadUInt64();
- ulong nacpSize = reader.ReadUInt64();
-
- ulong romfsOffset = reader.ReadUInt64();
- ulong romfsSize = reader.ReadUInt64();
-
- if (romfsSize != 0)
- {
- romfsStream = new HomebrewRomFsStream(input, obj.FileSize + (long)romfsOffset);
- }
-
- if (nacpSize != 0)
- {
- input.Seek(obj.FileSize + (long)nacpOffset, SeekOrigin.Begin);
-
- reader.Read(ControlData.ByteSpan);
-
- ref ApplicationControlProperty nacp = ref ControlData.Value;
-
- programInfo.Name = nacp.Title[(int)_device.System.State.DesiredTitleLanguage].NameString.ToString();
-
- if (string.IsNullOrWhiteSpace(programInfo.Name))
- {
- programInfo.Name = nacp.Title.ItemsRo.ToArray().FirstOrDefault(x => x.Name[0] != 0).NameString.ToString();
- }
-
- if (nacp.PresenceGroupId != 0)
- {
- programInfo.ProgramId = nacp.PresenceGroupId;
- }
- else if (nacp.SaveDataOwnerId != 0)
- {
- programInfo.ProgramId = nacp.SaveDataOwnerId;
- }
- else if (nacp.AddOnContentBaseId != 0)
- {
- programInfo.ProgramId = nacp.AddOnContentBaseId - 0x1000;
- }
- else
- {
- programInfo.ProgramId = 0000000000000000;
- }
- }
- }
- else
- {
- Logger.Warning?.Print(LogClass.Loader, $"Unsupported ASET header version found \"{asetVersion}\"");
- }
- }
- }
- }
- else
- {
- executable = new NsoExecutable(new LocalStorage(filePath, FileAccess.Read), Path.GetFileNameWithoutExtension(filePath));
- }
-
- _device.Configuration.ContentManager.LoadEntries(_device);
-
- _titleName = programInfo.Name;
- TitleId = programInfo.ProgramId;
- TitleIs64Bit = (npdm.Meta.Flags & 1) != 0;
- _device.System.LibHacHorizonManager.ArpIReader.ApplicationId = new LibHac.ApplicationId(TitleId);
-
- // Explicitly null titleid to disable the shader cache.
- Graphics.Gpu.GraphicsConfig.TitleId = null;
- _device.Gpu.HostInitalized.Set();
-
- ProgramLoadResult result = ProgramLoader.LoadNsos(_device.System.KernelContext, metaData, programInfo, executables: executable);
-
- if (romfsStream != null)
- {
- _device.Configuration.VirtualFileSystem.SetRomFs(result.ProcessId, romfsStream);
- }
-
- DiskCacheLoadState = result.DiskCacheLoadState;
-
- _device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, result.TamperInfo, _device.TamperMachine);
- }
-
- private MetaLoader GetDefaultNpdm()
- {
- Assembly asm = Assembly.GetCallingAssembly();
-
- using (Stream npdmStream = asm.GetManifestResourceStream("Ryujinx.HLE.Homebrew.npdm"))
- {
- var npdmBuffer = new byte[npdmStream.Length];
- npdmStream.Read(npdmBuffer);
-
- var metaLoader = new MetaLoader();
- metaLoader.Load(npdmBuffer).ThrowIfFailure();
-
- return metaLoader;
- }
- }
-
- private static (ulong applicationId, int programCount) GetMultiProgramInfo(VirtualFileSystem fileSystem, PartitionFileSystem pfs)
- {
- ulong mainProgramId = 0;
- Span<bool> hasIndex = stackalloc bool[0x10];
-
- fileSystem.ImportTickets(pfs);
-
- foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
- {
- using var ncaFile = new UniqueRef<IFile>();
-
- pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
-
- Nca nca = new Nca(fileSystem.KeySet, ncaFile.Release().AsStorage());
-
- if (nca.Header.ContentType != NcaContentType.Program)
- {
- continue;
- }
-
- int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program);
-
- if (nca.SectionExists(NcaSectionType.Data) && nca.Header.GetFsHeader(dataIndex).IsPatchSection())
- {
- continue;
- }
-
- ulong currentProgramId = nca.Header.TitleId;
- ulong currentMainProgramId = currentProgramId & ~0xFFFul;
-
- if (mainProgramId == 0 && currentMainProgramId != 0)
- {
- mainProgramId = currentMainProgramId;
- }
-
- if (mainProgramId != currentMainProgramId)
- {
- // As far as I know there aren't any multi-application game cards containing multi-program applications,
- // so because multi-application game cards are the only way we should run into multiple applications
- // we'll just return that there's a single program.
- return (mainProgramId, 1);
- }
-
- hasIndex[(int)(currentProgramId & 0xF)] = true;
- }
-
- int programCount = 0;
-
- for (int i = 0; i < hasIndex.Length && hasIndex[i]; i++)
- {
- programCount++;
- }
-
- return (mainProgramId, programCount);
- }
-
- private Result RegisterProgramMapInfo(PartitionFileSystem pfs)
- {
- (ulong applicationId, int programCount) = GetMultiProgramInfo(_device.Configuration.VirtualFileSystem, pfs);
-
- if (programCount <= 0)
- return Result.Success;
-
- Span<ProgramIndexMapInfo> mapInfo = stackalloc ProgramIndexMapInfo[0x10];
-
- for (int i = 0; i < programCount; i++)
- {
- mapInfo[i].ProgramId = new ProgramId(applicationId + (uint)i);
- mapInfo[i].MainProgramId = new ApplicationId(applicationId);
- mapInfo[i].ProgramIndex = (byte)i;
- }
-
- return _device.System.LibHacHorizonManager.NsClient.Fs.RegisterProgramIndexMapInfo(mapInfo.Slice(0, programCount));
- }
-
- private Result EnsureSaveData(ApplicationId applicationId)
- {
- Logger.Info?.Print(LogClass.Application, "Ensuring required savedata exists.");
-
- Uid user = _device.System.AccountManager.LastOpenedUser.UserId.ToLibHacUid();
-
- ref ApplicationControlProperty control = ref ControlData.Value;
-
- if (LibHac.Common.Utilities.IsZeros(ControlData.ByteSpan))
- {
- // If the current application doesn't have a loaded control property, create a dummy one
- // and set the savedata sizes so a user savedata will be created.
- control = ref new BlitStruct<ApplicationControlProperty>(1).Value;
-
- // The set sizes don't actually matter as long as they're non-zero because we use directory savedata.
- control.UserAccountSaveDataSize = 0x4000;
- control.UserAccountSaveDataJournalSize = 0x4000;
- control.SaveDataOwnerId = applicationId.Value;
-
- Logger.Warning?.Print(LogClass.Application,
- "No control file was found for this game. Using a dummy one instead. This may cause inaccuracies in some games.");
- }
-
- HorizonClient hos = _device.System.LibHacHorizonManager.RyujinxClient;
- Result resultCode = hos.Fs.EnsureApplicationCacheStorage(out _, out _, applicationId, in control);
-
- if (resultCode.IsFailure())
- {
- Logger.Error?.Print(LogClass.Application, $"Error calling EnsureApplicationCacheStorage. Result code {resultCode.ToStringWithName()}");
-
- return resultCode;
- }
-
- resultCode = hos.Fs.EnsureApplicationSaveData(out _, applicationId, in control, in user);
-
- if (resultCode.IsFailure())
- {
- Logger.Error?.Print(LogClass.Application, $"Error calling EnsureApplicationSaveData. Result code {resultCode.ToStringWithName()}");
- }
-
- return resultCode;
- }
- }
-}
diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs
index 2b77a7c2..1639532e 100644
--- a/Ryujinx.HLE/HOS/Horizon.cs
+++ b/Ryujinx.HLE/HOS/Horizon.cs
@@ -35,6 +35,7 @@ using Ryujinx.HLE.HOS.Services.SurfaceFlinger;
using Ryujinx.HLE.HOS.Services.Time.Clock;
using Ryujinx.HLE.HOS.SystemState;
using Ryujinx.HLE.Loaders.Executables;
+using Ryujinx.HLE.Loaders.Processes;
using Ryujinx.Horizon;
using System;
using System.Collections.Generic;
@@ -358,11 +359,11 @@ namespace Ryujinx.HLE.HOS
}
}
- public void LoadKip(string kipPath)
+ public bool LoadKip(string kipPath)
{
using var kipFile = new SharedRef<IStorage>(new LocalStorage(kipPath, FileAccess.Read));
- ProgramLoader.LoadKip(KernelContext, new KipExecutable(in kipFile));
+ return ProcessLoaderHelper.LoadKip(KernelContext, new KipExecutable(in kipFile));
}
public void ChangeDockedModeState(bool newState)
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/ProcessTamperInfo.cs b/Ryujinx.HLE/HOS/Kernel/Process/ProcessTamperInfo.cs
index 556703cf..4cf67172 100644
--- a/Ryujinx.HLE/HOS/Kernel/Process/ProcessTamperInfo.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Process/ProcessTamperInfo.cs
@@ -2,7 +2,7 @@ using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Kernel.Process
{
- internal class ProcessTamperInfo
+ class ProcessTamperInfo
{
public KProcess Process { get; }
public IEnumerable<string> BuildIds { get; }
diff --git a/Ryujinx.HLE/HOS/ModLoader.cs b/Ryujinx.HLE/HOS/ModLoader.cs
index a6dc9013..16512541 100644
--- a/Ryujinx.HLE/HOS/ModLoader.cs
+++ b/Ryujinx.HLE/HOS/ModLoader.cs
@@ -10,6 +10,7 @@ using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.Loaders.Executables;
using Ryujinx.HLE.Loaders.Mods;
+using Ryujinx.HLE.Loaders.Processes;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
@@ -547,7 +548,7 @@ namespace Ryujinx.HLE.HOS
return modLoadResult;
}
- if (nsos.Length != ApplicationLoader.ExeFsPrefixes.Length)
+ if (nsos.Length != ProcessConst.ExeFsPrefixes.Length)
{
throw new ArgumentOutOfRangeException("NSO Count is incorrect");
}
@@ -556,9 +557,9 @@ namespace Ryujinx.HLE.HOS
foreach (var mod in exeMods)
{
- for (int i = 0; i < ApplicationLoader.ExeFsPrefixes.Length; ++i)
+ for (int i = 0; i < ProcessConst.ExeFsPrefixes.Length; ++i)
{
- var nsoName = ApplicationLoader.ExeFsPrefixes[i];
+ var nsoName = ProcessConst.ExeFsPrefixes[i];
FileInfo nsoFile = new FileInfo(Path.Combine(mod.Path.FullName, nsoName));
if (nsoFile.Exists)
@@ -596,7 +597,7 @@ namespace Ryujinx.HLE.HOS
}
}
- for (int i = ApplicationLoader.ExeFsPrefixes.Length - 1; i >= 0; --i)
+ for (int i = ProcessConst.ExeFsPrefixes.Length - 1; i >= 0; --i)
{
if (modLoadResult.Stubs[1 << i] && !modLoadResult.Replaces[1 << i]) // Prioritizes replacements over stubs
{
diff --git a/Ryujinx.HLE/HOS/ProgramLoader.cs b/Ryujinx.HLE/HOS/ProgramLoader.cs
deleted file mode 100644
index 4ebcb7e7..00000000
--- a/Ryujinx.HLE/HOS/ProgramLoader.cs
+++ /dev/null
@@ -1,423 +0,0 @@
-using LibHac.Loader;
-using LibHac.Ncm;
-using LibHac.Util;
-using Ryujinx.Common;
-using Ryujinx.Common.Logging;
-using Ryujinx.Cpu;
-using Ryujinx.HLE.HOS.Kernel;
-using Ryujinx.HLE.HOS.Kernel.Common;
-using Ryujinx.HLE.HOS.Kernel.Memory;
-using Ryujinx.HLE.HOS.Kernel.Process;
-using Ryujinx.HLE.Loaders.Executables;
-using Ryujinx.Horizon.Common;
-using System;
-using System.Linq;
-using System.Runtime.InteropServices;
-using Npdm = LibHac.Loader.Npdm;
-
-namespace Ryujinx.HLE.HOS
-{
- struct ProgramInfo
- {
- public string Name;
- public ulong ProgramId;
- public readonly string TitleIdText;
- public readonly string DisplayVersion;
- public readonly bool DiskCacheEnabled;
- public readonly bool AllowCodeMemoryForJit;
-
- public ProgramInfo(in Npdm npdm, string displayVersion, bool diskCacheEnabled, bool allowCodeMemoryForJit)
- {
- ulong programId = npdm.Aci.ProgramId.Value;
-
- Name = StringUtils.Utf8ZToString(npdm.Meta.ProgramName);
- ProgramId = programId;
- TitleIdText = programId.ToString("x16");
- DisplayVersion = displayVersion;
- DiskCacheEnabled = diskCacheEnabled;
- AllowCodeMemoryForJit = allowCodeMemoryForJit;
- }
- }
-
- struct ProgramLoadResult
- {
- public static ProgramLoadResult Failed => new ProgramLoadResult(false, null, null, 0);
-
- public readonly bool Success;
- public readonly ProcessTamperInfo TamperInfo;
- public readonly IDiskCacheLoadState DiskCacheLoadState;
- public readonly ulong ProcessId;
-
- public ProgramLoadResult(bool success, ProcessTamperInfo tamperInfo, IDiskCacheLoadState diskCacheLoadState, ulong pid)
- {
- Success = success;
- TamperInfo = tamperInfo;
- DiskCacheLoadState = diskCacheLoadState;
- ProcessId = pid;
- }
- }
-
- static class ProgramLoader
- {
- private const bool AslrEnabled = true;
-
- private const int ArgsHeaderSize = 8;
- private const int ArgsDataSize = 0x9000;
- private const int ArgsTotalSize = ArgsHeaderSize + ArgsDataSize;
-
- public static bool LoadKip(KernelContext context, KipExecutable kip)
- {
- uint endOffset = kip.DataOffset + (uint)kip.Data.Length;
-
- if (kip.BssSize != 0)
- {
- endOffset = kip.BssOffset + kip.BssSize;
- }
-
- uint codeSize = BitUtils.AlignUp<uint>(kip.TextOffset + endOffset, KPageTableBase.PageSize);
-
- int codePagesCount = (int)(codeSize / KPageTableBase.PageSize);
-
- ulong codeBaseAddress = kip.Is64BitAddressSpace ? 0x8000000UL : 0x200000UL;
-
- ulong codeAddress = codeBaseAddress + kip.TextOffset;
-
- ProcessCreationFlags flags = 0;
-
- if (AslrEnabled)
- {
- // TODO: Randomization.
-
- flags |= ProcessCreationFlags.EnableAslr;
- }
-
- if (kip.Is64BitAddressSpace)
- {
- flags |= ProcessCreationFlags.AddressSpace64Bit;
- }
-
- if (kip.Is64Bit)
- {
- flags |= ProcessCreationFlags.Is64Bit;
- }
-
- ProcessCreationInfo creationInfo = new ProcessCreationInfo(
- kip.Name,
- kip.Version,
- kip.ProgramId,
- codeAddress,
- codePagesCount,
- flags,
- 0,
- 0);
-
- MemoryRegion memoryRegion = kip.UsesSecureMemory
- ? MemoryRegion.Service
- : MemoryRegion.Application;
-
- KMemoryRegionManager region = context.MemoryManager.MemoryRegions[(int)memoryRegion];
-
- Result result = region.AllocatePages(out KPageList pageList, (ulong)codePagesCount);
-
- if (result != Result.Success)
- {
- Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");
-
- return false;
- }
-
- KProcess process = new KProcess(context);
-
- var processContextFactory = new ArmProcessContextFactory(
- context.Device.System.TickSource,
- context.Device.Gpu,
- string.Empty,
- string.Empty,
- false,
- codeAddress,
- codeSize);
-
- result = process.InitializeKip(
- creationInfo,
- kip.Capabilities,
- pageList,
- context.ResourceLimit,
- memoryRegion,
- processContextFactory);
-
- if (result != Result.Success)
- {
- Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");
-
- return false;
- }
-
- result = LoadIntoMemory(process, kip, codeBaseAddress);
-
- if (result != Result.Success)
- {
- Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");
-
- return false;
- }
-
- process.DefaultCpuCore = kip.IdealCoreId;
-
- result = process.Start(kip.Priority, (ulong)kip.StackSize);
-
- if (result != Result.Success)
- {
- Logger.Error?.Print(LogClass.Loader, $"Process start returned error \"{result}\".");
-
- return false;
- }
-
- context.Processes.TryAdd(process.Pid, process);
-
- return true;
- }
-
- public static ProgramLoadResult LoadNsos(
- KernelContext context,
- MetaLoader metaData,
- ProgramInfo programInfo,
- byte[] arguments = null,
- params IExecutable[] executables)
- {
- context.Device.System.ServiceTable.WaitServicesReady();
-
- LibHac.Result rc = metaData.GetNpdm(out var npdm);
-
- if (rc.IsFailure())
- {
- return ProgramLoadResult.Failed;
- }
-
- ref readonly var meta = ref npdm.Meta;
-
- ulong argsStart = 0;
- uint argsSize = 0;
- ulong codeStart = (meta.Flags & 1) != 0 ? 0x8000000UL : 0x200000UL;
- uint codeSize = 0;
-
- var buildIds = executables.Select(e => (e switch
- {
- NsoExecutable nso => BitConverter.ToString(nso.BuildId.ItemsRo.ToArray()),
- NroExecutable nro => BitConverter.ToString(nro.Header.BuildId),
- _ => ""
- }).Replace("-", "").ToUpper());
-
- ulong[] nsoBase = new ulong[executables.Length];
-
- for (int index = 0; index < executables.Length; index++)
- {
- IExecutable nso = executables[index];
-
- uint textEnd = nso.TextOffset + (uint)nso.Text.Length;
- uint roEnd = nso.RoOffset + (uint)nso.Ro.Length;
- uint dataEnd = nso.DataOffset + (uint)nso.Data.Length + nso.BssSize;
-
- uint nsoSize = textEnd;
-
- if (nsoSize < roEnd)
- {
- nsoSize = roEnd;
- }
-
- if (nsoSize < dataEnd)
- {
- nsoSize = dataEnd;
- }
-
- nsoSize = BitUtils.AlignUp<uint>(nsoSize, KPageTableBase.PageSize);
-
- nsoBase[index] = codeStart + codeSize;
-
- codeSize += nsoSize;
-
- if (arguments != null && argsSize == 0)
- {
- argsStart = codeSize;
-
- argsSize = (uint)BitUtils.AlignDown(arguments.Length * 2 + ArgsTotalSize - 1, KPageTableBase.PageSize);
-
- codeSize += argsSize;
- }
- }
-
- int codePagesCount = (int)(codeSize / KPageTableBase.PageSize);
-
- int personalMmHeapPagesCount = (int)(meta.SystemResourceSize / KPageTableBase.PageSize);
-
- ProcessCreationInfo creationInfo = new ProcessCreationInfo(
- programInfo.Name,
- (int)meta.Version,
- programInfo.ProgramId,
- codeStart,
- codePagesCount,
- (ProcessCreationFlags)meta.Flags | ProcessCreationFlags.IsApplication,
- 0,
- personalMmHeapPagesCount);
-
- context.Device.System.LibHacHorizonManager.InitializeApplicationClient(new ProgramId(programInfo.ProgramId), in npdm);
-
- Result result;
-
- KResourceLimit resourceLimit = new KResourceLimit(context);
-
- long applicationRgSize = (long)context.MemoryManager.MemoryRegions[(int)MemoryRegion.Application].Size;
-
- result = resourceLimit.SetLimitValue(LimitableResource.Memory, applicationRgSize);
-
- if (result.IsSuccess)
- {
- result = resourceLimit.SetLimitValue(LimitableResource.Thread, 608);
- }
-
- if (result.IsSuccess)
- {
- result = resourceLimit.SetLimitValue(LimitableResource.Event, 700);
- }
-
- if (result.IsSuccess)
- {
- result = resourceLimit.SetLimitValue(LimitableResource.TransferMemory, 128);
- }
-
- if (result.IsSuccess)
- {
- result = resourceLimit.SetLimitValue(LimitableResource.Session, 894);
- }
-
- if (result != Result.Success)
- {
- Logger.Error?.Print(LogClass.Loader, $"Process initialization failed setting resource limit values.");
-
- return ProgramLoadResult.Failed;
- }
-
- KProcess process = new KProcess(context, programInfo.AllowCodeMemoryForJit);
-
- MemoryRegion memoryRegion = (MemoryRegion)((npdm.Acid.Flags >> 2) & 0xf);
-
- if (memoryRegion > MemoryRegion.NvServices)
- {
- Logger.Error?.Print(LogClass.Loader, $"Process initialization failed due to invalid ACID flags.");
-
- return ProgramLoadResult.Failed;
- }
-
- var processContextFactory = new ArmProcessContextFactory(
- context.Device.System.TickSource,
- context.Device.Gpu,
- programInfo.TitleIdText,
- programInfo.DisplayVersion,
- programInfo.DiskCacheEnabled,
- codeStart,
- codeSize);
-
- result = process.Initialize(
- creationInfo,
- MemoryMarshal.Cast<byte, uint>(npdm.KernelCapabilityData),
- resourceLimit,
- memoryRegion,
- processContextFactory);
-
- if (result != Result.Success)
- {
- Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");
-
- return ProgramLoadResult.Failed;
- }
-
- for (int index = 0; index < executables.Length; index++)
- {
- Logger.Info?.Print(LogClass.Loader, $"Loading image {index} at 0x{nsoBase[index]:x16}...");
-
- result = LoadIntoMemory(process, executables[index], nsoBase[index]);
-
- if (result != Result.Success)
- {
- Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");
-
- return ProgramLoadResult.Failed;
- }
- }
-
- process.DefaultCpuCore = meta.DefaultCpuId;
-
- result = process.Start(meta.MainThreadPriority, meta.MainThreadStackSize);
-
- if (result != Result.Success)
- {
- Logger.Error?.Print(LogClass.Loader, $"Process start returned error \"{result}\".");
-
- return ProgramLoadResult.Failed;
- }
-
- context.Processes.TryAdd(process.Pid, process);
-
- // Keep the build ids because the tamper machine uses them to know which process to associate a
- // tamper to and also keep the starting address of each executable inside a process because some
- // memory modifications are relative to this address.
- ProcessTamperInfo tamperInfo = new ProcessTamperInfo(
- process,
- buildIds,
- nsoBase,
- process.MemoryManager.HeapRegionStart,
- process.MemoryManager.AliasRegionStart,
- process.MemoryManager.CodeRegionStart);
-
- return new ProgramLoadResult(true, tamperInfo, processContextFactory.DiskCacheLoadState, process.Pid);
- }
-
- private static Result LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress)
- {
- ulong textStart = baseAddress + image.TextOffset;
- ulong roStart = baseAddress + image.RoOffset;
- ulong dataStart = baseAddress + image.DataOffset;
- ulong bssStart = baseAddress + image.BssOffset;
-
- ulong end = dataStart + (ulong)image.Data.Length;
-
- if (image.BssSize != 0)
- {
- end = bssStart + image.BssSize;
- }
-
- process.CpuMemory.Write(textStart, image.Text);
- process.CpuMemory.Write(roStart, image.Ro);
- process.CpuMemory.Write(dataStart, image.Data);
-
- process.CpuMemory.Fill(bssStart, image.BssSize, 0);
-
- Result SetProcessMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
- {
- if (size == 0)
- {
- return Result.Success;
- }
-
- size = BitUtils.AlignUp<ulong>(size, KPageTableBase.PageSize);
-
- return process.MemoryManager.SetProcessMemoryPermission(address, size, permission);
- }
-
- Result result = SetProcessMemoryPermission(textStart, (ulong)image.Text.Length, KMemoryPermission.ReadAndExecute);
-
- if (result != Result.Success)
- {
- return result;
- }
-
- result = SetProcessMemoryPermission(roStart, (ulong)image.Ro.Length, KMemoryPermission.Read);
-
- if (result != Result.Success)
- {
- return result;
- }
-
- return SetProcessMemoryPermission(dataStart, end - dataStart, KMemoryPermission.ReadAndWrite);
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForApplication.cs b/Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForApplication.cs
index 1b412d74..413bedce 100644
--- a/Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForApplication.cs
+++ b/Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForApplication.cs
@@ -190,7 +190,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
// TODO: Account actually calls nn::arp::detail::IReader::GetApplicationControlProperty() with the current Pid and store the result (NACP file) internally.
// But since we use LibHac and we load one Application at a time, it's not necessary.
- context.ResponseData.Write((byte)context.Device.Application.ControlData.Value.UserAccountSwitchLock);
+ context.ResponseData.Write((byte)context.Device.Processes.ActiveApplication.ApplicationControlProperties.UserAccountSwitchLock);
Logger.Stub?.PrintStub(LogClass.ServiceAcc);
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/ILibraryAppletSelfAccessor.cs b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/ILibraryAppletSelfAccessor.cs
index 00081e1b..72049714 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/ILibraryAppletSelfAccessor.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletAE/AllSystemAppletProxiesService/LibraryAppletProxy/ILibraryAppletSelfAccessor.cs
@@ -9,7 +9,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
public ILibraryAppletSelfAccessor(ServiceCtx context)
{
- if (context.Device.Application.TitleId == 0x0100000000001009)
+ if (context.Device.Processes.ActiveApplication.ProgramId == 0x0100000000001009)
{
// Create MiiEdit data.
_appletStandalone = new AppletStandalone()
@@ -25,7 +25,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
}
else
{
- throw new NotImplementedException($"{context.Device.Application.TitleId} applet is not implemented.");
+ throw new NotImplementedException($"{context.Device.Processes.ActiveApplication.ProgramId} applet is not implemented.");
}
}
diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs b/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs
index f8f88a1c..924f5429 100644
--- a/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs
+++ b/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs
@@ -115,28 +115,12 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
Uid userId = context.RequestData.ReadStruct<AccountUid>().ToLibHacUid();
// Mask out the low nibble of the program ID to get the application ID
- ApplicationId applicationId = new ApplicationId(context.Device.Application.TitleId & ~0xFul);
+ ApplicationId applicationId = new ApplicationId(context.Device.Processes.ActiveApplication.ProgramId & ~0xFul);
- BlitStruct<ApplicationControlProperty> controlHolder = context.Device.Application.ControlData;
-
- ref ApplicationControlProperty control = ref controlHolder.Value;
-
- if (LibHac.Common.Utilities.IsZeros(controlHolder.ByteSpan))
- {
- // If the current application doesn't have a loaded control property, create a dummy one
- // and set the savedata sizes so a user savedata will be created.
- control = ref new BlitStruct<ApplicationControlProperty>(1).Value;
-
- // The set sizes don't actually matter as long as they're non-zero because we use directory savedata.
- control.UserAccountSaveDataSize = 0x4000;
- control.UserAccountSaveDataJournalSize = 0x4000;
-
- Logger.Warning?.Print(LogClass.ServiceAm,
- "No control file was found for this game. Using a dummy one instead. This may cause inaccuracies in some games.");
- }
+ ApplicationControlProperty nacp = context.Device.Processes.ActiveApplication.ApplicationControlProperties;
LibHac.HorizonClient hos = context.Device.System.LibHacHorizonManager.AmClient;
- LibHac.Result result = hos.Fs.EnsureApplicationSaveData(out long requiredSize, applicationId, in control, in userId);
+ LibHac.Result result = hos.Fs.EnsureApplicationSaveData(out long requiredSize, applicationId, in nacp, in userId);
context.ResponseData.Write(requiredSize);
@@ -153,7 +137,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
// TODO: When above calls are implemented, switch to using ns:am
long desiredLanguageCode = context.Device.System.State.DesiredLanguageCode;
- int supportedLanguages = (int)context.Device.Application.ControlData.Value.SupportedLanguageFlag;
+ int supportedLanguages = (int)context.Device.Processes.ActiveApplication.ApplicationControlProperties.SupportedLanguageFlag;
int firstSupported = BitOperations.TrailingZeroCount(supportedLanguages);
if (firstSupported > (int)TitleLanguage.BrazilianPortuguese)
@@ -196,7 +180,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
public ResultCode GetDisplayVersion(ServiceCtx context)
{
// If an NACP isn't found, the buffer will be all '\0' which seems to be the correct implementation.
- context.ResponseData.Write(context.Device.Application.ControlData.Value.DisplayVersion);
+ context.ResponseData.Write(context.Device.Processes.ActiveApplication.ApplicationControlProperties.DisplayVersion);
return ResultCode.Success;
}
@@ -251,13 +235,12 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
long journalSize = context.RequestData.ReadInt64();
// Mask out the low nibble of the program ID to get the application ID
- ApplicationId applicationId = new ApplicationId(context.Device.Application.TitleId & ~0xFul);
+ ApplicationId applicationId = new ApplicationId(context.Device.Processes.ActiveApplication.ProgramId & ~0xFul);
- BlitStruct<ApplicationControlProperty> controlHolder = context.Device.Application.ControlData;
+ ApplicationControlProperty nacp = context.Device.Processes.ActiveApplication.ApplicationControlProperties;
LibHac.Result result = _horizon.Fs.CreateApplicationCacheStorage(out long requiredSize,
- out CacheStorageTargetMedia storageTarget, applicationId, in controlHolder.Value, index, saveSize,
- journalSize);
+ out CacheStorageTargetMedia storageTarget, applicationId, in nacp, index, saveSize, journalSize);
if (result.IsFailure()) return (ResultCode)result.Value;
@@ -677,7 +660,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
throw new InvalidSystemResourceException($"JIT (010000000000003B) system title not found! The JIT will not work, provide the system archive to fix this error. (See https://github.com/Ryujinx/Ryujinx#requirements for more information)");
}
- context.Device.Application.LoadServiceNca(filePath);
+ context.Device.LoadNca(filePath);
// FIXME: Most likely not how this should be done?
while (!context.Device.System.SmRegistry.IsServiceRegistered("jit:u"))
diff --git a/Ryujinx.HLE/HOS/Services/Arp/ApplicationLaunchProperty.cs b/Ryujinx.HLE/HOS/Services/Arp/ApplicationLaunchProperty.cs
index c985092b..3e4eca0a 100644
--- a/Ryujinx.HLE/HOS/Services/Arp/ApplicationLaunchProperty.cs
+++ b/Ryujinx.HLE/HOS/Services/Arp/ApplicationLaunchProperty.cs
@@ -33,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Services.Arp
return new ApplicationLaunchProperty
{
- TitleId = context.Device.Application.TitleId,
+ TitleId = context.Device.Processes.ActiveApplication.ProgramId,
Version = 0x00,
BaseGameStorageId = (byte)StorageId.BuiltInSystem,
UpdateGameStorageId = (byte)StorageId.None
diff --git a/Ryujinx.HLE/HOS/Services/Caps/IScreenShotApplicationService.cs b/Ryujinx.HLE/HOS/Services/Caps/IScreenShotApplicationService.cs
index 1789122e..e0c65f44 100644
--- a/Ryujinx.HLE/HOS/Services/Caps/IScreenShotApplicationService.cs
+++ b/Ryujinx.HLE/HOS/Services/Caps/IScreenShotApplicationService.cs
@@ -31,7 +31,7 @@ namespace Ryujinx.HLE.HOS.Services.Caps
byte[] screenshotData = context.Memory.GetSpan(screenshotDataPosition, (int)screenshotDataSize, true).ToArray();
- ResultCode resultCode = context.Device.System.CaptureManager.SaveScreenShot(screenshotData, appletResourceUserId, context.Device.Application.TitleId, out ApplicationAlbumEntry applicationAlbumEntry);
+ ResultCode resultCode = context.Device.System.CaptureManager.SaveScreenShot(screenshotData, appletResourceUserId, context.Device.Processes.ActiveApplication.ProgramId, out ApplicationAlbumEntry applicationAlbumEntry);
context.ResponseData.WriteStruct(applicationAlbumEntry);
@@ -60,7 +60,7 @@ namespace Ryujinx.HLE.HOS.Services.Caps
byte[] screenshotData = context.Memory.GetSpan(screenshotDataPosition, (int)screenshotDataSize, true).ToArray();
- ResultCode resultCode = context.Device.System.CaptureManager.SaveScreenShot(screenshotData, appletResourceUserId, context.Device.Application.TitleId, out ApplicationAlbumEntry applicationAlbumEntry);
+ ResultCode resultCode = context.Device.System.CaptureManager.SaveScreenShot(screenshotData, appletResourceUserId, context.Device.Processes.ActiveApplication.ProgramId, out ApplicationAlbumEntry applicationAlbumEntry);
context.ResponseData.WriteStruct(applicationAlbumEntry);
@@ -88,7 +88,7 @@ namespace Ryujinx.HLE.HOS.Services.Caps
byte[] screenshotData = context.Memory.GetSpan(screenshotDataPosition, (int)screenshotDataSize, true).ToArray();
- ResultCode resultCode = context.Device.System.CaptureManager.SaveScreenShot(screenshotData, appletResourceUserId, context.Device.Application.TitleId, out ApplicationAlbumEntry applicationAlbumEntry);
+ ResultCode resultCode = context.Device.System.CaptureManager.SaveScreenShot(screenshotData, appletResourceUserId, context.Device.Processes.ActiveApplication.ProgramId, out ApplicationAlbumEntry applicationAlbumEntry);
context.ResponseData.WriteStruct(applicationAlbumEntry);
diff --git a/Ryujinx.HLE/HOS/Services/Fatal/IService.cs b/Ryujinx.HLE/HOS/Services/Fatal/IService.cs
index 6d663a4d..c884e880 100644
--- a/Ryujinx.HLE/HOS/Services/Fatal/IService.cs
+++ b/Ryujinx.HLE/HOS/Services/Fatal/IService.cs
@@ -55,7 +55,7 @@ namespace Ryujinx.HLE.HOS.Services.Fatal
errorReport.AppendLine();
errorReport.AppendLine("ErrorReport log:");
- errorReport.AppendLine($"\tTitleId: {context.Device.Application.TitleId:x16}");
+ errorReport.AppendLine($"\tTitleId: {context.Device.Processes.ActiveApplication.ProgramIdText}");
errorReport.AppendLine($"\tPid: {pid}");
errorReport.AppendLine($"\tResultCode: {((int)resultCode & 0x1FF) + 2000}-{((int)resultCode >> 9) & 0x3FFF:d4}");
errorReport.AppendLine($"\tFatalPolicy: {fatalPolicy}");
@@ -64,7 +64,7 @@ namespace Ryujinx.HLE.HOS.Services.Fatal
{
errorReport.AppendLine("CPU Context:");
- if (context.Device.Application.TitleIs64Bit)
+ if (context.Device.Processes.ActiveApplication.Is64Bit)
{
CpuContext64 cpuContext64 = MemoryMarshal.Cast<byte, CpuContext64>(cpuContext)[0];
diff --git a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs
index 17a33b79..4317c8f6 100644
--- a/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs
+++ b/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs
@@ -334,7 +334,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
}
// TODO: Call nn::arp::GetApplicationControlProperty here when implemented.
- ApplicationControlProperty controlProperty = context.Device.Application.ControlData.Value;
+ ApplicationControlProperty controlProperty = context.Device.Processes.ActiveApplication.ApplicationControlProperties;
/*
diff --git a/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs b/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs
index 37143a5a..1b63f362 100644
--- a/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs
+++ b/Ryujinx.HLE/HOS/Services/Fs/IFileSystemProxy.cs
@@ -808,7 +808,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
{
byte programIndex = context.RequestData.ReadByte();
- if ((context.Device.Application.TitleId & 0xf) != programIndex)
+ if ((context.Device.Processes.ActiveApplication.ProgramId & 0xf) != programIndex)
{
throw new NotImplementedException($"Accessing storage from other programs is not supported (program index = {programIndex}).");
}
diff --git a/Ryujinx.HLE/HOS/Services/Ns/Aoc/IAddOnContentManager.cs b/Ryujinx.HLE/HOS/Services/Ns/Aoc/IAddOnContentManager.cs
index 0d552003..b8f9e3b9 100644
--- a/Ryujinx.HLE/HOS/Services/Ns/Aoc/IAddOnContentManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Ns/Aoc/IAddOnContentManager.cs
@@ -48,7 +48,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns.Aoc
// NOTE: Service call arp:r GetApplicationLaunchProperty to get TitleId using the PId.
- return CountAddOnContentImpl(context, context.Device.Application.TitleId);
+ return CountAddOnContentImpl(context, context.Device.Processes.ActiveApplication.ProgramId);
}
[CommandHipc(3)]
@@ -59,7 +59,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns.Aoc
// NOTE: Service call arp:r GetApplicationLaunchProperty to get TitleId using the PId.
- return ListAddContentImpl(context, context.Device.Application.TitleId);
+ return ListAddContentImpl(context, context.Device.Processes.ActiveApplication.ProgramId);
}
[CommandHipc(4)] // 1.0.0-6.2.0
@@ -79,7 +79,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns.Aoc
// NOTE: Service call arp:r GetApplicationLaunchProperty to get TitleId using the PId.
- return GetAddOnContentBaseIdImpl(context, context.Device.Application.TitleId);
+ return GetAddOnContentBaseIdImpl(context, context.Device.Processes.ActiveApplication.ProgramId);
}
[CommandHipc(6)] // 1.0.0-6.2.0
@@ -99,7 +99,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns.Aoc
// NOTE: Service call arp:r GetApplicationLaunchProperty to get TitleId using the PId.
- return PrepareAddOnContentImpl(context, context.Device.Application.TitleId);
+ return PrepareAddOnContentImpl(context, context.Device.Processes.ActiveApplication.ProgramId);
}
[CommandHipc(8)] // 4.0.0+
@@ -128,7 +128,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns.Aoc
// NOTE: Service call arp:r GetApplicationLaunchProperty to get TitleId using the PId.
// TODO: Found where stored value is used.
- ResultCode resultCode = GetAddOnContentBaseIdFromTitleId(context, context.Device.Application.TitleId);
+ ResultCode resultCode = GetAddOnContentBaseIdFromTitleId(context, context.Device.Processes.ActiveApplication.ProgramId);
if (resultCode != ResultCode.Success)
{
@@ -294,7 +294,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns.Aoc
// NOTE: Service calls arp:r GetApplicationControlProperty to get AddOnContentBaseId using TitleId,
// If the call fails, it returns ResultCode.InvalidPid.
- _addOnContentBaseId = context.Device.Application.ControlData.Value.AddOnContentBaseId;
+ _addOnContentBaseId = context.Device.Processes.ActiveApplication.ApplicationControlProperties.AddOnContentBaseId;
if (_addOnContentBaseId == 0)
{
@@ -308,7 +308,7 @@ namespace Ryujinx.HLE.HOS.Services.Ns.Aoc
{
uint index = context.RequestData.ReadUInt32();
- ResultCode resultCode = GetAddOnContentBaseIdFromTitleId(context, context.Device.Application.TitleId);
+ ResultCode resultCode = GetAddOnContentBaseIdFromTitleId(context, context.Device.Processes.ActiveApplication.ProgramId);
if (resultCode != ResultCode.Success)
{
diff --git a/Ryujinx.HLE/HOS/Services/Ns/IApplicationManagerInterface.cs b/Ryujinx.HLE/HOS/Services/Ns/IApplicationManagerInterface.cs
index d3a89178..249343d7 100644
--- a/Ryujinx.HLE/HOS/Services/Ns/IApplicationManagerInterface.cs
+++ b/Ryujinx.HLE/HOS/Services/Ns/IApplicationManagerInterface.cs
@@ -1,4 +1,8 @@
-namespace Ryujinx.HLE.HOS.Services.Ns
+using LibHac.Ns;
+using Ryujinx.Common.Utilities;
+using System;
+
+namespace Ryujinx.HLE.HOS.Services.Ns
{
[Service("ns:am")]
class IApplicationManagerInterface : IpcService
@@ -14,9 +18,9 @@
ulong position = context.Request.ReceiveBuff[0].Position;
- byte[] nacpData = context.Device.Application.ControlData.ByteSpan.ToArray();
+ ApplicationControlProperty nacp = context.Device.Processes.ActiveApplication.ApplicationControlProperties;
- context.Memory.Write(position, nacpData);
+ context.Memory.Write(position, SpanHelpers.AsByteSpan(ref nacp).ToArray());
return ResultCode.Success;
}
diff --git a/Ryujinx.HLE/HOS/Services/Ns/IReadOnlyApplicationControlDataInterface.cs b/Ryujinx.HLE/HOS/Services/Ns/IReadOnlyApplicationControlDataInterface.cs
index 3b6965d0..8f6acc1c 100644
--- a/Ryujinx.HLE/HOS/Services/Ns/IReadOnlyApplicationControlDataInterface.cs
+++ b/Ryujinx.HLE/HOS/Services/Ns/IReadOnlyApplicationControlDataInterface.cs
@@ -1,4 +1,7 @@
-namespace Ryujinx.HLE.HOS.Services.Ns
+using LibHac.Common;
+using LibHac.Ns;
+
+namespace Ryujinx.HLE.HOS.Services.Ns
{
class IReadOnlyApplicationControlDataInterface : IpcService
{
@@ -13,9 +16,9 @@
ulong position = context.Request.ReceiveBuff[0].Position;
- byte[] nacpData = context.Device.Application.ControlData.ByteSpan.ToArray();
+ ApplicationControlProperty nacp = context.Device.Processes.ActiveApplication.ApplicationControlProperties;
- context.Memory.Write(position, nacpData);
+ context.Memory.Write(position, SpanHelpers.AsByteSpan(ref nacp).ToArray());
return ResultCode.Success;
}
diff --git a/Ryujinx.HLE/HOS/Services/Pctl/ParentalControlServiceFactory/IParentalControlService.cs b/Ryujinx.HLE/HOS/Services/Pctl/ParentalControlServiceFactory/IParentalControlService.cs
index e0017808..02964749 100644
--- a/Ryujinx.HLE/HOS/Services/Pctl/ParentalControlServiceFactory/IParentalControlService.cs
+++ b/Ryujinx.HLE/HOS/Services/Pctl/ParentalControlServiceFactory/IParentalControlService.cs
@@ -56,8 +56,8 @@ namespace Ryujinx.HLE.HOS.Services.Pctl.ParentalControlServiceFactory
_titleId = titleId;
// TODO: Call nn::arp::GetApplicationControlProperty here when implemented, if it return ResultCode.Success we assign fields.
- _ratingAge = Array.ConvertAll(context.Device.Application.ControlData.Value.RatingAge.ItemsRo.ToArray(), Convert.ToInt32);
- _parentalControlFlag = context.Device.Application.ControlData.Value.ParentalControlFlag;
+ _ratingAge = Array.ConvertAll(context.Device.Processes.ActiveApplication.ApplicationControlProperties.RatingAge.ItemsRo.ToArray(), Convert.ToInt32);
+ _parentalControlFlag = context.Device.Processes.ActiveApplication.ApplicationControlProperties.ParentalControlFlag;
}
}
diff --git a/Ryujinx.HLE/HOS/Services/Sdb/Pdm/QueryService/QueryPlayStatisticsManager.cs b/Ryujinx.HLE/HOS/Services/Sdb/Pdm/QueryService/QueryPlayStatisticsManager.cs
index 1d6cc118..52a07d46 100644
--- a/Ryujinx.HLE/HOS/Services/Sdb/Pdm/QueryService/QueryPlayStatisticsManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Sdb/Pdm/QueryService/QueryPlayStatisticsManager.cs
@@ -6,7 +6,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
{
@@ -16,8 +15,6 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
internal static ResultCode GetPlayStatistics(ServiceCtx context, bool byUserId = false)
{
- ref readonly var controlProperty = ref context.Device.Application.ControlData.Value;
-
ulong inputPosition = context.Request.SendBuff[0].Position;
ulong inputSize = context.Request.SendBuff[0].Size;
@@ -34,7 +31,7 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
}
}
- PlayLogQueryCapability queryCapability = (PlayLogQueryCapability)controlProperty.PlayLogQueryCapability;
+ PlayLogQueryCapability queryCapability = (PlayLogQueryCapability)context.Device.Processes.ActiveApplication.ApplicationControlProperties.PlayLogQueryCapability;
List<ulong> titleIds = new List<ulong>();
@@ -48,7 +45,7 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
// Check if input title ids are in the whitelist.
foreach (ulong titleId in titleIds)
{
- if (!controlProperty.PlayLogQueryableApplicationId.ItemsRo.Contains(titleId))
+ if (!context.Device.Processes.ActiveApplication.ApplicationControlProperties.PlayLogQueryableApplicationId.ItemsRo.Contains(titleId))
{
return (ResultCode)Am.ResultCode.ObjectInvalid;
}