diff --git a/libraries/KernelDebug/library.properties b/libraries/KernelDebug/library.properties index 3c4633901..c7ef3b7b9 100644 --- a/libraries/KernelDebug/library.properties +++ b/libraries/KernelDebug/library.properties @@ -1,5 +1,5 @@ name=KernelDebug -version=1.0.0 +version=1.5.0 author=Adam Green maintainer=Arduino sentence=The GDB compatible kernel debug monitor for Cortex-M devices. diff --git a/libraries/KernelDebug/src/KernelDebug.cpp b/libraries/KernelDebug/src/KernelDebug.cpp index eee90ceca..a70c9d686 100644 --- a/libraries/KernelDebug/src/KernelDebug.cpp +++ b/libraries/KernelDebug/src/KernelDebug.cpp @@ -1,4 +1,4 @@ -/* Copyright 2020 Adam Green (https://github.com/adamgreen/) +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -31,6 +31,7 @@ extern "C" { // Source code for armv7-m module which is included here, configured for supporting kernel mode debugging. #include #include + #include } @@ -134,8 +135,10 @@ static void readThreadContext(MriContext* pContext, uint32_t* pSP, osRtxThread_t // Forward declaration of external functions used by KernelDebug. // Will be setting initial breakpoint on setup() routine. extern "C" void setup(); -// The debugger uses this handler to catch faults, debug events, etc. +// The debugger uses this handler to handle debug events, etc. extern "C" void mriExceptionHandler(void); +// The debugger uses this handler to handle faults. +extern "C" void mriFaultHandler(void); @@ -241,10 +244,10 @@ static void restoreSystemHandlerPriorities(const SystemHandlerPriorities* pPrior static void switchFaultHandlersToDebugger(void) { - NVIC_SetVector(HardFault_IRQn, (uint32_t)&mriExceptionHandler); - NVIC_SetVector(MemoryManagement_IRQn, (uint32_t)&mriExceptionHandler); - NVIC_SetVector(BusFault_IRQn, (uint32_t)&mriExceptionHandler); - NVIC_SetVector(UsageFault_IRQn, (uint32_t)&mriExceptionHandler); + NVIC_SetVector(HardFault_IRQn, (uint32_t)&mriFaultHandler); + NVIC_SetVector(MemoryManagement_IRQn, (uint32_t)&mriFaultHandler); + NVIC_SetVector(BusFault_IRQn, (uint32_t)&mriFaultHandler); + NVIC_SetVector(UsageFault_IRQn, (uint32_t)&mriFaultHandler); } @@ -287,27 +290,6 @@ void Platform_CommSendChar(int character) -static const char g_memoryMapXml[] = "" - "" - "" - " " - " 0x20000" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " 0x200" - " " - ""; - extern "C" uint32_t Platform_GetDeviceMemoryMapXmlSize(void) { return sizeof(g_memoryMapXml) - 1; @@ -331,12 +313,7 @@ extern "C" uint32_t Platform_GetUidSize(void) return 0; } -extern "C" int Semihost_IsDebuggeeMakingSemihostCall(void) -{ - return 0; -} - -int Semihost_HandleSemihostRequest(void) +int Semihost_HandleMbedSemihostRequest(PlatformSemihostParameters* pParameters) { return 0; } @@ -617,3 +594,55 @@ void Platform_RtosSetThreadState(uint32_t threadId, PlatformThreadState state) void Platform_RtosRestorePrevThreadState(void) { } + + + + + +// This class can be used instead of Serial for sending output to the PC via GDB. +DebugSerial::DebugSerial() +{ +} + +// Methods that must be implemented for Print subclasses. +size_t DebugSerial::write(uint8_t byte) +{ + return write(&byte, sizeof(byte)); +} + +size_t DebugSerial::write(const uint8_t *pBuffer, size_t size) +{ + const int STDOUT_FILE_NO = 1; + const char* pCurr = (const char*)pBuffer; + int bytesWritten = 0; + + while (size > 0) { + int result = mriNewlib_SemihostWrite(STDOUT_FILE_NO, pCurr, size); + if (result == -1) { + break; + } + size -= result; + pCurr += result; + bytesWritten += result; + } + return bytesWritten; +} + +void DebugSerial::flush() +{ +} + +void DebugSerial::begin(unsigned long baud, uint16_t mode) +{ + // Silence compiler warnings about unused parameters. + (void)baud; + (void)mode; +} + +void DebugSerial::end() +{ +} + + +// Instantiate the single instance of this stream. +class DebugSerial arduino::DebugSerial; diff --git a/libraries/KernelDebug/src/KernelDebug.h b/libraries/KernelDebug/src/KernelDebug.h index 1e27dde5d..e8d2b57d6 100644 --- a/libraries/KernelDebug/src/KernelDebug.h +++ b/libraries/KernelDebug/src/KernelDebug.h @@ -62,4 +62,27 @@ class KernelDebug { #define debugBreak() { __asm volatile ("bkpt #0"); } #endif + +// This class can be used instead of Serial for sending output to the PC via GDB. +class DebugSerial : public Print +{ +public: + DebugSerial(); + + // Leaving out input Stream related methods so that compiler throws errors if user tries to use them. + + // Methods that must be implemented for Print subclasses. + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buffer, size_t size); + virtual void flush(); + + // Additional methods defined by HardwareSerial that user might call. + void begin(unsigned long baud) { begin(baud, SERIAL_8N1); } + void begin(unsigned long baudrate, uint16_t config); + void end(); + operator bool() { return true; } + +protected: +} extern DebugSerial; + } // namespace arduino diff --git a/libraries/KernelDebug/src/armv7-m_asm.S b/libraries/KernelDebug/src/armv7-m_asm.S index 0e31d3dd3..c86ff02d1 100644 --- a/libraries/KernelDebug/src/armv7-m_asm.S +++ b/libraries/KernelDebug/src/armv7-m_asm.S @@ -1,4 +1,4 @@ -/* Copyright 2020 Adam Green (https://github.com/adamgreen/) +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -90,40 +90,28 @@ EXC_RETURN (exception LR) Once the registers are stacked, mriDebugException is called and upon return, the values are popped off of the - stack and placed back into the original registers, except for PSP, PRIMASK, FAULTMASK, and CONTROL which always - maintain their original value. + stack and placed back into the original registers. */ mriExceptionHandler: - /* Check to see if we should just return because a MRI initiated memory read/write failed. */ - ldr r0, =mriCortexMFlags - ldr r0, [r0] - tst r0, #CORTEXM_FLAGS_ACTIVE_DEBUG - beq 1$ - /* MRI has initiated a memory read/write that has failed. Unless MRI has a critical bug, it is safe to use MSP - for calling C code at this point to take care of setting the flag to indicate that the read/write has failed - and advanced the PC past precise read faulting instructions. */ - mov r0, lr - mrs r1, psp - mrs r2, msp - push {r1, lr} - bl mriCortexHandleDebuggerFault - pop {r1, pc} - /* Point R0 to the top of the debugger stack, where MSP should be pointed. */ -1$: ldr r0, =mriCortexMDebuggerStack + ldr r0, =mriCortexMDebuggerStack ldr r1, =CORTEXM_DEBUGGER_STACK_SIZE * 8 add r0, r0, r1 - /* Save away copy of MSP value at the time of the fault into R0. */ -3$: mrs r1, msp - /* Set MSP to top of debugger stack. */ - msr msp, r0 + /* Save away copy of MSP value at the time of the fault into R1. */ + mrs r1, msp + /* Set MSP to top of debugger stack if it hasn't been disabled. */ + ldr r2, =mriCortexMFlags + ldr r2, [r2] + tst r2, #CORTEXM_FLAGS_NO_DEBUG_STACK + it eq + msreq msp, r0 /* Saving integer registers to debugger stack. */ /* R4 - R11, EXC_RETURN */ push {r4-r11, lr} /* MSP, PSP, PRIMASK, BASEPRI, FAULTMASK, CONTROL */ - mov r4, r1 /* MSP was saved away in R0 previously. */ + mov r4, r1 /* MSP was saved away in R1 previously. */ mrs r5, psp mrs r6, primask mrs r7, basepri @@ -155,19 +143,19 @@ mriExceptionHandler: push {r1} vpush.32 {s16-s31} vpush.32 {s0-s15} - b 5$ + /* b 5$ */ /* Fall through to 5$ */ #endif /* MRI_DEVICE_HAS_FPU */ /* All registers integer and float have been pushed on stack. */ - /* Will pass start of integer registers into mriCortexMExceptionHandler via R1. */ + /* Will pass start of floating point registers into mriCortexMExceptionHandler via R1. */ 5$: mrs r1, msp /* Save pointer to integer regs in the R4 non-volatile register. */ mov r4, r0 /* Let C code take care of calling mriDebugException. */ - /* mriCortexMExceptionHandler(R0=pIntegerRegs, R1=pFloatingRegs); */ + /* mriCortexMExceptionHandler(IntegerRegisters* R0=pIntegerRegs, uint32_t* R1=pFloatingRegs); */ bl mriCortexMExceptionHandler /* Unstack floating point registers. */ @@ -186,16 +174,19 @@ mriExceptionHandler: cbz r1, 6$ vpop.32 {s16-s31} /* If there are more than 16 FP registers to unstack then unstack FPSCR. */ - it hi + itt hi pophi {r2} - vmsr fpscr, r2 + vmsrhi fpscr, r2 #endif /* MRI_DEVICE_HAS_FPU */ /* Unstack integer registers. */ 6$: pop {r4-r9} + msr psp, r5 + msr primask, r6 msr basepri, r7 + msr faultmask, r8 + msr control, r9 mov r0, r4 /* R0 = original MSP */ - /* Just drop the PSP value since updating it could really corrupt things. */ /* R4 - R11, EXC_RETURN */ pop {r4-r11, lr} @@ -210,15 +201,80 @@ mriExceptionHandler: + .global mriFaultHandler + .type mriFaultHandler, function + .thumb_func + /* extern "C" void mriFaultHandler(void); + Call mriPendFaultToDebugMon(), implemented in C, to determine how this particular fault should be handled. If it + returns a negative return value, then continue onto mriExceptionHandler which will enter MRI. Otherwise + mriPendFaultToDebugMon() has done everything needed to handle this fault and can just return to let code continue + executing. All of the fault handlers will just jump to this one as they are all handled the same way. + */ +mriFaultHandler: + /* Point R12 to the top of the debugger stack, where MSP should be pointed. */ + ldr r12, =mriCortexMDebuggerStack + ldr r0, =CORTEXM_DEBUGGER_STACK_SIZE * 8 + add r12, r12, r0 + + /* Save away MSP, PSP, and LR values at the time of the fault into R0-R2 to be passed into C functions. */ + mrs r0, psp + mrs r1, msp + mov r2, lr + + /* Check for GDB initiated memory read/write failures. */ + /* Save mriCortexMFlags in r3. */ + ldr r3, =mriCortexMFlags + ldr r3, [r3] + tst r3, #CORTEXM_FLAGS_ACTIVE_DEBUG + beq 1$ + + /* MRI has initiated a memory read/write that has failed. Unless MRI has a critical bug, it is safe to use MSP + for calling C code at this point to take care of setting the flag to indicate that the read/write has failed + and advance the PC past precise read faulting instructions. */ + push {r1, lr} + /* Call mriCortexHandleDebuggerFault(uint32_t R0=psp, uint32_t R1=msp, uint32_t R2=excReturn) */ + bl mriCortexHandleDebuggerFault + pop {r1, pc} + +1$: + /* Get here if this is a fault that should be debugged by MRI. */ + /* Set MSP to top of debugger stack if this feature hasn't been disabled. */ + tst r3, #CORTEXM_FLAGS_NO_DEBUG_STACK + it eq + msreq msp, r12 + + /* Save original MSP and LR on the current stack and then call into C code. */ + push {r1, lr} + /* Call mriPendFaultToDebugMon(uint32_t R0=psp, uint32_t R1=msp, uint32_t R2=excReturn) */ + bl mriPendFaultToDebugMon + movs r0, r0 + bmi 2$ + + /* mriPendFaultToDebugMon() returned with R0 >= 0 & DebugMon pended so just return from fault handler. */ + /* Restore MSP and LR values from the stack and return. */ + pop {r1, lr} + msr msp, r1 + bx lr + +2$: + /* mriPendFaultToDebugMon() returned with R0 < 0 which means it didn't pend to DebugMon. */ + /* Give platform opportunity to save crash dump. */ + bl mriPlatform_HandleFaultFromHighPriorityCode + /* Restore MSP and LR values from the stack and jump to main mriExceptionHandler routine. */ + pop {r1, lr} + msr msp, r1 + b mriExceptionHandler + .pool + .size mriFaultHandler, .-mriFaultHandler + + #if 0 .global HardFault_Handler .type HardFault_Handler, function .thumb_func - /* extern "C" void HardFault_Handler(void); - Override Hard Faults and send to MriExceptionHandler. - */ + /* extern "C" void HardFault_Handler(void); */ HardFault_Handler: - b mriExceptionHandler + b mriFaultHandler .pool .size HardFault_Handler, .-HardFault_Handler @@ -226,11 +282,9 @@ HardFault_Handler: .global MemManage_Handler .type MemManage_Handler, function .thumb_func - /* extern "C" void MemManage_Handler(void); - Override MPU Memory Faults and send to MriExceptionHandler. - */ + /* extern "C" void MemManage_Handler(void); */ MemManage_Handler: - b mriExceptionHandler + b mriFaultHandler .pool .size MemManage_Handler, .-MemManage_Handler @@ -238,11 +292,9 @@ MemManage_Handler: .global BusFault_Handler .type BusFault_Handler, function .thumb_func - /* extern "C" void BusFault_Handler(void); - Override Bus Faults and send to MriExceptionHandler. - */ + /* extern "C" void BusFault_Handler(void); */ BusFault_Handler: - b mriExceptionHandler + b mriFaultHandler .pool .size BusFault_Handler, .-BusFault_Handler @@ -250,11 +302,9 @@ BusFault_Handler: .global UsageFault_Handler .type UsageFault_Handler, function .thumb_func - /* extern "C" void UsageFault_Handler(void); - Override Instruction Usage Faults and send to MriExceptionHandler. - */ + /* extern "C" void UsageFault_Handler(void); */ UsageFault_Handler: - b mriExceptionHandler + b mriFaultHandler .pool .size UsageFault_Handler, .-UsageFault_Handler #endif // 0 @@ -264,7 +314,7 @@ UsageFault_Handler: .type DebugMon_Handler, function .thumb_func /* extern "C" void DebugMon_Handler(void); - Override Debug Monintor exceptions and send to MriExceptionHandler. + Override Debug Monitor exceptions and send to MriExceptionHandler. */ DebugMon_Handler: b mriExceptionHandler diff --git a/libraries/MRI/library.properties b/libraries/MRI/library.properties index a6c3dd277..4ab9e3058 100644 --- a/libraries/MRI/library.properties +++ b/libraries/MRI/library.properties @@ -1,5 +1,5 @@ name=MRI - Monitor for Remote Inspection -version=1.0.0 +version=1.5.0 author=Adam Green maintainer=Arduino sentence=MRI - Monitor for Remote Inspection. The GDB compatible debug monitor for Cortex-M devices. diff --git a/libraries/MRI/src/architectures/armv7-m/armv7-m.h b/libraries/MRI/src/architectures/armv7-m/armv7-m.h index a5ddf39ae..c0f57d445 100644 --- a/libraries/MRI/src/architectures/armv7-m/armv7-m.h +++ b/libraries/MRI/src/architectures/armv7-m/armv7-m.h @@ -1,4 +1,4 @@ -/* Copyright 2020 Adam Green (https://github.com/adamgreen/) +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -34,9 +34,11 @@ #define CORTEXM_FLAGS_ACTIVE_DEBUG (1 << 0) #define CORTEXM_FLAGS_FAULT_DURING_DEBUG (1 << 1) #define CORTEXM_FLAGS_SINGLE_STEPPING (1 << 2) -#define CORTEXM_FLAGS_RESTORE_BASEPRI (1 << 3) +#define CORTEXM_FLAGS_RESTORE_PRI (1 << 3) #define CORTEXM_FLAGS_SVC_STEP (1 << 4) #define CORTEXM_FLAGS_CTRL_C (1 << 5) +#define CORTEXM_FLAGS_NO_DEBUG_STACK (1 << 6) +#define CORTEXM_FLAGS_PEND_FROM_FAULT (1 << 7) /* Special memory area used by the debugger for its stack so that it doesn't interfere with the task's stack contents. @@ -72,6 +74,9 @@ #define LR 14 #define PC 15 #define CPSR 16 +#define MSP 17 +#define PSP 18 +#define PRIMASK 19 #define BASEPRI 20 @@ -87,8 +92,9 @@ #endif /* NOTE: The largest buffer is required for receiving the 'G' command which receives the contents of the registers from - the debugger as two hex digits per byte. Also need a character for the 'G' command itself. */ -#define CORTEXM_PACKET_BUFFER_SIZE (1 + 2 * sizeof(uint32_t) * CONTEXT_SIZE) + the debugger as two hex digits per byte. Also need a character for the 'G' command itself and another 4 for the '$', + '#', and 2-byte checksum. */ +#define CORTEXM_PACKET_BUFFER_SIZE (1 + 2 * sizeof(uint32_t) * CONTEXT_SIZE + 4) typedef struct { @@ -103,8 +109,9 @@ typedef struct uint32_t mmfar; uint32_t bfar; uint32_t originalPC; - uint32_t originalBasePriority; - uint32_t subPriorityBitCount; + uint32_t basepri; + uint32_t primask; + uint32_t priorityBitShift; int maxStackUsed; char packetBuffer[CORTEXM_PACKET_BUFFER_SIZE]; } CortexMState; diff --git a/libraries/MRI/src/architectures/armv7-m/armv7-m.x b/libraries/MRI/src/architectures/armv7-m/armv7-m.x index 1348ef431..1fbcea04c 100644 --- a/libraries/MRI/src/architectures/armv7-m/armv7-m.x +++ b/libraries/MRI/src/architectures/armv7-m/armv7-m.x @@ -1,4 +1,4 @@ -/* Copyright 2020 Adam Green (https://github.com/adamgreen/) +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -13,18 +13,18 @@ limitations under the License. */ /* Routines to expose the Cortex-M functionality to the mri debugger. */ -#include -#include -#include +#include +#include #include #include #include +#include #include "debug_cm3.h" #include "armv7-m.h" -/* Disable any macro used for errno and use the int global instead. */ -#undef errno -extern int errno; +/* Bits in CFSR which indicate that stacking/unstacking fault has occurred during exception entry/exit. */ +#define CFSR_STACK_ERROR_BITS 0x00001818 + /* Fake stack used when task encounters stacking/unstacking fault. */ static const uint32_t g_fakeStack[] = { 0xDEADDEAD, 0xDEADDEAD, 0xDEADDEAD, 0xDEADDEAD, @@ -133,14 +133,20 @@ void mriExceptionHandler(void); static void fillDebuggerStack(void); static void clearState(void); -static void determineSubPriorityBitCount(void); +static void determinePriorityBitShift(void); static void configureDWTandFPB(void); static void defaultSvcAndSysTickInterruptsToLowerPriority(uint8_t priority); static void defaultExternalInterruptsToLowerPriority(uint8_t priority, IRQn_Type highestExternalIrq); +static void disableDebuggerStack(void); static void enableDebugMonitorAtSpecifiedPriority(uint8_t priority); void mriCortexMInit(Token* pParameterTokens, uint8_t debugMonPriority, IRQn_Type highestExternalIrq) { - if (!MRI_THREAD_MRI) + if (MRI_THREAD_MRI) + { + /* Always set DebugMon interrupt priority to lowest level, 255, when using threaded MRI. */ + debugMonPriority = 255; + } + else { /* Reference routine in ASM module to make sure that is gets linked in. */ void (* volatile dummyReference)(void) = mriExceptionHandler; @@ -150,19 +156,25 @@ void mriCortexMInit(Token* pParameterTokens, uint8_t debugMonPriority, IRQn_Type fillDebuggerStack(); clearState(); - determineSubPriorityBitCount(); + determinePriorityBitShift(); configureDWTandFPB(); - if (!MRI_THREAD_MRI) + if (debugMonPriority == 0) { defaultSvcAndSysTickInterruptsToLowerPriority(debugMonPriority+1); defaultExternalInterruptsToLowerPriority(debugMonPriority+1, highestExternalIrq); } + else + { + /* When not running MRI at highest priority, the user is responsible for the priority level of all the */ + /* other interrupts in the system. Only the user knows what they want to be able to debug and what should */ + /* run in the background while the debugger is active. */ + /* Don't want to change MSP to point to special debugger stack during debug exceptions if higher priority */ + /* interrupts exist that can run while stopped in debugger. */ + disableDebuggerStack(); + } Platform_DisableSingleStep(); clearMonitorPending(); - if (MRI_THREAD_MRI) - enableDebugMonitorAtSpecifiedPriority(255); - else - enableDebugMonitorAtSpecifiedPriority(debugMonPriority); + enableDebugMonitorAtSpecifiedPriority(debugMonPriority); } static void fillDebuggerStack(void) @@ -176,7 +188,7 @@ static void fillDebuggerStack(void) static void clearState(void) { - memset(&mriCortexMState, 0, sizeof(mriCortexMState)); + mri_memset(&mriCortexMState, 0, sizeof(mriCortexMState)); } /* Cortex-M7 microcontrollers name the SHP priority registers SHPR unlike other ARMv7-M devices. */ @@ -184,20 +196,20 @@ static void clearState(void) #define SHP SHPR #endif -static void determineSubPriorityBitCount(void) +static void determinePriorityBitShift(void) { const uint32_t debugMonExceptionNumber = 12; uint32_t zeroBitCount; - uint32_t subPriorityBitCount; + uint32_t priorityBitShift; /* Setting DebugMon priority to 0xFF to see how many lsbits read back as zero. */ - /* DebugMon priority will be later set correctly by mriCortexMInit(). */ + /* DebugMon priority will later be set correctly by mriCortexMInit(). */ SCB->SHP[debugMonExceptionNumber-4] = 0xFF; zeroBitCount = 32 - (uint32_t)__CLZ(~(SCB->SHP[debugMonExceptionNumber-4] | 0xFFFFFF00)); - subPriorityBitCount = NVIC_GetPriorityGrouping() + 1; - if (zeroBitCount > subPriorityBitCount) - subPriorityBitCount = zeroBitCount; - mriCortexMState.subPriorityBitCount = subPriorityBitCount; + priorityBitShift = NVIC_GetPriorityGrouping() + 1; + if (zeroBitCount > priorityBitShift) + priorityBitShift = zeroBitCount; + mriCortexMState.priorityBitShift = priorityBitShift; } static void configureDWTandFPB(void) @@ -222,6 +234,11 @@ static void defaultExternalInterruptsToLowerPriority(uint8_t priority, IRQn_Type mriCortexMSetPriority((IRQn_Type)irq, priority, 0); } +static void disableDebuggerStack(void) +{ + mriCortexMFlags |= CORTEXM_FLAGS_NO_DEBUG_STACK; +} + static void enableDebugMonitorAtSpecifiedPriority(uint8_t priority) { mriCortexMSetPriority(DebugMonitor_IRQn, priority, priority); @@ -231,8 +248,8 @@ static void enableDebugMonitorAtSpecifiedPriority(uint8_t priority) void mriCortexMSetPriority(IRQn_Type irq, uint8_t priority, uint8_t subPriority) { - uint8_t fullPriority = (priority << mriCortexMState.subPriorityBitCount) | - (subPriority & ((1 << mriCortexMState.subPriorityBitCount) -1)); + uint8_t fullPriority = (priority << mriCortexMState.priorityBitShift) | + (subPriority & ((1 << mriCortexMState.priorityBitShift) -1)); if ((int32_t)irq >= 0) { @@ -246,9 +263,9 @@ void mriCortexMSetPriority(IRQn_Type irq, uint8_t priority, uint8_t subPriority) static void cleanupIfSingleStepping(void); -static void restoreBasePriorityIfNeeded(void); -static uint32_t shouldRestoreBasePriority(void); -static void clearRestoreBasePriorityFlag(void); +static void restorePriorityRegsIfNeeded(void); +static uint32_t shouldRestorePriorityRegs(void); +static void clearPriorityRestoreFlag(); static void removeHardwareBreakpointOnSvcHandlerIfNeeded(void); static int shouldRemoveHardwareBreakpointOnSvcHandler(void); static void clearSvcStepFlag(void); @@ -264,28 +281,30 @@ void Platform_DisableSingleStep(void) static void cleanupIfSingleStepping(void) { - restoreBasePriorityIfNeeded(); + restorePriorityRegsIfNeeded(); removeHardwareBreakpointOnSvcHandlerIfNeeded(); } -static void restoreBasePriorityIfNeeded(void) +static void restorePriorityRegsIfNeeded(void) { - if (shouldRestoreBasePriority()) + if (shouldRestorePriorityRegs()) { - clearRestoreBasePriorityFlag(); - Context_Set(&mriCortexMState.context, BASEPRI, mriCortexMState.originalBasePriority); - mriCortexMState.originalBasePriority = 0; + clearPriorityRestoreFlag(); + Context_Set(&mriCortexMState.context, PRIMASK, mriCortexMState.primask); + Context_Set(&mriCortexMState.context, BASEPRI, mriCortexMState.basepri); + mriCortexMState.primask = 0; + mriCortexMState.basepri = 0; } } -static uint32_t shouldRestoreBasePriority(void) +static uint32_t shouldRestorePriorityRegs(void) { - return mriCortexMFlags & CORTEXM_FLAGS_RESTORE_BASEPRI; + return mriCortexMFlags & CORTEXM_FLAGS_RESTORE_PRI; } -static void clearRestoreBasePriorityFlag(void) +static void clearPriorityRestoreFlag() { - mriCortexMFlags &= ~CORTEXM_FLAGS_RESTORE_BASEPRI; + mriCortexMFlags &= ~CORTEXM_FLAGS_RESTORE_PRI; } static void removeHardwareBreakpointOnSvcHandlerIfNeeded(void) @@ -329,27 +348,37 @@ static int doesPCPointToSVCInstruction(void); static void setHardwareBreakpointOnSvcHandler(void); static void setSvcStepFlag(void); static void setSingleSteppingFlag(void); -static void setSingleSteppingFlag(void); -static void recordCurrentBasePriorityAndRaisePriorityToDisableNonDebugInterrupts(void); -static int doesPCPointToBASEPRIUpdateInstruction(void); +static int advancePastPriorityModifyingInstruction(void); +static int checkCurrentInstruction(void); static uint16_t getFirstHalfWordOfCurrentInstruction(void); static uint16_t getSecondHalfWordOfCurrentInstruction(void); static uint16_t throwingMemRead16(uint32_t address); -static int isFirstHalfWordOfMSR(uint16_t instructionHalfWord0); -static int isSecondHalfWordOfMSRModifyingBASEPRI(uint16_t instructionHalfWord1); -static int isSecondHalfWordOfMSR_BASEPRI(uint16_t instructionHalfWord1); -static int isSecondHalfWordOfMSR_BASEPRI_MAX(uint16_t instructionHalfWord1); -static void recordCurrentBasePriority(void); -static void setRestoreBasePriorityFlag(void); +static int isInstructionMSR(uint16_t firstWord, uint16_t secondWord); +static int processInstructionMSR(uint16_t firstWord, uint16_t secondWord); +static int isInstructionCPS(uint16_t firstWord); +static int processInstructionCPS(uint16_t firstWord); +static int isInstructionMRS(uint16_t firstWord, uint16_t secondWord); +static int processInstructionMRS(uint16_t firstWord, uint16_t secondWord); +static void recordCurrentBasePriorityAndRaisePriorityToDisableNonDebugInterrupts(void); +static void recordCurrentPriorityRegs(void); +static void setRestorePriorityRegsFlag(void); static uint8_t calculateBasePriorityForThisCPU(uint8_t basePriority); void Platform_EnableSingleStep(void) { + int didAdvancePastPriorityInstruction; + if (MRI_THREAD_MRI) { setSingleSteppingFlag(); return; } + didAdvancePastPriorityInstruction = advancePastPriorityModifyingInstruction(); + if (didAdvancePastPriorityInstruction) + { + return; + } + if (!doesPCPointToSVCInstruction()) { setSingleSteppingFlag(); @@ -408,15 +437,18 @@ static void setSingleSteppingFlag(void) mriCortexMFlags |= CORTEXM_FLAGS_SINGLE_STEPPING; } -static void recordCurrentBasePriorityAndRaisePriorityToDisableNonDebugInterrupts(void) +static int advancePastPriorityModifyingInstruction(void) { - if (!doesPCPointToBASEPRIUpdateInstruction()) - recordCurrentBasePriority(); - Context_Set(&mriCortexMState.context, BASEPRI, - calculateBasePriorityForThisCPU(mriCortexMGetPriority(DebugMonitor_IRQn) + 1)); + if (checkCurrentInstruction()) + { + /* Current instruction is related to priority registers and was simulated so advance PC past it. */ + Platform_AdvanceProgramCounterToNextInstruction(); + return 1; + } + return 0; } -static int doesPCPointToBASEPRIUpdateInstruction(void) +static int checkCurrentInstruction(void) { uint16_t firstWord = 0; uint16_t secondWord = 0; @@ -432,7 +464,16 @@ static int doesPCPointToBASEPRIUpdateInstruction(void) return 0; } - return isFirstHalfWordOfMSR(firstWord) && isSecondHalfWordOfMSRModifyingBASEPRI(secondWord); + /* MSR and CPSI* instructions can modify the PRIMASK and BASEPRI registers. */ + if (isInstructionMSR(firstWord, secondWord)) + return processInstructionMSR(firstWord, secondWord); + if (isInstructionCPS(firstWord)) + return processInstructionCPS(firstWord); + /* MRS instructions might want to read the real values of PRIMASK and BASEPRI and not the values as modified + by MRI. */ + if (isInstructionMRS(firstWord, secondWord)) + return processInstructionMRS(firstWord, secondWord); + return 0; } static uint16_t getFirstHalfWordOfCurrentInstruction(void) @@ -453,49 +494,105 @@ static uint16_t throwingMemRead16(uint32_t address) return instructionWord; } -static int isFirstHalfWordOfMSR(uint16_t instructionHalfWord0) +static int isInstructionMSR(uint16_t firstWord, uint16_t secondWord) { - static const unsigned short MSRMachineCode = 0xF380; - static const unsigned short MSRMachineCodeMask = 0xFFF0; + return ((firstWord & 0xFFF0) == 0xF380) && ((secondWord & 0xFF00) == 0x8800); +} + +static int processInstructionMSR(uint16_t firstWord, uint16_t secondWord) +{ + uint16_t Rn = firstWord & 0x000F; + uint16_t SYSm = secondWord & 0x00FF; - return MSRMachineCode == (instructionHalfWord0 & MSRMachineCodeMask); + switch (SYSm) + { + case 16: // PRIMASK + Context_Set(&mriCortexMState.context, PRIMASK, Context_Get(&mriCortexMState.context, Rn)); + return 1; + case 17: // BASEPRI + Context_Set(&mriCortexMState.context, BASEPRI, Context_Get(&mriCortexMState.context, Rn)); + return 1; + case 18: // BASEPRI_MAX + { + uint32_t basepriVal = Context_Get(&mriCortexMState.context, BASEPRI); + uint32_t RnVal = Context_Get(&mriCortexMState.context, Rn); + if (basepriVal == 0 || RnVal < basepriVal) + { + Context_Set(&mriCortexMState.context, BASEPRI, RnVal); + } + return 1; + } + default: + return 0; + } } -static int isSecondHalfWordOfMSRModifyingBASEPRI(uint16_t instructionHalfWord1) +static int isInstructionCPS(uint16_t firstWord) { - return isSecondHalfWordOfMSR_BASEPRI(instructionHalfWord1) || - isSecondHalfWordOfMSR_BASEPRI_MAX(instructionHalfWord1); + return (firstWord & 0xFFEC) == 0xB660; } -static int isSecondHalfWordOfMSR_BASEPRI(uint16_t instructionHalfWord1) +static int processInstructionCPS(uint16_t firstWord) { - static const unsigned short BASEPRIMachineCode = 0x8811; + uint16_t enable = (firstWord & 0x0010) >> 4; + uint16_t I = firstWord & 0x0002; - return instructionHalfWord1 == BASEPRIMachineCode; + if (I) + { + Context_Set(&mriCortexMState.context, PRIMASK, enable); + return 1; + } + return 0; } -static int isSecondHalfWordOfMSR_BASEPRI_MAX(uint16_t instructionHalfWord1) +static int isInstructionMRS(uint16_t firstWord, uint16_t secondWord) { - static const unsigned short BASEPRI_MAXMachineCode = 0x8812; + return ((firstWord & 0xFFFF) == 0xF3EF) && ((secondWord & 0xF000) == 0x8000); +} + +static int processInstructionMRS(uint16_t firstWord, uint16_t secondWord) +{ + uint16_t Rn = (secondWord & 0x0F00) >> 8; + uint16_t SYSm = secondWord & 0x00FF; + + switch (SYSm) + { + case 16: // PRIMASK + Context_Set(&mriCortexMState.context, Rn, Context_Get(&mriCortexMState.context, PRIMASK)); + return 1; + case 17: // BASEPRI + case 18: // BASEPRI_MAX + Context_Set(&mriCortexMState.context, Rn, Context_Get(&mriCortexMState.context, BASEPRI)); + return 1; + default: + return 0; + } +} - return instructionHalfWord1 == BASEPRI_MAXMachineCode; +static void recordCurrentBasePriorityAndRaisePriorityToDisableNonDebugInterrupts(void) +{ + recordCurrentPriorityRegs(); + Context_Set(&mriCortexMState.context, PRIMASK, 0); + Context_Set(&mriCortexMState.context, BASEPRI, + calculateBasePriorityForThisCPU(mriCortexMGetPriority(DebugMonitor_IRQn) + 1)); } -static void recordCurrentBasePriority(void) +static void recordCurrentPriorityRegs(void) { - mriCortexMState.originalBasePriority = Context_Get(&mriCortexMState.context, BASEPRI); - setRestoreBasePriorityFlag(); + mriCortexMState.primask = Context_Get(&mriCortexMState.context, PRIMASK); + mriCortexMState.basepri = Context_Get(&mriCortexMState.context, BASEPRI); + setRestorePriorityRegsFlag(); } -static void setRestoreBasePriorityFlag(void) +static void setRestorePriorityRegsFlag(void) { - mriCortexMFlags |= CORTEXM_FLAGS_RESTORE_BASEPRI; + mriCortexMFlags |= CORTEXM_FLAGS_RESTORE_PRI; } static uint8_t calculateBasePriorityForThisCPU(uint8_t basePriority) { /* Different Cortex-M3 chips support different number of bits in the priority register. */ - return basePriority << mriCortexMState.subPriorityBitCount; + return basePriority << mriCortexMState.priorityBitShift; } @@ -511,7 +608,7 @@ uint8_t mriCortexMGetPriority(IRQn_Type irq) { priority = SCB->SHP[((uint32_t)irq & 0xF)-4]; } - return priority >> mriCortexMState.subPriorityBitCount; + return priority >> mriCortexMState.priorityBitShift; } @@ -534,6 +631,7 @@ uint32_t Platform_GetPacketBufferSize(void) static PlatformTrapReason cacheTrapReason(void); +static uint32_t encounteredStackingException(void); static PlatformTrapReason findMatchedWatchpoint(void); static PlatformTrapReason getReasonFromMatchComparator(const DWT_COMP_Type* pComparator); static uint32_t hasControlCBeenDetected(); @@ -577,9 +675,14 @@ uint8_t Platform_DetermineCauseOfException(void) PlatformTrapReason cacheTrapReason(void) { PlatformTrapReason reason = { MRI_PLATFORM_TRAP_TYPE_UNKNOWN, 0x00000000 }; - uint32_t debugFaultStatus = mriCortexMState.dfsr; - if (debugFaultStatus & SCB_DFSR_BKPT) + + if (encounteredStackingException()) + { + /* Stacking faults are more important than breakpoints and lead to an unknown PC anyway. */ + return reason; + } + else if (debugFaultStatus & SCB_DFSR_BKPT) { /* Was caused by hardware or software breakpoint. If PC points to BKPT then report as software breakpoint. */ if (Platform_TypeOfCurrentInstruction() == MRI_PLATFORM_INSTRUCTION_HARDCODED_BREAKPOINT) @@ -594,6 +697,11 @@ PlatformTrapReason cacheTrapReason(void) return reason; } +static uint32_t encounteredStackingException(void) +{ + return mriCortexMState.cfsr & CFSR_STACK_ERROR_BITS; +} + static PlatformTrapReason findMatchedWatchpoint(void) { PlatformTrapReason reason = { MRI_PLATFORM_TRAP_TYPE_UNKNOWN, 0x00000000 }; @@ -898,11 +1006,13 @@ static void setActiveDebugFlag(void) static void checkStack(void); static void clearControlCFlag(void); static void clearActiveDebugFlag(void); +static void clearPendedFromFaultFlag(void); void Platform_LeavingDebugger(void) { checkStack(); clearControlCFlag(); clearActiveDebugFlag(); + clearPendedFromFaultFlag(); clearMonitorPending(); } @@ -916,6 +1026,11 @@ static void clearActiveDebugFlag(void) mriCortexMFlags &= ~CORTEXM_FLAGS_ACTIVE_DEBUG; } +static void clearPendedFromFaultFlag(void) +{ + mriCortexMFlags &= ~CORTEXM_FLAGS_PEND_FROM_FAULT; +} + static void checkStack(void) { uint32_t* pCurr = (uint32_t*)mriCortexMDebuggerStack; @@ -1026,9 +1141,11 @@ static int isInstructionMbedSemihostBreakpoint(uint16_t instruction) static int isInstructionNewlibSemihostBreakpoint(uint16_t instruction) { - static const uint16_t newlibSemihostBreakpointMachineCode = 0xbeff; + static const uint16_t newlibSemihostBreakpointMinMachineCode = 0xbe00 | MRI_NEWLIB_SEMIHOST_MIN; + static const uint16_t newlibSemihostBreakpointMaxMachineCode = 0xbe00 | MRI_NEWLIB_SEMIHOST_MAX; - return (newlibSemihostBreakpointMachineCode == instruction); + return (instruction >= newlibSemihostBreakpointMinMachineCode && + instruction <= newlibSemihostBreakpointMaxMachineCode); } static int isInstructionHardcodedBreakpoint(uint16_t instruction) @@ -1052,11 +1169,9 @@ PlatformSemihostParameters Platform_GetSemihostCallParameters(void) } -void Platform_SetSemihostCallReturnAndErrnoValues(int returnValue, int err) +void Platform_SetSemihostCallReturnAndErrnoValues(int returnValue, int errNo) { Context_Set(&mriCortexMState.context, R0, returnValue); - if (returnValue < 0) - errno = err; } @@ -1235,6 +1350,102 @@ void Platform_ResetDevice(void) } +/* Cache related registers as defined in ARMv7-M Architecture Reference Manual but only partially in CMSIS headers. */ +#define SCB_CLIDR (*(__IM uint32_t*)0xE000ED78) /* Cache Level ID register */ +#define SCB_CTR (*(__IM uint32_t*)0xE000ED7C) /* Cache Type register */ +#define SCB_ICIMVAU (*(__OM uint32_t*)0xE000EF58) /* I-Cache Invalidate by MVA to PoU */ +#define SCB_DCCMVAU (*(__OM uint32_t*)0xE000EF64) /* D-Cache Clean by MVA to PoU */ +#define SCB_BPIALL (*(__OM uint32_t*)0xE000EF78) /* Branch Predictor Invalidate All */ + +static int levelOfCacheUnification(void); +static void cleanDataCacheToPointOfUnification(uint32_t address, uint32_t size); +static uint32_t getDCacheLineSize(void); +static void invalidateInstructionCacheToPointOfUnification(uint32_t address, uint32_t size); +static uint32_t getICacheLineSize(void); +static void invalidateAllBranchPredictions(void); +void Platform_SyncICacheToDCache(void *pv, uint32_t size) +{ + uint32_t address = (uint32_t)pv; + + if (size == 0 || levelOfCacheUnification() == 0) + return; + + __DSB(); + cleanDataCacheToPointOfUnification(address, size); + __DSB(); + invalidateInstructionCacheToPointOfUnification(address, size); + invalidateAllBranchPredictions(); + __DSB(); + __ISB(); +} + +static int levelOfCacheUnification(void) +{ + const uint32_t LoUU_BitShift = 27; + const uint32_t LoUU_BitMask = 0x7 << LoUU_BitShift; + + return (SCB_CLIDR & LoUU_BitMask) >> LoUU_BitShift; +} + +static void cleanDataCacheToPointOfUnification(uint32_t address, uint32_t size) +{ + uint32_t lineSize = getDCacheLineSize(); + int32_t op_size = size + (address & (lineSize - 1U)); + uint32_t op_addr = address; /* & ~(lineSize - 1U) */ + + do + { + /* Register forces lineSize alignment by setting lsb to 0, so don't need to do in op_addr calc above too. */ + SCB_DCCMVAU = op_addr; + op_addr += lineSize; + op_size -= lineSize; + } while ( op_size > 0 ); +} + +static uint32_t getDCacheLineSize(void) +{ + const uint32_t DminLine_BitShift = 16; + const uint32_t DminLine_BitMask = 0xF << DminLine_BitShift; + + uint32_t DminLineLog2 = (SCB_CTR & DminLine_BitMask) >> DminLine_BitShift; + uint32_t DminLineWords = 1 << DminLineLog2; + uint32_t DminLineBytes = DminLineWords * sizeof(uint32_t); + + return DminLineBytes; +} + +static void invalidateInstructionCacheToPointOfUnification(uint32_t address, uint32_t size) +{ + uint32_t lineSize = getICacheLineSize(); + int32_t op_size = size + (address & (lineSize - 1U)); + uint32_t op_addr = address; /* & ~(lineSize - 1U) */ + + do + { + /* Register forces lineSize alignment by setting lsb to 0, so don't need to do in op_addr calc above too. */ + SCB_ICIMVAU = op_addr; + op_addr += lineSize; + op_size -= lineSize; + } while ( op_size > 0 ); +} + +static uint32_t getICacheLineSize(void) +{ + const uint32_t IminLine_BitMask = 0xF; + + uint32_t IminLineLog2 = SCB_CTR & IminLine_BitMask; + uint32_t IminLineWords = 1 << IminLineLog2; + uint32_t IminLineBytes = IminLineWords * sizeof(uint32_t); + + return IminLineBytes; +} + +static void invalidateAllBranchPredictions(void) +{ + SCB_BPIALL = 1; +} + + #if !MRI_THREAD_MRI /****************************************************************************************************/ @@ -1262,9 +1473,6 @@ static ContextSection g_contextEntries[CONTEXT_ENTRIES]; /* Bit in LR set to 0 when automatic stacking of floating point registers occurs during exception handling. */ #define LR_FLOAT_STACK (1 << 4) -/* Bits in CFSR which indicate that stacking/unstacking fault has occurred during exception entry/exit. */ -#define CFSR_STACK_ERROR_BITS 0x00001818 - typedef struct IntegerRegisters @@ -1323,15 +1531,18 @@ static uint32_t isImpreciseBusFaultRaw(void); static ExceptionStack* getExceptionStack(uint32_t excReturn, uint32_t psp, uint32_t msp); static void advancePCToNextInstruction(ExceptionStack* pExceptionStack); static void clearFaultStatusBits(void); -void mriCortexHandleDebuggerFault(uint32_t excReturn, uint32_t psp, uint32_t msp) +void mriCortexHandleDebuggerFault(uint32_t psp, uint32_t msp, uint32_t excReturn) { /* Encountered memory fault when GDB attempted to access an invalid address. - Set flag to let debugger thread know that its access failed and advance past the faulting instruction + Set flag to let MRI know that its access failed and advance past the faulting instruction if it was a precise bus fault so that it doesn't just occur again on return. */ setFaultDetectedFlag(); if (!isImpreciseBusFaultRaw()) - advancePCToNextInstruction(getExceptionStack(excReturn, psp, msp)); + { + ExceptionStack* pExceptionStack = getExceptionStack(excReturn, psp, msp); + advancePCToNextInstruction(pExceptionStack); + } clearFaultStatusBits(); } @@ -1375,11 +1586,163 @@ static void clearFaultStatusBits(void) SCB->CFSR = SCB->CFSR; } +static int wasFaultCausedByStackingException(void); +static int isExceptionPriorityLowEnoughToDebug(uint32_t exceptionNumber); +static int hasDebugMonInterruptBeenDisabled(); +static void recordAndClearFaultStatusBits(uint32_t exceptionNumber); +static void disableInterruptMaskingIfNecessary(void); +static void treatDebugEventHardFaultAsDebugMonInterrupt(void); +static void setPendedFromFaultBit(void); +int mriPendFaultToDebugMon(uint32_t psp, uint32_t msp, uint32_t excReturn) +{ + /* This handler will be called from the fault handlers (Hard Fault, etc.) + What needs to be done depends on CPU state when the fault occurs. + */ + if (wasFaultCausedByStackingException()) + { + /* Return -1 to let asm caller know that it wasn't safe to pend DebugMon interrupt because of stacking error. */ + return -1; + } + + ExceptionStack* pExceptionStack = getExceptionStack(excReturn, psp, msp); + uint32_t exceptionNumber = pExceptionStack->xpsr & 0xFF; + if (isExceptionPriorityLowEnoughToDebug(exceptionNumber)) + { + /* Pend DebugMon interrupt to debug the fault. + + Returns 0 to let asm routine know that it can now just return to let the pended DebugMon run. + */ + recordAndClearFaultStatusBits(getCurrentlyExecutingExceptionNumber()); + disableInterruptMaskingIfNecessary(); + treatDebugEventHardFaultAsDebugMonInterrupt(); + setPendedFromFaultBit(); + setMonitorPending(); + return 0; + } + else + { + /* Exception occurred in code too high priority to debug so start a crash dump. + + Returns -1 to let asm routine know that it should call Platform_HandleFaultFromHighPriorityCode() to handle + this special case by doing something like dumping a crash dump since MRI can't debug it. + */ + return -1; + } +} + +static int wasFaultCausedByStackingException(void) +{ + return SCB->CFSR & CFSR_STACK_ERROR_BITS; +} + +static int isExceptionPriorityLowEnoughToDebug(uint32_t exceptionNumber) +{ + if (hasDebugMonInterruptBeenDisabled()) + { + /* User code has entered critical section using PRIMASK or BASEPRI which disables debug monitor. */ + return 0; + } + else if (exceptionNumber == 0) + { + /* Can always debug main thread as it has lowest priority. */ + return 1; + } + else if (exceptionNumber >= 1 && exceptionNumber <= 3) + { + /* NMI & HardFault are always higher priority than DebugMon. */ + return 0; + } + else + { + return mriCortexMGetPriority((IRQn_Type)(-16+exceptionNumber)) > mriCortexMGetPriority(DebugMonitor_IRQn); + } +} + +static int hasDebugMonInterruptBeenDisabled() +{ + /* Was user code in a critical section that disabled DebugMon interrupt when debug event occurred? */ + uint32_t primask = __get_PRIMASK(); + uint32_t basepri = __get_BASEPRI(); + uint32_t debugMonPriority = mriCortexMGetPriority(DebugMonitor_IRQn); + + if (primask != 0 && debugMonPriority > 0) + { + /* All interrupts have been masked and if DebugMon is running at priority lower than 0 then there is no way + to safely pend a transition to the DebugMon handler. */ + return 1; + } + else if (basepri != 0x00 && (basepri >> mriCortexMState.priorityBitShift) <= debugMonPriority) + { + return 1; + } + else + { + return 0; + } +} + +static void recordAndClearFaultStatusBits(uint32_t exceptionNumber) +{ + mriCortexMState.exceptionNumber = exceptionNumber; + mriCortexMState.dfsr = SCB->DFSR; + mriCortexMState.hfsr = SCB->HFSR; + mriCortexMState.cfsr = SCB->CFSR; + mriCortexMState.mmfar = SCB->MMFAR; + mriCortexMState.bfar = SCB->BFAR; + + /* Clear fault status bits by writing 1s to bits that are already set. */ + SCB->DFSR = mriCortexMState.dfsr; + SCB->HFSR = mriCortexMState.hfsr; + SCB->CFSR = mriCortexMState.cfsr; +} + +static void disableInterruptMaskingIfNecessary(void) +{ + /* When DebugMon is running at priority level 0 then can re-enable interrupts and pend DebugMon but must record + the fact that PRIMASK was set so that it can be restored when leaving debugger. */ + uint32_t primask = __get_PRIMASK(); + uint32_t basepri = __get_BASEPRI(); + + if (primask != 0) + { + mriCortexMState.primask = primask; + mriCortexMState.basepri = basepri; + setRestorePriorityRegsFlag(); + __set_PRIMASK(0); + } +} + +static void treatDebugEventHardFaultAsDebugMonInterrupt(void) +{ + static const uint32_t debugEventBit = 1 << 31; + static const uint32_t debugMonExceptionNumber = 12; + + /* Treat as DebugMon interrupt if only the DEBUGEVT bit is set in the HFSR. */ + if (mriCortexMState.hfsr == debugEventBit) + { + mriCortexMState.exceptionNumber = debugMonExceptionNumber; + } +} + + +static void setPendedFromFaultBit(void) +{ + mriCortexMFlags |= CORTEXM_FLAGS_PEND_FROM_FAULT; +} + + +__attribute__((weak)) void Platform_HandleFaultFromHighPriorityCode(void) +{ + /* This weak implemention does nothing and just returns to allow a jump directly to mriExceptionHandler to occur. + A platform may want to provide a strong implementation to generate a crash dump in this scenario if MRI can't + safely communicate with GDB from the HardFault priority level. + */ +} + static ExceptionStack* getExceptionStack(uint32_t excReturn, uint32_t psp, uint32_t msp); -static void recordAndClearFaultStatusBits(uint32_t exceptionNumber); -static uint32_t encounteredStackingException(void); +static int wasPendedFromFault(void); static int prepareThreadContext(ExceptionStack* pExceptionStack, IntegerRegisters* pIntegerRegs, uint32_t* pFloatingRegs); static void allocateFakeFloatRegAndCallMriDebugException(void); void mriCortexMExceptionHandler(IntegerRegisters* pIntegerRegs, uint32_t* pFloatingRegs) @@ -1387,47 +1750,77 @@ void mriCortexMExceptionHandler(IntegerRegisters* pIntegerRegs, uint32_t* pFloat uint32_t excReturn = pIntegerRegs->excReturn; uint32_t msp = pIntegerRegs->msp; uint32_t psp = pIntegerRegs->psp; - uint32_t exceptionNumber = getCurrentlyExecutingExceptionNumber(); ExceptionStack* pExceptionStack = getExceptionStack(excReturn, psp, msp); int needToFakeFloatRegs = 0; - if (isExternalInterrupt(exceptionNumber) && !Platform_CommHasReceiveData()) + /* If we know that DebugMon was pended from a fault handler then it wasn't a comm channel interrupt and there */ + /* is no need to record/clear the fault status bits as this was done before pending DebugMon. */ + if (!wasPendedFromFault()) { - /* Just return if communication channel had a pending interrupt when last debug session completed. */ - return; + uint32_t exceptionNumber = getCurrentlyExecutingExceptionNumber(); + if (isExternalInterrupt(exceptionNumber) && !Platform_CommHasReceiveData()) + { + /* Just return if communication channel had a pending interrupt when last debug session completed. */ + return; + } + + recordAndClearFaultStatusBits(exceptionNumber); } - recordAndClearFaultStatusBits(exceptionNumber); mriCortexMState.taskSP = (uint32_t)pExceptionStack; if (encounteredStackingException()) pExceptionStack = (ExceptionStack*)g_fakeStack; /* Setup scatter gather list for context. */ needToFakeFloatRegs = prepareThreadContext(pExceptionStack, pIntegerRegs, pFloatingRegs); + + /* Record some stats about the exception stack to help move it later if the user changes the SP. */ + uint32_t exceptionStackSize = mriCortexMState.sp - mriCortexMState.taskSP; + int isExceptionStackMSP = msp == (uint32_t)pExceptionStack; + int isExceptionStackPSP = psp == (uint32_t)pExceptionStack; + uint32_t origSP = mriCortexMState.sp; + if (needToFakeFloatRegs) allocateFakeFloatRegAndCallMriDebugException(); else mriDebugException(&mriCortexMState.context); -} -static void recordAndClearFaultStatusBits(uint32_t exceptionNumber) -{ - mriCortexMState.exceptionNumber = exceptionNumber; - mriCortexMState.dfsr = SCB->DFSR; - mriCortexMState.hfsr = SCB->HFSR; - mriCortexMState.cfsr = SCB->CFSR; - mriCortexMState.mmfar = SCB->MMFAR; - mriCortexMState.bfar = SCB->BFAR; + /* If exception stack has been modified by user then will need to move exception record. */ + if (mriCortexMState.sp != origSP) + { + if (isExceptionStackMSP) + { + Context_Set(&mriCortexMState.context, MSP, mriCortexMState.sp - exceptionStackSize); + } + if (isExceptionStackPSP) + { + Context_Set(&mriCortexMState.context, PSP, mriCortexMState.sp - exceptionStackSize); + } + } - /* Clear fault status bits by writing 1s to bits that are already set. */ - SCB->DFSR = mriCortexMState.dfsr; - SCB->HFSR = mriCortexMState.hfsr; - SCB->CFSR = mriCortexMState.cfsr; + uint32_t newMSP = Context_Get(&mriCortexMState.context, MSP); + uint32_t newPSP = Context_Get(&mriCortexMState.context, PSP); + uint32_t oldSP = 0x00000000; + uint32_t newSP = 0x00000000; + if (isExceptionStackMSP && msp != newMSP) + { + oldSP = msp; + newSP = newMSP; + } + else if (isExceptionStackPSP && psp != newPSP) + { + oldSP = psp; + newSP = newPSP; + } + if (oldSP != newSP) + { + mri_memmove((void*)newSP, (void*)oldSP, exceptionStackSize); + } } -static uint32_t encounteredStackingException(void) +static int wasPendedFromFault(void) { - return mriCortexMState.cfsr & CFSR_STACK_ERROR_BITS; + return mriCortexMFlags & CORTEXM_FLAGS_PEND_FROM_FAULT; } static int prepareThreadContext(ExceptionStack* pExceptionStack, IntegerRegisters* pIntegerRegs, uint32_t* pFloatingRegs) @@ -1505,7 +1898,7 @@ static void allocateFakeFloatRegAndCallMriDebugException(void) { uint32_t fakeFloats[33]; - memset(&fakeFloats, 0, sizeof(fakeFloats)); + mri_memset(&fakeFloats, 0, sizeof(fakeFloats)); g_contextEntries[6].pValues = fakeFloats; g_contextEntries[6].count = sizeof(fakeFloats)/sizeof(fakeFloats[0]); diff --git a/libraries/MRI/src/architectures/armv7-m/debug_cm3.h b/libraries/MRI/src/architectures/armv7-m/debug_cm3.h index cbc2058a5..0e56ffb25 100644 --- a/libraries/MRI/src/architectures/armv7-m/debug_cm3.h +++ b/libraries/MRI/src/architectures/armv7-m/debug_cm3.h @@ -681,6 +681,7 @@ static __INLINE void initFPB(void) enableFPB(); } +#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) /* Memory Protection Unit Type Register Bits. */ /* Number of instruction regions supported by MPU. 0 for Cortex-M3 */ @@ -850,6 +851,8 @@ static __INLINE uint32_t getMPURegionAttributeAndSize(void) return MPU->RASR; } +#endif + static __INLINE uint32_t getCurrentlyExecutingExceptionNumber(void) { return (__get_IPSR() & 0xFF); diff --git a/libraries/MRI/src/core/buffer.c b/libraries/MRI/src/core/buffer.c index 0d1aea1a2..a641f5124 100644 --- a/libraries/MRI/src/core/buffer.c +++ b/libraries/MRI/src/core/buffer.c @@ -1,4 +1,4 @@ -/* Copyright 2020 Adam Green (https://github.com/adamgreen/) +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,7 +15,7 @@ /* 'Class' which represents a text buffer. Has routines to both extract and inject strings of various types into the buffer while verifying that no overflow takes place. */ #include -#include +#include #include #include #include @@ -41,6 +41,15 @@ void Buffer_SetEndOfBuffer(Buffer* pBuffer) } +void Buffer_Advance(Buffer* pBuffer, size_t amount) +{ + size_t bytesLeft = Buffer_BytesLeft(pBuffer); + if (amount > bytesLeft) + amount = bytesLeft; + pBuffer->pCurrent += amount; +} + + size_t Buffer_BytesLeft(Buffer* pBuffer) { if (Buffer_OverrunDetected(pBuffer)) @@ -147,7 +156,7 @@ uint8_t Buffer_ReadByteAsHex(Buffer* pBuffer) void Buffer_WriteString(Buffer* pBuffer, const char* pString) { - Buffer_WriteSizedString(pBuffer, pString, strlen(pString)); + Buffer_WriteSizedString(pBuffer, pString, mri_strlen(pString)); } @@ -163,10 +172,25 @@ void Buffer_WriteSizedString(Buffer* pBuffer, const char* pString, size_t length } -void Buffer_WriteStringAsHex(Buffer* pBuffer, const char* pString) +size_t Buffer_WriteStringAsHex(Buffer* pBuffer, const char* pString) { - while (*pString) + return Buffer_WriteSizedStringAsHex(pBuffer, pString, mri_strlen(pString)); +} + + +size_t Buffer_WriteSizedStringAsHex(Buffer* pBuffer, const char* pString, size_t length) +{ + size_t charLimit = Buffer_BytesLeft(pBuffer) / 2; + size_t charsWritten; + + if (length > charLimit) + length = charLimit; + charsWritten = length; + while (length--) Buffer_WriteByteAsHex(pBuffer, *pString++); + + // Returns the number of source string characters consumed and not number of hex digits written to buffer. + return charsWritten; } @@ -411,7 +435,7 @@ static int doesBufferContainThisString(Buffer* pBuffer, const char* pDesiredStri { const char* pBufferString = pBuffer->pCurrent; - return (strncmp(pBufferString, pDesiredString, stringLength) == 0) && + return (mri_strncmp(pBufferString, pDesiredString, stringLength) == 0) && (Buffer_BytesLeft(pBuffer) == stringLength || pBufferString[stringLength] == ':' || pBufferString[stringLength] == ';' || diff --git a/libraries/MRI/src/core/buffer.h b/libraries/MRI/src/core/buffer.h index c04f28ee1..d0fc448b5 100644 --- a/libraries/MRI/src/core/buffer.h +++ b/libraries/MRI/src/core/buffer.h @@ -1,4 +1,4 @@ -/* Copyright 2020 Adam Green (https://github.com/adamgreen/) +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -31,6 +31,7 @@ typedef struct void mriBuffer_Init(Buffer* pBuffer, char* pBufferStart, size_t bufferSize); void mriBuffer_Reset(Buffer* pBuffer); void mriBuffer_SetEndOfBuffer(Buffer* pBuffer); +void mriBuffer_Advance(Buffer* pBuffer, size_t amount); size_t mriBuffer_BytesLeft(Buffer* pBuffer); int mriBuffer_OverrunDetected(Buffer* pBuffer); size_t mriBuffer_GetLength(Buffer* pBuffer); @@ -41,7 +42,8 @@ void mriBuffer_WriteByteAsHex(Buffer* pBuffer, uint8_t byte); uint8_t mriBuffer_ReadByteAsHex(Buffer* pBuffer); void mriBuffer_WriteString(Buffer* pBuffer, const char* pString); void mriBuffer_WriteSizedString(Buffer* pBuffer, const char* pString, size_t length); -void mriBuffer_WriteStringAsHex(Buffer* pBuffer, const char* pString); +size_t mriBuffer_WriteStringAsHex(Buffer* pBuffer, const char* pString); +size_t mriBuffer_WriteSizedStringAsHex(Buffer* pBuffer, const char* pString, size_t length); uint32_t mriBuffer_ReadUIntegerAsHex(Buffer* pBuffer); void mriBuffer_WriteUIntegerAsHex(Buffer* pBuffer, uint32_t value); int32_t mriBuffer_ReadIntegerAsHex(Buffer* pBuffer); @@ -51,26 +53,28 @@ int mriBuffer_MatchesString(Buffer* pBuffer, const char* pString, size_t st int mriBuffer_MatchesHexString(Buffer* pBuffer, const char* pString, size_t stringLength); /* Macroes which allow code to drop the mri namespace prefix. */ -#define Buffer_Init mriBuffer_Init -#define Buffer_Reset mriBuffer_Reset -#define Buffer_SetEndOfBuffer mriBuffer_SetEndOfBuffer -#define Buffer_BytesLeft mriBuffer_BytesLeft -#define Buffer_OverrunDetected mriBuffer_OverrunDetected -#define Buffer_GetLength mriBuffer_GetLength -#define Buffer_GetArray mriBuffer_GetArray -#define Buffer_WriteChar mriBuffer_WriteChar -#define Buffer_ReadChar mriBuffer_ReadChar -#define Buffer_WriteByteAsHex mriBuffer_WriteByteAsHex -#define Buffer_ReadByteAsHex mriBuffer_ReadByteAsHex -#define Buffer_WriteString mriBuffer_WriteString -#define Buffer_WriteSizedString mriBuffer_WriteSizedString -#define Buffer_WriteStringAsHex mriBuffer_WriteStringAsHex -#define Buffer_ReadUIntegerAsHex mriBuffer_ReadUIntegerAsHex -#define Buffer_WriteUIntegerAsHex mriBuffer_WriteUIntegerAsHex -#define Buffer_ReadIntegerAsHex mriBuffer_ReadIntegerAsHex -#define Buffer_WriteIntegerAsHex mriBuffer_WriteIntegerAsHex -#define Buffer_IsNextCharEqualTo mriBuffer_IsNextCharEqualTo -#define Buffer_MatchesString mriBuffer_MatchesString -#define Buffer_MatchesHexString mriBuffer_MatchesHexString +#define Buffer_Init mriBuffer_Init +#define Buffer_Reset mriBuffer_Reset +#define Buffer_SetEndOfBuffer mriBuffer_SetEndOfBuffer +#define Buffer_Advance mriBuffer_Advance +#define Buffer_BytesLeft mriBuffer_BytesLeft +#define Buffer_OverrunDetected mriBuffer_OverrunDetected +#define Buffer_GetLength mriBuffer_GetLength +#define Buffer_GetArray mriBuffer_GetArray +#define Buffer_WriteChar mriBuffer_WriteChar +#define Buffer_ReadChar mriBuffer_ReadChar +#define Buffer_WriteByteAsHex mriBuffer_WriteByteAsHex +#define Buffer_ReadByteAsHex mriBuffer_ReadByteAsHex +#define Buffer_WriteString mriBuffer_WriteString +#define Buffer_WriteSizedString mriBuffer_WriteSizedString +#define Buffer_WriteStringAsHex mriBuffer_WriteStringAsHex +#define Buffer_WriteSizedStringAsHex mriBuffer_WriteSizedStringAsHex +#define Buffer_ReadUIntegerAsHex mriBuffer_ReadUIntegerAsHex +#define Buffer_WriteUIntegerAsHex mriBuffer_WriteUIntegerAsHex +#define Buffer_ReadIntegerAsHex mriBuffer_ReadIntegerAsHex +#define Buffer_WriteIntegerAsHex mriBuffer_WriteIntegerAsHex +#define Buffer_IsNextCharEqualTo mriBuffer_IsNextCharEqualTo +#define Buffer_MatchesString mriBuffer_MatchesString +#define Buffer_MatchesHexString mriBuffer_MatchesHexString #endif /* BUFFER_H_ */ diff --git a/libraries/MRI/src/core/cmd_file.c b/libraries/MRI/src/core/cmd_file.c index bc18471d2..0fefebda9 100644 --- a/libraries/MRI/src/core/cmd_file.c +++ b/libraries/MRI/src/core/cmd_file.c @@ -13,8 +13,8 @@ limitations under the License. */ /* Handling and issuing routines for gdb file commands. */ -#include #include +#include #include #include #include diff --git a/libraries/MRI/src/core/cmd_memory.c b/libraries/MRI/src/core/cmd_memory.c index c56fe2ea4..82cd0ea02 100644 --- a/libraries/MRI/src/core/cmd_memory.c +++ b/libraries/MRI/src/core/cmd_memory.c @@ -1,4 +1,4 @@ -/* Copyright 2017 Adam Green (https://github.com/adamgreen/) +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ limitations under the License. */ /* Handlers for memory related gdb commands. */ +#include #include #include #include @@ -47,7 +48,7 @@ uint32_t HandleMemoryReadCommand(void) return 0; } - InitBuffer(); + InitPacketBuffers(); result = ReadMemoryIntoHexBuffer(pBuffer, ADDR32_TO_POINTER(addressLength.address), addressLength.length); if (result == 0) PrepareStringResponse(MRI_ERROR_MEMORY_ACCESS_FAILURE); @@ -111,6 +112,8 @@ uint32_t HandleBinaryMemoryWriteCommand(void) { Buffer* pBuffer = GetBuffer(); AddressLength addressLength; + uint32_t* pv; + uint32_t length; __try { @@ -122,14 +125,18 @@ uint32_t HandleBinaryMemoryWriteCommand(void) return 0; } - if (WriteBinaryBufferToMemory(pBuffer, ADDR32_TO_POINTER(addressLength.address), addressLength.length)) + pv = ADDR32_TO_POINTER(addressLength.address); + length = addressLength.length; + + if (WriteBinaryBufferToMemory(pBuffer, pv, length)) { + Platform_SyncICacheToDCache(pv, length); PrepareStringResponse("OK"); } else { if (Buffer_OverrunDetected(pBuffer)) - PrepareStringResponse( MRI_ERROR_BUFFER_OVERRUN); + PrepareStringResponse(MRI_ERROR_BUFFER_OVERRUN); else PrepareStringResponse(MRI_ERROR_MEMORY_ACCESS_FAILURE); } diff --git a/libraries/MRI/src/core/cmd_query.c b/libraries/MRI/src/core/cmd_query.c index f9951d42b..f786f7d3c 100644 --- a/libraries/MRI/src/core/cmd_query.c +++ b/libraries/MRI/src/core/cmd_query.c @@ -1,4 +1,4 @@ -/* Copyright 2020 Adam Green (https://github.com/adamgreen/) +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -13,7 +13,7 @@ limitations under the License. */ /* Handler for gdb query commands. */ -#include +#include #include #include #include @@ -102,8 +102,9 @@ uint32_t HandleQueryCommand(void) */ static uint32_t handleQuerySupportedCommand(void) { - static const char querySupportResponse[] = "qXfer:memory-map:read+;qXfer:features:read+;PacketSize="; - uint32_t PacketSize = Platform_GetPacketBufferSize(); + static const char querySupportResponse[] = "qXfer:memory-map:read+;qXfer:features:read+;vContSupported+;PacketSize="; + /* Subtract 4 for packet overhead ('$', '#', and 2-byte checksum) as GDB doesn't count those bytes. */ + uint32_t PacketSize = Platform_GetPacketBufferSize()-4; Buffer* pBuffer = GetInitializedBuffer(); Buffer_WriteString(pBuffer, querySupportResponse); @@ -176,7 +177,7 @@ static void readQueryTransferReadArguments(Buffer* pBuffer, AnnexOffsetLength* p { static const char readCommand[] = "read"; - memset(pAnnexOffsetLength, 0, sizeof(*pAnnexOffsetLength)); + mri_memset(pAnnexOffsetLength, 0, sizeof(*pAnnexOffsetLength)); if (!Buffer_IsNextCharEqualTo(pBuffer, ':') || !Buffer_MatchesString(pBuffer, readCommand, sizeof(readCommand)-1) || !Buffer_IsNextCharEqualTo(pBuffer, ':') ) @@ -249,7 +250,7 @@ static void handleQueryTransferReadCommand(AnnexOffsetLength* pArguments) validMemoryMapBytes = pArguments->annexSize - offset; } - InitBuffer(); + InitPacketBuffers(); outputBufferSize = Buffer_BytesLeft(pBuffer); if (length > outputBufferSize) @@ -294,7 +295,7 @@ static uint32_t handleQueryTransferFeaturesCommand(void) static void validateAnnexIs(const char* pAnnex, const char* pExpected) { - if (pAnnex == NULL || 0 != strcmp(pAnnex, pExpected)) + if (pAnnex == NULL || 0 != mri_strcmp(pAnnex, pExpected)) __throw(invalidArgumentException); } diff --git a/libraries/MRI/src/core/cmd_registers.c b/libraries/MRI/src/core/cmd_registers.c index 877f0a565..40ba3c96b 100644 --- a/libraries/MRI/src/core/cmd_registers.c +++ b/libraries/MRI/src/core/cmd_registers.c @@ -13,7 +13,7 @@ limitations under the License. */ /* Command handler for gdb commands related to CPU registers. */ -#include +#include #include #include #include diff --git a/libraries/MRI/src/core/cmd_step.c b/libraries/MRI/src/core/cmd_step.c index 2e603d9ee..3fca2f426 100644 --- a/libraries/MRI/src/core/cmd_step.c +++ b/libraries/MRI/src/core/cmd_step.c @@ -1,4 +1,4 @@ -/* Copyright 2017 Adam Green (https://github.com/adamgreen/) +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -41,9 +41,18 @@ uint32_t HandleSingleStepCommand(void) if (returnValue) { + uint32_t pcBefore = Platform_GetProgramCounter(); + Platform_EnableSingleStep(); + if (Platform_GetProgramCounter() != pcBefore) + { + /* Platform code ended up advancing the program counter instead of enabling single step so just return + stop response to GDB. */ + return Send_T_StopResponse(); + } if (Platform_RtosIsSetThreadStateSupported()) + { Platform_RtosSetThreadState(Platform_RtosGetHaltedThreadId(), MRI_PLATFORM_THREAD_SINGLE_STEPPING); - Platform_EnableSingleStep(); + } } return returnValue; diff --git a/libraries/MRI/src/core/cmd_thread.c b/libraries/MRI/src/core/cmd_thread.c index e0d64b47d..18802c9ff 100644 --- a/libraries/MRI/src/core/cmd_thread.c +++ b/libraries/MRI/src/core/cmd_thread.c @@ -28,7 +28,7 @@ Where xxxxxxxx is the hexadecimal representation of the ID for the thread to use for future register read/write commands. */ -uint32_t mriCmd_HandleThreadContextCommand(void) +uint32_t HandleThreadContextCommand(void) { Buffer* pBuffer = GetBuffer(); diff --git a/libraries/MRI/src/core/cmd_vcont.c b/libraries/MRI/src/core/cmd_vcont.c index d4f693224..047663fb0 100644 --- a/libraries/MRI/src/core/cmd_vcont.c +++ b/libraries/MRI/src/core/cmd_vcont.c @@ -1,4 +1,4 @@ -/* Copyright 2020 Adam Green (https://github.com/adamgreen/) +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ limitations under the License. */ /* Handler for gdb's vCont and vCont? commands which support multithreaded single stepping/continuing. */ +#include #include #include #include @@ -23,7 +24,6 @@ #include #include #include -#include typedef enum @@ -128,10 +128,13 @@ static uint32_t handleVContQueryCommand(void) */ static uint32_t handleVContCommand(void) { - Action continueAction = { {0, THREAD_ID_NONE}, {0, 0}, ACTION_NONE }; - Action stepAction = { {0, THREAD_ID_NONE}, {0, 0}, ACTION_NONE }; Buffer* pBuffer = GetBuffer(); Buffer replayBuffer = *pBuffer; + Action continueAction; + Action stepAction; + + mri_memset(&continueAction, 0, sizeof(continueAction)); + mri_memset(&stepAction, 0, sizeof(stepAction)); __try firstParsePass(pBuffer, &continueAction, &stepAction); @@ -239,8 +242,9 @@ static int isActionSpecificToHaltedThreadId(const Action* pAction) static Action parseAction(Buffer* pBuffer) { - Action action = { {0, THREAD_ID_NONE}, {0, 0}, ACTION_NONE }; char ch = Buffer_ReadChar(pBuffer); + Action action; + mri_memset(&action, 0, sizeof(action)); switch (ch) { case 'c': diff --git a/libraries/MRI/src/core/context.c b/libraries/MRI/src/core/context.c index beee65b07..a6ba1570d 100644 --- a/libraries/MRI/src/core/context.c +++ b/libraries/MRI/src/core/context.c @@ -36,7 +36,7 @@ uint32_t Context_Count(MriContext* pThis) return count; } -uint32_t mriContext_Get(const MriContext* pThis, uint32_t index) +uint32_t Context_Get(const MriContext* pThis, uint32_t index) { uint32_t i; uint32_t count = 0; @@ -53,7 +53,7 @@ uint32_t mriContext_Get(const MriContext* pThis, uint32_t index) __throw_and_return(bufferOverrunException, 0); } -void mriContext_Set(MriContext* pThis, uint32_t index, uint32_t newValue) +void Context_Set(MriContext* pThis, uint32_t index, uint32_t newValue) { uint32_t i; uint32_t count = 0; diff --git a/libraries/MRI/src/core/core.h b/libraries/MRI/src/core/core.h index 2c63db3ee..b6267840e 100644 --- a/libraries/MRI/src/core/core.h +++ b/libraries/MRI/src/core/core.h @@ -1,4 +1,4 @@ -/* Copyright 2020 Adam Green (https://github.com/adamgreen/) +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ #include #include #include +#include typedef struct @@ -32,7 +33,7 @@ typedef struct /* Real name of functions are in mri namespace. */ void mriDebugException(MriContext* pContext); -void mriCore_InitBuffer(void); +void mriCore_InitPacketBuffers(void); Buffer* mriCore_GetBuffer(void); Buffer* mriCore_GetInitializedBuffer(void); void mriCore_PrepareStringResponse(const char* pErrorString); @@ -40,11 +41,14 @@ void mriCore_PrepareStringResponse(const char* pErrorString); int mriCore_WasControlCFlagSentFromGdb(void); void mriCore_RecordControlCFlagSentFromGdb(int controlCFlag); +int mriCore_WasControlCEncountered(void); +void mriCore_ControlCEncountered(void); int mriCore_WasSemihostCallCancelledByGdb(void); void mriCore_FlagSemihostCallAsHandled(void); int mriCore_IsFirstException(void); int mriCore_WasSuccessfullyInit(void); void mriCore_RequestResetOnNextContinue(void); +int mriCore_WasResetOnNextContinueRequested(void); void mriCore_SetSingleSteppingRange(const AddressRange* pRange); MriContext* mriCore_GetContext(void); @@ -62,19 +66,24 @@ void mriCore_GdbCommandHandlingLoop(void); typedef int (*TempBreakpointCallbackPtr)(void*); int mriCore_SetTempBreakpoint(uint32_t breakpointAddress, TempBreakpointCallbackPtr pCallback, void* pvContext); +void mriCoreSetDebuggerHooks(MriDebuggerHookPtr pEnteringHook, MriDebuggerHookPtr pLeavingHook, void* pvContext); + /* Macroes which allow code to drop the mri namespace prefix. */ -#define InitBuffer mriCore_InitBuffer +#define InitPacketBuffers mriCore_InitPacketBuffers #define GetBuffer mriCore_GetBuffer #define GetInitializedBuffer mriCore_GetInitializedBuffer #define PrepareStringResponse mriCore_PrepareStringResponse #define WasControlCFlagSentFromGdb mriCore_WasControlCFlagSentFromGdb #define RecordControlCFlagSentFromGdb mriCore_RecordControlCFlagSentFromGdb +#define WasControlCEncountered mriCore_WasControlCEncountered +#define ControlCEncountered mriCore_ControlCEncountered #define WasSemihostCallCancelledByGdb mriCore_WasSemihostCallCancelledByGdb #define FlagSemihostCallAsHandled mriCore_FlagSemihostCallAsHandled #define IsFirstException mriCore_IsFirstException #define WasSuccessfullyInit mriCore_WasSuccessfullyInit #define RequestResetOnNextContinue mriCore_RequestResetOnNextContinue +#define WasResetOnNextContinueRequested mriCore_WasResetOnNextContinueRequested #define SetSingleSteppingRange mriCore_SetSingleSteppingRange #define GetContext mriCore_GetContext #define SetContext mriCore_SetContext @@ -86,6 +95,7 @@ int mriCore_SetTempBreakpoint(uint32_t breakpointAddress, TempBreakpointCall #define SendPacketToGdb mriCore_SendPacketToGdb #define GdbCommandHandlingLoop mriCore_GdbCommandHandlingLoop #define SetTempBreakpoint mriCore_SetTempBreakpoint +#define SetDebuggerHooks mriCoreSetDebuggerHooks /* Macro to convert 32-bit addresses sent from GDB to pointer. */ #if _LP64 diff --git a/libraries/MRI/src/core/fileio.h b/libraries/MRI/src/core/fileio.h index ac97d3099..de13a141f 100644 --- a/libraries/MRI/src/core/fileio.h +++ b/libraries/MRI/src/core/fileio.h @@ -16,22 +16,50 @@ #ifndef FILEIO_H_ #define FILEIO_H_ -#define O_RDONLY 0x0 -#define O_WRONLY 0x1 -#define O_RDWR 0x2 -#define O_APPEND 0x8 -#define O_CREAT 0x200 -#define O_TRUNC 0x400 - -#define S_IRUSR 0400 -#define S_IWUSR 0200 -#define S_IRGRP 040 -#define S_IWGRP 020 -#define S_IROTH 04 -#define S_IWOTH 02 - -#define SEEK_SET 0 -#define SEEK_CUR 1 -#define SEEK_END 2 +#include + +#define GDB_O_RDONLY 0x0 +#define GDB_O_WRONLY 0x1 +#define GDB_O_RDWR 0x2 +#define GDB_O_APPEND 0x8 +#define GDB_O_CREAT 0x200 +#define GDB_O_TRUNC 0x400 +#define GDB_O_EXCL 0x800 + +#define GDB_S_IFREG 0100000 +#define GDB_S_IFDIR 040000 +#define GDB_S_IRUSR 0400 +#define GDB_S_IWUSR 0200 +#define GDB_S_IXUSR 0100 +#define GDB_S_IRGRP 040 +#define GDB_S_IWGRP 020 +#define GDB_S_IXGRP 010 +#define GDB_S_IROTH 04 +#define GDB_S_IWOTH 02 +#define GDB_S_IXOTH 01 + +#define GDB_SEEK_SET 0 +#define GDB_SEEK_CUR 1 +#define GDB_SEEK_END 2 + +typedef struct +{ + uint32_t device; + uint32_t inode; + uint32_t mode; + uint32_t numberOfLinks; + uint32_t userId; + uint32_t groupId; + uint32_t deviceType; + uint32_t totalSizeUpperWord; + uint32_t totalSizeLowerWord; + uint32_t blockSizeUpperWord; + uint32_t blockSizeLowerWord; + uint32_t blockCountUpperWord; + uint32_t blockCountLowerWord; + uint32_t lastAccessTime; + uint32_t lastModifiedTime; + uint32_t lastChangeTime; +} GdbStats; #endif /* FILEIO_H_ */ diff --git a/libraries/MRI/src/core/gdb_console.c b/libraries/MRI/src/core/gdb_console.c index 9bb594352..fc0e78d92 100644 --- a/libraries/MRI/src/core/gdb_console.c +++ b/libraries/MRI/src/core/gdb_console.c @@ -1,4 +1,4 @@ -/* Copyright 2014 Adam Green (https://github.com/adamgreen/) +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,6 +14,7 @@ */ /* Routines to output text to stdout on the gdb console. */ #include +#include #include #include #include @@ -21,10 +22,9 @@ #include -static void writeStringToExclusiveGdbCommChannel(const char* pString); -void WriteStringToGdbConsole(const char* pString) +size_t WriteStringToGdbConsole(const char* pString) { - writeStringToExclusiveGdbCommChannel(pString); + return WriteSizedStringToGdbConsole(pString, mri_strlen(pString)); } /* Send the 'O' command to gdb to output text to its console. @@ -32,14 +32,16 @@ void WriteStringToGdbConsole(const char* pString) Command Format: OXX... Where XX is the hexadecimal representation of each character in the string to be sent to the gdb console. */ -static void writeStringToExclusiveGdbCommChannel(const char* pString) +size_t WriteSizedStringToGdbConsole(const char* pString, size_t length) { Buffer* pBuffer = GetInitializedBuffer(); + size_t charsWritten = 0; Buffer_WriteChar(pBuffer, 'O'); - Buffer_WriteStringAsHex(pBuffer, pString); - if (!Buffer_OverrunDetected(pBuffer)) - SendPacketToGdb(); + charsWritten = Buffer_WriteSizedStringAsHex(pBuffer, pString, length); + SendPacketToGdb(); + + return charsWritten; } @@ -51,7 +53,7 @@ void WriteHexValueToGdbConsole(uint32_t Value) Buffer_Init(&BufferObject, StringBuffer, sizeof(StringBuffer)); Buffer_WriteString(&BufferObject, "0x"); Buffer_WriteUIntegerAsHex(&BufferObject, Value); - Buffer_WriteChar(&BufferObject, '\0'); + Buffer_SetEndOfBuffer(&BufferObject); - WriteStringToGdbConsole(StringBuffer); + WriteSizedStringToGdbConsole(Buffer_GetArray(&BufferObject), Buffer_GetLength(&BufferObject)); } diff --git a/libraries/MRI/src/core/gdb_console.h b/libraries/MRI/src/core/gdb_console.h index 3c0de6ab1..5d64b90c0 100644 --- a/libraries/MRI/src/core/gdb_console.h +++ b/libraries/MRI/src/core/gdb_console.h @@ -1,4 +1,4 @@ -/* Copyright 2014 Adam Green (https://github.com/adamgreen/) +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,11 +19,13 @@ #include /* Real name of functions are in mri namespace. */ -void mriGdbConsole_WriteString(const char* pString); +size_t mriGdbConsole_WriteString(const char* pString); +size_t mriGdbConsole_WriteSizedString(const char* pString, size_t length); void mriGdbConsole_WriteHexValue(uint32_t value); /* Macroes which allow code to drop the mri namespace prefix. */ -#define WriteStringToGdbConsole mriGdbConsole_WriteString -#define WriteHexValueToGdbConsole mriGdbConsole_WriteHexValue +#define WriteStringToGdbConsole mriGdbConsole_WriteString +#define WriteSizedStringToGdbConsole mriGdbConsole_WriteSizedString +#define WriteHexValueToGdbConsole mriGdbConsole_WriteHexValue #endif /* GDB_CONSOLE_H_ */ diff --git a/libraries/MRI/src/core/libc.c b/libraries/MRI/src/core/libc.c new file mode 100644 index 000000000..ff79e8a9a --- /dev/null +++ b/libraries/MRI/src/core/libc.c @@ -0,0 +1,141 @@ +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +/* Implementation of Standard C Library functions that MRI makes use of. + + Having its own implementation of these means that users won't hit difficulties if they try to single step + through the real Standard C Library. + + NOTE: The debuggee shouldn't call these versions as that would defeat their purpose. +*/ +#include +#include + +void* mri_memcpy(void* pvDest, const void* pvSrc, size_t len) +{ + uint8_t* pDest = (uint8_t*)pvDest; + const uint8_t* pSrc = (const uint8_t*)pvSrc; + + while (len--) + { + *pDest++ = *pSrc++; + } + return pvDest; +} + + + +void* mri_memset(void *pvDest, int val, size_t len) +{ + uint8_t* pDest = (uint8_t*)pvDest; + while (len--) + { + *pDest++ = (uint8_t)val; + } + return pvDest; +} + + + +int mri_strcmp(const char* pc1, const char* pc2) +{ + uint8_t* p1 = (uint8_t*)pc1; + uint8_t* p2 = (uint8_t*)pc2; + int cmp = 0; + + do + { + cmp = *p1 - *p2++; + } while (cmp == 0 && *p1++); + return cmp; +} + + + + +int mri_strncmp(const char* pc1, const char* pc2, size_t len) +{ + uint8_t* p1 = (uint8_t*)pc1; + uint8_t* p2 = (uint8_t*)pc2; + int cmp = 0; + + if (len == 0) + { + return 0; + } + + do + { + cmp = *p1 - *p2++; + } while (cmp == 0 && --len > 0 && *p1++); + return cmp; +} + + + +size_t mri_strlen(const char* p) +{ + const char* pStart = p; + while (*p) + { + p++; + } + return p - pStart; +} + + + +char* mri_strstr(const char* pHaystack, const char* pNeedle) +{ + size_t len = mri_strlen(pNeedle); + + while (*pHaystack) + { + if (mri_strncmp(pHaystack, pNeedle, len) == 0) + { + return (char*)pHaystack; + } + pHaystack++; + } + return NULL; +} + + + +void* mri_memmove(void* pvDest, const void* pvSrc, size_t len) +{ + uint8_t* pDest = (uint8_t*)pvDest; + uint8_t* pDestEnd = pDest + len; + uint8_t* pSrc = (uint8_t*)pvSrc; + uint8_t* pSrcEnd = pSrc + len; + int dir = 1; + uint8_t* pDestCurr = pDest; + uint8_t* pSrcCurr = pSrc; + + if (pDest > pSrc && pDest < pSrcEnd) + { + dir = -1; + pDestCurr = pDestEnd - 1; + pSrcCurr = pSrcEnd - 1; + } + + while (len--) + { + *pDestCurr = *pSrcCurr; + pDestCurr += dir; + pSrcCurr += dir; + } + + return pvDest; +} diff --git a/libraries/MRI/src/core/libc.h b/libraries/MRI/src/core/libc.h new file mode 100644 index 000000000..42497b6d4 --- /dev/null +++ b/libraries/MRI/src/core/libc.h @@ -0,0 +1,35 @@ +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +/* Implementation of Standard C Library functions that MRI makes use of. + + Having its own implementation of these means that users won't hit difficulties if they try to single step + through the real Standard C Library. + + NOTE: The debuggee shouldn't call these versions as that would defeat their purpose. +*/ +#ifndef LIBC_H_ +#define LIBC_H_ + +#include + +void* mri_memcpy(void* pDest, const void* pSrc, size_t len); +void* mri_memset(void* pDest, int val, size_t len); +int mri_strcmp(const char* p1, const char* p2); +int mri_strncmp(const char* p1, const char* p2, size_t len); +size_t mri_strlen(const char* p); +char* mri_strstr(const char* pHaystack, const char* pNeedle); +void* mri_memmove(void* pvDest, const void* pvSrc, size_t len); + +#endif /* LIBC_H_ */ diff --git a/libraries/MRI/src/core/memory.c b/libraries/MRI/src/core/memory.c index 8e12aa5f8..c0e606476 100644 --- a/libraries/MRI/src/core/memory.c +++ b/libraries/MRI/src/core/memory.c @@ -191,10 +191,6 @@ static int writeHexBufferToWordMemory(Buffer* pBuffer, void* pvMemory) static int writeBinaryBufferToByteMemory(Buffer* pBuffer, void* pvMemory, uint32_t writeByteCount); -static char unescapeCharIfNecessary(Buffer* pBuffer, char currentChar); -static int isEscapePrefixChar(char charToCheck); -static char readNextCharAndUnescape(Buffer* pBuffer); -static char unescapeByte(char charToUnescape); static int writeBinaryBufferToHalfWordMemory(Buffer* pBuffer, void* pvMemory); static int readBytesFromBinaryBuffer(Buffer* pBuffer, void* pvMemory, uint32_t writeByteCount); static int writeBinaryBufferToWordMemory(Buffer* pBuffer, void* pvMemory); @@ -220,14 +216,9 @@ static int writeBinaryBufferToByteMemory(Buffer* pBuffer, void* pvMemory, uint3 char currChar; __try - { - __throwing_func( currChar = Buffer_ReadChar(pBuffer) ); - __throwing_func( currChar = unescapeCharIfNecessary(pBuffer, currChar) ); - } + currChar = Buffer_ReadChar(pBuffer); __catch - { __rethrow_and_return(0); - } Platform_MemWrite8(p++, (uint8_t)currChar); if (Platform_WasMemoryFaultEncountered()) @@ -237,36 +228,6 @@ static int writeBinaryBufferToByteMemory(Buffer* pBuffer, void* pvMemory, uint3 return 1; } -static char unescapeCharIfNecessary(Buffer* pBuffer, char currentChar) -{ - if (isEscapePrefixChar(currentChar)) - return readNextCharAndUnescape(pBuffer); - - return currentChar; -} - -static int isEscapePrefixChar(char charToCheck) -{ - return charToCheck == '}'; -} - -static char readNextCharAndUnescape(Buffer* pBuffer) -{ - char nextChar; - - __try - nextChar = Buffer_ReadChar(pBuffer); - __catch - __rethrow_and_return('\0'); - - return unescapeByte(nextChar); -} - -static char unescapeByte(char charToUnescape) -{ - return charToUnescape ^ 0x20; -} - static int writeBinaryBufferToHalfWordMemory(Buffer* pBuffer, void* pvMemory) { uint16_t value; @@ -290,17 +251,10 @@ static int readBytesFromBinaryBuffer(Buffer* pBuffer, void* pvMemory, uint32_t while (writeByteCount-- > 0) { - char currChar; __try - { - __throwing_func( currChar = Buffer_ReadChar(pBuffer) ); - __throwing_func( currChar = unescapeCharIfNecessary(pBuffer, currChar) ); - } + *p++ = Buffer_ReadChar(pBuffer); __catch - { __rethrow_and_return(0); - } - *p++ = (uint8_t)currChar; } return 1; diff --git a/libraries/MRI/src/core/mri.c b/libraries/MRI/src/core/mri.c index a09862d8d..17edd7839 100644 --- a/libraries/MRI/src/core/mri.c +++ b/libraries/MRI/src/core/mri.c @@ -1,4 +1,4 @@ -/* Copyright 2020 Adam Green (https://github.com/adamgreen/) +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,9 +14,8 @@ */ /* Monitor for Remote Inspection - Provides core mri routines to initialize the debug monitor, query its state, and invoke it into action when a debug event occurs on the target hardware. */ -#include -#include #include +#include #include #include #include @@ -25,7 +24,7 @@ #include #include #include -#include +#include #include #include #include @@ -49,7 +48,6 @@ typedef struct void* pvEnteringLeavingContext; MriContext* pContext; Packet packet; - Buffer buffer; uint32_t tempBreakpointAddress; uint32_t flags; AddressRange rangeForSingleStepping; @@ -67,6 +65,7 @@ static MriCore g_mri; #define MRI_FLAGS_TEMP_BREAKPOINT (1 << 3) #define MRI_FLAGS_RESET_ON_CONTINUE (1 << 4) #define MRI_FLAGS_RANGED_SINGLE_STEP (1 << 5) +#define MRI_FLAGS_ENCOUNTERED_CTRL_C (1 << 6) /* Calculates the number of items in a static array at compile time. */ #define ARRAY_SIZE(X) (sizeof(X)/sizeof(X[0])) @@ -90,7 +89,7 @@ void mriInit(const char* pDebuggerParameters) static void clearCoreStructure(void) { - memset(&g_mri, 0, sizeof(g_mri)); + mri_memset(&g_mri, 0, sizeof(g_mri)); } static void initializePlatformSpecificModulesWithDebuggerParameters(const char* pDebuggerParameters) @@ -157,7 +156,7 @@ static void setTempBreakpointFlag(void) } -void mriSetDebuggerHooks(MriDebuggerHookPtr pEnteringHook, MriDebuggerHookPtr pLeavingHook, void* pvContext) +void mriCoreSetDebuggerHooks(MriDebuggerHookPtr pEnteringHook, MriDebuggerHookPtr pLeavingHook, void* pvContext) { g_mri.pEnteringHook = pEnteringHook; g_mri.pLeavingHook = pLeavingHook; @@ -165,6 +164,7 @@ void mriSetDebuggerHooks(MriDebuggerHookPtr pEnteringHook, MriDebuggerHookPtr pL } +static void clearControlCEncounteredFlag(void); static int wasTempBreakpointHit(void); static void clearTempBreakpoint(void); static void clearTempBreakpointFlag(void); @@ -174,13 +174,13 @@ static void determineSignalValue(void); static int isDebugTrap(void); static void prepareForDebuggerExit(void); static void clearFirstExceptionFlag(void); -static int hasResetBeenRequested(void); static void waitForAckToBeTransmitted(void); void mriDebugException(MriContext* pContext) { int justSingleStepped; SetContext(pContext); + clearControlCEncounteredFlag(); justSingleStepped = Platform_IsSingleStepping(); if (wasTempBreakpointHit()) @@ -238,6 +238,11 @@ void mriDebugException(MriContext* pContext) prepareForDebuggerExit(); } +static void clearControlCEncounteredFlag(void) +{ + g_mri.flags &= ~MRI_FLAGS_ENCOUNTERED_CTRL_C; +} + static int wasTempBreakpointHit(void) { return (isTempBreakpointSet() && @@ -263,16 +268,26 @@ static void clearTempBreakpointFlag(void) static int areSingleSteppingInRange(void) { - // Ignore ranged single stepping if CTRL+C was pressed or... - if (g_mri.signalValue == SIGINT) - return 0; - // if a debug breakpoint/watchpoint was hit. - if (g_mri.signalValue == SIGTRAP) + switch (g_mri.signalValue) { - PlatformTrapReason reason = Platform_GetTrapReason(); - if (reason.type != MRI_PLATFORM_TRAP_TYPE_UNKNOWN) + case SIGINT: + case SIGSEGV: + case SIGBUS: + case SIGILL: + /* Ignore ranged single stepping if CTRL+C was pressed, or a fault was encountered, or... */ return 0; + case SIGTRAP: + { + /* if a debug breakpoint/watchpoint was hit. */ + PlatformTrapReason reason = Platform_GetTrapReason(); + if (reason.type != MRI_PLATFORM_TRAP_TYPE_UNKNOWN) + return 0; + break; + } + default: + break; } + return g_mri.flags & MRI_FLAGS_RANGED_SINGLE_STEP; } @@ -293,7 +308,7 @@ static int isDebugTrap(void) static void prepareForDebuggerExit(void) { - if (hasResetBeenRequested()) { + if (WasResetOnNextContinueRequested() && !Platform_IsSingleStepping()) { waitForAckToBeTransmitted(); Platform_ResetDevice(); } @@ -303,16 +318,11 @@ static void prepareForDebuggerExit(void) clearFirstExceptionFlag(); } -static int hasResetBeenRequested(void) -{ - return (int)(g_mri.flags & MRI_FLAGS_RESET_ON_CONTINUE); -} - static void waitForAckToBeTransmitted(void) { while ( !Platform_CommHasTransmitCompleted() ) { - // Waiting for ACK to be sent back to GDB for last command received. + /* Waiting for ACK to be sent back to GDB for last command received. */ } } @@ -337,7 +347,7 @@ void GdbCommandHandlingLoop(void) } while (!startDebuggeeUpAgain); } -__attribute__((weak)) uint32_t mriPlatform_HandleGDBComand(Buffer* pBuffer); +__attribute__((weak)) uint32_t Platform_HandleGDBCommand(Buffer* pBuffer); static int handleGDBCommand(void) { Buffer* pBuffer = GetBuffer(); @@ -372,8 +382,8 @@ static int handleGDBCommand(void) getPacketFromGDB(); - if (mriPlatform_HandleGDBComand) - handlerResult = mriPlatform_HandleGDBComand(pBuffer); + if (Platform_HandleGDBCommand) + handlerResult = Platform_HandleGDBCommand(pBuffer); if (handlerResult == 0) { Buffer_Reset(pBuffer); @@ -397,21 +407,21 @@ static int handleGDBCommand(void) static void getPacketFromGDB(void) { - InitBuffer(); - Packet_GetFromGDB(&g_mri.packet, &g_mri.buffer); + InitPacketBuffers(); + Packet_GetFromGDB(&g_mri.packet); } -void InitBuffer(void) +void InitPacketBuffers(void) { - Buffer_Init(&g_mri.buffer, Platform_GetPacketBuffer(), Platform_GetPacketBufferSize()); + Packet_Init(&g_mri.packet, Platform_GetPacketBuffer(), Platform_GetPacketBufferSize()); } void PrepareStringResponse(const char* pErrorString) { - InitBuffer(); - Buffer_WriteString(&g_mri.buffer, pErrorString); + InitPacketBuffers(); + Buffer_WriteString(GetBuffer(), pErrorString); } @@ -431,6 +441,21 @@ void RequestResetOnNextContinue(void) g_mri.flags |= MRI_FLAGS_RESET_ON_CONTINUE; } +int WasControlCEncountered(void) +{ + return (int)(g_mri.flags & MRI_FLAGS_ENCOUNTERED_CTRL_C); +} + +void ControlCEncountered(void) +{ + g_mri.flags |= MRI_FLAGS_ENCOUNTERED_CTRL_C; +} + +int WasResetOnNextContinueRequested(void) +{ + return (int)(g_mri.flags & MRI_FLAGS_RESET_ON_CONTINUE); +} + void SetSingleSteppingRange(const AddressRange* pRange) { g_mri.rangeForSingleStepping = *pRange; @@ -510,25 +535,25 @@ int GetSemihostErrno(void) Buffer* GetBuffer(void) { - return &g_mri.buffer; + return &g_mri.packet.dataBuffer; } Buffer* GetInitializedBuffer(void) { - InitBuffer(); - return &g_mri.buffer; + InitPacketBuffers(); + return GetBuffer(); } void SendPacketToGdb(void) { - if (Buffer_OverrunDetected(&g_mri.buffer)) + if (Buffer_OverrunDetected(GetBuffer())) { - InitBuffer(); - Buffer_WriteString(&g_mri.buffer, MRI_ERROR_BUFFER_OVERRUN); + InitPacketBuffers(); + Buffer_WriteString(GetBuffer(), MRI_ERROR_BUFFER_OVERRUN); } - Buffer_SetEndOfBuffer(&g_mri.buffer); - Packet_SendToGDB(&g_mri.packet, &g_mri.buffer); + Buffer_SetEndOfBuffer(GetBuffer()); + Packet_SendToGDB(&g_mri.packet); } diff --git a/libraries/MRI/src/core/mri.h b/libraries/MRI/src/core/mri.h index f7d3ea5f8..d360f242b 100644 --- a/libraries/MRI/src/core/mri.h +++ b/libraries/MRI/src/core/mri.h @@ -1,4 +1,4 @@ -/* Copyright 2020 Adam Green (https://github.com/adamgreen/) +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -123,6 +123,7 @@ int mriNewlib_SemihostRead(int file, char *ptr, int len); int mriNewlib_SemihostLSeek(int file, int offset, int whence); int mriNewlib_SemihostClose(int file); int mriNewlib_SemihostFStat(int file, void *pStat); +int mriNewlib_SemihostGetErrNo(void); diff --git a/libraries/MRI/src/core/packet.c b/libraries/MRI/src/core/packet.c index c033e3a30..1f9422be8 100644 --- a/libraries/MRI/src/core/packet.c +++ b/libraries/MRI/src/core/packet.c @@ -1,4 +1,4 @@ -/* Copyright 2014 Adam Green (https://github.com/adamgreen/) +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -13,14 +13,21 @@ limitations under the License. */ /* 'Class' to manage the sending and receiving of packets to/from gdb. Takes care of crc and ack/nak handling too. */ -#include #include +#include #include #include #include -static void initPacketStructure(Packet* pPacket, Buffer* pBuffer); +void Packet_Init(Packet* pPacket, char* pBufferStart, size_t bufferSize) +{ + Buffer_Init(&pPacket->dataBuffer, pBufferStart+1, bufferSize-4); + Buffer_Init(&pPacket->packetBuffer, pBufferStart, bufferSize); +} + + +static void initPacketStructure(Packet* pPacket); static void getMostRecentPacket(Packet* pPacket); static void getPacketDataAndExpectedChecksum(Packet* pPacket); static void waitForStartOfNextPacket(Packet* pPacket); @@ -28,14 +35,16 @@ static char getNextCharFromGdb(Packet* pPacket); static int getPacketData(Packet* pPacket); static void clearChecksum(Packet* pPacket); static void updateChecksum(Packet* pPacket, char nextChar); +static int isEscapePrefixChar(char charToCheck); +static char unescapeChar(char charToUnescape); static void extractExpectedChecksum(Packet* pPacket); static int isChecksumValid(Packet* pPacket); static void sendACKToGDB(void); static void sendNAKToGDB(void); static void resetBufferToEnableFutureReadingOfValidPacketData(Packet* pPacket); -void Packet_GetFromGDB(Packet* pPacket, Buffer* pBuffer) +void Packet_GetFromGDB(Packet* pPacket) { - initPacketStructure(pPacket, pBuffer); + initPacketStructure(pPacket); do { getMostRecentPacket(pPacket); @@ -44,10 +53,12 @@ void Packet_GetFromGDB(Packet* pPacket, Buffer* pBuffer) resetBufferToEnableFutureReadingOfValidPacketData(pPacket); } -static void initPacketStructure(Packet* pPacket, Buffer* pBuffer) +static void initPacketStructure(Packet* pPacket) { - memset(pPacket, 0, sizeof(*pPacket)); - pPacket->pBuffer = pBuffer; + pPacket->lastChar = '\0'; + pPacket->calculatedChecksum = 0; + pPacket->expectedChecksum = 0; + Buffer_Reset(&pPacket->packetBuffer); } static void getMostRecentPacket(Packet* pPacket) @@ -99,13 +110,21 @@ static int getPacketData(Packet* pPacket) { char nextChar; - Buffer_Reset(pPacket->pBuffer); + Buffer_Reset(&pPacket->dataBuffer); clearChecksum(pPacket); nextChar = getNextCharFromGdb(pPacket); - while (Buffer_BytesLeft(pPacket->pBuffer) > 0 && nextChar != '$' && nextChar != '#') + while (Buffer_BytesLeft(&pPacket->dataBuffer) > 0 && nextChar != '$' && nextChar != '#') { updateChecksum(pPacket, nextChar); - Buffer_WriteChar(pPacket->pBuffer, nextChar); + if (isEscapePrefixChar(nextChar)) + { + nextChar = getNextCharFromGdb(pPacket); + if (nextChar == '$' || nextChar == '#') + break; + updateChecksum(pPacket, nextChar); + nextChar = unescapeChar(nextChar); + } + Buffer_WriteChar(&pPacket->dataBuffer, nextChar); nextChar = getNextCharFromGdb(pPacket); } @@ -123,6 +142,16 @@ static void updateChecksum(Packet* pPacket, char nextChar) pPacket->calculatedChecksum += (unsigned char)nextChar; } +static int isEscapePrefixChar(char charToCheck) +{ + return charToCheck == '}'; +} + +static char unescapeChar(char charToUnescape) +{ + return charToUnescape ^ 0x20; +} + static void extractExpectedChecksum(Packet* pPacket) { __try @@ -160,24 +189,25 @@ static void sendNAKToGDB(void) static void resetBufferToEnableFutureReadingOfValidPacketData(Packet* pPacket) { - Buffer_SetEndOfBuffer(pPacket->pBuffer); - Buffer_Reset(pPacket->pBuffer); + Buffer_SetEndOfBuffer(&pPacket->dataBuffer); + Buffer_Reset(&pPacket->dataBuffer); } +static void completePacket(Packet* pPacket); +static void storePacketHeaderByte(Packet* pPacket); +static void processPacketData(Packet* pPacket); +static void storePacketChecksum(Packet* pPacket); static void sendPacket(Packet* pPacket); -static void sendPacketHeaderByte(void); -static void sendPacketData(Packet* pPacket); -static void sendPacketChecksum(Packet* pPacket); -static void sendByteAsHex(unsigned char byte); static int receiveCharAfterSkippingControlC(Packet* pPacket); -void Packet_SendToGDB(Packet* pPacket, Buffer* pBuffer) +void Packet_SendToGDB(Packet* pPacket) { char charFromGdb; /* Keeps looping until GDB sends back the '+' packet acknowledge character. If GDB sends a '$' then it is trying to send a packet so cancel this send attempt. */ - initPacketStructure(pPacket, pBuffer); + initPacketStructure(pPacket); + completePacket(pPacket); do { sendPacket(pPacket); @@ -185,42 +215,46 @@ void Packet_SendToGDB(Packet* pPacket, Buffer* pBuffer) } while (charFromGdb != '+' && charFromGdb != '$'); } -static void sendPacket(Packet* pPacket) +static void completePacket(Packet* pPacket) { - /* Send packet of format: "$#<1ByteChecksumInHex>" */ - Buffer_Reset(pPacket->pBuffer); + /* Complete packet by adding '$' header and '#' checksum terminator -> "$#<2HexDigitsOfChecksum>" */ + Buffer_Reset(&pPacket->dataBuffer); clearChecksum(pPacket); - sendPacketHeaderByte(); - sendPacketData(pPacket); - sendPacketChecksum(pPacket); + storePacketHeaderByte(pPacket); + processPacketData(pPacket); + storePacketChecksum(pPacket); + + Buffer_SetEndOfBuffer(&pPacket->packetBuffer); } -static void sendPacketHeaderByte(void) +static void storePacketHeaderByte(Packet* pPacket) { - Platform_CommSendChar('$'); + Buffer_WriteChar(&pPacket->packetBuffer, '$'); } -static void sendPacketData(Packet* pPacket) +static void processPacketData(Packet* pPacket) { - while (Buffer_BytesLeft(pPacket->pBuffer) > 0) + size_t length = 0; + while (Buffer_BytesLeft(&pPacket->dataBuffer) > 0) { - char currChar = Buffer_ReadChar(pPacket->pBuffer); - Platform_CommSendChar(currChar); + char currChar = Buffer_ReadChar(&pPacket->dataBuffer); updateChecksum(pPacket, currChar); + length++; } + Buffer_Advance(&pPacket->packetBuffer, length); } -static void sendPacketChecksum(Packet* pPacket) +static void storePacketChecksum(Packet* pPacket) { - Platform_CommSendChar('#'); - sendByteAsHex(pPacket->calculatedChecksum); + Buffer_WriteChar(&pPacket->packetBuffer, '#'); + Buffer_WriteByteAsHex(&pPacket->packetBuffer, pPacket->calculatedChecksum); } -static void sendByteAsHex(unsigned char byte) +static void sendPacket(Packet* pPacket) { - Platform_CommSendChar(NibbleToHexChar[EXTRACT_HI_NIBBLE(byte)]); - Platform_CommSendChar(NibbleToHexChar[EXTRACT_LO_NIBBLE(byte)]); + Buffer_Reset(&pPacket->packetBuffer); + Platform_CommSendBuffer(&pPacket->packetBuffer); } static int receiveCharAfterSkippingControlC(Packet* pPacket) @@ -228,11 +262,19 @@ static int receiveCharAfterSkippingControlC(Packet* pPacket) static const int controlC = 0x03; int nextChar; - do + nextChar = getNextCharFromGdb(pPacket); + while (nextChar == controlC) { + ControlCEncountered(); nextChar = getNextCharFromGdb(pPacket); } - while (nextChar == controlC); return nextChar; } + + +__attribute__((weak)) void Platform_CommSendBuffer(Buffer* pBuffer) +{ + while (Buffer_BytesLeft(pBuffer)) + Platform_CommSendChar(Buffer_ReadChar(pBuffer)); +} diff --git a/libraries/MRI/src/core/packet.h b/libraries/MRI/src/core/packet.h index 6ff6f3f3d..2ad102df6 100644 --- a/libraries/MRI/src/core/packet.h +++ b/libraries/MRI/src/core/packet.h @@ -1,4 +1,4 @@ -/* Copyright 2014 Adam Green (https://github.com/adamgreen/) +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -21,15 +21,19 @@ typedef struct { - Buffer* pBuffer; + /* This is the complete buffer with room for '$', '#', and 2-byte checksum. */ + Buffer packetBuffer; + /* This is a subset of pPacketBuffer, after room has been made for '$', '#', and 2-byte checksum. */ + Buffer dataBuffer; char lastChar; unsigned char calculatedChecksum; unsigned char expectedChecksum; } Packet; /* Real name of functions are in mri namespace. */ -void mriPacket_GetFromGDB(Packet* pPacket, Buffer* pBuffer); -void mriPacket_SendToGDB(Packet* pPacket, Buffer* pBuffer); +void mriPacket_Init(Packet* pPacket, char* pBufferStart, size_t bufferSize); +void mriPacket_GetFromGDB(Packet* pPacket); +void mriPacket_SendToGDB(Packet* pPacket); /* Macroes which allow code to drop the mri namespace prefix. */ #define Packet_Init mriPacket_Init diff --git a/libraries/MRI/src/core/platforms.h b/libraries/MRI/src/core/platforms.h index 35a9e9e0e..9d7353e11 100644 --- a/libraries/MRI/src/core/platforms.h +++ b/libraries/MRI/src/core/platforms.h @@ -1,4 +1,4 @@ -/* Copyright 2020 Adam Green (https://github.com/adamgreen/) +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -35,13 +35,15 @@ uint8_t mriPlatform_MemRead8(const void* pv); void mriPlatform_MemWrite32(void* pv, uint32_t value); void mriPlatform_MemWrite16(void* pv, uint16_t value); void mriPlatform_MemWrite8(void* pv, uint8_t value); +void mriPlatform_SyncICacheToDCache(void *pv, uint32_t size); uint32_t mriPlatform_CommHasReceiveData(void); uint32_t mriPlatform_CommHasTransmitCompleted(void); int mriPlatform_CommReceiveChar(void); +void mriPlatform_CommSendBuffer(Buffer* pBuffer); void mriPlatform_CommSendChar(int character); -uint32_t mriPlatform_HandleGDBComand(Buffer* pBuffer); +uint32_t mriPlatform_HandleGDBCommand(Buffer* pBuffer); typedef enum { @@ -111,7 +113,7 @@ typedef struct PlatformInstructionType mriPlatform_TypeOfCurrentInstruction(void); PlatformSemihostParameters mriPlatform_GetSemihostCallParameters(void); -void mriPlatform_SetSemihostCallReturnAndErrnoValues(int returnValue, int err); +void mriPlatform_SetSemihostCallReturnAndErrnoValues(int returnValue, int errNo); const uint8_t* mriPlatform_GetUid(void); uint32_t mriPlatform_GetUidSize(void); @@ -140,6 +142,7 @@ int mriPlatform_RtosIsSetThreadStateSupported(void); void mriPlatform_RtosSetThreadState(uint32_t threadId, PlatformThreadState state); void mriPlatform_RtosRestorePrevThreadState(void); +void mriPlatform_HandleFaultFromHighPriorityCode(void); /* Macroes which allow code to drop the mri namespace prefix. */ #define Platform_Init mriPlatform_Init @@ -153,10 +156,13 @@ void mriPlatform_RtosRestorePrevThreadState(void); #define Platform_MemWrite32 mriPlatform_MemWrite32 #define Platform_MemWrite16 mriPlatform_MemWrite16 #define Platform_MemWrite8 mriPlatform_MemWrite8 +#define Platform_SyncICacheToDCache mriPlatform_SyncICacheToDCache #define Platform_CommHasReceiveData mriPlatform_CommHasReceiveData #define Platform_CommHasTransmitCompleted mriPlatform_CommHasTransmitCompleted #define Platform_CommReceiveChar mriPlatform_CommReceiveChar +#define Platform_CommSendBuffer mriPlatform_CommSendBuffer #define Platform_CommSendChar mriPlatform_CommSendChar +#define Platform_HandleGDBCommand mriPlatform_HandleGDBCommand #define Platform_DetermineCauseOfException mriPlatform_DetermineCauseOfException #define Platform_GetTrapReason mriPlatform_GetTrapReason #define Platform_DisplayFaultCauseToGdbConsole mriPlatform_DisplayFaultCauseToGdbConsole @@ -194,5 +200,6 @@ void mriPlatform_RtosRestorePrevThreadState(void); #define Platform_RtosIsSetThreadStateSupported mriPlatform_RtosIsSetThreadStateSupported #define Platform_RtosSetThreadState mriPlatform_RtosSetThreadState #define Platform_RtosRestorePrevThreadState mriPlatform_RtosRestorePrevThreadState +#define Platform_HandleFaultFromHighPriorityCode mriPlatform_HandleFaultFromHighPriorityCode #endif /* PLATFORMS_H_ */ diff --git a/libraries/MRI/src/core/semihost.h b/libraries/MRI/src/core/semihost.h index b5f8e4c54..534f51e49 100644 --- a/libraries/MRI/src/core/semihost.h +++ b/libraries/MRI/src/core/semihost.h @@ -1,4 +1,4 @@ -/* Copyright 2014 Adam Green (https://github.com/adamgreen/) +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,16 +17,19 @@ #define SEMIHOST_H_ #include +#include /* Real name of functions are in mri namespace. */ int mriSemihost_IsDebuggeeMakingSemihostCall(void); int mriSemihost_HandleSemihostRequest(void); +int mriSemihost_WriteToFileOrConsole(const TransferParameters* pParameters); int mriSemihost_HandleNewlibSemihostRequest(PlatformSemihostParameters* pSemihostParameters); int mriSemihost_HandleMbedSemihostRequest(PlatformSemihostParameters* pParameters); /* Macroes which allow code to drop the mri namespace prefix. */ #define Semihost_IsDebuggeeMakingSemihostCall mriSemihost_IsDebuggeeMakingSemihostCall #define Semihost_HandleSemihostRequest mriSemihost_HandleSemihostRequest +#define Semihost_WriteToFileOrConsole mriSemihost_WriteToFileOrConsole #define Semihost_HandleNewlibSemihostRequest mriSemihost_HandleNewlibSemihostRequest #define Semihost_HandleMbedSemihostRequest mriSemihost_HandleMbedSemihostRequest diff --git a/libraries/MRI/src/core/posix4win.h b/libraries/MRI/src/core/signal.h similarity index 82% rename from libraries/MRI/src/core/posix4win.h rename to libraries/MRI/src/core/signal.h index 014d071a4..41ea9b30b 100644 --- a/libraries/MRI/src/core/posix4win.h +++ b/libraries/MRI/src/core/signal.h @@ -13,15 +13,21 @@ limitations under the License. */ /* Monitor for Remote Inspection. */ -#ifndef POSIX4WIN_H_ -#define POSIX4WIN_H_ -#ifdef WIN32 +#ifndef SIGNAL_H_ +#define SIGNAL_H_ +#include +#ifndef SIGTRAP #define SIGTRAP 5 +#endif + +#ifndef SIGBUS #define SIGBUS 10 -#define SIGSTOP 18 +#endif +#ifndef SIGSTOP +#define SIGSTOP 18 +#endif -#endif /* WIN32 */ -#endif /* POSIX4WIN_H_ */ +#endif /* SIGNAL_H_ */ diff --git a/libraries/MRI/src/core/token.c b/libraries/MRI/src/core/token.c index af86b1085..afa304f08 100644 --- a/libraries/MRI/src/core/token.c +++ b/libraries/MRI/src/core/token.c @@ -1,4 +1,4 @@ -/* Copyright 2014 Adam Green (https://github.com/adamgreen/) +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -13,7 +13,7 @@ limitations under the License. */ /* 'Class' used to parse and tokenize a string based on provided list of separators. */ -#include +#include #include #define ARRAY_SIZE(X) (sizeof(X)/sizeof(X[0])) @@ -34,7 +34,7 @@ void Token_InitWith(Token* pToken, const char* pTheseTokenSeparators) static void clearTokenObject(Token* pToken) { - memset(pToken->tokenPointers, 0, sizeof(pToken->tokenPointers)); + mri_memset(pToken->tokenPointers, 0, sizeof(pToken->tokenPointers)); pToken->tokenCount = 0; pToken->copyOfString[0] = '\0'; } @@ -156,7 +156,7 @@ const char* Token_MatchingString(Token* pToken, const char* pTokenToSearchFor) for (i = 0 ; i < pToken->tokenCount ; i++) { - if (0 == strcmp(pToken->tokenPointers[i], pTokenToSearchFor)) + if (0 == mri_strcmp(pToken->tokenPointers[i], pTokenToSearchFor)) return pToken->tokenPointers[i]; } return NULL; @@ -169,7 +169,7 @@ const char* Token_MatchingStringPrefix(Token* pToken, const char* pTokenPrefixTo for (i = 0 ; i < pToken->tokenCount ; i++) { - if (pToken->tokenPointers[i] == strstr(pToken->tokenPointers[i], pTokenPrefixToSearchFor)) + if (pToken->tokenPointers[i] == mri_strstr(pToken->tokenPointers[i], pTokenPrefixToSearchFor)) return pToken->tokenPointers[i]; } return NULL; @@ -179,7 +179,7 @@ const char* Token_MatchingStringPrefix(Token* pToken, const char* pTokenPrefixTo static void adjustTokenPointers(Token* pToken, const char* pOriginalStringCopyBaseAddress); void Token_Copy(Token* pTokenCopy, Token* pTokenOriginal) { - *pTokenCopy = *pTokenOriginal; + mri_memcpy(pTokenCopy, pTokenOriginal, sizeof(*pTokenCopy)); adjustTokenPointers(pTokenCopy, pTokenOriginal->copyOfString); } diff --git a/libraries/MRI/src/core/version.h b/libraries/MRI/src/core/version.h index 41f97b74b..1dc7a11e5 100644 --- a/libraries/MRI/src/core/version.h +++ b/libraries/MRI/src/core/version.h @@ -2,11 +2,11 @@ #ifndef MRI_VERSION_STRING -#define MRI_BRANCH "https://github.com/adamgreen/mri" +#define MRI_BRANCH "https://github.com/adamgreen/mri/tree/version_1.5" #define MRI_VERSION_MAJOR 1 -#define MRI_VERSION_MINOR 1 -#define MRI_VERSION_BUILD 20200511 +#define MRI_VERSION_MINOR 5 +#define MRI_VERSION_BUILD 20230106 #define MRI_VERSION_SUBBUILD 0 #define MRI_STR(X) MRI_STR2(X) diff --git a/libraries/MRI/src/semihost/newlib/newlib_stubs.S b/libraries/MRI/src/semihost/newlib/newlib_stubs.S new file mode 100644 index 000000000..d22cec923 --- /dev/null +++ b/libraries/MRI/src/semihost/newlib/newlib_stubs.S @@ -0,0 +1,140 @@ +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +/* Implementation of semihost assembly language routines to be used to redirect standard I/O (stdin/stdout/stderr) + from the newlib library to the MRI debug monitor. */ +#include "newlib_stubs.h" + + .text + .code 16 + .syntax unified + + .global mriNewlib_SemihostWrite + .section .text.mriNewlib_SemihostWrite + .type mriNewlib_SemihostWrite, function + /* extern "C" int mriNewlib_SemihostWrite(int file, char *ptr, int len); + Issues semihost write call to PC via gdb. + */ +mriNewlib_SemihostWrite: + bkpt MRI_NEWLIB_SEMIHOST_WRITE + bx lr + + + .global mriNewlib_SemihostRead + .section .text.mriNewlib_SemihostRead + .type mriNewlib_SemihostRead, function + /* extern "C" int mriNewlib_SemihostRead(int file, char *ptr, int len); + Issues semihost read call to PC via gdb. + */ +mriNewlib_SemihostRead: + bkpt MRI_NEWLIB_SEMIHOST_READ + bx lr + + + .global mriNewLib_SemihostOpen + .section .text.mriNewLib_SemihostOpen + .type mriNewLib_SemihostOpen, function + /* extern "C" int mriNewLib_SemihostOpen(const char *pFilename, int flags, int mode); + Issues semihost open file call to PC via gdb. + */ +mriNewLib_SemihostOpen: + bkpt MRI_NEWLIB_SEMIHOST_OPEN + bx lr + + + .global mriNewLib_SemihostRename + .section .text.mriNewLib_SemihostRename + .type mriNewLib_SemihostRename, function + /* extern "C" int mriNewLib_SemihostRename(const char *pOldFilename, const char *pNewFilename); + Issues file rename call to PC via GDB. + */ +mriNewLib_SemihostRename: + bkpt MRI_NEWLIB_SEMIHOST_RENAME + bx lr + + .global mriNewLib_SemihostUnlink + .section .text.mriNewLib_SemihostUnlink + .type mriNewLib_SemihostUnlink, function + /* extern "C" int mriNewLib_SemihostUnlink(const char *pFilename); + Issues file delete (unlink) call to PC via GDB. + */ +mriNewLib_SemihostUnlink: + bkpt MRI_NEWLIB_SEMIHOST_UNLINK + bx lr + + + .global mriNewLib_SemihostStat + .section .text.mriNewLib_SemihostStat + .type mriNewLib_SemihostStat, function + /* extern "C" int mriNewLib_SemihostStat(const char *pFilename, struct stat *pStat); + Issues stat call to PC via GDB. + */ +mriNewLib_SemihostStat: + bkpt MRI_NEWLIB_SEMIHOST_STAT + bx lr + + + .global mriNewlib_SemihostLSeek + .section .text.mriNewlib_SemihostLSeek + .type mriNewlib_SemihostLSeek, function + /* extern "C" int mriNewlib_SemihostLSeek(int file, int offset, int whence); + Issues seek call to PC via GDB. + */ +mriNewlib_SemihostLSeek: + bkpt MRI_NEWLIB_SEMIHOST_LSEEK + bx lr + + + .global mriNewlib_SemihostClose + .section .text.mriNewlib_SemihostClose + .type mriNewlib_SemihostClose, function + /* extern "C" int mriNewlib_SemihostClose(int file); + Issues file close call to PC via GDB. + */ +mriNewlib_SemihostClose: + bkpt MRI_NEWLIB_SEMIHOST_CLOSE + bx lr + + + .global mriNewlib_SemihostFStat + .section .text.mriNewlib_SemihostFStat + .type mriNewlib_SemihostFStat, function + /* extern "C" int mriNewlib_SemihostFStat(int file, struct stat *pStat); + Issues stat call to PC via GDB. + */ +mriNewlib_SemihostFStat: + bkpt MRI_NEWLIB_SEMIHOST_FSTAT + bx lr + + + .global mriNewlib_SemihostGetErrNo + .section .text.mriNewlib_SemihostGetErrNo + .type mriNewlib_SemihostGetErrNo, function + /* extern "C" int mriNewlib_SemihostGetErrNo(); + Retrieves the errno recorded for the last failed newlib semihost call. + */ +mriNewlib_SemihostGetErrNo: + bkpt MRI_NEWLIB_SEMIHOST_GET_ERRNO + bx lr + + + .global mriSetDebuggerHooks + .section .text.mriSetDebuggerHooks + .type mriSetDebuggerHooks, function + /* extern "C" void mriSetDebuggerHooks(MriDebuggerHookPtr pEnteringHook, MriDebuggerHookPtr pLeavingHook, void* pvContext); + Tells MRI which hook functions to call when entering and leaving the debugger. + */ +mriSetDebuggerHooks: + bkpt MRI_NEWLIB_SEMIHOST_SET_HOOKS + bx lr diff --git a/libraries/MRI/src/semihost/newlib/newlib_stubs.h b/libraries/MRI/src/semihost/newlib/newlib_stubs.h new file mode 100644 index 000000000..615a672ca --- /dev/null +++ b/libraries/MRI/src/semihost/newlib/newlib_stubs.h @@ -0,0 +1,36 @@ +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +/* Breakpoint constants shared between assembly language stubs and MRI's semihost hooks. */ + +#ifndef MRI_NEWLIB_STUBS_H_ +#define MRI_NEWLIB_STUBS_H_ + +#define MRI_NEWLIB_SEMIHOST_MIN 0xf5 + +#define MRI_NEWLIB_SEMIHOST_SET_HOOKS 0xf5 +#define MRI_NEWLIB_SEMIHOST_GET_ERRNO 0xf6 +#define MRI_NEWLIB_SEMIHOST_WRITE 0xf7 +#define MRI_NEWLIB_SEMIHOST_READ 0xf8 +#define MRI_NEWLIB_SEMIHOST_OPEN 0xf9 +#define MRI_NEWLIB_SEMIHOST_RENAME 0xfa +#define MRI_NEWLIB_SEMIHOST_UNLINK 0xfb +#define MRI_NEWLIB_SEMIHOST_STAT 0xfc +#define MRI_NEWLIB_SEMIHOST_LSEEK 0xfd +#define MRI_NEWLIB_SEMIHOST_CLOSE 0xfe +#define MRI_NEWLIB_SEMIHOST_FSTAT 0xff + +#define MRI_NEWLIB_SEMIHOST_MAX 0xff + +#endif /* MRI_NEWLIB_STUBS_H_ */ diff --git a/libraries/MRI/src/semihost/newlib/semihost_newlib.c b/libraries/MRI/src/semihost/newlib/semihost_newlib.c new file mode 100644 index 000000000..0db2083f9 --- /dev/null +++ b/libraries/MRI/src/semihost/newlib/semihost_newlib.c @@ -0,0 +1,187 @@ +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +/* Semihost functionality for redirecting stdin/stdout/stderr I/O to the GNU console. */ +#include +#include +#include +#include +#include +#include "newlib_stubs.h" + + +static uint16_t getFirstHalfWordOfCurrentInstruction(void); +static uint16_t throwingMemRead16(uint32_t address); +static int handleNewlibSemihostWriteRequest(PlatformSemihostParameters* pSemihostParameters); +static int handleNewlibSemihostReadRequest(PlatformSemihostParameters* pSemihostParameters); +static int handleNewlibSemihostOpenRequest(PlatformSemihostParameters* pSemihostParameters); +static int handleNewlibSemihostUnlinkRequest(PlatformSemihostParameters* pSemihostParameters); +static int handleNewlibSemihostLSeekRequest(PlatformSemihostParameters* pSemihostParameters); +static int handleNewlibSemihostCloseRequest(PlatformSemihostParameters* pSemihostParameters); +static int handleNewlibSemihostFStatRequest(PlatformSemihostParameters* pSemihostParameters); +static int handleNewlibSemihostStatRequest(PlatformSemihostParameters* pSemihostParameters); +static int handleNewlibSemihostRenameRequest(PlatformSemihostParameters* pSemihostParameters); +static int handleNewlibSemihostGetErrNoRequest(PlatformSemihostParameters* pSemihostParameters); +static int handleNewlibSemihostSetHooksRequest(PlatformSemihostParameters* pSemihostParameters); +int Semihost_HandleNewlibSemihostRequest(PlatformSemihostParameters* pSemihostParameters) +{ + uint16_t semihostOperation = getFirstHalfWordOfCurrentInstruction() & 0x00FF; + + switch (semihostOperation) + { + case MRI_NEWLIB_SEMIHOST_WRITE: + return handleNewlibSemihostWriteRequest(pSemihostParameters); + case MRI_NEWLIB_SEMIHOST_READ: + return handleNewlibSemihostReadRequest(pSemihostParameters); + case MRI_NEWLIB_SEMIHOST_OPEN: + return handleNewlibSemihostOpenRequest(pSemihostParameters); + case MRI_NEWLIB_SEMIHOST_UNLINK: + return handleNewlibSemihostUnlinkRequest(pSemihostParameters); + case MRI_NEWLIB_SEMIHOST_LSEEK: + return handleNewlibSemihostLSeekRequest(pSemihostParameters); + case MRI_NEWLIB_SEMIHOST_CLOSE: + return handleNewlibSemihostCloseRequest(pSemihostParameters); + case MRI_NEWLIB_SEMIHOST_FSTAT: + return handleNewlibSemihostFStatRequest(pSemihostParameters); + case MRI_NEWLIB_SEMIHOST_STAT: + return handleNewlibSemihostStatRequest(pSemihostParameters); + case MRI_NEWLIB_SEMIHOST_RENAME: + return handleNewlibSemihostRenameRequest(pSemihostParameters); + case MRI_NEWLIB_SEMIHOST_GET_ERRNO: + return handleNewlibSemihostGetErrNoRequest(pSemihostParameters); + case MRI_NEWLIB_SEMIHOST_SET_HOOKS: + return handleNewlibSemihostSetHooksRequest(pSemihostParameters); + default: + return 0; + } +} + +static uint16_t getFirstHalfWordOfCurrentInstruction(void) +{ + return throwingMemRead16(Platform_GetProgramCounter()); +} + +static uint16_t throwingMemRead16(uint32_t address) +{ + uint16_t instructionWord = Platform_MemRead16((const uint16_t*)address); + if (Platform_WasMemoryFaultEncountered()) + __throw_and_return(memFaultException, 0); + return instructionWord; +} + +static int handleNewlibSemihostWriteRequest(PlatformSemihostParameters* pSemihostParameters) +{ + TransferParameters parameters; + + parameters.fileDescriptor = pSemihostParameters->parameter1; + parameters.bufferAddress = pSemihostParameters->parameter2; + parameters.bufferSize = pSemihostParameters->parameter3; + + return Semihost_WriteToFileOrConsole(¶meters); +} + +static int handleNewlibSemihostReadRequest(PlatformSemihostParameters* pSemihostParameters) +{ + TransferParameters parameters; + + parameters.fileDescriptor = pSemihostParameters->parameter1; + parameters.bufferAddress = pSemihostParameters->parameter2; + parameters.bufferSize = pSemihostParameters->parameter3; + + return IssueGdbFileReadRequest(¶meters); +} + +static int handleNewlibSemihostOpenRequest(PlatformSemihostParameters* pSemihostParameters) +{ + OpenParameters parameters; + + parameters.filenameAddress = pSemihostParameters->parameter1; + parameters.filenameLength = mri_strlen((const char*)parameters.filenameAddress) + 1; + parameters.flags = pSemihostParameters->parameter2; + parameters.mode = pSemihostParameters->parameter3; + + return IssueGdbFileOpenRequest(¶meters); +} + +static int handleNewlibSemihostUnlinkRequest(PlatformSemihostParameters* pSemihostParameters) +{ + RemoveParameters parameters; + + parameters.filenameAddress = pSemihostParameters->parameter1; + parameters.filenameLength = mri_strlen((const char*)parameters.filenameAddress) + 1; + + return IssueGdbFileUnlinkRequest(¶meters); +} + +static int handleNewlibSemihostLSeekRequest(PlatformSemihostParameters* pSemihostParameters) +{ + SeekParameters parameters; + + parameters.fileDescriptor = pSemihostParameters->parameter1; + parameters.offset = pSemihostParameters->parameter2; + parameters.whence = pSemihostParameters->parameter3; + + return IssueGdbFileSeekRequest(¶meters); +} + +static int handleNewlibSemihostCloseRequest(PlatformSemihostParameters* pSemihostParameters) +{ + return IssueGdbFileCloseRequest(pSemihostParameters->parameter1); +} + +static int handleNewlibSemihostFStatRequest(PlatformSemihostParameters* pSemihostParameters) +{ + return IssueGdbFileFStatRequest(pSemihostParameters->parameter1, pSemihostParameters->parameter2); +} + +static int handleNewlibSemihostStatRequest(PlatformSemihostParameters* pSemihostParameters) +{ + StatParameters parameters; + + parameters.filenameAddress = pSemihostParameters->parameter1; + parameters.filenameLength = mri_strlen((const char*) parameters.filenameAddress) + 1; + parameters.fileStatBuffer = pSemihostParameters->parameter2; + return IssueGdbFileStatRequest(¶meters); +} + +static int handleNewlibSemihostRenameRequest(PlatformSemihostParameters* pSemihostParameters) +{ + RenameParameters parameters; + + parameters.origFilenameAddress = pSemihostParameters->parameter1; + parameters.origFilenameLength = mri_strlen((const char*)parameters.origFilenameAddress) + 1; + parameters.newFilenameAddress = pSemihostParameters->parameter2; + parameters.newFilenameLength = mri_strlen((const char*)parameters.newFilenameAddress) + 1; + return IssueGdbFileRenameRequest(¶meters); +} + +static int handleNewlibSemihostGetErrNoRequest(PlatformSemihostParameters* pSemihostParameters) +{ + SetSemihostReturnValues(GetSemihostErrno(), 0); + FlagSemihostCallAsHandled(); + return 1; +} + +static int handleNewlibSemihostSetHooksRequest(PlatformSemihostParameters* pSemihostParameters) +{ + MriDebuggerHookPtr pEnteringHook = (MriDebuggerHookPtr)pSemihostParameters->parameter1; + MriDebuggerHookPtr pLeavingHook = (MriDebuggerHookPtr)pSemihostParameters->parameter2; + void* pvContext = (void*)pSemihostParameters->parameter3; + + mriCoreSetDebuggerHooks(pEnteringHook, pLeavingHook, pvContext); + + SetSemihostReturnValues(0, 0); + FlagSemihostCallAsHandled(); + return 1; +} diff --git a/libraries/MRI/src/semihost/semihost.c b/libraries/MRI/src/semihost/semihost.c new file mode 100644 index 000000000..f9dde742a --- /dev/null +++ b/libraries/MRI/src/semihost/semihost.c @@ -0,0 +1,72 @@ +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +/* Semihost functionality for redirecting operations such as file I/O to the GNU debugger. */ +#include +#include +#include +#include +#include + + +int Semihost_IsDebuggeeMakingSemihostCall(void) +{ + PlatformInstructionType instructionType = Platform_TypeOfCurrentInstruction(); + + return (instructionType == MRI_PLATFORM_INSTRUCTION_MBED_SEMIHOST_CALL || + instructionType == MRI_PLATFORM_INSTRUCTION_NEWLIB_SEMIHOST_CALL); +} + +int Semihost_HandleSemihostRequest(void) +{ + PlatformInstructionType instructionType = Platform_TypeOfCurrentInstruction(); + PlatformSemihostParameters parameters = Platform_GetSemihostCallParameters(); + + if (instructionType == MRI_PLATFORM_INSTRUCTION_MBED_SEMIHOST_CALL) + return Semihost_HandleMbedSemihostRequest(¶meters); + else if (instructionType == MRI_PLATFORM_INSTRUCTION_NEWLIB_SEMIHOST_CALL) + return Semihost_HandleNewlibSemihostRequest(¶meters); + else + return 0; +} + + +static int writeToGdbConsole(const TransferParameters* pParameters); +int Semihost_WriteToFileOrConsole(const TransferParameters* pParameters) +{ + const uint32_t STDOUT_FILE_NO = 1; + if (pParameters->fileDescriptor == STDOUT_FILE_NO) + { + return writeToGdbConsole(pParameters); + } + return IssueGdbFileWriteRequest(pParameters); +} + +static int writeToGdbConsole(const TransferParameters* pParameters) +{ + const char* pBuffer = (const char*)pParameters->bufferAddress; + size_t length = pParameters->bufferSize; + + size_t charsWritten = WriteSizedStringToGdbConsole(pBuffer, length); + + SetSemihostReturnValues(charsWritten, 0); + FlagSemihostCallAsHandled(); + + if (WasControlCEncountered()) + { + SetSignalValue(SIGINT); + return 0; + } + return 1; +} diff --git a/libraries/MRI/src/variants/Nano_33_BLE.h b/libraries/MRI/src/variants/Nano_33_BLE.h new file mode 100644 index 000000000..5d3c0621a --- /dev/null +++ b/libraries/MRI/src/variants/Nano_33_BLE.h @@ -0,0 +1,27 @@ +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +/* Nano 33 BLE Memory layout placed in g_memoryMapXml. */ +#ifndef MRI_NANO_33_BLE_H_ +#define MRI_NANO_33_BLE_H_ + +static const char g_memoryMapXml[] = "" + "" + "" + " 0x1000" + " " + " " + ""; + +#endif /* MRI_NANO_33_BLE_H_ */ diff --git a/libraries/MRI/src/variants/Portenta_H7.h b/libraries/MRI/src/variants/Portenta_H7.h new file mode 100644 index 000000000..8edeb4a61 --- /dev/null +++ b/libraries/MRI/src/variants/Portenta_H7.h @@ -0,0 +1,44 @@ +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +/* Portenta H7 Memory layout placed in g_memoryMapXml. */ +#ifndef MRI_PORTENTA_H7_H_ +#define MRI_PORTENTA_H7_H_ + +static const char g_memoryMapXml[] = "" + "" + "" +#ifndef CORE_CM4 + " " + " " +#endif + " 0x20000" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " 0x200" +#ifndef CORE_CM4 + " " +#endif + ""; + +#endif /* MRI_PORTENTA_H7_H_ */ diff --git a/libraries/MRI/src/variants/mri_variant.h b/libraries/MRI/src/variants/mri_variant.h new file mode 100644 index 000000000..5c89eeab9 --- /dev/null +++ b/libraries/MRI/src/variants/mri_variant.h @@ -0,0 +1,27 @@ +/* Copyright 2022 Adam Green (https://github.com/adamgreen/) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +/* Pull in variant specific header which defines memory layout in g_memoryMapXml. */ +#ifndef MRI_VARIANT_H_ +#define MRI_VARIANT_H_ + +#if defined(STM32H747xx) + #include "Portenta_H7.h" +#elif defined(NRF52840_XXAA) + #include "Nano_33_BLE.h" +#else + #error "Unrecognized variant for MRI/ThreadDebug/KernelDebug." +#endif + +#endif /* MRI_VARIANT_H_ */ diff --git a/libraries/ThreadDebug/examples/ThreadDebug/ThreadDebug.ino b/libraries/ThreadDebug/examples/ThreadDebug/ThreadDebug.ino index c3c74ef22..6336da5e8 100644 --- a/libraries/ThreadDebug/examples/ThreadDebug/ThreadDebug.ino +++ b/libraries/ThreadDebug/examples/ThreadDebug/ThreadDebug.ino @@ -1,4 +1,4 @@ -/* This example demonstrates how to include the ThreadMRI library which allows debugging of the Portenta H7 and Nano 33 BLE [Sense] +/* This example demonstrates how to include the ThreadMRI library which allows debugging of the Portenta H7 and Nano 33 BLE [Sense] with GDB via a serial interface. To connect to the target, launch gdb with the following parameters @@ -18,10 +18,18 @@ UsbDebugCommInterface debugComm(&SerialUSB); ThreadDebug threadDebug(&debugComm, DEBUG_BREAK_IN_SETUP); +// Redirect Serial.print*() output to GDB instead of SerialUSB where it would conflict with ThreadDebug. +// NOTE: Calls to Serial.print*() will block waiting for GDB to be connected so only useful to use this redefine +// when actively debugging the program. +#undef Serial +#define Serial DebugSerial + void setup() { } void loop() { + static uint32_t count; + Serial.print("Iteration: "); Serial.println(count++); } diff --git a/libraries/ThreadDebug/library.properties b/libraries/ThreadDebug/library.properties index bff9d7e2e..8d41ed7c4 100644 --- a/libraries/ThreadDebug/library.properties +++ b/libraries/ThreadDebug/library.properties @@ -1,5 +1,5 @@ name=ThreadDebug -version=1.0.0 +version=1.5.0 author=Adam Green maintainer=Arduino sentence=The GDB compatible thread debug monitor for Cortex-M devices. diff --git a/libraries/ThreadDebug/src/ThreadDebug.cpp b/libraries/ThreadDebug/src/ThreadDebug.cpp index a2737ecef..4ace0bab9 100644 --- a/libraries/ThreadDebug/src/ThreadDebug.cpp +++ b/libraries/ThreadDebug/src/ThreadDebug.cpp @@ -34,6 +34,7 @@ extern "C" // Source code for armv7-m module which is included here, configured for supporting thread mode debugging. #include #include + #include } @@ -61,7 +62,7 @@ static const char* g_threadNamesToIgnore[] = { // Bit in LR set to 0 when automatic stacking of floating point registers occurs during exception handling. #define LR_FLOAT_STACK (1 << 4) -// RTX Thread synchronization flag used to indicate that a debug event has occured. +// RTX Thread synchronization flag used to indicate that a debug event has occurred. #define MRI_THREAD_DEBUG_EVENT_FLAG (1 << 0) // Lower nibble of EXC_RETURN in LR will have one of these values if interrupted code was running in thread mode. @@ -75,7 +76,7 @@ static const char* g_threadNamesToIgnore[] = { #define ARRAY_SIZE(X) (sizeof(X)/sizeof(X[0])) // Assert routine that will dump error text to USB GDB connection before entering infinite loop. If user is logging MRI -// remote communications then they will see the error text in the log before debug stub becomes unresponseive. +// remote communications then they will see the error text in the log before debug stub becomes unresponsive. #undef ASSERT #define ASSERT(X) \ if (!(X)) { \ @@ -94,7 +95,6 @@ static const char* g_threadNamesToIgnore[] = { // If non-NULL, this is the thread that we want to single step. // If NULL, single stepping is not enabled. -// Accessed by this module and the assembly language handlers in ThreadDebug_asm.S. volatile osThreadId_t mriThreadSingleStepThreadId; // Structures used to track information about all of the application's threads. It tracks a thread's original priority @@ -156,7 +156,7 @@ struct ThreadList if (pInfo->state != MRI_PLATFORM_THREAD_FROZEN) { thawThread(pInfo, pInfo->priority, pInfo->basePriority); } - if (shouldThawIdleThreadDuringSingleStep(pInfo)) { + if (needToThawIdleThread(pInfo)) { // Gives RTX a thread to run if single stepping thread is waiting on sync object. thawThread(pInfo, osPriorityIdle+1, osPriorityIdle+1); } @@ -171,11 +171,9 @@ struct ThreadList pThread->priority_base = basePriority; } - bool shouldThawIdleThreadDuringSingleStep(ThreadInfo* pInfo) + bool needToThawIdleThread(ThreadInfo* pInfo) { - return pInfo->threadId == osRtxInfo.thread.idle && - pInfo->state == (uint8_t)MRI_PLATFORM_THREAD_FROZEN && - mriThreadSingleStepThreadId != 0; + return pInfo->threadId == osRtxInfo.thread.idle && pInfo->state == (uint8_t)MRI_PLATFORM_THREAD_FROZEN; } void sort() @@ -281,7 +279,7 @@ static uint32_t g_maxThreadCount; static char g_threadExtraInfo[64]; // This flag is set to a non-zero value if the DebugMon handler is to re-enable DWT watchpoints and FPB breakpoints -// after being disabled by the HardFault handler when a debug event is encounted in handler mode. +// after being disabled by the HardFault handler when a debug event is encountered in handler mode. static volatile uint32_t g_enableDWTandFPB; // This flag is set to a non-zero value if a DebugMon interrupt was pended because GDB sent CTRL+C. @@ -356,6 +354,7 @@ static bool hasEncounteredDebugEvent(); static void recordAndClearFaultStatusBits(); static void wakeMriMainToDebugCurrentThread(); static void stopSingleStepping(); +static void recordRtxHandlers(); static void recordAndSwitchFaultHandlersToDebugger(); static const char* getThreadStateName(uint8_t threadState); static bool isDebugThreadActive(); @@ -580,9 +579,6 @@ static void readThreadContext(MriContext* pContext, uint32_t* pSP, osThreadId_t static void switchRtxHandlersToDebugStubsForSingleStepping() { - mriThreadOrigSVCall = NVIC_GetVector(SVCall_IRQn); - mriThreadOrigPendSV = NVIC_GetVector(PendSV_IRQn); - mriThreadOrigSysTick = NVIC_GetVector(SysTick_IRQn); NVIC_SetVector(SVCall_IRQn, (uint32_t)mriSVCHandlerStub); NVIC_SetVector(PendSV_IRQn, (uint32_t)mriPendSVHandlerStub); NVIC_SetVector(SysTick_IRQn, (uint32_t)mriSysTickHandlerStub); @@ -624,17 +620,14 @@ ThreadDebug::~ThreadDebug() // IMPORTANT NOTE: You are attempting to destroy the connection to GDB which isn't allowed. // Don't allow your ThreadDebug object to go out of scope like this. - debugBreak(); - for (;;) { - // Loop forever. - } + ASSERT ( false ); } // --------------------------------------------------------------------------------------------------------------------- -// Global Platform_* functions needed by MRI to initialize and communicate with MRI. +// Global Platform_* functions needed by MRI to initialize and communicate with GDB. // These functions will perform most of their work through the DebugSerial singleton. // --------------------------------------------------------------------------------------------------------------------- void Platform_Init(Token* pParameterTokens) @@ -650,9 +643,17 @@ void Platform_Init(Token* pParameterTokens) mriThreadSingleStepThreadId = NULL; Context_Init(&mriCortexMState.context, g_contextSections, ARRAY_SIZE(g_contextSections)); Context_Init(&g_threadContext, g_threadContextSections, ARRAY_SIZE(g_threadContextSections)); + recordRtxHandlers(); recordAndSwitchFaultHandlersToDebugger(); } +static void recordRtxHandlers() +{ + mriThreadOrigSVCall = NVIC_GetVector(SVCall_IRQn); + mriThreadOrigPendSV = NVIC_GetVector(PendSV_IRQn); + mriThreadOrigSysTick = NVIC_GetVector(SysTick_IRQn); +} + static void recordAndSwitchFaultHandlersToDebugger() { mriThreadOrigHardFault = NVIC_GetVector(HardFault_IRQn); @@ -690,47 +691,18 @@ int Platform_CommReceiveChar(void) void Platform_CommSendChar(int character) { - g_pComm->write(character); + char data = character; + + g_pComm->write(&data, sizeof(data)); } +void Platform_CommSendBuffer(Buffer* pBuffer) +{ + g_pComm->write(Buffer_GetArray(pBuffer), Buffer_GetLength(pBuffer)); +} -#ifdef STM32H747xx -static const char g_memoryMapXml[] = "" - "" - "" -#ifndef CORE_CM4 - " " - " " -#endif - " 0x20000" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " 0x200" -#ifndef CORE_CM4 - " " -#endif - ""; -#endif -#ifdef NRF52840_XXAA -static const char g_memoryMapXml[] = "" - "" - "" - " 0x1000" - " " - " " - ""; -#endif uint32_t Platform_GetDeviceMemoryMapXmlSize(void) { @@ -755,12 +727,7 @@ uint32_t Platform_GetUidSize(void) return 0; } -int Semihost_IsDebuggeeMakingSemihostCall(void) -{ - return 0; -} - -int Semihost_HandleSemihostRequest(void) +int Semihost_HandleMbedSemihostRequest(PlatformSemihostParameters* pParameters) { return 0; } @@ -894,9 +861,8 @@ void Platform_RtosRestorePrevThreadState(void) // --------------------------------------------------------------------------------------------------------------------- extern "C" void mriDebugMonitorHandler(uint32_t excReturn) { - while (!isThreadMode(excReturn)) { - // DebugMon is running at such low priority that we should be getting ready to return to thread mode. - } + // DebugMon is running at such low priority that we should be getting ready to return to thread mode. + ASSERT ( isThreadMode(excReturn) ); if (g_enableDWTandFPB > 0) { enableDWTandITM(); @@ -1124,9 +1090,9 @@ uint32_t UartDebugCommInterface::wrappingIncrement(uint32_t val) return (val + 1) & (sizeof(_queue) - 1); } -void UartDebugCommInterface::write(uint8_t c) +void UartDebugCommInterface::write(const char* pBuffer, size_t bufferLength) { - _serial.write(&c, 1); + _serial.write(pBuffer, bufferLength); } void UartDebugCommInterface::attach(void (*pCallback)()) @@ -1177,9 +1143,9 @@ uint8_t UsbDebugCommInterface::read() return _pSerial->read(); } -void UsbDebugCommInterface::write(uint8_t c) +void UsbDebugCommInterface::write(const char* pBuffer, size_t bufferLength) { - _pSerial->write(c); + _pSerial->send((uint8_t*)pBuffer, bufferLength); } void UsbDebugCommInterface::attach(void (*pCallback)()) @@ -1216,13 +1182,65 @@ uint8_t RPCDebugCommInterface::read() return _pSerial->read(); } -void RPCDebugCommInterface::write(uint8_t c) +void RPCDebugCommInterface::write(const char* pBuffer, size_t bufferLength) { - _pSerial->write(c); + _pSerial->write(pBuffer, bufferLength); } void RPCDebugCommInterface::attach(void (*pCallback)()) { _pSerial->attach(pCallback); } -#endif \ No newline at end of file +#endif + + + + + +// This class can be used instead of Serial for sending output to the PC via GDB. +DebugSerial::DebugSerial() +{ +} + +// Methods that must be implemented for Print subclasses. +size_t DebugSerial::write(uint8_t byte) +{ + return write(&byte, sizeof(byte)); +} + +size_t DebugSerial::write(const uint8_t *pBuffer, size_t size) +{ + const int STDOUT_FILE_NO = 1; + const char* pCurr = (const char*)pBuffer; + int bytesWritten = 0; + + while (size > 0) { + int result = mriNewlib_SemihostWrite(STDOUT_FILE_NO, pCurr, size); + if (result == -1) { + break; + } + size -= result; + pCurr += result; + bytesWritten += result; + } + return bytesWritten; +} + +void DebugSerial::flush() +{ +} + +void DebugSerial::begin(unsigned long baud, uint16_t mode) +{ + // Silence compiler warnings about unused parameters. + (void)baud; + (void)mode; +} + +void DebugSerial::end() +{ +} + + +// Instantiate the single instance of this stream. +class DebugSerial arduino::DebugSerial; diff --git a/libraries/ThreadDebug/src/ThreadDebug.h b/libraries/ThreadDebug/src/ThreadDebug.h index 3cecdeb5d..b309baae4 100644 --- a/libraries/ThreadDebug/src/ThreadDebug.h +++ b/libraries/ThreadDebug/src/ThreadDebug.h @@ -79,7 +79,7 @@ class DebugCommInterface { virtual bool readable() = 0; virtual bool writeable() = 0; virtual uint8_t read() = 0; - virtual void write(uint8_t c) = 0; + virtual void write(const char* pBuffer, size_t bufferLength) = 0; virtual void attach(void (*pCallback)()) = 0; }; @@ -97,7 +97,7 @@ class UsbDebugCommInterface : public DebugCommInterface { virtual bool readable(); virtual bool writeable(); virtual uint8_t read(); - virtual void write(uint8_t c); + virtual void write(const char* pBuffer, size_t bufferLength); virtual void attach(void (*pCallback)()); protected: @@ -115,7 +115,7 @@ class RPCDebugCommInterface : public DebugCommInterface { virtual bool readable(); virtual bool writeable(); virtual uint8_t read(); - virtual void write(uint8_t c); + virtual void write(const char* pBuffer, size_t bufferLength); virtual void attach(void (*pCallback)()); protected: @@ -132,7 +132,7 @@ class UartDebugCommInterface : public DebugCommInterface { virtual bool readable(); virtual bool writeable(); virtual uint8_t read(); - virtual void write(uint8_t c); + virtual void write(const char* pBuffer, size_t bufferLength); virtual void attach(void (*pCallback)()); protected: @@ -153,4 +153,27 @@ class UartDebugCommInterface : public DebugCommInterface { #define debugBreak() { __asm volatile ("bkpt #0"); } #endif + +// This class can be used instead of Serial for sending output to the PC via GDB. +class DebugSerial : public Print +{ +public: + DebugSerial(); + + // Leaving out input Stream related methods so that compiler throws errors if user tries to use them. + + // Methods that must be implemented for Print subclasses. + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buffer, size_t size); + virtual void flush(); + + // Additional methods defined by HardwareSerial that user might call. + void begin(unsigned long baud) { begin(baud, SERIAL_8N1); } + void begin(unsigned long baudrate, uint16_t config); + void end(); + operator bool() { return true; } + +protected: +} extern DebugSerial; + } // namespace arduino diff --git a/libraries/ThreadDebug/src/ThreadDebug_asm.S b/libraries/ThreadDebug/src/ThreadDebug_asm.S index 435272bc4..fa395ed00 100644 --- a/libraries/ThreadDebug/src/ThreadDebug_asm.S +++ b/libraries/ThreadDebug/src/ThreadDebug_asm.S @@ -24,7 +24,7 @@ /* Hard Fault Status Register */ .equ HFSR, 0xE000ED2C - /* This bit is set in HFSR if a hard fault was forced by debug event occuring in handler mode. */ + /* This bit is set in HFSR if a hard fault was forced by debug event occurring in handler mode. */ .equ HFSR_DEBUG_EVENT_BIT, (1 << 31) /* System register and bits for pending DebugMon interrupt. */ diff --git a/variants/PORTENTA_H7_M7/variant.cpp b/variants/PORTENTA_H7_M7/variant.cpp index 4e85cf618..5bb0fad1b 100644 --- a/variants/PORTENTA_H7_M7/variant.cpp +++ b/variants/PORTENTA_H7_M7/variant.cpp @@ -15,10 +15,6 @@ AnalogPinDescription g_AAnalogPinDescription[] = { { PA_6, NULL } // A7 ADC1_INP7 }; -AnalogPinDescription g_AAnalogOutPinDescription[] = { - { PA_4, NULL }, // A6 DAC1_OUT1 -}; - PinDescription g_APinDescription[] = { // D0 - D7 { PH_15, NULL, NULL, NULL }, // D0 @@ -40,188 +36,188 @@ PinDescription g_APinDescription[] = { { PA_9, NULL, NULL, NULL }, // D14 // A0 - A6 - { PA_0C, NULL, NULL, NULL }, // A0 ADC2_INP0 - { PA_1C, NULL, NULL, NULL }, // A1 ADC2_INP1 - { PC_2C, NULL, NULL, NULL }, // A2 ADC3_INP0 - { PC_3C, NULL, NULL, NULL }, // A3 ADC3_INP1 - { PC_2_ALT0, NULL, NULL, NULL }, // A4 ADC1_INP12 - { PC_3_ALT0, NULL, NULL, NULL }, // A5 ADC1_INP13 - { PA_4, NULL, NULL, NULL }, // A6 ADC1_INP18 - { PA_6, NULL, NULL, NULL }, // A7 ADC1_INP7 + { PA_0C, NULL, NULL, NULL }, // A0 ADC2_INP0 D15 + { PA_1C, NULL, NULL, NULL }, // A1 ADC2_INP1 D16 + { PC_2C, NULL, NULL, NULL }, // A2 ADC3_INP0 D17 + { PC_3C, NULL, NULL, NULL }, // A3 ADC3_INP1 D18 + { PC_2_ALT0, NULL, NULL, NULL }, // A4 ADC1_INP12 D19 + { PC_3_ALT0, NULL, NULL, NULL }, // A5 ADC1_INP13 D20 + { PA_4, NULL, NULL, NULL }, // A6 ADC1_INP18 D21 + { PA_6, NULL, NULL, NULL }, // A7 ADC1_INP7 D22 // LEDS { PK_5, NULL, NULL, NULL }, // LEDR { PK_6, NULL, NULL, NULL }, // LEDG { PK_7, NULL, NULL, NULL }, // LEDB - { PA_0, NULL, NULL, NULL }, - { PA_1, NULL, NULL, NULL }, - { PA_2, NULL, NULL, NULL }, - { PA_3, NULL, NULL, NULL }, - { PA_4, NULL, NULL, NULL }, - { PA_5, NULL, NULL, NULL }, - { PA_6, NULL, NULL, NULL }, - { PA_7, NULL, NULL, NULL }, - { PA_8, NULL, NULL, NULL }, - { PA_9, NULL, NULL, NULL }, - { PA_10, NULL, NULL, NULL }, - { PA_11, NULL, NULL, NULL }, - { PA_12, NULL, NULL, NULL }, - { PA_13, NULL, NULL, NULL }, - { PA_14, NULL, NULL, NULL }, - { PA_15, NULL, NULL, NULL }, - { PB_0, NULL, NULL, NULL }, - { PB_1, NULL, NULL, NULL }, - { PB_2, NULL, NULL, NULL }, - { PB_3, NULL, NULL, NULL }, - { PB_4, NULL, NULL, NULL }, - { PB_5, NULL, NULL, NULL }, - { PB_6, NULL, NULL, NULL }, - { PB_7, NULL, NULL, NULL }, - { PB_8, NULL, NULL, NULL }, - { PB_9, NULL, NULL, NULL }, - { PB_10, NULL, NULL, NULL }, - { PB_11, NULL, NULL, NULL }, - { PB_12, NULL, NULL, NULL }, - { PB_13, NULL, NULL, NULL }, - { PB_14, NULL, NULL, NULL }, - { PB_15, NULL, NULL, NULL }, - { PC_0, NULL, NULL, NULL }, - { PC_1, NULL, NULL, NULL }, - { PC_2, NULL, NULL, NULL }, - { PC_3, NULL, NULL, NULL }, - { PC_4, NULL, NULL, NULL }, - { PC_5, NULL, NULL, NULL }, - { PC_6, NULL, NULL, NULL }, - { PC_7, NULL, NULL, NULL }, - { PC_8, NULL, NULL, NULL }, - { PC_9, NULL, NULL, NULL }, - { PC_10, NULL, NULL, NULL }, - { PC_11, NULL, NULL, NULL }, - { PC_12, NULL, NULL, NULL }, - { PC_13, NULL, NULL, NULL }, - { PC_14, NULL, NULL, NULL }, - { PC_15, NULL, NULL, NULL }, - { PD_0, NULL, NULL, NULL }, - { PD_1, NULL, NULL, NULL }, - { PD_2, NULL, NULL, NULL }, - { PD_3, NULL, NULL, NULL }, - { PD_4, NULL, NULL, NULL }, - { PD_5, NULL, NULL, NULL }, - { PD_6, NULL, NULL, NULL }, - { PD_7, NULL, NULL, NULL }, - { PD_8, NULL, NULL, NULL }, - { PD_9, NULL, NULL, NULL }, - { PD_10, NULL, NULL, NULL }, - { PD_11, NULL, NULL, NULL }, - { PD_12, NULL, NULL, NULL }, - { PD_13, NULL, NULL, NULL }, - { PD_14, NULL, NULL, NULL }, - { PD_15, NULL, NULL, NULL }, - { PE_0, NULL, NULL, NULL }, - { PE_1, NULL, NULL, NULL }, - { PE_2, NULL, NULL, NULL }, - { PE_3, NULL, NULL, NULL }, - { PE_4, NULL, NULL, NULL }, - { PE_5, NULL, NULL, NULL }, - { PE_6, NULL, NULL, NULL }, - { PE_7, NULL, NULL, NULL }, - { PE_8, NULL, NULL, NULL }, - { PE_9, NULL, NULL, NULL }, - { PE_10, NULL, NULL, NULL }, - { PE_11, NULL, NULL, NULL }, - { PE_12, NULL, NULL, NULL }, - { PE_13, NULL, NULL, NULL }, - { PE_14, NULL, NULL, NULL }, - { PE_15, NULL, NULL, NULL }, - { PF_0, NULL, NULL, NULL }, - { PF_1, NULL, NULL, NULL }, - { PF_2, NULL, NULL, NULL }, - { PF_3, NULL, NULL, NULL }, - { PF_4, NULL, NULL, NULL }, - { PF_5, NULL, NULL, NULL }, - { PF_6, NULL, NULL, NULL }, - { PF_7, NULL, NULL, NULL }, - { PF_8, NULL, NULL, NULL }, - { PF_9, NULL, NULL, NULL }, - { PF_10, NULL, NULL, NULL }, - { PF_11, NULL, NULL, NULL }, - { PF_12, NULL, NULL, NULL }, - { PF_13, NULL, NULL, NULL }, - { PF_14, NULL, NULL, NULL }, - { PF_15, NULL, NULL, NULL }, - { PG_0, NULL, NULL, NULL }, - { PG_1, NULL, NULL, NULL }, - { PG_2, NULL, NULL, NULL }, - { PG_3, NULL, NULL, NULL }, - { PG_4, NULL, NULL, NULL }, - { PG_5, NULL, NULL, NULL }, - { PG_6, NULL, NULL, NULL }, - { PG_7, NULL, NULL, NULL }, - { PG_8, NULL, NULL, NULL }, - { PG_9, NULL, NULL, NULL }, - { PG_10, NULL, NULL, NULL }, - { PG_11, NULL, NULL, NULL }, - { PG_12, NULL, NULL, NULL }, - { PG_13, NULL, NULL, NULL }, - { PG_14, NULL, NULL, NULL }, - { PG_15, NULL, NULL, NULL }, - { PH_0, NULL, NULL, NULL }, - { PH_1, NULL, NULL, NULL }, - { PH_2, NULL, NULL, NULL }, - { PH_3, NULL, NULL, NULL }, - { PH_4, NULL, NULL, NULL }, - { PH_5, NULL, NULL, NULL }, - { PH_6, NULL, NULL, NULL }, - { PH_7, NULL, NULL, NULL }, - { PH_8, NULL, NULL, NULL }, - { PH_9, NULL, NULL, NULL }, - { PH_10, NULL, NULL, NULL }, - { PH_11, NULL, NULL, NULL }, - { PH_12, NULL, NULL, NULL }, - { PH_13, NULL, NULL, NULL }, - { PH_14, NULL, NULL, NULL }, - { PH_15, NULL, NULL, NULL }, - { PI_0, NULL, NULL, NULL }, - { PI_1, NULL, NULL, NULL }, - { PI_2, NULL, NULL, NULL }, - { PI_3, NULL, NULL, NULL }, - { PI_4, NULL, NULL, NULL }, - { PI_5, NULL, NULL, NULL }, - { PI_6, NULL, NULL, NULL }, - { PI_7, NULL, NULL, NULL }, - { PI_8, NULL, NULL, NULL }, - { PI_9, NULL, NULL, NULL }, - { PI_10, NULL, NULL, NULL }, - { PI_11, NULL, NULL, NULL }, - { PI_12, NULL, NULL, NULL }, - { PI_13, NULL, NULL, NULL }, - { PI_14, NULL, NULL, NULL }, - { PI_15, NULL, NULL, NULL }, - { PJ_0, NULL, NULL, NULL }, - { PJ_1, NULL, NULL, NULL }, - { PJ_2, NULL, NULL, NULL }, - { PJ_3, NULL, NULL, NULL }, - { PJ_4, NULL, NULL, NULL }, - { PJ_5, NULL, NULL, NULL }, - { PJ_6, NULL, NULL, NULL }, - { PJ_7, NULL, NULL, NULL }, - { PJ_8, NULL, NULL, NULL }, - { PJ_9, NULL, NULL, NULL }, - { PJ_10, NULL, NULL, NULL }, - { PJ_11, NULL, NULL, NULL }, - { PJ_12, NULL, NULL, NULL }, - { PJ_13, NULL, NULL, NULL }, - { PJ_14, NULL, NULL, NULL }, - { PJ_15, NULL, NULL, NULL }, - { PK_0, NULL, NULL, NULL }, - { PK_1, NULL, NULL, NULL }, - { PK_2, NULL, NULL, NULL }, - { PK_3, NULL, NULL, NULL }, - { PK_4, NULL, NULL, NULL }, - { PK_5, NULL, NULL, NULL }, - { PK_6, NULL, NULL, NULL }, - { PK_7, NULL, NULL, NULL }, + { PA_0, NULL, NULL, NULL }, //D26 + { PA_1, NULL, NULL, NULL }, //D27 + { PA_2, NULL, NULL, NULL }, //D28 + { PA_3, NULL, NULL, NULL }, //D29 + { PA_4, NULL, NULL, NULL }, //D30 + { PA_5, NULL, NULL, NULL }, //D31 + { PA_6, NULL, NULL, NULL }, //D32 + { PA_7, NULL, NULL, NULL }, //D33 + { PA_8, NULL, NULL, NULL }, //D34 + { PA_9, NULL, NULL, NULL }, //D35 + { PA_10, NULL, NULL, NULL }, //D36 + { PA_11, NULL, NULL, NULL }, //D37 + { PA_12, NULL, NULL, NULL }, //D38 + { PA_13, NULL, NULL, NULL }, //D39 + { PA_14, NULL, NULL, NULL }, //D40 + { PA_15, NULL, NULL, NULL }, //D41 + { PB_0, NULL, NULL, NULL }, //D42 + { PB_1, NULL, NULL, NULL }, //D43 + { PB_2, NULL, NULL, NULL }, //D44 + { PB_3, NULL, NULL, NULL }, //D45 + { PB_4, NULL, NULL, NULL }, //D46 + { PB_5, NULL, NULL, NULL }, //D47 + { PB_6, NULL, NULL, NULL }, //D48 + { PB_7, NULL, NULL, NULL }, //D49 + { PB_8, NULL, NULL, NULL }, //D50 + { PB_9, NULL, NULL, NULL }, //D51 + { PB_10, NULL, NULL, NULL }, //D52 + { PB_11, NULL, NULL, NULL }, //D53 + { PB_12, NULL, NULL, NULL }, //D54 + { PB_13, NULL, NULL, NULL }, //D55 + { PB_14, NULL, NULL, NULL }, //D56 + { PB_15, NULL, NULL, NULL }, //D57 + { PC_0, NULL, NULL, NULL }, //D58 + { PC_1, NULL, NULL, NULL }, //D59 + { PC_2, NULL, NULL, NULL }, //D60 + { PC_3, NULL, NULL, NULL }, //D61 + { PC_4, NULL, NULL, NULL }, //D62 + { PC_5, NULL, NULL, NULL }, //D63 + { PC_6, NULL, NULL, NULL }, //D64 + { PC_7, NULL, NULL, NULL }, //D65 + { PC_8, NULL, NULL, NULL }, //D66 + { PC_9, NULL, NULL, NULL }, //D67 + { PC_10, NULL, NULL, NULL }, //D68 + { PC_11, NULL, NULL, NULL }, //D69 + { PC_12, NULL, NULL, NULL }, //D70 + { PC_13, NULL, NULL, NULL }, //D71 + { PC_14, NULL, NULL, NULL }, //D72 + { PC_15, NULL, NULL, NULL }, //D73 + { PD_0, NULL, NULL, NULL }, //D74 + { PD_1, NULL, NULL, NULL }, //D75 + { PD_2, NULL, NULL, NULL }, //D76 + { PD_3, NULL, NULL, NULL }, //D77 + { PD_4, NULL, NULL, NULL }, //D78 + { PD_5, NULL, NULL, NULL }, //D79 + { PD_6, NULL, NULL, NULL }, //D80 + { PD_7, NULL, NULL, NULL }, //D81 + { PD_8, NULL, NULL, NULL }, //D82 + { PD_9, NULL, NULL, NULL }, //D83 + { PD_10, NULL, NULL, NULL }, //D84 + { PD_11, NULL, NULL, NULL }, //D85 + { PD_12, NULL, NULL, NULL }, //D86 + { PD_13, NULL, NULL, NULL }, //D87 + { PD_14, NULL, NULL, NULL }, //D88 + { PD_15, NULL, NULL, NULL }, //D89 + { PE_0, NULL, NULL, NULL }, //D90 + { PE_1, NULL, NULL, NULL }, //D91 + { PE_2, NULL, NULL, NULL }, //D92 + { PE_3, NULL, NULL, NULL }, //D93 + { PE_4, NULL, NULL, NULL }, //D94 + { PE_5, NULL, NULL, NULL }, //D95 + { PE_6, NULL, NULL, NULL }, //D96 + { PE_7, NULL, NULL, NULL }, //D97 + { PE_8, NULL, NULL, NULL }, //D98 + { PE_9, NULL, NULL, NULL }, //D99 + { PE_10, NULL, NULL, NULL }, //D100 + { PE_11, NULL, NULL, NULL }, //D101 + { PE_12, NULL, NULL, NULL }, //D102 + { PE_13, NULL, NULL, NULL }, //D103 + { PE_14, NULL, NULL, NULL }, //D104 + { PE_15, NULL, NULL, NULL }, //D105 + { PF_0, NULL, NULL, NULL }, //D106 + { PF_1, NULL, NULL, NULL }, //D107 + { PF_2, NULL, NULL, NULL }, //D108 + { PF_3, NULL, NULL, NULL }, //D109 + { PF_4, NULL, NULL, NULL }, //D110 + { PF_5, NULL, NULL, NULL }, //D111 + { PF_6, NULL, NULL, NULL }, //D112 + { PF_7, NULL, NULL, NULL }, //D113 + { PF_8, NULL, NULL, NULL }, //D114 + { PF_9, NULL, NULL, NULL }, //D115 + { PF_10, NULL, NULL, NULL }, //D116 + { PF_11, NULL, NULL, NULL }, //D117 + { PF_12, NULL, NULL, NULL }, //D118 + { PF_13, NULL, NULL, NULL }, //D119 + { PF_14, NULL, NULL, NULL }, //D120 + { PF_15, NULL, NULL, NULL }, //D121 + { PG_0, NULL, NULL, NULL }, //D122 + { PG_1, NULL, NULL, NULL }, //D123 + { PG_2, NULL, NULL, NULL }, //D124 + { PG_3, NULL, NULL, NULL }, //D125 + { PG_4, NULL, NULL, NULL }, //D126 + { PG_5, NULL, NULL, NULL }, //D127 + { PG_6, NULL, NULL, NULL }, //D128 + { PG_7, NULL, NULL, NULL }, //D129 + { PG_8, NULL, NULL, NULL }, //D130 + { PG_9, NULL, NULL, NULL }, //D131 + { PG_10, NULL, NULL, NULL }, //D132 + { PG_11, NULL, NULL, NULL }, //D133 + { PG_12, NULL, NULL, NULL }, //D134 + { PG_13, NULL, NULL, NULL }, //D135 + { PG_14, NULL, NULL, NULL }, //D136 + { PG_15, NULL, NULL, NULL }, //D137 + { PH_0, NULL, NULL, NULL }, //D138 + { PH_1, NULL, NULL, NULL }, //D139 + { PH_2, NULL, NULL, NULL }, //D140 + { PH_3, NULL, NULL, NULL }, //D141 + { PH_4, NULL, NULL, NULL }, //D142 + { PH_5, NULL, NULL, NULL }, //D143 + { PH_6, NULL, NULL, NULL }, //D144 + { PH_7, NULL, NULL, NULL }, //D145 + { PH_8, NULL, NULL, NULL }, //D146 + { PH_9, NULL, NULL, NULL }, //D147 + { PH_10, NULL, NULL, NULL }, //D148 + { PH_11, NULL, NULL, NULL }, //D149 + { PH_12, NULL, NULL, NULL }, //D150 + { PH_13, NULL, NULL, NULL }, //D151 + { PH_14, NULL, NULL, NULL }, //D152 + { PH_15, NULL, NULL, NULL }, //D153 + { PI_0, NULL, NULL, NULL }, //D154 + { PI_1, NULL, NULL, NULL }, //D155 + { PI_2, NULL, NULL, NULL }, //D156 + { PI_3, NULL, NULL, NULL }, //D157 + { PI_4, NULL, NULL, NULL }, //D158 + { PI_5, NULL, NULL, NULL }, //D159 + { PI_6, NULL, NULL, NULL }, //D160 + { PI_7, NULL, NULL, NULL }, //D161 + { PI_8, NULL, NULL, NULL }, //D162 + { PI_9, NULL, NULL, NULL }, //D163 + { PI_10, NULL, NULL, NULL }, //D164 + { PI_11, NULL, NULL, NULL }, //D165 + { PI_12, NULL, NULL, NULL }, //D166 + { PI_13, NULL, NULL, NULL }, //D167 + { PI_14, NULL, NULL, NULL }, //D168 + { PI_15, NULL, NULL, NULL }, //D169 + { PJ_0, NULL, NULL, NULL }, //D170 + { PJ_1, NULL, NULL, NULL }, //D171 + { PJ_2, NULL, NULL, NULL }, //D172 + { PJ_3, NULL, NULL, NULL }, //D173 + { PJ_4, NULL, NULL, NULL }, //D174 + { PJ_5, NULL, NULL, NULL }, //D175 + { PJ_6, NULL, NULL, NULL }, //D176 + { PJ_7, NULL, NULL, NULL }, //D177 + { PJ_8, NULL, NULL, NULL }, //D178 + { PJ_9, NULL, NULL, NULL }, //D179 + { PJ_10, NULL, NULL, NULL }, //D180 + { PJ_11, NULL, NULL, NULL }, //D181 + { PJ_12, NULL, NULL, NULL }, //D182 + { PJ_13, NULL, NULL, NULL }, //D183 + { PJ_14, NULL, NULL, NULL }, //D184 + { PJ_15, NULL, NULL, NULL }, //D185 + { PK_0, NULL, NULL, NULL }, //D186 + { PK_1, NULL, NULL, NULL }, //D187 + { PK_2, NULL, NULL, NULL }, //D188 + { PK_3, NULL, NULL, NULL }, //D189 + { PK_4, NULL, NULL, NULL }, //D190 + { PK_5, NULL, NULL, NULL }, //D191 + { PK_6, NULL, NULL, NULL }, //D192 + { PK_7, NULL, NULL, NULL }, //D193 }; extern "C" { @@ -258,15 +254,18 @@ class SecureQSPIFBlockDevice: public QSPIFBlockDevice { static uint8_t *_boardInfo = (uint8_t*)(0x801F000); static bool has_otp_info = false; +static SecureQSPIFBlockDevice secure_root; + // 8Kbit secure OTP area (on MX25L12833F) bool getSecureFlashData() { - static PortentaBoardInfo info; - static SecureQSPIFBlockDevice secure_root; + static PortentaBoardInfo* info = new PortentaBoardInfo(); secure_root.init(); - auto ret = secure_root.readSecure(&info, 0, sizeof(PortentaBoardInfo)); - if (info.magic == OTP_QSPI_MAGIC) { - _boardInfo = (uint8_t*)&info; + auto ret = secure_root.readSecure(info, 0, sizeof(PortentaBoardInfo)); + if (info->magic == OTP_QSPI_MAGIC) { + _boardInfo = (uint8_t*)info; has_otp_info = true; + } else { + delete info; } secure_root.deinit(); return ret == 0; @@ -408,4 +407,4 @@ void bootM4() { #endif } -#endif \ No newline at end of file +#endif