Add NCE code

This commit is contained in:
gdk 2023-07-03 19:28:05 -03:00 committed by Emmanuel Hansen
parent a1e34041fa
commit 0970972f0d
40 changed files with 2702 additions and 40 deletions

View file

@ -16,13 +16,15 @@ namespace Ryujinx.HLE.HOS
ulong codeSize);
}
class ArmProcessContext<T> : IArmProcessContext where T : class, IVirtualMemoryManagerTracked, IMemoryManager
class ArmProcessContext<T> : IArmProcessContext where T : class, IVirtualMemoryManagerTracked, ICpuMemoryManager
{
private readonly ulong _pid;
private readonly GpuContext _gpuContext;
private readonly ICpuContext _cpuContext;
private T _memoryManager;
public ulong ReservedSize { get; }
public IVirtualMemoryManager AddressSpace => _memoryManager;
public ulong AddressSpaceSize { get; }
@ -33,7 +35,8 @@ namespace Ryujinx.HLE.HOS
GpuContext gpuContext,
T memoryManager,
ulong addressSpaceSize,
bool for64Bit)
bool for64Bit,
ulong reservedSize = 0UL)
{
if (memoryManager is IRefCounted rc)
{
@ -46,8 +49,8 @@ namespace Ryujinx.HLE.HOS
_gpuContext = gpuContext;
_cpuContext = cpuEngine.CreateCpuContext(memoryManager, for64Bit);
_memoryManager = memoryManager;
AddressSpaceSize = addressSpaceSize;
ReservedSize = reservedSize;
}
public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks)
@ -78,6 +81,11 @@ namespace Ryujinx.HLE.HOS
_cpuContext.InvalidateCacheRegion(address, size);
}
public void PatchCodeForNce(ulong textAddress, ulong textSize, ulong patchRegionAddress, ulong patchRegionSize)
{
_cpuContext.PatchCodeForNce(textAddress, textSize, patchRegionAddress, patchRegionSize);
}
public void Dispose()
{
if (_memoryManager is IRefCounted rc)

View file

@ -4,6 +4,7 @@ using Ryujinx.Cpu;
using Ryujinx.Cpu.AppleHv;
using Ryujinx.Cpu.Jit;
using Ryujinx.Cpu.LightningJit;
using Ryujinx.Cpu.Nce;
using Ryujinx.Graphics.Gpu;
using Ryujinx.HLE.HOS.Kernel;
using Ryujinx.HLE.HOS.Kernel.Process;
@ -46,14 +47,31 @@ namespace Ryujinx.HLE.HOS
public IProcessContext Create(KernelContext context, ulong pid, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler, bool for64Bit)
{
IArmProcessContext processContext;
AddressSpace addressSpace = null;
bool isArm64Host = RuntimeInformation.ProcessArchitecture == Architecture.Arm64;
if (OperatingSystem.IsMacOS() && isArm64Host && for64Bit && context.Device.Configuration.UseHypervisor)
{
var cpuEngine = new HvEngine(_tickSource);
var memoryManager = new HvMemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler);
processContext = new ArmProcessContext<HvMemoryManager>(pid, cpuEngine, _gpu, memoryManager, addressSpaceSize, for64Bit);
if (OperatingSystem.IsMacOS())
{
var cpuEngine = new HvEngine(_tickSource);
var memoryManager = new HvMemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler);
processContext = new ArmProcessContext<HvMemoryManager>(pid, cpuEngine, _gpu, memoryManager, addressSpaceSize, for64Bit);
}
else
{
if (!AddressSpace.TryCreate(context.Memory, addressSpaceSize, MemoryBlock.GetPageSize() == MemoryManagerHostMapped.PageSize, out addressSpace))
{
throw new Exception("Address space creation failed");
}
Logger.Info?.Print(LogClass.Cpu, $"NCE Base AS Address: 0x{addressSpace.Base.Pointer.ToInt64():X} Size: 0x{addressSpace.AddressSpaceSize:X}");
var cpuEngine = new NceEngine(_tickSource);
var memoryManager = new MemoryManagerNative(addressSpace, context.Memory, addressSpaceSize, invalidAccessHandler);
processContext = new ArmProcessContext<MemoryManagerNative>(pid, cpuEngine, _gpu, memoryManager, addressSpace.AddressSpaceSize, for64Bit, memoryManager.ReservedSize);
}
}
else
{
@ -70,8 +88,6 @@ namespace Ryujinx.HLE.HOS
? new LightningJitEngine(_tickSource)
: new JitEngine(_tickSource);
AddressSpace addressSpace = null;
if (mode == MemoryManagerMode.HostMapped || mode == MemoryManagerMode.HostMappedUnsafe)
{
if (!AddressSpace.TryCreate(context.Memory, addressSpaceSize, MemoryBlock.GetPageSize() == MemoryManagerHostMapped.PageSize, out addressSpace))

View file

@ -107,6 +107,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
MemoryRegion memRegion,
ulong address,
ulong size,
ulong reservedSize,
KMemoryBlockSlabManager slabManager)
{
if ((uint)addrSpaceType > (uint)AddressSpaceType.Addr39Bits)
@ -128,6 +129,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
memRegion,
address,
size,
reservedSize,
slabManager);
if (result != Result.Success)
@ -155,6 +157,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
MemoryRegion memRegion,
ulong address,
ulong size,
ulong reservedSize,
KMemoryBlockSlabManager slabManager)
{
ulong endAddr = address + size;
@ -178,7 +181,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
CodeRegionStart = 0x200000;
codeRegionSize = 0x3fe00000;
AslrRegionStart = 0x200000;
AslrRegionEnd = AslrRegionStart + 0xffe00000;
AslrRegionEnd = 0x100000000;
stackAndTlsIoStart = 0x200000;
stackAndTlsIoEnd = 0x40000000;
break;
@ -191,7 +194,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
CodeRegionStart = 0x8000000;
codeRegionSize = 0x78000000;
AslrRegionStart = 0x8000000;
AslrRegionEnd = AslrRegionStart + 0xff8000000;
AslrRegionEnd = 0x1000000000;
stackAndTlsIoStart = 0x8000000;
stackAndTlsIoEnd = 0x80000000;
break;
@ -204,7 +207,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
CodeRegionStart = 0x200000;
codeRegionSize = 0x3fe00000;
AslrRegionStart = 0x200000;
AslrRegionEnd = AslrRegionStart + 0xffe00000;
AslrRegionEnd = 0x100000000;
stackAndTlsIoStart = 0x200000;
stackAndTlsIoEnd = 0x40000000;
break;
@ -222,8 +225,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
codeRegionSize = BitUtils.AlignUp<ulong>(endAddr, RegionAlignment) - CodeRegionStart;
stackAndTlsIoStart = 0;
stackAndTlsIoEnd = 0;
AslrRegionStart = 0x8000000;
addrSpaceEnd = 1UL << addressSpaceWidth;
AslrRegionStart = reservedSize + 0x8000000;
addrSpaceEnd = reservedSize + (1UL << addressSpaceWidth);
AslrRegionEnd = addrSpaceEnd;
}
else
@ -234,8 +237,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
tlsIoRegion.Size = 0x1000000000;
CodeRegionStart = BitUtils.AlignDown(address, RegionAlignment);
codeRegionSize = BitUtils.AlignUp(endAddr, RegionAlignment) - CodeRegionStart;
AslrRegionStart = 0x8000000;
AslrRegionEnd = AslrRegionStart + 0x7ff8000000;
AslrRegionStart = reservedSize + 0x8000000;
AslrRegionEnd = 0x8000000000;
stackAndTlsIoStart = 0;
stackAndTlsIoEnd = 0;
}

View file

@ -7,11 +7,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
interface IProcessContext : IDisposable
{
IVirtualMemoryManager AddressSpace { get; }
ulong ReservedSize { get; }
ulong AddressSpaceSize { get; }
IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks);
void Execute(IExecutionContext context, ulong codeAddress);
void InvalidateCacheRegion(ulong address, ulong size);
void PatchCodeForNce(ulong textAddress, ulong textSize, ulong patchRegionAddress, ulong patchRegionSize);
}
}

View file

@ -139,7 +139,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr);
ulong codeAddress = creationInfo.CodeAddress;
ulong codeAddress = creationInfo.CodeAddress + Context.ReservedSize;
ulong codeSize = (ulong)creationInfo.CodePagesCount * KPageTableBase.PageSize;
@ -154,6 +154,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
memRegion,
codeAddress,
codeSize,
Context.ReservedSize,
slabManager);
if (result != Result.Success)
@ -189,7 +190,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
KResourceLimit resourceLimit,
MemoryRegion memRegion,
IProcessContextFactory contextFactory,
ThreadStart customThreadStart = null)
ThreadStart customThreadStart = null,
ulong entrypointOffset = 0UL)
{
ResourceLimit = resourceLimit;
_memRegion = memRegion;
@ -247,7 +249,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
bool aslrEnabled = creationInfo.Flags.HasFlag(ProcessCreationFlags.EnableAslr);
ulong codeAddress = creationInfo.CodeAddress;
ulong codeAddress = creationInfo.CodeAddress + Context.ReservedSize;
ulong codeSize = codePagesCount * KPageTableBase.PageSize;
@ -258,6 +260,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
memRegion,
codeAddress,
codeSize,
Context.ReservedSize,
slabManager);
if (result != Result.Success)
@ -303,6 +306,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
CleanUpForError();
}
_entrypoint += entrypointOffset;
return result;
}
@ -347,7 +352,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
Flags = creationInfo.Flags;
TitleId = creationInfo.TitleId;
_entrypoint = creationInfo.CodeAddress;
_entrypoint = creationInfo.CodeAddress + Context.ReservedSize;
_imageSize = (ulong)creationInfo.CodePagesCount * KPageTableBase.PageSize;
switch (Flags & ProcessCreationFlags.AddressSpaceMask)

View file

@ -7,6 +7,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
class ProcessContext : IProcessContext
{
public IVirtualMemoryManager AddressSpace { get; }
public ulong ReservedSize => 0UL;
public ulong AddressSpaceSize { get; }
@ -30,6 +31,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{
}
public void PatchCodeForNce(ulong textAddress, ulong textSize, ulong patchRegionAddress, ulong patchRegionSize)
{
}
public void Dispose()
{
}

View file

@ -133,6 +133,8 @@ namespace Ryujinx.HLE.Loaders.Processes
return resultCode;
}
private const int ReservedPatchSize = 0x100000;
public static bool LoadKip(KernelContext context, KipExecutable kip)
{
uint endOffset = kip.DataOffset + (uint)kip.Data.Length;
@ -197,7 +199,9 @@ namespace Ryujinx.HLE.Loaders.Processes
return false;
}
result = LoadIntoMemory(process, kip, codeBaseAddress);
// TODO: Support NCE of KIPs too.
result = LoadIntoMemory(process, kip, codeBaseAddress, 0UL);
if (result != Result.Success)
{
Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");
@ -257,6 +261,7 @@ namespace Ryujinx.HLE.Loaders.Processes
_ => "",
}).ToUpper());
ulong[] nsoPatch = new ulong[executables.Length];
ulong[] nsoBase = new ulong[executables.Length];
for (int index = 0; index < executables.Length; index++)
@ -281,6 +286,10 @@ namespace Ryujinx.HLE.Loaders.Processes
nsoSize = BitUtils.AlignUp<uint>(nsoSize, KPageTableBase.PageSize);
nsoPatch[index] = codeStart + codeSize;
codeSize += ReservedPatchSize;
nsoBase[index] = codeStart + codeSize;
codeSize += nsoSize;
@ -304,7 +313,7 @@ namespace Ryujinx.HLE.Loaders.Processes
programId,
codeStart,
codePagesCount,
(ProcessCreationFlags)meta.Flags | ProcessCreationFlags.IsApplication,
(ProcessCreationFlags)meta.Flags,
0,
personalMmHeapPagesCount);
@ -381,7 +390,8 @@ namespace Ryujinx.HLE.Loaders.Processes
MemoryMarshal.Cast<byte, uint>(npdm.KernelCapabilityData),
resourceLimit,
memoryRegion,
processContextFactory);
processContextFactory,
entrypointOffset: ReservedPatchSize);
if (result != Result.Success)
{
@ -392,9 +402,13 @@ 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 nsoPatchAddress = process.Context.ReservedSize + nsoPatch[index];
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, nsoPatchAddress);
result = LoadIntoMemory(process, executables[index], nsoBase[index]);
if (result != Result.Success)
{
Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");
@ -433,7 +447,7 @@ namespace Ryujinx.HLE.Loaders.Processes
device.System.State.DesiredTitleLanguage);
}
public static Result LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress)
private static Result LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress, ulong patchAddress)
{
ulong textStart = baseAddress + image.TextOffset;
ulong roStart = baseAddress + image.RoOffset;
@ -453,6 +467,8 @@ namespace Ryujinx.HLE.Loaders.Processes
process.CpuMemory.Fill(bssStart, image.BssSize, 0);
process.Context.PatchCodeForNce(textStart, (ulong)image.Text.Length, patchAddress, ReservedPatchSize);
Result SetProcessMemoryPermission(ulong address, ulong size, KMemoryPermission permission)
{
if (size == 0)