Skip to content

Commit 3d7df56

Browse files
committed
Updates to ThreadMRI library
Pulling over changes from MRI repository, many of which were made to ease future porting efforts and better integrate the thread support. ThreadMRI class updates: * Add THREADMRI_BREAK_ON_SETUP macro to make it clearer what the breakInSetup parameter to the ThreadMRI constructor is being used for. * Move the g_contextEntries ScatterGatherEntry array into ThreadMRI instead of the CortexMState object since the required size depends on the layout of the register context used by each different RTOS. Call ScatterGather_Init() from Platform_Init() since it knows the size of the array. * Fixed a bug in advancePCToNextInstruction() which was dereferencing the current instruction incorrectly. Hardcode MRI_THREAD_MRI to a value of 1 in armv7-m.h for now. Fixed a bug in mriScatterGather_Set() where it was always throwing a bufferOverrunException, even when the set was successful. Dropping the initial "_" from include file protection macroes so that they don't conflict with the Standard C Library reserved prefix. I also pulled mriCortexMDebuggerStack and mriCortexMFlags objects out of CortexMState object to make it easier for assembly language code to access. Before the assembly language code needed to know the offset of these fields in the structure when accessing them. Now it can just refer to the individual globals directly. Platform_EnteringDebugger() in armv7-m.c now takes care of setting the the CORTEXM_FLAGS_ACTIVE_DEBUG and Platform_LeavingDebugger() takes care of clearing it so that handler/thread mode specific code doesn't have to anymore. Don't need to do it from the ThreadMRI object itself. mriCortexMInit() now takes a highestExternalIrq parameter that can be passed in from device specific init routines to indicate how many external interrupt sources should be defaulted to sub-zero priorities. Previously each particular device had its own loop to lower the priority of its external interrupts. That duplicate code across multiple devices is now gone. Add debugMonPriority parameter mriCortexMInit() function to allow port to specify the priority it desires for the DebugMonitor interrupt handler. Typically this will be 0, the highest priority, but there are cases when you might have code that should continue to run at the highest priority in the background, even when halted in GDB. In these cases, it makes sense for the background ISRs to be given a priority of 0 and DebugMonitor a priority of 1. The other default handler priorities are lowered to fall below DebugMonitor by mriCortexMInit() so that they can be debugged. Expose mriCortexMSetPriority() API which can be used by device/board specific code to set interrupt priority using MRI code that doesn't rely on __NVIC_PRIO_BITS being set correctly in the CMSIS headers. It instead determines the number of sub-priority bits at runtime. Expose the mriCortexMGetPriority() API publicly. This function also uses the runtime calculated sub-priority bit count. Updated target XML to mark LR as a code pointer as well so that GDB knows to try looking up the matching symbol when dumping it. Simplify device porting: * Now handle spurious UART interrupts in CortexM code rather than having all CortexM devices contain duplicated code to handle it. This means that ports no longer need to implement: * Platform_CommCausedInterrupt() * Platform_CommClearInterrupt() * Ports no longer need to implement: mriPlatform_CommUartIndex() * Cortex-M7 names their system handler priority register array SHPR instead of SHP like the rest of the ARMv7-M family for some reason. Added a macro to take care of this name change.
1 parent c91367a commit 3d7df56

31 files changed

+592
-227
lines changed

libraries/ThreadMRI/examples/ThreadMRI/ThreadMRI.ino

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
1-
/* This example demonstrates how to include the MRI library which
2-
allows debugging the Portenta H7 Cortex-M7 core with GDB via a
3-
serial interface.
1+
/* This example demonstrates how to include the ThreadMRI library which allows debugging of the Portenta H7
2+
with GDB via a serial (HardwareSerial or USBSerial) interface.
43
*/
54

65
#include <ThreadMRI.h>
76

8-
//ThreadMRI g_debugger(Serial1, USART1_IRQn, 115200, true);
9-
ThreadMRI g_debugger(Serial, OTG_HS_IRQn, 115200, true);
7+
//ThreadMRI g_debugger(Serial1, USART1_IRQn, 115200, THREADMRI_BREAK_ON_SETUP);
8+
ThreadMRI g_debugger(Serial, OTG_HS_IRQn, 115200, THREADMRI_BREAK_ON_SETUP);
9+
//ThreadMRI g_debugger(Serial, false);
1010

1111
extern "C" void testContext(void);
1212

1313
void setup() {
14-
//testContext();
15-
//__debugbreak();
1614
}
1715

1816
void loop() {

libraries/ThreadMRI/src/ThreadMRI.cpp

Lines changed: 36 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,15 @@ volatile uint32_t mriThreadOrigUsageFault;
113113
// Address of the original Serial peripheral ISR to be hooked.
114114
void (*g_origSerialISR)(void);
115115

116+
// Entries to track the chunks of the context in a scatter list.
117+
#if MRI_DEVICE_HAS_FPU
118+
#define CONTEXT_ENTRIES (5 + 3)
119+
#else
120+
#define CONTEXT_ENTRIES 5
121+
#endif
122+
123+
static ScatterGatherEntry g_contextEntries[CONTEXT_ENTRIES];
124+
116125
// UNDONE: For debugging. If different than g_haltedThreadId then the mriMain() thread was signalled when the previous
117126
// instance was still running.
118127
static volatile osThreadId_t g_debugThreadId;
@@ -139,8 +148,6 @@ static void resumeApplicationThreads();
139148
static void readThreadContext(osThreadId_t thread);
140149
static void switchRtxHandlersToDebugStubsForSingleStepping();
141150
static void restoreRtxHandlers();
142-
static void setDebugActiveFlag();
143-
static void clearDebugActiveFlag();
144151
static void callSerialBeginFromSetup();
145152
static int justEnteredSetupCallback(void* pv);
146153
static void hookSerialISR();
@@ -235,13 +242,11 @@ static __NO_RETURN void mriMain(void *pv)
235242
if (Platform_IsSingleStepping()) {
236243
restoreRtxHandlers();
237244
}
238-
setDebugActiveFlag();
239245

240246
osThreadSetPriority(osThreadGetId(), osPriorityNormal);
241247
mriDebugException();
242248
osThreadSetPriority(osThreadGetId(), osPriorityRealtime7);
243249

244-
clearDebugActiveFlag();
245250
if (Platform_IsSingleStepping()) {
246251
mriThreadSingleStepThreadId = g_haltedThreadId;
247252
switchRtxHandlersToDebugStubsForSingleStepping();
@@ -297,35 +302,35 @@ static void readThreadContext(osThreadId_t thread)
297302

298303
uint32_t* pThreadContext = (uint32_t*)pThread->sp;
299304
// R0 - R3
300-
mriCortexMState.contextEntries[0].pValues = pThreadContext + offset + 8;
301-
mriCortexMState.contextEntries[0].count = 4;
305+
g_contextEntries[0].pValues = pThreadContext + offset + 8;
306+
g_contextEntries[0].count = 4;
302307
// R4 - R11
303-
mriCortexMState.contextEntries[1].pValues = pThreadContext + offset + 0;
304-
mriCortexMState.contextEntries[1].count = 8;
308+
g_contextEntries[1].pValues = pThreadContext + offset + 0;
309+
g_contextEntries[1].count = 8;
305310
// R12
306-
mriCortexMState.contextEntries[2].pValues = pThreadContext + offset + 12;
307-
mriCortexMState.contextEntries[2].count = 1;
311+
g_contextEntries[2].pValues = pThreadContext + offset + 12;
312+
g_contextEntries[2].count = 1;
308313
// SP - Point scatter gather context to correct location for SP but set it to correct value once CPSR is more easily
309314
// fetched.
310-
mriCortexMState.contextEntries[3].pValues = &mriCortexMState.sp;
311-
mriCortexMState.contextEntries[3].count = 1;
315+
g_contextEntries[3].pValues = &mriCortexMState.sp;
316+
g_contextEntries[3].count = 1;
312317
// LR, PC, CPSR
313-
mriCortexMState.contextEntries[4].pValues = pThreadContext + offset + 13;
314-
mriCortexMState.contextEntries[4].count = 3;
318+
g_contextEntries[4].pValues = pThreadContext + offset + 13;
319+
g_contextEntries[4].count = 3;
315320
// Set SP to correct value using alignment bit in CPSR. Memory for SP is already tracked by context.
316321
uint32_t cpsr = ScatterGather_Get(&mriCortexMState.context, CPSR);
317322
mriCortexMState.sp = pThread->sp + sizeof(uint32_t) * (stackedCount + ((cpsr >> PSR_STACK_ALIGN_SHIFT) & 1));
318323

319324
if (offset != 0) {
320325
// S0 - S15
321-
mriCortexMState.contextEntries[5].pValues = pThreadContext + 32;
322-
mriCortexMState.contextEntries[5].count = 16;
326+
g_contextEntries[5].pValues = pThreadContext + 32;
327+
g_contextEntries[5].count = 16;
323328
// S16 - S31
324-
mriCortexMState.contextEntries[6].pValues = pThreadContext + 0;
325-
mriCortexMState.contextEntries[6].count = 16;
329+
g_contextEntries[6].pValues = pThreadContext + 0;
330+
g_contextEntries[6].count = 16;
326331
// FPSCR
327-
mriCortexMState.contextEntries[7].pValues = pThreadContext + 48;
328-
mriCortexMState.contextEntries[7].count = 1;
332+
g_contextEntries[7].pValues = pThreadContext + 48;
333+
g_contextEntries[7].count = 1;
329334
}
330335
}
331336

@@ -346,16 +351,6 @@ static void restoreRtxHandlers()
346351
NVIC_SetVector(SysTick_IRQn, mriThreadOrigSysTick);
347352
}
348353

349-
static void setDebugActiveFlag()
350-
{
351-
mriCortexMState.flags |= CORTEXM_FLAGS_ACTIVE_DEBUG;
352-
}
353-
354-
static void clearDebugActiveFlag()
355-
{
356-
mriCortexMState.flags &= ~CORTEXM_FLAGS_ACTIVE_DEBUG;
357-
}
358-
359354
static void callSerialBeginFromSetup()
360355
{
361356
mriCore_SetTempBreakpoint((uint32_t)setup, justEnteredSetupCallback, NULL);
@@ -401,13 +396,16 @@ ThreadMRI::~ThreadMRI() {
401396
// ---------------------------------------------------------------------------------------------------------------------
402397
void Platform_Init(Token* pParameterTokens)
403398
{
399+
uint32_t debugMonPriority = 255;
400+
404401
__try
405-
mriCortexMInit((Token*)pParameterTokens);
402+
mriCortexMInit((Token*)pParameterTokens, debugMonPriority, (IRQn_Type)0);
406403
__catch
407404
__rethrow;
408405

409406
g_enableDWTandFPB = 0;
410407
mriThreadSingleStepThreadId = NULL;
408+
ScatterGather_Init(&mriCortexMState.context, g_contextEntries, sizeof(g_contextEntries)/sizeof(g_contextEntries[0]));
411409
recordAndSwitchFaultHandlersToDebugger();
412410
}
413411

@@ -446,15 +444,6 @@ void Platform_CommSendChar(int character)
446444
g_pSerial->write(character);
447445
}
448446

449-
int Platform_CommCausedInterrupt(void)
450-
{
451-
return 0;
452-
}
453-
454-
void Platform_CommClearInterrupt(void)
455-
{
456-
}
457-
458447

459448

460449

@@ -598,7 +587,7 @@ static bool hasEncounteredDebugEvent()
598587

599588
static bool hasControlCBeenDetected()
600589
{
601-
return mriCortexMState.flags & CORTEXM_FLAGS_CTRL_C;
590+
return mriCortexMFlags & CORTEXM_FLAGS_CTRL_C;
602591
}
603592

604593
static void recordAndClearFaultStatusBits()
@@ -620,7 +609,7 @@ static void wakeMriMainToDebugCurrentThread()
620609
{
621610
disableSingleStep();
622611
g_debugThreadId = osThreadGetId();
623-
g_haltedThreadId = g_debugThreadId; // UNDONE: osThreadGetId();
612+
g_haltedThreadId = g_debugThreadId;
624613
osThreadFlagsSet(mriThreadId, MRI_THREAD_DEBUG_EVENT_FLAG);
625614
}
626615

@@ -632,12 +621,12 @@ static void stopSingleStepping()
632621

633622
static bool isDebugThreadActive()
634623
{
635-
return (mriCortexMState.flags & CORTEXM_FLAGS_ACTIVE_DEBUG) && mriThreadId == osThreadGetId();
624+
return (mriCortexMFlags & CORTEXM_FLAGS_ACTIVE_DEBUG) && mriThreadId == osThreadGetId();
636625
}
637626

638627
static void setFaultDetectedFlag()
639628
{
640-
mriCortexMState.flags |= CORTEXM_FLAGS_FAULT_DURING_DEBUG;
629+
mriCortexMFlags |= CORTEXM_FLAGS_FAULT_DURING_DEBUG;
641630
}
642631

643632
static bool isImpreciseBusFault()
@@ -649,7 +638,7 @@ static void advancePCToNextInstruction(uint32_t excReturn, uint32_t psp, uint32_
649638
{
650639
uint32_t* pSP = threadSP(excReturn, psp, msp);
651640
uint32_t* pPC = pSP + 7;
652-
uint16_t currentInstruction = *(uint16_t*)pPC;
641+
uint16_t currentInstruction = *(uint16_t*)*pPC;
653642
if (isInstruction32Bit(currentInstruction)) {
654643
*pPC += sizeof(uint32_t);
655644
} else {
@@ -694,10 +683,10 @@ static void serialISRHook()
694683

695684
static bool isDebuggerActive()
696685
{
697-
return mriCortexMState.flags & CORTEXM_FLAGS_ACTIVE_DEBUG;
686+
return mriCortexMFlags & CORTEXM_FLAGS_ACTIVE_DEBUG;
698687
}
699688

700689
static void setControlCFlag()
701690
{
702-
mriCortexMState.flags |= CORTEXM_FLAGS_CTRL_C;
691+
mriCortexMFlags |= CORTEXM_FLAGS_CTRL_C;
703692
}

libraries/ThreadMRI/src/ThreadMRI.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
#pragma once
1818

1919

20+
// Pass THREADMRI_BREAK_ON_SETUP as breakInSetup parameter of ThreadMRI constructors to halt in setup().
21+
#define THREADMRI_BREAK_ON_SETUP true
22+
23+
2024
class ThreadMRI {
2125
public:
2226
// You must declare your ThreadMRI object as a global or function scoped static so that it doesn't get

0 commit comments

Comments
 (0)