thermosphere: rewrite debug pause & fix single step state machine

This commit is contained in:
TuxSH
2020-01-16 01:18:34 +00:00
parent 6b8a843ffb
commit 906d6a4f20
13 changed files with 92 additions and 46 deletions

View File

@@ -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();
}