mirror of
https://git.ryujinx.app/projects/Kenji-NX.git
synced 2026-09-27 12:37:54 +02:00
Android changes
This commit is contained in:
@@ -82,6 +82,13 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
|
||||
// Apply Nsos patches.
|
||||
device.Configuration.VirtualFileSystem.ModLoader.ApplyNsoPatches(programId, nsoExecutables);
|
||||
|
||||
// Don't use PTC if ExeFS files have been replaced.
|
||||
bool enablePtc = device.System.EnablePtc && !modLoadResult.Modified;
|
||||
if (!enablePtc)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Ptc, "Detected unsupported ExeFs modifications. PTC disabled.");
|
||||
}
|
||||
|
||||
string programName = "";
|
||||
|
||||
if (!isHomebrew && programId > 0x010000000000FFFF)
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
|
||||
return programs;
|
||||
}
|
||||
|
||||
internal static (bool, ProcessResult) TryLoad<TMetaData, TFormat, THeader, TEntry>(this PartitionFileSystemCore<TMetaData, TFormat, THeader, TEntry> partitionFileSystem, Switch device, string path, ulong applicationId, out string errorMessage)
|
||||
internal static (bool, ProcessResult) TryLoad<TMetaData, TFormat, THeader, TEntry>(this PartitionFileSystemCore<TMetaData, TFormat, THeader, TEntry> partitionFileSystem, Switch device, Stream stream, ulong applicationId, out string errorMessage)
|
||||
where TMetaData : PartitionFileSystemMetaCore<TFormat, THeader, TEntry>, new()
|
||||
where TFormat : IPartitionFileSystemFormat
|
||||
where THeader : unmanaged, IPartitionFileSystemHeader
|
||||
|
||||
@@ -35,6 +35,12 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
public bool LoadXci(string path, ulong applicationId)
|
||||
{
|
||||
FileStream stream = new(path, FileMode.Open, FileAccess.Read);
|
||||
|
||||
return LoadXci(stream, applicationId);
|
||||
}
|
||||
|
||||
public bool LoadXci(Stream stream, ulong applicationId, Stream updateStream = null)
|
||||
{
|
||||
Xci xci = new(_device.Configuration.VirtualFileSystem.KeySet, stream.AsStorage());
|
||||
|
||||
if (!xci.HasPartition(XciPartitionType.Secure))
|
||||
@@ -44,7 +50,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
return false;
|
||||
}
|
||||
|
||||
(bool success, ProcessResult processResult) = xci.OpenPartition(XciPartitionType.Secure).TryLoad(_device, path, applicationId, out string errorMessage);
|
||||
(bool success, ProcessResult processResult) = xci.OpenPartition(XciPartitionType.Secure).TryLoad(_device, stream, applicationId, out string errorMessage);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
@@ -69,10 +75,16 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
public bool LoadNsp(string path, ulong applicationId)
|
||||
{
|
||||
FileStream file = new(path, FileMode.Open, FileAccess.Read);
|
||||
PartitionFileSystem partitionFileSystem = new();
|
||||
partitionFileSystem.Initialize(file.AsStorage()).ThrowIfFailure();
|
||||
|
||||
(bool success, ProcessResult processResult) = partitionFileSystem.TryLoad(_device, path, applicationId, out string errorMessage);
|
||||
return LoadNsp(file, applicationId);
|
||||
}
|
||||
|
||||
public bool LoadNsp(Stream stream, ulong applicationId, Stream updateStream = null)
|
||||
{
|
||||
PartitionFileSystem partitionFileSystem = new();
|
||||
partitionFileSystem.Initialize(stream.AsStorage()).ThrowIfFailure();
|
||||
|
||||
(bool success, ProcessResult processResult) = partitionFileSystem.TryLoad(_device, stream, applicationId, out string errorMessage);
|
||||
|
||||
if (processResult.ProcessId == 0)
|
||||
{
|
||||
@@ -101,7 +113,13 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
public bool LoadNca(string path)
|
||||
{
|
||||
FileStream file = new(path, FileMode.Open, FileAccess.Read);
|
||||
Nca nca = new(_device.Configuration.VirtualFileSystem.KeySet, file.AsStorage(false));
|
||||
|
||||
return LoadNca(file);
|
||||
}
|
||||
|
||||
public bool LoadNca(Stream ncaStream)
|
||||
{
|
||||
Nca nca = new(_device.Configuration.VirtualFileSystem.KeySet, ncaStream.AsStorage(false));
|
||||
|
||||
ProcessResult processResult = nca.Load(_device, null, null);
|
||||
|
||||
@@ -243,5 +261,109 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool LoadNxo(Stream stream, bool isNro, string name)
|
||||
{
|
||||
var nacpData = new BlitStruct<ApplicationControlProperty>(1);
|
||||
IFileSystem dummyExeFs = null;
|
||||
Stream romfsStream = null;
|
||||
|
||||
string programName = "";
|
||||
ulong programId = 0000000000000000;
|
||||
|
||||
// Load executable.
|
||||
IExecutable executable;
|
||||
|
||||
if (isNro)
|
||||
{
|
||||
NroExecutable nro = new(stream.AsStorage());
|
||||
|
||||
executable = nro;
|
||||
|
||||
// Open RomFS if exists.
|
||||
IStorage romFsStorage = nro.OpenNroAssetSection(LibHac.Tools.Ro.NroAssetType.RomFs, false);
|
||||
romFsStorage.GetSize(out long romFsSize).ThrowIfFailure();
|
||||
if (romFsSize != 0)
|
||||
{
|
||||
romfsStream = romFsStorage.AsStream();
|
||||
}
|
||||
|
||||
// Load Nacp if exists.
|
||||
IStorage nacpStorage = nro.OpenNroAssetSection(LibHac.Tools.Ro.NroAssetType.Nacp, false);
|
||||
nacpStorage.GetSize(out long nacpSize).ThrowIfFailure();
|
||||
if (nacpSize != 0)
|
||||
{
|
||||
nacpStorage.Read(0, nacpData.ByteSpan);
|
||||
|
||||
programName = nacpData.Value.Title[(int)_device.System.State.DesiredTitleLanguage].NameString.ToString();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(programName))
|
||||
{
|
||||
programName = Array.Find(nacpData.Value.Title.ItemsRo.ToArray(), x => x.Name[0] != 0).NameString.ToString();
|
||||
}
|
||||
|
||||
if (nacpData.Value.PresenceGroupId != 0)
|
||||
{
|
||||
programId = nacpData.Value.PresenceGroupId;
|
||||
}
|
||||
else if (nacpData.Value.SaveDataOwnerId != 0)
|
||||
{
|
||||
programId = nacpData.Value.SaveDataOwnerId;
|
||||
}
|
||||
else if (nacpData.Value.AddOnContentBaseId != 0)
|
||||
{
|
||||
programId = nacpData.Value.AddOnContentBaseId - 0x1000;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Add icon maybe ?
|
||||
}
|
||||
else
|
||||
{
|
||||
executable = new NsoExecutable(new LocalStorage(name, FileAccess.Read), programName);
|
||||
}
|
||||
|
||||
// Explicitly null TitleId to disable the shader cache.
|
||||
Graphics.Gpu.GraphicsConfig.TitleId = null;
|
||||
_device.Gpu.HostInitalized.Set();
|
||||
|
||||
ProcessResult processResult = ProcessLoaderHelper.LoadNsos(_device,
|
||||
_device.System.KernelContext,
|
||||
dummyExeFs.GetNpdm(),
|
||||
nacpData,
|
||||
diskCacheEnabled: false,
|
||||
diskCacheSelector: null,
|
||||
allowCodeMemoryForJit: true,
|
||||
programName,
|
||||
programId,
|
||||
0,
|
||||
null,
|
||||
executable);
|
||||
|
||||
// Make sure the process id is valid.
|
||||
if (processResult.ProcessId != 0)
|
||||
{
|
||||
// Load RomFS.
|
||||
if (romfsStream != null)
|
||||
{
|
||||
_device.Configuration.VirtualFileSystem.SetRomFs(processResult.ProcessId, romfsStream);
|
||||
}
|
||||
|
||||
// Start process.
|
||||
if (_processesByPid.TryAdd(processResult.ProcessId, processResult))
|
||||
{
|
||||
if (processResult.Start(_device))
|
||||
{
|
||||
_latestPid = processResult.ProcessId;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using LibHac.Account;
|
||||
using LibHac.Account;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
@@ -11,6 +11,7 @@ using LibHac.Tools.FsSystem;
|
||||
using LibHac.Tools.FsSystem.NcaUtils;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Cpu.Nce;
|
||||
using Ryujinx.HLE.HOS;
|
||||
using Ryujinx.HLE.HOS.Kernel;
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
@@ -21,6 +22,7 @@ using Ryujinx.HLE.Loaders.Processes.Extensions;
|
||||
using Ryujinx.Horizon.Common;
|
||||
using Ryujinx.Horizon.Sdk.Arp;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using ApplicationId = LibHac.Ncm.ApplicationId;
|
||||
|
||||
@@ -232,7 +234,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
ulong programId,
|
||||
byte programIndex,
|
||||
byte[] arguments = null,
|
||||
params ReadOnlySpan<IExecutable> executables)
|
||||
params IExecutable[] executables)
|
||||
{
|
||||
context.Device.System.ServiceTable.WaitServicesReady();
|
||||
|
||||
@@ -250,20 +252,16 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
ulong argsStart = 0;
|
||||
uint argsSize = 0;
|
||||
ulong codeStart = ((meta.Flags & 1) != 0 ? 0x8000000UL : 0x200000UL) + CodeStartOffset;
|
||||
uint codeSize = 0;
|
||||
ulong codeSize = 0;
|
||||
|
||||
var buildIds = new string[executables.Length];
|
||||
|
||||
for (int i = 0; i < executables.Length; i++)
|
||||
var buildIds = executables.Select(e => (e switch
|
||||
{
|
||||
buildIds[i] = (executables[i] switch
|
||||
{
|
||||
NsoExecutable nso => Convert.ToHexString(nso.BuildId.ItemsRo.ToArray()),
|
||||
NroExecutable nro => Convert.ToHexString(nro.Header.BuildId),
|
||||
_ => "",
|
||||
}).ToUpper();
|
||||
}
|
||||
}).ToUpper());
|
||||
|
||||
NceCpuCodePatch[] nsoPatch = new NceCpuCodePatch[executables.Length];
|
||||
ulong[] nsoBase = new ulong[executables.Length];
|
||||
|
||||
for (int index = 0; index < executables.Length; index++)
|
||||
@@ -288,6 +286,16 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
|
||||
nsoSize = BitUtils.AlignUp<uint>(nsoSize, KPageTableBase.PageSize);
|
||||
|
||||
bool for64Bit = ((ProcessCreationFlags)meta.Flags).HasFlag(ProcessCreationFlags.Is64Bit);
|
||||
|
||||
NceCpuCodePatch codePatch = ArmProcessContextFactory.CreateCodePatchForNce(context, for64Bit, nso.Text);
|
||||
nsoPatch[index] = codePatch;
|
||||
|
||||
if (codePatch != null)
|
||||
{
|
||||
codeSize += codePatch.Size;
|
||||
}
|
||||
|
||||
nsoBase[index] = codeStart + codeSize;
|
||||
|
||||
codeSize += nsoSize;
|
||||
@@ -389,7 +397,8 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
MemoryMarshal.Cast<byte, uint>(npdm.KernelCapabilityData),
|
||||
resourceLimit,
|
||||
memoryRegion,
|
||||
processContextFactory);
|
||||
processContextFactory,
|
||||
entrypointOffset: nsoPatch[0]?.Size ?? 0UL);
|
||||
|
||||
if (result != Result.Success)
|
||||
{
|
||||
@@ -400,9 +409,12 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
|
||||
for (int index = 0; index < executables.Length; index++)
|
||||
{
|
||||
Logger.Info?.Print(LogClass.Loader, $"Loading image {index} at 0x{nsoBase[index]:x16}...");
|
||||
ulong nsoBaseAddress = process.Context.ReservedSize + nsoBase[index];
|
||||
|
||||
Logger.Info?.Print(LogClass.Loader, $"Loading image {index} at 0x{nsoBaseAddress:x16}...");
|
||||
|
||||
result = LoadIntoMemory(process, executables[index], nsoBaseAddress, nsoPatch[index]);
|
||||
|
||||
result = LoadIntoMemory(process, executables[index], nsoBase[index]);
|
||||
if (result != Result.Success)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");
|
||||
@@ -460,7 +472,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
return processResult;
|
||||
}
|
||||
|
||||
public static Result LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress)
|
||||
private static Result LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress, NceCpuCodePatch codePatch = null)
|
||||
{
|
||||
ulong textStart = baseAddress + image.TextOffset;
|
||||
ulong roStart = baseAddress + image.RoOffset;
|
||||
@@ -480,6 +492,11 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
|
||||
process.CpuMemory.Fill(bssStart, image.BssSize, 0);
|
||||
|
||||
if (codePatch != null)
|
||||
{
|
||||
codePatch.Write(process.CpuMemory, baseAddress - codePatch.Size, textStart);
|
||||
}
|
||||
|
||||
Result SetProcessMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
|
||||
{
|
||||
if (size == 0)
|
||||
|
||||
Reference in New Issue
Block a user