/ src / Ryujinx.HLE / HOS / ArmProcessContextFactory.cs
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  }