diff --git a/src/ARMeilleure/Instructions/NativeInterface.cs b/src/ARMeilleure/Instructions/NativeInterface.cs
index dd53b17c9..f69cc1e0a 100644
--- a/src/ARMeilleure/Instructions/NativeInterface.cs
+++ b/src/ARMeilleure/Instructions/NativeInterface.cs
@@ -2,6 +2,8 @@ using ARMeilleure.Memory;
using ARMeilleure.State;
using ARMeilleure.Translation;
using System;
+using System.Threading;
+using ExecutionContext = ARMeilleure.State.ExecutionContext;
namespace ARMeilleure.Instructions
{
@@ -175,7 +177,7 @@ namespace ARMeilleure.Instructions
ExecutionContext context = GetContext();
- if (context.DebugStopped == 1)
+ if (Optimizations.EnableDebugging && context.Interrupted)
{
return false;
}
diff --git a/src/ARMeilleure/State/ExecutionContext.cs b/src/ARMeilleure/State/ExecutionContext.cs
index de4528d11..a414dd3f4 100644
--- a/src/ARMeilleure/State/ExecutionContext.cs
+++ b/src/ARMeilleure/State/ExecutionContext.cs
@@ -14,7 +14,7 @@ namespace ARMeilleure.State
internal IntPtr NativeContextPtr => _nativeContext.BasePtr;
- private bool _interrupted;
+ internal bool Interrupted { get; private set; }
private readonly ICounter _counter;
@@ -103,9 +103,9 @@ namespace ARMeilleure.State
internal int ShouldStep;
internal int DebugStopped;
-
- // This is only valid while debugging is enabled.
- public ulong DebugPc;
+
+ public ulong DebugPc; // This is only valid while debugging is enabled.
+ public Barrier StepBarrier = new Barrier(2);
public ExecutionContext(
IJitMemoryAllocator allocator,
@@ -141,9 +141,9 @@ namespace ARMeilleure.State
internal void CheckInterrupt()
{
- if (_interrupted)
+ if (Interrupted)
{
- _interrupted = false;
+ Interrupted = false;
_interruptCallback?.Invoke(this);
}
@@ -153,31 +153,13 @@ namespace ARMeilleure.State
public void RequestInterrupt()
{
- _interrupted = true;
+ Interrupted = true;
}
- public void DebugStop()
+ public void RequestDebugStep()
{
- if (Interlocked.CompareExchange(ref DebugStopped, 1, 0) == 0)
- {
- RequestInterrupt();
- }
- }
-
- public bool DebugStep()
- {
- if (DebugStopped != 1)
- {
- return false;
- }
-
- ShouldStep = 1;
- return true;
- }
-
- public void DebugContinue()
- {
- Interlocked.CompareExchange(ref DebugStopped, 0, 1);
+ Interlocked.Exchange(ref ShouldStep, 1);
+ RequestInterrupt();
}
internal void OnBreak(ulong address, int imm)
diff --git a/src/ARMeilleure/Translation/Translator.cs b/src/ARMeilleure/Translation/Translator.cs
index 99db92280..035005aa1 100644
--- a/src/ARMeilleure/Translation/Translator.cs
+++ b/src/ARMeilleure/Translation/Translator.cs
@@ -145,17 +145,17 @@ namespace ARMeilleure.Translation
context.DebugPc = address;
do
{
- context.DebugPc = ExecuteSingle(context, context.DebugPc);
-
- while (context.DebugStopped == 1)
+ if (Interlocked.CompareExchange(ref context.ShouldStep, 0, 1) == 1)
{
- if (Interlocked.CompareExchange(ref context.ShouldStep, 0, 1) == 1)
- {
- context.DebugPc = Step(context, context.DebugPc);
- context.RequestInterrupt();
- }
- context.CheckInterrupt();
+ context.DebugPc = Step(context, context.DebugPc);
+ context.StepBarrier.SignalAndWait();
+ context.StepBarrier.SignalAndWait();
}
+ else
+ {
+ context.DebugPc = ExecuteSingle(context, context.DebugPc);
+ }
+ context.CheckInterrupt();
}
while (context.Running && context.DebugPc != 0);
}
diff --git a/src/Ryujinx.Cpu/AppleHv/Arm/ExceptionLevel.cs b/src/Ryujinx.Cpu/AppleHv/Arm/ExceptionLevel.cs
new file mode 100644
index 000000000..96e3ae59a
--- /dev/null
+++ b/src/Ryujinx.Cpu/AppleHv/Arm/ExceptionLevel.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.Cpu.AppleHv.Arm
+{
+ enum ExceptionLevel: uint
+ {
+ PstateMask = 0xfffffff0,
+ EL1h = 0b0101,
+ El1t = 0b0100,
+ EL0 = 0b0000,
+ }
+}
diff --git a/src/Ryujinx.Cpu/AppleHv/HvExecutionContext.cs b/src/Ryujinx.Cpu/AppleHv/HvExecutionContext.cs
index db195e738..220b3bad6 100644
--- a/src/Ryujinx.Cpu/AppleHv/HvExecutionContext.cs
+++ b/src/Ryujinx.Cpu/AppleHv/HvExecutionContext.cs
@@ -11,7 +11,18 @@ namespace Ryujinx.Cpu.AppleHv
class HvExecutionContext : IExecutionContext
{
///
- public ulong Pc => _impl.ElrEl1;
+ public ulong Pc
+ {
+ get
+ {
+ uint currentEl = Pstate & ~((uint)ExceptionLevel.PstateMask);
+ if (currentEl == (uint)ExceptionLevel.EL1h)
+ {
+ return _impl.ElrEl1;
+ }
+ return _impl.Pc;
+ }
+ }
///
public long TpidrEl0
@@ -71,7 +82,6 @@ namespace Ryujinx.Cpu.AppleHv
private readonly IHvExecutionContext _shadowContext;
private IHvExecutionContext _impl;
private int _shouldStep;
- private int _debugStopped;
private readonly ExceptionCallbacks _exceptionCallbacks;
@@ -83,6 +93,7 @@ namespace Ryujinx.Cpu.AppleHv
_shadowContext = new HvExecutionContextShadow();
_impl = _shadowContext;
_exceptionCallbacks = exceptionCallbacks;
+ StepBarrier = new(2);
Running = true;
}
@@ -133,39 +144,31 @@ namespace Ryujinx.Cpu.AppleHv
}
///
- public void DebugStop()
+ public void RequestDebugStep()
{
- if (Interlocked.CompareExchange(ref _debugStopped, 1, 0) == 0)
- {
- RequestInterrupt();
- }
- }
-
- ///
- public bool DebugStep()
- {
- if (_debugStopped != 1)
- {
- return false;
- }
-
- _shouldStep = 1;
- return true;
- }
-
- ///
- public void DebugContinue()
- {
- Interlocked.CompareExchange(ref _debugStopped, 0, 1);
+ Interlocked.Exchange(ref _shouldStep, 1);
}
///
public ulong DebugPc
{
- get => _impl.ElrEl1;
- set => _impl.ElrEl1 = value;
+ get => Pc;
+ set
+ {
+ uint currentEl = Pstate & ~((uint)ExceptionLevel.PstateMask);
+ if (currentEl == (uint)ExceptionLevel.EL1h)
+ {
+ _impl.ElrEl1 = value;
+ }
+ else
+ {
+ _impl.Pc = value;
+ }
+ }
}
+ public Barrier StepBarrier { get; private set; }
+
///
public void StopRunning()
{
@@ -183,13 +186,17 @@ namespace Ryujinx.Cpu.AppleHv
{
if (Interlocked.CompareExchange(ref _shouldStep, 0, 1) == 1)
{
- uint currentEl = Pstate & ~(0xfffffff0);
- if (currentEl == 0b0101)
+ uint currentEl = Pstate & ~((uint)ExceptionLevel.PstateMask);
+ if (currentEl == (uint)ExceptionLevel.EL1h)
{
HvApi.hv_vcpu_get_sys_reg(vcpu.Handle, HvSysReg.SPSR_EL1, out ulong spsr).ThrowOnError();
spsr |= (1 << 21);
HvApi.hv_vcpu_set_sys_reg(vcpu.Handle, HvSysReg.SPSR_EL1, spsr);
}
+ else
+ {
+ Pstate |= (1 << 21);
+ }
HvApi.hv_vcpu_set_sys_reg(vcpu.Handle, HvSysReg.MDSCR_EL1, 1);
}
@@ -206,7 +213,6 @@ namespace Ryujinx.Cpu.AppleHv
{
throw new Exception($"Unhandled exception from guest kernel with ESR 0x{hvEsr:X} ({hvEc}).");
}
-
address = SynchronousException(memoryManager, ref vcpu);
HvApi.hv_vcpu_set_reg(vcpu.Handle, HvReg.PC, address).ThrowOnError();
}
@@ -266,13 +272,14 @@ namespace Ryujinx.Cpu.AppleHv
HvApi.hv_vcpu_set_sys_reg(vcpuHandle, HvSysReg.SPSR_EL1, spsr).ThrowOnError();
HvApi.hv_vcpu_set_sys_reg(vcpuHandle, HvSysReg.MDSCR_EL1, 0);
ReturnToPool(vcpu);
+ StepBarrier.SignalAndWait();
+ StepBarrier.SignalAndWait();
InterruptHandler();
vcpu = RentFromPool(memoryManager.AddressSpace, vcpu);
break;
case ExceptionClass.BrkAarch64:
ReturnToPool(vcpu);
BreakHandler(elr, (ushort)esr);
- InterruptHandler();
vcpu = RentFromPool(memoryManager.AddressSpace, vcpu);
break;
default:
diff --git a/src/Ryujinx.Cpu/AppleHv/HvExecutionContextVcpu.cs b/src/Ryujinx.Cpu/AppleHv/HvExecutionContextVcpu.cs
index 4e4b6ef59..4299902b2 100644
--- a/src/Ryujinx.Cpu/AppleHv/HvExecutionContextVcpu.cs
+++ b/src/Ryujinx.Cpu/AppleHv/HvExecutionContextVcpu.cs
@@ -138,6 +138,7 @@ namespace Ryujinx.Cpu.AppleHv
private readonly ulong _vcpu;
private int _interruptRequested;
+ private int _breakRequested;
public HvExecutionContextVcpu(ulong vcpu)
{
diff --git a/src/Ryujinx.Cpu/IExecutionContext.cs b/src/Ryujinx.Cpu/IExecutionContext.cs
index 2f4abdedc..40438d6fc 100644
--- a/src/Ryujinx.Cpu/IExecutionContext.cs
+++ b/src/Ryujinx.Cpu/IExecutionContext.cs
@@ -1,5 +1,6 @@
using ARMeilleure.State;
using System;
+using System.Threading;
namespace Ryujinx.Cpu
{
@@ -115,10 +116,9 @@ namespace Ryujinx.Cpu
void StopRunning();
// TODO: comments
- void DebugStop();
- bool DebugStep();
- void DebugContinue();
+ void RequestDebugStep();
ulong DebugPc { get; set; }
+ Barrier StepBarrier { get; }
}
}
diff --git a/src/Ryujinx.Cpu/Jit/JitExecutionContext.cs b/src/Ryujinx.Cpu/Jit/JitExecutionContext.cs
index 2f3e0d59b..e12c28d30 100644
--- a/src/Ryujinx.Cpu/Jit/JitExecutionContext.cs
+++ b/src/Ryujinx.Cpu/Jit/JitExecutionContext.cs
@@ -1,5 +1,7 @@
using ARMeilleure.Memory;
using ARMeilleure.State;
+using System.Threading;
+using ExecutionContext = ARMeilleure.State.ExecutionContext;
namespace Ryujinx.Cpu.Jit
{
@@ -117,13 +119,7 @@ namespace Ryujinx.Cpu.Jit
}
///
- public void DebugStop() => _impl.DebugStop();
-
- ///
- public bool DebugStep() => _impl.DebugStep();
-
- ///
- public void DebugContinue() => _impl.DebugContinue();
+ public void RequestDebugStep() => _impl.RequestDebugStep();
///
public ulong DebugPc
@@ -132,6 +128,9 @@ namespace Ryujinx.Cpu.Jit
set => _impl.DebugPc = value;
}
+ ///
+ public Barrier StepBarrier => _impl.StepBarrier;
+
///
public void StopRunning()
{
diff --git a/src/Ryujinx.HLE/Debugger/Debugger.cs b/src/Ryujinx.HLE/Debugger/Debugger.cs
index 70877daea..ce0102ecc 100644
--- a/src/Ryujinx.HLE/Debugger/Debugger.cs
+++ b/src/Ryujinx.HLE/Debugger/Debugger.cs
@@ -53,6 +53,7 @@ namespace Ryujinx.HLE.Debugger
private IVirtualMemoryManager GetMemory() => Device.System.DebugGetApplicationProcess().CpuMemory;
private void InvalidateCacheRegion(ulong address, ulong size) =>
Device.System.DebugGetApplicationProcess().InvalidateCacheRegion(address, size);
+ private KernelContext KernelContext => Device.System.KernelContext;
const int GdbRegisterCount = 68;
@@ -77,7 +78,7 @@ namespace Ryujinx.HLE.Debugger
}
}
- private string GdbReadRegister(Ryujinx.Cpu.IExecutionContext state, int gdbRegId)
+ private string GdbReadRegister(IExecutionContext state, int gdbRegId)
{
switch (gdbRegId)
{
@@ -724,13 +725,32 @@ namespace Ryujinx.HLE.Debugger
public void ThreadBreak(IExecutionContext ctx, ulong address, int imm)
{
- KThread thread = GetThread(ctx.ThreadUid);
-
- thread.DebugStop();
-
Logger.Notice.Print(LogClass.GdbStub, $"Break hit on thread {ctx.ThreadUid} at pc {address:x016}");
Messages.Add(new ThreadBreakMessage(ctx, address, imm));
+
+ KThread currentThread = GetThread(ctx.ThreadUid);
+
+ if (currentThread.Context.Running &&
+ currentThread.Owner != null &&
+ currentThread.GetUserDisableCount() != 0 &&
+ currentThread.Owner.PinnedThreads[currentThread.CurrentCore] == null)
+ {
+ KernelContext.CriticalSection.Enter();
+
+ currentThread.Owner.PinThread(currentThread);
+
+ currentThread.SetUserInterruptFlag();
+
+ KernelContext.CriticalSection.Leave();
+ }
+
+ if (currentThread.IsSchedulable)
+ {
+ KernelContext.Schedulers[currentThread.CurrentCore].Schedule();
+ }
+
+ currentThread.HandlePostSyscall();
}
}
}
diff --git a/src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs b/src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
index 261ec649c..9cdd90de5 100644
--- a/src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
+++ b/src/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
@@ -749,14 +749,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{
KThread currentThread = KernelStatic.GetCurrentThread();
- if (currentThread.GetDebugState() != DebugState.Running)
- {
- KernelContext.CriticalSection.Enter();
- currentThread.Suspend(ThreadSchedState.ThreadPauseFlag);
- currentThread.DebugHalt.Set();
- KernelContext.CriticalSection.Leave();
- }
-
if (currentThread.Context.Running &&
currentThread.Owner != null &&
currentThread.GetUserDisableCount() != 0 &&
diff --git a/src/Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs b/src/Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs
index 2cfdbd687..717ed9c77 100644
--- a/src/Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs
+++ b/src/Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs
@@ -1,5 +1,6 @@
using ARMeilleure.State;
using Ryujinx.Cpu;
+using System.Threading;
namespace Ryujinx.HLE.HOS.Kernel.Process
{
@@ -24,6 +25,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
private readonly ulong[] _x = new ulong[32];
public ulong DebugPc { get; set; }
+ public Barrier StepBarrier { get; }
public ulong GetX(int index) => _x[index];
public void SetX(int index, ulong value) => _x[index] = value;
@@ -35,16 +37,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{
}
- public void DebugStop()
- {
- }
-
- public bool DebugStep()
- {
- return false;
- }
-
- public void DebugContinue()
+ public void RequestDebugStep()
{
}
diff --git a/src/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs b/src/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
index aac0f2f8d..dcc992b71 100644
--- a/src/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
+++ b/src/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
@@ -1443,15 +1443,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
lock (_activityOperationLock)
{
if (_debugState != (int)DebugState.Stopped
- || (_forcePauseFlags & ThreadSchedState.ThreadPauseFlag) == 0
- || !Context.DebugStep())
+ || (_forcePauseFlags & ThreadSchedState.ThreadPauseFlag) == 0)
{
return false;
}
- DebugHalt.Reset();
+ Context.RequestDebugStep();
Resume(ThreadSchedState.ThreadPauseFlag);
- DebugHalt.WaitOne();
+ Context.StepBarrier.SignalAndWait();
+ Suspend(ThreadSchedState.ThreadPauseFlag);
+ Context.StepBarrier.SignalAndWait();
return true;
}
@@ -1467,12 +1468,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
return;
}
- if ((_forcePauseFlags & ThreadSchedState.ThreadPauseFlag) == 0)
- {
- Suspend(ThreadSchedState.ThreadPauseFlag);
- }
-
- Context.DebugStop();
+ Suspend(ThreadSchedState.ThreadPauseFlag);
+ Context.RequestInterrupt();
DebugHalt.WaitOne();
_debugState = (int)DebugState.Stopped;
@@ -1489,8 +1486,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
return;
}
- Context.DebugContinue();
-
if ((_forcePauseFlags & ThreadSchedState.ThreadPauseFlag) != 0)
{
Resume(ThreadSchedState.ThreadPauseFlag);