mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-15 09:36:35 +00:00
thermosphere: gdb/debug: avoid pause/unpause race condition in vCont + bugfix
This commit is contained in:
parent
9ef2532b9d
commit
36ca87491d
6 changed files with 39 additions and 15 deletions
|
@ -50,7 +50,7 @@ static void debugManagerDoPauseCores(u32 coreList)
|
||||||
do {
|
do {
|
||||||
desiredList |= readList;
|
desiredList |= readList;
|
||||||
remainingList &= ~readList;
|
remainingList &= ~readList;
|
||||||
} while (atomic_compare_exchange_weak(&g_debugManager.pausedCoreList, &readList, desiredList));
|
} while (!atomic_compare_exchange_weak(&g_debugManager.pausedCoreList, &readList, desiredList));
|
||||||
|
|
||||||
if (remainingList != BIT(currentCoreCtx->coreId)) {
|
if (remainingList != BIT(currentCoreCtx->coreId)) {
|
||||||
// We need to notify other cores...
|
// We need to notify other cores...
|
||||||
|
@ -116,10 +116,13 @@ void debugManagerPauseCores(u32 coreList)
|
||||||
restoreInterruptFlags(flags);
|
restoreInterruptFlags(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void debugManagerUnpauseCores(u32 coreList, u32 singleStepList)
|
void debugManagerSetSingleStepCoreList(u32 coreList)
|
||||||
{
|
{
|
||||||
singleStepList &= coreList;
|
atomic_store(&g_debugManager.singleStepCoreList, coreList);
|
||||||
|
}
|
||||||
|
|
||||||
|
void debugManagerUnpauseCores(u32 coreList)
|
||||||
|
{
|
||||||
FOREACH_BIT (tmp, coreId, coreList) {
|
FOREACH_BIT (tmp, coreId, coreList) {
|
||||||
if (&g_debugManager.debugEventInfos[coreId].handled) {
|
if (&g_debugManager.debugEventInfos[coreId].handled) {
|
||||||
// Discard already handled debug events
|
// Discard already handled debug events
|
||||||
|
@ -127,8 +130,6 @@ void debugManagerUnpauseCores(u32 coreList, u32 singleStepList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since we're using a debugger lock, a simple stlr should be fine...
|
|
||||||
atomic_store(&g_debugManager.singleStepCoreList, singleStepList);
|
|
||||||
atomic_fetch_and(&g_debugManager.pausedCoreList, ~coreList);
|
atomic_fetch_and(&g_debugManager.pausedCoreList, ~coreList);
|
||||||
|
|
||||||
__sev();
|
__sev();
|
||||||
|
@ -198,7 +199,18 @@ void debugManagerBreakCores(u32 coreList)
|
||||||
if (coreList & ~BIT(coreId)) {
|
if (coreList & ~BIT(coreId)) {
|
||||||
generateSgiForList(ThermosphereSgi_ReportDebuggerBreak, coreList & ~BIT(coreId));
|
generateSgiForList(ThermosphereSgi_ReportDebuggerBreak, coreList & ~BIT(coreId));
|
||||||
}
|
}
|
||||||
if (coreList & BIT(coreId)) {
|
if (coreList & BIT(coreId) && !debugManagerIsCorePaused(coreId)) {
|
||||||
debugManagerReportEvent(DBGEVENT_DEBUGGER_BREAK);
|
debugManagerReportEvent(DBGEVENT_DEBUGGER_BREAK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void debugManagerContinueCores(u32 coreList)
|
||||||
|
{
|
||||||
|
u32 coreId = currentCoreCtx->coreId;
|
||||||
|
if (coreList & ~BIT(coreId)) {
|
||||||
|
generateSgiForList(ThermosphereSgi_DebuggerContinue, coreList & ~BIT(coreId));
|
||||||
|
}
|
||||||
|
if (coreList & BIT(coreId) && debugManagerIsCorePaused(coreId)) {
|
||||||
|
debugManagerUnpauseCores(BIT(coreId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -55,7 +55,8 @@ bool debugManagerHandlePause(void);
|
||||||
// "Pause" makes sure all cores reaches the pause function before proceeding.
|
// "Pause" makes sure all cores reaches the pause function before proceeding.
|
||||||
// "Unpause" doesn't synchronize, it just makes sure the core resumes & that "pause" can be called again.
|
// "Unpause" doesn't synchronize, it just makes sure the core resumes & that "pause" can be called again.
|
||||||
void debugManagerPauseCores(u32 coreList);
|
void debugManagerPauseCores(u32 coreList);
|
||||||
void debugManagerUnpauseCores(u32 coreList, u32 singleStepList);
|
void debugManagerUnpauseCores(u32 coreList);
|
||||||
|
void debugManagerSetSingleStepCoreList(u32 coreList);
|
||||||
|
|
||||||
void debugManagerSetSteppingRange(u32 coreId, uintptr_t startAddr, uintptr_t endAddr);
|
void debugManagerSetSteppingRange(u32 coreId, uintptr_t startAddr, uintptr_t endAddr);
|
||||||
|
|
||||||
|
@ -67,6 +68,7 @@ const DebugEventInfo *debugManagerGetCoreDebugEvent(u32 coreId);
|
||||||
void debugManagerReportEvent(DebugEventType type, ...);
|
void debugManagerReportEvent(DebugEventType type, ...);
|
||||||
|
|
||||||
void debugManagerBreakCores(u32 coreList);
|
void debugManagerBreakCores(u32 coreList);
|
||||||
|
void debugManagerContinueCores(u32 coreList);
|
||||||
|
|
||||||
static inline bool debugManagerIsCorePaused(u32 coreId)
|
static inline bool debugManagerIsCorePaused(u32 coreId)
|
||||||
{
|
{
|
||||||
|
|
|
@ -347,7 +347,8 @@ GDB_DECLARE_HANDLER(ContinueOrStepDeprecated)
|
||||||
debugManagerSetSteppingRange(coreId, 0, 0);
|
debugManagerSetSteppingRange(coreId, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
debugManagerUnpauseCores(coreList, ssMask);
|
debugManagerSetSingleStepCoreList(ssMask);
|
||||||
|
debugManagerUnpauseCores(coreList);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -461,8 +462,9 @@ GDB_DECLARE_VERBOSE_HANDLER(Continue)
|
||||||
cmd = nextCmd;
|
cmd = nextCmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debugManagerSetSingleStepCoreList(stepCoreList);
|
||||||
debugManagerBreakCores(stopCoreList);
|
debugManagerBreakCores(stopCoreList);
|
||||||
debugManagerUnpauseCores(continueCoreList, stepCoreList);
|
debugManagerContinueCores(continueCoreList);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -220,6 +220,7 @@ void handleIrqException(ExceptionStackFrame *frame, bool isLowerEl, bool isA32)
|
||||||
|
|
||||||
bool isGuestInterrupt = false;
|
bool isGuestInterrupt = false;
|
||||||
bool isMaintenanceInterrupt = false;
|
bool isMaintenanceInterrupt = false;
|
||||||
|
bool isPaused = false;
|
||||||
|
|
||||||
switch (irqId) {
|
switch (irqId) {
|
||||||
case ThermosphereSgi_ExecuteFunction:
|
case ThermosphereSgi_ExecuteFunction:
|
||||||
|
@ -232,7 +233,11 @@ void handleIrqException(ExceptionStackFrame *frame, bool isLowerEl, bool isA32)
|
||||||
debugManagerPauseSgiHandler();
|
debugManagerPauseSgiHandler();
|
||||||
break;
|
break;
|
||||||
case ThermosphereSgi_ReportDebuggerBreak:
|
case ThermosphereSgi_ReportDebuggerBreak:
|
||||||
// See bottom half
|
case ThermosphereSgi_DebuggerContinue:
|
||||||
|
// See bottom halves
|
||||||
|
// Because exceptions (other debug events) are handling w/ interrupts off, if
|
||||||
|
// we get there, there's no race condition possible with debugManagerReportEvent
|
||||||
|
isPaused = debugManagerIsCorePaused(currentCoreCtx->coreId);
|
||||||
break;
|
break;
|
||||||
case GIC_IRQID_MAINTENANCE:
|
case GIC_IRQID_MAINTENANCE:
|
||||||
isMaintenanceInterrupt = true;
|
isMaintenanceInterrupt = true;
|
||||||
|
@ -274,8 +279,10 @@ void handleIrqException(ExceptionStackFrame *frame, bool isLowerEl, bool isA32)
|
||||||
exceptionEnterInterruptibleHypervisorCode();
|
exceptionEnterInterruptibleHypervisorCode();
|
||||||
unmaskIrq();
|
unmaskIrq();
|
||||||
transportInterfaceIrqHandlerBottomHalf(transportIface);
|
transportInterfaceIrqHandlerBottomHalf(transportIface);
|
||||||
} else if (irqId == ThermosphereSgi_ReportDebuggerBreak) {
|
} else if (irqId == ThermosphereSgi_ReportDebuggerBreak && !isPaused) {
|
||||||
debugManagerReportEvent(DBGEVENT_DEBUGGER_BREAK);
|
debugManagerReportEvent(DBGEVENT_DEBUGGER_BREAK);
|
||||||
|
} else if (irqId == ThermosphereSgi_DebuggerContinue && isPaused) {
|
||||||
|
debugManagerUnpauseCores(BIT(currentCoreCtx->coreId));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,9 +39,10 @@ typedef struct IrqManager {
|
||||||
|
|
||||||
typedef enum ThermosphereSgi {
|
typedef enum ThermosphereSgi {
|
||||||
ThermosphereSgi_ExecuteFunction = 0,
|
ThermosphereSgi_ExecuteFunction = 0,
|
||||||
ThermosphereSgi_VgicUpdate = 1,
|
ThermosphereSgi_VgicUpdate,
|
||||||
ThermosphereSgi_DebugPause = 2,
|
ThermosphereSgi_DebugPause,
|
||||||
ThermosphereSgi_ReportDebuggerBreak = 3,
|
ThermosphereSgi_ReportDebuggerBreak,
|
||||||
|
ThermosphereSgi_DebuggerContinue,
|
||||||
|
|
||||||
ThermosphereSgi_Max,
|
ThermosphereSgi_Max,
|
||||||
} ThermosphereSgi;
|
} ThermosphereSgi;
|
||||||
|
|
|
@ -75,7 +75,7 @@ void testProcessDataCallback(TransportInterface *iface, void *p, size_t sz)
|
||||||
{
|
{
|
||||||
(void)iface;
|
(void)iface;
|
||||||
(void)sz;
|
(void)sz;
|
||||||
debugManagerUnpauseCores(BIT(0), BIT(0));
|
debugManagerUnpauseCores(BIT(0));
|
||||||
TestCtx *ctx = (TestCtx *)p;
|
TestCtx *ctx = (TestCtx *)p;
|
||||||
DEBUG("EL2 [core %u]: you typed: %s\n", currentCoreCtx->coreId, ctx->buf);
|
DEBUG("EL2 [core %u]: you typed: %s\n", currentCoreCtx->coreId, ctx->buf);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue