From 65d7a16a872d9416efd67e837a7736dc4f5f8e35 Mon Sep 17 00:00:00 2001 From: svc64 Date: Fri, 6 Oct 2023 15:33:35 +0300 Subject: [PATCH] Debugger refactor --- .../Instructions/NativeInterface.cs | 4 +- src/ARMeilleure/State/ExecutionContext.cs | 38 +++------- src/ARMeilleure/Translation/Translator.cs | 18 ++--- src/Ryujinx.Cpu/AppleHv/Arm/ExceptionLevel.cs | 10 +++ src/Ryujinx.Cpu/AppleHv/HvExecutionContext.cs | 69 ++++++++++--------- .../AppleHv/HvExecutionContextVcpu.cs | 1 + src/Ryujinx.Cpu/IExecutionContext.cs | 6 +- src/Ryujinx.Cpu/Jit/JitExecutionContext.cs | 13 ++-- src/Ryujinx.HLE/Debugger/Debugger.cs | 30 ++++++-- .../HOS/Kernel/Process/KProcess.cs | 8 --- .../Kernel/Process/ProcessExecutionContext.cs | 13 +--- .../HOS/Kernel/Threading/KThread.cs | 19 ++--- 12 files changed, 115 insertions(+), 114 deletions(-) create mode 100644 src/Ryujinx.Cpu/AppleHv/Arm/ExceptionLevel.cs 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);