thermosphere: rewrite debug pause & fix single step state machine
This commit is contained in:
@@ -14,46 +14,74 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdatomic.h>
|
||||
|
||||
#include "debug_pause.h"
|
||||
#include "core_ctx.h"
|
||||
#include "irq.h"
|
||||
#include "spinlock.h"
|
||||
#include "single_step.h"
|
||||
|
||||
// Reminder: use these functions behind a lock
|
||||
|
||||
static Barrier g_debugPauseBarrier;
|
||||
static RecursiveSpinlock g_debugPauseContinueLocks[4];
|
||||
static atomic_uint g_debugPausePausedCoreList;
|
||||
static atomic_uint g_debugPauseSingleStepCoreList;
|
||||
|
||||
void debugPauseSgiTopHalf(void)
|
||||
void debugPauseSgiHandler(void)
|
||||
{
|
||||
currentCoreCtx->wasPaused = true;
|
||||
barrierWait(&g_debugPauseBarrier);
|
||||
}
|
||||
|
||||
void debugPauseSgiBottomHalf(void)
|
||||
void debugPauseWaitAndUpdateSingleStep(void)
|
||||
{
|
||||
recursiveSpinlockLock(&g_debugPauseContinueLocks[currentCoreCtx->coreId]);
|
||||
maskIrq(); // <- unlikely race condition here? If it happens, it shouldn't happen more than once/should be fine anyway
|
||||
recursiveSpinlockUnlock(&g_debugPauseContinueLocks[currentCoreCtx->coreId]);
|
||||
u32 coreId = currentCoreCtx->coreId;
|
||||
if (atomic_load(&g_debugPausePausedCoreList) & BIT(coreId)) {
|
||||
unmaskIrq();
|
||||
do {
|
||||
__wfe();
|
||||
} while (atomic_load(&g_debugPausePausedCoreList) & BIT(coreId));
|
||||
maskIrq();
|
||||
}
|
||||
|
||||
currentCoreCtx->wasPaused = false;
|
||||
|
||||
// Single-step: if inactive and requested, start single step; cancel if active and not requested
|
||||
u32 ssReqd = (atomic_load(&g_debugPauseSingleStepCoreList) & ~BIT(currentCoreCtx->coreId)) != 0;
|
||||
SingleStepState singleStepState = singleStepGetNextState(currentCoreCtx->guestFrame);
|
||||
if (ssReqd && singleStepState == SingleStepState_Inactive) {
|
||||
singleStepSetNextState(currentCoreCtx->guestFrame, SingleStepState_ActiveNotPending);
|
||||
} else if (!ssReqd && singleStepState != SingleStepState_Inactive) {
|
||||
singleStepSetNextState(currentCoreCtx->guestFrame, SingleStepState_Inactive);
|
||||
}
|
||||
}
|
||||
|
||||
void debugPauseCores(u32 coreList)
|
||||
{
|
||||
coreList &= ~BIT(currentCoreCtx->coreId);
|
||||
// Since we're using a debugger lock, a simple stlr should be fine...
|
||||
atomic_store(&g_debugPausePausedCoreList, coreList);
|
||||
|
||||
barrierInit(&g_debugPauseBarrier, coreList | BIT(currentCoreCtx->coreId));
|
||||
FOREACH_BIT (tmp, core, coreList) {
|
||||
recursiveSpinlockLock(&g_debugPauseContinueLocks[core]);
|
||||
if (coreList != BIT(currentCoreCtx->coreId)) {
|
||||
// We need to notify other cores...
|
||||
u32 otherCores = coreList & ~BIT(currentCoreCtx->coreId);
|
||||
barrierInit(&g_debugPauseBarrier, otherCores | BIT(currentCoreCtx->coreId));
|
||||
generateSgiForList(ThermosphereSgi_DebugPause, otherCores);
|
||||
barrierWait(&g_debugPauseBarrier);
|
||||
}
|
||||
|
||||
generateSgiForList(ThermosphereSgi_DebugPause, coreList);
|
||||
barrierWait(&g_debugPauseBarrier);
|
||||
if (coreList & BIT(currentCoreCtx->coreId)) {
|
||||
currentCoreCtx->wasPaused = true;
|
||||
}
|
||||
}
|
||||
|
||||
void debugUnpauseCores(u32 coreList)
|
||||
void debugUnpauseCores(u32 coreList, u32 singleStepList)
|
||||
{
|
||||
coreList &= ~BIT(currentCoreCtx->coreId);
|
||||
singleStepList &= coreList;
|
||||
|
||||
FOREACH_BIT (tmp, core, coreList) {
|
||||
recursiveSpinlockUnlock(&g_debugPauseContinueLocks[core]);
|
||||
}
|
||||
// Since we're using a debugger lock, a simple stlr should be fine...
|
||||
atomic_store(&g_debugPauseSingleStepCoreList, singleStepList);
|
||||
atomic_store(&g_debugPausePausedCoreList, 0);
|
||||
|
||||
__sev();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user