1
0
Fork 0
mirror of https://github.com/Atmosphere-NX/Atmosphere.git synced 2024-12-18 16:32:05 +00:00

thermosphere: add debug pause logic

This commit is contained in:
TuxSH 2020-01-14 02:09:51 +00:00
parent b6a130547a
commit 1369697058
6 changed files with 113 additions and 6 deletions

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "debug_pause.h"
#include "core_ctx.h"
#include "irq.h"
#include "spinlock.h"
// Reminder: use these functions behind a lock
static Barrier g_debugPauseBarrier;
static RecursiveSpinlock g_debugPauseContinueLocks[4];
void debugPauseSgiTopHalf(void)
{
barrierWait(&g_debugPauseBarrier);
}
void debugPauseSgiBottomHalf(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]);
}
void debugPauseCores(u32 coreList)
{
coreList &= ~BIT(currentCoreCtx->coreId);
barrierInit(&g_debugPauseBarrier, coreList | BIT(currentCoreCtx->coreId));
FOREACH_BIT (tmp, core, coreList) {
recursiveSpinlockLock(&g_debugPauseContinueLocks[core]);
}
generateSgiForList(ThermosphereSgi_DebugPause, coreList);
barrierWait(&g_debugPauseBarrier);
}
void debugUnpauseCores(u32 coreList)
{
coreList &= ~BIT(currentCoreCtx->coreId);
FOREACH_BIT (tmp, core, coreList) {
recursiveSpinlockUnlock(&g_debugPauseContinueLocks[core]);
}
}

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "utils.h"
void debugPauseSgiTopHalf(void);
void debugPauseSgiBottomHalf(void);
// Note: these functions are not reentrant! (need a global debug lock...)
// These functions also run with interrupts unmasked (but we know we're in our code -- should be safe if we take care)
// while the core is paused.
// "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.
void debugPauseCores(u32 coreList);
void debugUnpauseCores(u32 coreList);

View file

@ -21,6 +21,7 @@
#include "timer.h" #include "timer.h"
#include "guest_timers.h" #include "guest_timers.h"
#include "transport_interface.h" #include "transport_interface.h"
#include "debug_pause.h"
IrqManager g_irqManager = {0}; IrqManager g_irqManager = {0};
@ -212,7 +213,7 @@ void handleIrqException(ExceptionStackFrame *frame, bool isLowerEl, bool isA32)
u32 irqId = iar & 0x3FF; u32 irqId = iar & 0x3FF;
u32 srcCore = (iar >> 10) & 7; u32 srcCore = (iar >> 10) & 7;
//DEBUG("EL2 [core %d]: Received irq %x\n", (int)currentCoreCtx->coreId, irqId); DEBUG("EL2 [core %d]: Received irq %x\n", (int)currentCoreCtx->coreId, irqId);
if (irqId == GIC_IRQID_SPURIOUS) { if (irqId == GIC_IRQID_SPURIOUS) {
// Spurious interrupt received // Spurious interrupt received
@ -226,6 +227,7 @@ void handleIrqException(ExceptionStackFrame *frame, bool isLowerEl, bool isA32)
bool isGuestInterrupt = false; bool isGuestInterrupt = false;
bool isMaintenanceInterrupt = false; bool isMaintenanceInterrupt = false;
bool hasBottomHalf = false;
switch (irqId) { switch (irqId) {
case ThermosphereSgi_ExecuteFunction: case ThermosphereSgi_ExecuteFunction:
@ -234,6 +236,10 @@ void handleIrqException(ExceptionStackFrame *frame, bool isLowerEl, bool isA32)
case ThermosphereSgi_VgicUpdate: case ThermosphereSgi_VgicUpdate:
// Nothing in particular to do here // Nothing in particular to do here
break; break;
case ThermosphereSgi_DebugPause:
debugPauseSgiTopHalf();
hasBottomHalf = true;
break;
case GIC_IRQID_MAINTENANCE: case GIC_IRQID_MAINTENANCE:
isMaintenanceInterrupt = true; isMaintenanceInterrupt = true;
break; break;
@ -246,6 +252,7 @@ void handleIrqException(ExceptionStackFrame *frame, bool isLowerEl, bool isA32)
} }
TransportInterface *transportIface = irqId >= 32 ? transportInterfaceIrqHandlerTopHalf(irqId) : NULL; TransportInterface *transportIface = irqId >= 32 ? transportInterfaceIrqHandlerTopHalf(irqId) : NULL;
hasBottomHalf = hasBottomHalf || transportIface != NULL;
// Priority drop // Priority drop
gicc->eoir = iar; gicc->eoir = iar;
@ -270,9 +277,15 @@ void handleIrqException(ExceptionStackFrame *frame, bool isLowerEl, bool isA32)
recursiveSpinlockUnlock(&g_irqManager.lock); recursiveSpinlockUnlock(&g_irqManager.lock);
// Bottom half part // Bottom half part
if (transportIface != NULL) { if (hasBottomHalf) {
exceptionEnterInterruptibleHypervisorCode(frame); exceptionEnterInterruptibleHypervisorCode(frame);
unmaskIrq(); unmaskIrq();
transportInterfaceIrqHandlerBottomHalf(transportIface);
if (irqId == ThermosphereSgi_DebugPause) {
debugPauseSgiBottomHalf();
} else if (transportIface != NULL) {
transportInterfaceIrqHandlerBottomHalf(transportIface);
}
} }
} }

View file

@ -41,8 +41,9 @@ typedef struct IrqManager {
typedef enum ThermosphereSgi { typedef enum ThermosphereSgi {
ThermosphereSgi_ExecuteFunction = 0, ThermosphereSgi_ExecuteFunction = 0,
ThermosphereSgi_VgicUpdate = 1, ThermosphereSgi_VgicUpdate = 1,
ThermosphereSgi_DebugPause = 2,
ThermosphereSgi_Max = 2, ThermosphereSgi_Max,
} ThermosphereSgi; } ThermosphereSgi;
extern IrqManager g_irqManager; extern IrqManager g_irqManager;

View file

@ -41,6 +41,7 @@ static void loadKernelViaSemihosting(void)
#include "platform/uart.h" #include "platform/uart.h"
#include "debug_pause.h"
typedef struct TestCtx { typedef struct TestCtx {
char buf[512+1]; char buf[512+1];
} TestCtx; } TestCtx;
@ -50,6 +51,7 @@ static TestCtx g_testCtx;
size_t testReceiveCallback(TransportInterface *iface, void *p) size_t testReceiveCallback(TransportInterface *iface, void *p)
{ {
TestCtx *ctx = (TestCtx *)p; TestCtx *ctx = (TestCtx *)p;
debugPauseCores(BIT(0));
return transportInterfaceReadDataUntil(iface, ctx->buf, 512, '\r'); return transportInterfaceReadDataUntil(iface, ctx->buf, 512, '\r');
} }
@ -57,6 +59,7 @@ void testProcessDataCallback(TransportInterface *iface, void *p, size_t sz)
{ {
(void)iface; (void)iface;
(void)sz; (void)sz;
debugUnpauseCores(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);
} }
@ -71,7 +74,7 @@ void test(void)
testProcessDataCallback, testProcessDataCallback,
&g_testCtx &g_testCtx
); );
transportInterfaceSetInterruptAffinity(iface, BIT(0)); transportInterfaceSetInterruptAffinity(iface, BIT(1));
} }
void thermosphereMain(ExceptionStackFrame *frame, u64 pct) void thermosphereMain(ExceptionStackFrame *frame, u64 pct)

View file

@ -16,9 +16,9 @@
#pragma once #pragma once
#include "core_ctx.h"
#include "utils.h" #include "utils.h"
#include "sysreg.h" #include "sysreg.h"
#include "core_ctx.h"
typedef struct Spinlock { typedef struct Spinlock {
u32 lock; u32 lock;