1616// the USB serial connection.
1717#include < Arduino.h>
1818#include " ThreadMRI.h"
19+ #include < cmsis_os2.h>
20+ #include < rtx_os.h>
1921extern " C"
2022{
2123 #include " core/mri.h"
@@ -25,12 +27,6 @@ extern "C"
2527 #include " architectures/armv7-m/armv7-m.h"
2628 #include " architectures/armv7-m/debug_cm3.h"
2729}
28- // UNDONE: Might not need this.
29- #include < signal.h>
30- #include < string.h>
31-
32- #include < cmsis_os2.h>
33- #include < rtx_os.h>
3430
3531// UNDONE: Switch back to the USB/CDC based serial port.
3632#undef Serial
@@ -63,23 +59,30 @@ static const char g_memoryMapXml[] = "<?xml version=\"1.0\"?>"
6359// Bit in LR set to 0 when automatic stacking of floating point registers occurs during exception handling.
6460#define LR_FLOAT_STACK (1 << 4 )
6561
66- // Thread flag used to indicate that a debug event has occured.
62+ // Thread syncronization flag used to indicate that a debug event has occured.
6763#define MRI_THREAD_DEBUG_EVENT_FLAG (1 << 0 )
6864
6965osThreadId_t g_mriThreadId;
7066
7167volatile osThreadId_t g_haltingThreadId;
7268
69+ // UNDONE: Get rid of.
70+ volatile osThreadId_t g_test;
71+
7372osThreadId_t g_threads[64 ];
7473uint32_t g_threadCount;
7574
75+ volatile osThreadId_t mriThreadSingleStepThreadId;
76+
77+ volatile uint32_t mriThreadEnableDWTandFPB;
78+
7679
7780ThreadMRI::ThreadMRI ()
7881{
7982 mriInit (" " );
8083}
8184
82- // UNDONE: This is just for initial bringup .
85+ // Main entry point into MRI debugger core .
8386extern " C" void mriDebugException (void );
8487
8588// UNDONE: Could push into debugException() API.
@@ -109,10 +112,12 @@ static void suspendAllApplicationThreads() {
109112 g_threadCount = osThreadEnumerate (g_threads, sizeof (g_threads)/sizeof (g_threads[0 ]));
110113 for (uint32_t i = 0 ; i < g_threadCount ; i++) {
111114 osThreadId_t thread = g_threads[i];
115+ const char * pThreadName = osThreadGetName (thread);
112116
113- if (thread != g_mriThreadId) {
117+ if (thread != g_mriThreadId && strcmp (pThreadName, " rtx_idle " ) != 0 ) {
114118 osThreadSuspend (thread);
115- } else {
119+ }
120+ else {
116121 g_threads[i] = 0 ;
117122 }
118123 }
@@ -176,20 +181,32 @@ static void readThreadContext(osThreadId_t thread) {
176181
177182static __NO_RETURN void mriMain (void *pv)
178183{
184+ // Run the code which suspends, resumes, etc the other threads at highest priority so that it doesn't context
185+ // switch to one of the other threads. Switch to normal priority when running mriDebugException() though.
186+ osThreadSetPriority (osThreadGetId (), osPriorityRealtime7);
187+
179188 while (1 ) {
180- // Wait for next debug event to occur. Set priority to highest level before blocking so that it can safely
181- // put all of the other application threads to sleep upon wakeup.
182- osThreadSetPriority (osThreadGetId (), osPriorityRealtime7);
183- osThreadFlagsWait (MRI_THREAD_DEBUG_EVENT_FLAG, osFlagsWaitAny, osWaitForever);
184- suspendAllApplicationThreads ();
185- osThreadSetPriority (osThreadGetId (), osPriorityNormal);
189+ int waitResult = osThreadFlagsWait (MRI_THREAD_DEBUG_EVENT_FLAG, osFlagsWaitAny, osWaitForever);
190+ while (waitResult < 0 ) {
191+ // Something bad has happened if we hang here.
192+ }
193+ suspendAllApplicationThreads ();
186194
187- if (g_haltingThreadId == 0 ) {
188- continue ;
195+ while (g_haltingThreadId == 0 ) {
196+ // Something bad has happened if we hang here.
189197 }
190198 readThreadContext (g_haltingThreadId);
199+
200+ osThreadSetPriority (osThreadGetId (), osPriorityNormal);
191201 mriDebugException ();
192- resumeApplicationThreads ();
202+ osThreadSetPriority (osThreadGetId (), osPriorityRealtime7);
203+
204+ if (Platform_IsSingleStepping ()) {
205+ mriThreadSingleStepThreadId = g_haltingThreadId;
206+ osThreadResume (mriThreadSingleStepThreadId);
207+ } else {
208+ resumeApplicationThreads ();
209+ }
193210 g_haltingThreadId = 0 ;
194211 }
195212}
@@ -200,51 +217,143 @@ static __NO_RETURN void mriMain(void *pv)
200217// Global Platform_* functions needed by MRI to initialize and communicate with MRI.
201218// These functions will perform most of their work through the DebugSerial singleton.
202219// ---------------------------------------------------------------------------------------------------------------------
220+ // Assembly Language fault handling stubs. They do some preprocessing and then call the C handler below if appropriate.
221+ extern " C" void mriDebugMonitorHandlerStub (void );
222+ extern " C" void mriFaultHandlerStub (void );
223+ // Assembly Language stubs for RTX context switching routines. They check to see if DebugMon should be pended before
224+ // calling the actual RTX handlers.
225+ extern " C" void mriSVCHandlerStub (void );
226+ extern " C" void mriPendSVHandlerStub (void );
227+ extern " C" void mriSysTickHandlerStub (void );
228+
229+
230+
203231// Forward Function Declarations
232+ static bool hasEncounteredDebugEvent ();
233+ static void recordAndClearFaultStatusBits ();
234+ static void wakeMriMainToDebugCurrentThread ();
235+ static void stopSingleStepping ();
204236static void switchFaultHandlersToDebugger ();
237+ static void switchRtxHandlersToDebugStubs ();
238+
205239
206- static void mriDebugMonitorHandler (void )
240+ extern " C" void mriDebugMonitorHandler (uint32_t excReturn)
241+ {
242+ excReturn &= 0xF ;
243+ bool isThreadMode = (excReturn == 0xD || excReturn == 0x9 );
244+ while (!isThreadMode) {
245+ // DebugMon is running at such low priority that we should be getting ready to return to thread mode.
246+ }
247+
248+ if (!hasEncounteredDebugEvent ()) {
249+ if (mriThreadEnableDWTandFPB) {
250+ enableDWTandITM ();
251+ enableFPB ();
252+ mriThreadEnableDWTandFPB = 0 ;
253+ }
254+ if (mriThreadSingleStepThreadId) {
255+ // Code is written to handle case where single stepping gets enabled because current thread was the one
256+ // to be single stepped but then a higher priority interrupt comes in and makes another thread the
257+ // current thread so single stepping should be disabled again.
258+ if (mriThreadSingleStepThreadId == osThreadGetId ()) {
259+ enableSingleStep ();
260+ } else {
261+ disableSingleStep ();
262+ }
263+ }
264+
265+ return ;
266+ }
267+
268+ // Get here when a debug event of interest has occurred in a thread.
269+ recordAndClearFaultStatusBits ();
270+ stopSingleStepping ();
271+ wakeMriMainToDebugCurrentThread ();
272+ }
273+
274+ // This function is called if a fault (hard, mem, bus, usage) has occurred while running code in thread mode.
275+ // It is also called when a debug event has forced a hard fault while running code in handler mode.
276+ extern " C" void mriFaultHandler (uint32_t excReturn)
277+ {
278+ excReturn &= 0xF ;
279+ bool isThreadMode = (excReturn == 0xD || excReturn == 0x9 );
280+ if (isThreadMode) {
281+ recordAndClearFaultStatusBits ();
282+ stopSingleStepping ();
283+ wakeMriMainToDebugCurrentThread ();
284+ return ;
285+ }
286+
287+ // The asm stub calling this function has already verified that a debug event during handler mode caused
288+ // this fault.
289+ mriThreadEnableDWTandFPB = 1 ;
290+ SCB->DFSR = SCB->DFSR ;
291+ SCB->HFSR = SCB_HFSR_DEBUGEVT_Msk;
292+ disableDWTandITM ();
293+ disableFPB ();
294+ setMonitorPending ();
295+ }
296+
297+ static bool hasEncounteredDebugEvent ()
298+ {
299+ return SCB->DFSR != 0 ;
300+
301+ }
302+
303+ static void recordAndClearFaultStatusBits ()
207304{
208- // Record information about cause of exception/debug event.
209305 mriCortexMState.exceptionNumber = getCurrentlyExecutingExceptionNumber ();
210306 mriCortexMState.dfsr = SCB->DFSR ;
211307 mriCortexMState.hfsr = SCB->HFSR ;
212308 mriCortexMState.cfsr = SCB->CFSR ;
213309 mriCortexMState.mmfar = SCB->MMFAR ;
214310 mriCortexMState.bfar = SCB->BFAR ;
215311
216- // Clear the debug event bits as they are already recorded.
217- if (mriCortexMState.exceptionNumber == 12 ) {
218- SCB->DFSR = mriCortexMState.dfsr ;
219- }
312+ // Clear fault status bits by writing 1s to bits that are already set.
313+ SCB->DFSR = mriCortexMState.dfsr ;
314+ SCB->HFSR = mriCortexMState.hfsr ;
315+ SCB->CFSR = mriCortexMState.cfsr ;
316+ }
220317
221- g_haltingThreadId = osThreadGetId ();
318+ static void wakeMriMainToDebugCurrentThread ()
319+ {
320+ disableSingleStep ();
321+ g_test = osThreadGetId ();
322+ g_haltingThreadId = g_test; // UNDONE: osThreadGetId();
222323 osThreadFlagsSet (g_mriThreadId, MRI_THREAD_DEBUG_EVENT_FLAG);
223324}
224325
225- static void mriFaultHandler ( void )
326+ static void stopSingleStepping ( )
226327{
227- // UNDONE: Differentiate.
228- mriDebugMonitorHandler () ;
328+ disableSingleStep ();
329+ mriThreadSingleStepThreadId = NULL ;
229330}
230331
231-
232332void Platform_Init (Token* pParameterTokens)
233333{
234334 __try
235335 mriCortexMInit ((Token*)pParameterTokens);
236336 __catch
237337 __rethrow;
238338
339+ mriThreadEnableDWTandFPB = 0 ;
340+ mriThreadSingleStepThreadId = NULL ;
239341 switchFaultHandlersToDebugger ();
240- NVIC_SetVector (DebugMonitor_IRQn, ( uint32_t )mriDebugMonitorHandler );
342+ switchRtxHandlersToDebugStubs ( );
241343}
242344
243345static void switchFaultHandlersToDebugger (void ) {
244- NVIC_SetVector (HardFault_IRQn, (uint32_t )mriFaultHandler);
245- NVIC_SetVector (MemoryManagement_IRQn, (uint32_t )mriFaultHandler);
246- NVIC_SetVector (BusFault_IRQn, (uint32_t )mriFaultHandler);
247- NVIC_SetVector (UsageFault_IRQn, (uint32_t )mriFaultHandler);
346+ NVIC_SetVector (HardFault_IRQn, (uint32_t )mriFaultHandlerStub);
347+ NVIC_SetVector (MemoryManagement_IRQn, (uint32_t )mriFaultHandlerStub);
348+ NVIC_SetVector (BusFault_IRQn, (uint32_t )mriFaultHandlerStub);
349+ NVIC_SetVector (UsageFault_IRQn, (uint32_t )mriFaultHandlerStub);
350+ NVIC_SetVector (DebugMonitor_IRQn, (uint32_t )mriDebugMonitorHandlerStub);
351+ }
352+
353+ static void switchRtxHandlersToDebugStubs (void ) {
354+ NVIC_SetVector (SVCall_IRQn, (uint32_t )mriSVCHandlerStub);
355+ NVIC_SetVector (PendSV_IRQn, (uint32_t )mriPendSVHandlerStub);
356+ NVIC_SetVector (SysTick_IRQn, (uint32_t )mriSysTickHandlerStub);
248357}
249358
250359
0 commit comments