Cpu: add option to force all exclusive memory accesses to be ordered on AppleHv.
parent
3394736b07
commit
ac732a20b0
|
|
@ -267,6 +267,31 @@
|
|||
"zh_TW": "使用 Hypervisor"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "SettingsTabSystemHvForceOrderedAtomics",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "",
|
||||
"el_GR": "",
|
||||
"en_US": "Force Ordered Atomics on Hypervisor",
|
||||
"es_ES": "",
|
||||
"fr_FR": "",
|
||||
"he_IL": "",
|
||||
"it_IT": "",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "",
|
||||
"no_NO": "",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "",
|
||||
"ru_RU": "",
|
||||
"sv_SE": "",
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "",
|
||||
"zh_TW": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "MenuBarFile",
|
||||
"Translations": {
|
||||
|
|
@ -16518,6 +16543,31 @@
|
|||
"zh_TW": "使用 Hypervisor 取代 JIT。使用時可大幅提高效能,但在目前狀態下可能不穩定。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "HvForceOrderedAtomicsTooltip",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "",
|
||||
"el_GR": "",
|
||||
"en_US": "Force all exclusive memory accesses to be ordered on Hypervisor.\n\nSome games like The Legend of Zelda: Breath of the Wild and Splatoon 2 require this setting to be ON when using Hypervisor to prevent softlocks and crashes.\n\nLeave OFF if unsure.",
|
||||
"es_ES": "",
|
||||
"fr_FR": "",
|
||||
"he_IL": "",
|
||||
"it_IT": "",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "",
|
||||
"no_NO": "",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "",
|
||||
"ru_RU": "",
|
||||
"sv_SE": "",
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "",
|
||||
"zh_TW": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "DRamTooltip",
|
||||
"Translations": {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Intrinsics;
|
||||
|
||||
namespace Ryujinx.Cpu.AppleHv
|
||||
{
|
||||
static class HvCodePatcher
|
||||
{
|
||||
private const uint XMask = 0x3f808000u;
|
||||
private const uint XValue = 0x8000000u;
|
||||
|
||||
private const uint ZrIndex = 31u;
|
||||
|
||||
public static void RewriteUnorderedExclusiveInstructions(Span<byte> code)
|
||||
{
|
||||
Span<uint> codeUint = MemoryMarshal.Cast<byte, uint>(code);
|
||||
Span<Vector128<uint>> codeVector = MemoryMarshal.Cast<byte, Vector128<uint>>(code);
|
||||
|
||||
Vector128<uint> mask = Vector128.Create(XMask);
|
||||
Vector128<uint> value = Vector128.Create(XValue);
|
||||
|
||||
for (int index = 0; index < codeVector.Length; index++)
|
||||
{
|
||||
Vector128<uint> v = codeVector[index];
|
||||
|
||||
if (Vector128.EqualsAny(Vector128.BitwiseAnd(v, mask), value))
|
||||
{
|
||||
int baseIndex = index * 4;
|
||||
|
||||
for (int instIndex = baseIndex; instIndex < baseIndex + 4; instIndex++)
|
||||
{
|
||||
ref uint inst = ref codeUint[instIndex];
|
||||
|
||||
if ((inst & XMask) != XValue)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isPair = (inst & (1u << 21)) != 0;
|
||||
bool isLoad = (inst & (1u << 22)) != 0;
|
||||
|
||||
uint rt2 = (inst >> 10) & 0x1fu;
|
||||
uint rs = (inst >> 16) & 0x1fu;
|
||||
|
||||
if (isLoad && rs != ZrIndex)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isPair && rt2 != ZrIndex)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set the ordered flag.
|
||||
inst |= 1u << 15;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -25,6 +25,8 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
private readonly MemoryBlock _backingMemory;
|
||||
private readonly PageTable<ulong> _pageTable;
|
||||
|
||||
private readonly bool _forceOrderedAtomics;
|
||||
|
||||
private readonly ManagedPageFlags _pages;
|
||||
|
||||
public bool UsesPrivateAllocations => false;
|
||||
|
|
@ -46,11 +48,13 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
/// </summary>
|
||||
/// <param name="backingMemory">Physical backing memory where virtual memory will be mapped to</param>
|
||||
/// <param name="addressSpaceSize">Size of the address space</param>
|
||||
/// <param name="forceOrderedAtomics">Force all exclusive memory accesses to be ordered</param>
|
||||
/// <param name="invalidAccessHandler">Optional function to handle invalid memory accesses</param>
|
||||
public HvMemoryManager(MemoryBlock backingMemory, ulong addressSpaceSize, InvalidAccessHandler invalidAccessHandler = null)
|
||||
public HvMemoryManager(MemoryBlock backingMemory, ulong addressSpaceSize, bool forceOrderedAtomics, InvalidAccessHandler invalidAccessHandler = null)
|
||||
{
|
||||
_backingMemory = backingMemory;
|
||||
_pageTable = new PageTable<ulong>();
|
||||
_forceOrderedAtomics = forceOrderedAtomics;
|
||||
_invalidAccessHandler = invalidAccessHandler;
|
||||
AddressSpaceSize = addressSpaceSize;
|
||||
|
||||
|
|
@ -317,6 +321,18 @@ namespace Ryujinx.Cpu.AppleHv
|
|||
|
||||
public void Reprotect(ulong va, ulong size, MemoryPermission protection)
|
||||
{
|
||||
if (_forceOrderedAtomics && protection.HasFlag(MemoryPermission.Execute))
|
||||
{
|
||||
// Some applications use unordered exclusive memory access instructions
|
||||
// where it is not valid to do so, leading to memory re-ordering that
|
||||
// makes the code behave incorrectly on some CPUs.
|
||||
// To work around this, we force all such accesses to be ordered.
|
||||
|
||||
using WritableRegion writableRegion = GetWritableRegion(va, (int)size);
|
||||
|
||||
HvCodePatcher.RewriteUnorderedExclusiveInstructions(writableRegion.Memory.Span);
|
||||
}
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ namespace Ryujinx.HLE.HOS
|
|||
if (OperatingSystem.IsMacOS() && isArm64Host && for64Bit && context.Device.Configuration.UseHypervisor)
|
||||
{
|
||||
HvEngine cpuEngine = new(_tickSource);
|
||||
HvMemoryManager memoryManager = new(context.Memory, addressSpaceSize, invalidAccessHandler);
|
||||
HvMemoryManager memoryManager = new(context.Memory, addressSpaceSize, context.Device.Configuration.HvForceOrderedAtomics, invalidAccessHandler);
|
||||
processContext = new ArmProcessContext<HvMemoryManager>(pid, cpuEngine, _gpu, memoryManager, addressSpaceSize, for64Bit);
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -164,6 +164,11 @@ namespace Ryujinx.HLE
|
|||
/// </summary>
|
||||
internal readonly bool UseHypervisor;
|
||||
|
||||
/// <summary>
|
||||
/// Force all exclusive memory accesses to be ordered on Hypervisor.
|
||||
/// </summary>
|
||||
internal readonly bool HvForceOrderedAtomics;
|
||||
|
||||
/// <summary>
|
||||
/// Multiplayer LAN Interface ID (device GUID)
|
||||
/// </summary>
|
||||
|
|
@ -232,6 +237,7 @@ namespace Ryujinx.HLE
|
|||
AspectRatio aspectRatio,
|
||||
float audioVolume,
|
||||
bool useHypervisor,
|
||||
bool hvForceOrderedAtomics,
|
||||
string multiplayerLanInterfaceId,
|
||||
MultiplayerMode multiplayerMode,
|
||||
bool multiplayerDisableP2p,
|
||||
|
|
@ -261,6 +267,7 @@ namespace Ryujinx.HLE
|
|||
AspectRatio = aspectRatio;
|
||||
AudioVolume = audioVolume;
|
||||
UseHypervisor = useHypervisor;
|
||||
HvForceOrderedAtomics = hvForceOrderedAtomics;
|
||||
MultiplayerLanInterfaceId = multiplayerLanInterfaceId;
|
||||
MultiplayerMode = multiplayerMode;
|
||||
MultiplayerDisableP2p = multiplayerDisableP2p;
|
||||
|
|
|
|||
|
|
@ -333,6 +333,7 @@ namespace Ryujinx.Headless
|
|||
options.AspectRatio,
|
||||
options.AudioVolume,
|
||||
options.UseHypervisor ?? true,
|
||||
options.HvForceOrderedAtomics,
|
||||
options.MultiplayerLanInterfaceId,
|
||||
Common.Configuration.Multiplayer.MultiplayerMode.Disabled,
|
||||
false,
|
||||
|
|
|
|||
|
|
@ -79,6 +79,9 @@ namespace Ryujinx.Headless
|
|||
if (NeedsOverride(nameof(UseHypervisor)) && OperatingSystem.IsMacOS())
|
||||
UseHypervisor = configurationState.System.UseHypervisor;
|
||||
|
||||
if (NeedsOverride(nameof(HvForceOrderedAtomics)) && OperatingSystem.IsMacOS())
|
||||
HvForceOrderedAtomics = configurationState.System.HvForceOrderedAtomics;
|
||||
|
||||
if (NeedsOverride(nameof(MultiplayerLanInterfaceId)))
|
||||
MultiplayerLanInterfaceId = configurationState.Multiplayer.LanInterfaceId;
|
||||
|
||||
|
|
@ -339,6 +342,9 @@ namespace Ryujinx.Headless
|
|||
[Option("use-hypervisor", Required = false, Default = true, HelpText = "Uses Hypervisor over JIT if available.")]
|
||||
public bool? UseHypervisor { get; set; }
|
||||
|
||||
[Option("hv-force-ordered-atomics", Required = false, Default = false, HelpText = "Forces all exclusive memory accesses to be ordered on Hypervisor.")]
|
||||
public bool HvForceOrderedAtomics { get; set; }
|
||||
|
||||
[Option("lan-interface-id", Required = false, Default = "0", HelpText = "GUID for the network interface used by LAN.")]
|
||||
public string MultiplayerLanInterfaceId { get; set; }
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ namespace Ryujinx.Ava.Systems.Configuration
|
|||
/// <summary>
|
||||
/// The current version of the file format
|
||||
/// </summary>
|
||||
public const int CurrentVersion = 70;
|
||||
public const int CurrentVersion = 71;
|
||||
|
||||
/// <summary>
|
||||
/// Version of the configuration file format
|
||||
|
|
@ -464,6 +464,11 @@ namespace Ryujinx.Ava.Systems.Configuration
|
|||
/// </summary>
|
||||
public bool UseHypervisor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Force all exclusive memory accesses to be ordered on Hypervisor.
|
||||
/// </summary>
|
||||
public bool HvForceOrderedAtomics { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables or disables the GDB stub
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ namespace Ryujinx.Ava.Systems.Configuration
|
|||
System.IgnoreControllerApplet.Value = cff.IgnoreApplet;
|
||||
System.SkipUserProfilesManager.Value = cff.SkipUserProfiles;
|
||||
System.UseHypervisor.Value = cff.UseHypervisor;
|
||||
System.HvForceOrderedAtomics.Value = cff.HvForceOrderedAtomics;
|
||||
|
||||
UI.GuiColumns.FavColumn.Value = shouldLoadFromFile ? cff.GuiColumns.FavColumn : UI.GuiColumns.FavColumn.Value;
|
||||
UI.GuiColumns.IconColumn.Value = shouldLoadFromFile ? cff.GuiColumns.IconColumn : UI.GuiColumns.IconColumn.Value;
|
||||
|
|
@ -484,7 +485,8 @@ namespace Ryujinx.Ava.Systems.Configuration
|
|||
};
|
||||
}
|
||||
),
|
||||
(69, static cff => cff.SkipUserProfiles = false)
|
||||
(69, static cff => cff.SkipUserProfiles = false),
|
||||
(70, static cff => cff.HvForceOrderedAtomics = false)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -412,6 +412,11 @@ namespace Ryujinx.Ava.Systems.Configuration
|
|||
/// </summary>
|
||||
public ReactiveObject<bool> UseHypervisor { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Force all exclusive memory accesses to be ordered on Hypervisor.
|
||||
/// </summary>
|
||||
public ReactiveObject<bool> HvForceOrderedAtomics { get; private set; }
|
||||
|
||||
public SystemSection()
|
||||
{
|
||||
Language = new ReactiveObject<Language>();
|
||||
|
|
@ -465,6 +470,8 @@ namespace Ryujinx.Ava.Systems.Configuration
|
|||
AudioVolume.LogChangesToValue(nameof(AudioVolume));
|
||||
UseHypervisor = new ReactiveObject<bool>();
|
||||
UseHypervisor.LogChangesToValue(nameof(UseHypervisor));
|
||||
HvForceOrderedAtomics = new ReactiveObject<bool>();
|
||||
HvForceOrderedAtomics.LogChangesToValue(nameof(HvForceOrderedAtomics));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -936,6 +943,7 @@ namespace Ryujinx.Ava.Systems.Configuration
|
|||
Graphics.AspectRatio,
|
||||
System.AudioVolume,
|
||||
System.UseHypervisor,
|
||||
System.HvForceOrderedAtomics,
|
||||
Multiplayer.LanInterfaceId,
|
||||
Multiplayer.Mode,
|
||||
Multiplayer.DisableP2p,
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ namespace Ryujinx.Ava.Systems.Configuration
|
|||
IgnoreApplet = System.IgnoreControllerApplet,
|
||||
SkipUserProfiles = System.SkipUserProfilesManager,
|
||||
UseHypervisor = System.UseHypervisor,
|
||||
HvForceOrderedAtomics = System.HvForceOrderedAtomics,
|
||||
GuiColumns = new GuiColumns
|
||||
{
|
||||
FavColumn = UI.GuiColumns.FavColumn,
|
||||
|
|
@ -215,6 +216,7 @@ namespace Ryujinx.Ava.Systems.Configuration
|
|||
System.IgnoreControllerApplet.Value = false;
|
||||
System.SkipUserProfilesManager.Value = false;
|
||||
System.UseHypervisor.Value = true;
|
||||
System.HvForceOrderedAtomics.Value = false;
|
||||
Multiplayer.LanInterfaceId.Value = "0";
|
||||
Multiplayer.Mode.Value = MultiplayerMode.Disabled;
|
||||
Multiplayer.DisableP2p.Value = false;
|
||||
|
|
|
|||
|
|
@ -276,6 +276,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||
public bool IsVulkanSelected =>
|
||||
GraphicsBackendIndex == 1 || (GraphicsBackendIndex == 0 && !OperatingSystem.IsMacOS());
|
||||
public bool UseHypervisor { get; set; }
|
||||
public bool HvForceOrderedAtomics { get; set; }
|
||||
public bool DisableP2P { get; set; }
|
||||
|
||||
public bool ShowDirtyHacks => ConfigurationState.Instance.Hacks.ShowDirtyHacks;
|
||||
|
|
@ -673,6 +674,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||
EnableLowPowerPptc = config.System.EnableLowPowerPtc;
|
||||
MemoryMode = (int)config.System.MemoryManagerMode.Value;
|
||||
UseHypervisor = config.System.UseHypervisor;
|
||||
HvForceOrderedAtomics = config.System.HvForceOrderedAtomics;
|
||||
TurboMultiplier = config.System.TickScalar;
|
||||
|
||||
// Graphics
|
||||
|
|
@ -784,6 +786,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||
config.System.EnableLowPowerPtc.Value = EnableLowPowerPptc;
|
||||
config.System.MemoryManagerMode.Value = (MemoryManagerMode)MemoryMode;
|
||||
config.System.UseHypervisor.Value = UseHypervisor;
|
||||
config.System.HvForceOrderedAtomics.Value = HvForceOrderedAtomics;
|
||||
config.System.TickScalar.Value = TurboMultiplier;
|
||||
|
||||
// Graphics
|
||||
|
|
|
|||
|
|
@ -71,6 +71,12 @@
|
|||
<TextBlock Text="{ext:Locale SettingsTabSystemUseHypervisor}"
|
||||
ToolTip.Tip="{ext:Locale UseHypervisorTooltip}" />
|
||||
</CheckBox>
|
||||
<CheckBox IsChecked="{Binding HvForceOrderedAtomics}"
|
||||
IsVisible="{x:Static helper:RunningPlatform.IsArmMac}"
|
||||
ToolTip.Tip="{ext:Locale HvForceOrderedAtomicsTooltip}">
|
||||
<TextBlock Text="{ext:Locale SettingsTabSystemHvForceOrderedAtomics}"
|
||||
ToolTip.Tip="{ext:Locale HvForceOrderedAtomicsTooltip}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
<Separator Height="1" />
|
||||
<StackPanel
|
||||
|
|
|
|||
Loading…
Reference in New Issue