ArmProcessContextFactory.cs
1 using Ryujinx.Common.Configuration; 2 using Ryujinx.Common.Logging; 3 using Ryujinx.Cpu; 4 using Ryujinx.Cpu.AppleHv; 5 using Ryujinx.Cpu.Jit; 6 using Ryujinx.Cpu.LightningJit; 7 using Ryujinx.Graphics.Gpu; 8 using Ryujinx.HLE.HOS.Kernel; 9 using Ryujinx.HLE.HOS.Kernel.Process; 10 using Ryujinx.Memory; 11 using System; 12 using System.Runtime.InteropServices; 13 14 namespace Ryujinx.HLE.HOS 15 { 16 class ArmProcessContextFactory : IProcessContextFactory 17 { 18 private readonly ITickSource _tickSource; 19 private readonly GpuContext _gpu; 20 private readonly string _titleIdText; 21 private readonly string _displayVersion; 22 private readonly bool _diskCacheEnabled; 23 private readonly ulong _codeAddress; 24 private readonly ulong _codeSize; 25 26 public IDiskCacheLoadState DiskCacheLoadState { get; private set; } 27 28 public ArmProcessContextFactory( 29 ITickSource tickSource, 30 GpuContext gpu, 31 string titleIdText, 32 string displayVersion, 33 bool diskCacheEnabled, 34 ulong codeAddress, 35 ulong codeSize) 36 { 37 _tickSource = tickSource; 38 _gpu = gpu; 39 _titleIdText = titleIdText; 40 _displayVersion = displayVersion; 41 _diskCacheEnabled = diskCacheEnabled; 42 _codeAddress = codeAddress; 43 _codeSize = codeSize; 44 } 45 46 public IProcessContext Create(KernelContext context, ulong pid, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler, bool for64Bit) 47 { 48 IArmProcessContext processContext; 49 50 bool isArm64Host = RuntimeInformation.ProcessArchitecture == Architecture.Arm64; 51 52 if (OperatingSystem.IsMacOS() && isArm64Host && for64Bit && context.Device.Configuration.UseHypervisor) 53 { 54 var cpuEngine = new HvEngine(_tickSource); 55 var memoryManager = new HvMemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler); 56 processContext = new ArmProcessContext<HvMemoryManager>(pid, cpuEngine, _gpu, memoryManager, addressSpaceSize, for64Bit); 57 } 58 else 59 { 60 MemoryManagerMode mode = context.Device.Configuration.MemoryManagerMode; 61 62 if (!MemoryBlock.SupportsFlags(MemoryAllocationFlags.ViewCompatible)) 63 { 64 Logger.Warning?.Print(LogClass.Cpu, "Host system doesn't support views, falling back to software page table"); 65 66 mode = MemoryManagerMode.SoftwarePageTable; 67 } 68 69 ICpuEngine cpuEngine = isArm64Host && (mode == MemoryManagerMode.HostMapped || mode == MemoryManagerMode.HostMappedUnsafe) 70 ? new LightningJitEngine(_tickSource) 71 : new JitEngine(_tickSource); 72 73 AddressSpace addressSpace = null; 74 75 // We want to use host tracked mode if the host page size is > 4KB. 76 if ((mode == MemoryManagerMode.HostMapped || mode == MemoryManagerMode.HostMappedUnsafe) && MemoryBlock.GetPageSize() <= 0x1000) 77 { 78 if (!AddressSpace.TryCreate(context.Memory, addressSpaceSize, out addressSpace)) 79 { 80 Logger.Warning?.Print(LogClass.Cpu, "Address space creation failed, falling back to software page table"); 81 82 mode = MemoryManagerMode.SoftwarePageTable; 83 } 84 } 85 86 switch (mode) 87 { 88 case MemoryManagerMode.SoftwarePageTable: 89 var memoryManager = new MemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler); 90 processContext = new ArmProcessContext<MemoryManager>(pid, cpuEngine, _gpu, memoryManager, addressSpaceSize, for64Bit); 91 break; 92 93 case MemoryManagerMode.HostMapped: 94 case MemoryManagerMode.HostMappedUnsafe: 95 if (addressSpace == null) 96 { 97 var memoryManagerHostTracked = new MemoryManagerHostTracked(context.Memory, addressSpaceSize, mode == MemoryManagerMode.HostMappedUnsafe, invalidAccessHandler); 98 processContext = new ArmProcessContext<MemoryManagerHostTracked>(pid, cpuEngine, _gpu, memoryManagerHostTracked, addressSpaceSize, for64Bit); 99 } 100 else 101 { 102 if (addressSpaceSize != addressSpace.AddressSpaceSize) 103 { 104 Logger.Warning?.Print(LogClass.Emulation, $"Allocated address space (0x{addressSpace.AddressSpaceSize:X}) is smaller than guest application requirements (0x{addressSpaceSize:X})"); 105 } 106 107 var memoryManagerHostMapped = new MemoryManagerHostMapped(addressSpace, mode == MemoryManagerMode.HostMappedUnsafe, invalidAccessHandler); 108 processContext = new ArmProcessContext<MemoryManagerHostMapped>(pid, cpuEngine, _gpu, memoryManagerHostMapped, addressSpace.AddressSpaceSize, for64Bit); 109 } 110 break; 111 112 default: 113 throw new InvalidOperationException($"{nameof(mode)} contains an invalid value: {mode}"); 114 } 115 } 116 117 DiskCacheLoadState = processContext.Initialize(_titleIdText, _displayVersion, _diskCacheEnabled, _codeAddress, _codeSize); 118 119 return processContext; 120 } 121 } 122 }