From 1452902401970408f60c16ef878be620f4875a5a Mon Sep 17 00:00:00 2001 From: Adam Green Date: Sat, 7 Jan 2023 14:22:45 -0800 Subject: [PATCH 1/2] Upgrade MRI to version 1.5 This upgrades the version of the MRI library sources used by KernelDebug and ThreadDebug to the latest that I am actively supporting. Changes that will benefit both ThreadDebug and KernelDebug include: * I added the libraries/MRI/src/variants folder to hold the definition of g_memoryMapXml specific to each Arduino variant which supports MRI. Before these definitions were duplicated between ThreadDebug and KernelDebug. * Has cache fix to enable soft breakpoints for code running out of RAM. * Fixed cases where single stepping would sometimes hang if the code being stepped over caused a crash. * I have added a DebugSerial object which can be used in place of Serial and/or SerialUSB to send output to the GDB console during the development process. MRI contains changes which make sending such output to GDB more efficient so I added this DebugSerial object to take advantage of it. The ThreadDebug example has been modified to show using this object to allow Serial.print() calls when using ThreadDebug which previously caused problems. Some of the changes included in this version update will benefit ThreadDebug: * Platform_CommSendBuffer() is now overridden by ThreadDebug to send packets to GDB in one USB call instead of sending a byte at a time as it did before. * The original RTX OS handlers like SVCall, PendSV, and SysTick only need to be saved once, during init, and not each time that ThreadDebug's versions are switched in. * When running a test pass on ThreadDebug this time, I noticed that user threads weren't being locked as expected when I used the `set scheduler-locking step` command in GDB. I have always had this case in my test pass so I don't know how I didn't notice it was broken before. Anyway it is now fixed by making sure that the RTX idle thread is never allowed to remain frozen. If it has been requested by GDB to be frozen, it is thawed at one priority level higher than normal so that it stops all other frozen threads from running. Other changes might not be a direct benefit to ThreadDebug but they will be for KernelDebug: * Faults will now pend to DebugMon so that invalid memory accesses initiated from GDB will no longer result in double fault CPU hard hangs. This pending to DebugMon for faults was actually copied from behavior first created for ThreadDebug back in 2020. * Better handling of crashes the occur when the stack pointer becomes corrupted. Previously stacking exceptions could result in CPU hard hangs due to double faulting. * Now has better code to handle single stepping through critical sections. * Can now modify the current SP pointer from GDB. Probably not something most people would want to do though. Can also update the value of the PRIMASK, BASEPRI, FAULTMASK, and CONTROL special registers. Other important updates to MRI included in version 1.5 are: * Can now step into Standard C Library calls like memset() with no weird side effects. * MRI now supports running the DebugMon interrupt handler at priorities other than 0. This allows important code such as USB or Bluetooth stacks to run in the background while GDB/MRI are debugging lower priority code. I first explored this ability for ThreadDebug but now use it in other projects to do things like communicate with GDB over BLE. * Anywhere that the application under debug might want to call into MRI (semihosting, setting debugger hooks, etc), it now uses unique hardcoded `bkpt` instructions rather than just making function calls. This allows them to be called when MRI is installed as a separate boot loader on a device. * Unescaping of binary packet data sent from GDB has been pushed lower down into the software stack, to the packet layer. This is where it should have been done in the first place. Thanks go to @xiaoxiang781216, @icecream95, and @PetteriAimonen for their MRI contributions that are included in this update. --- libraries/KernelDebug/library.properties | 2 +- libraries/KernelDebug/src/KernelDebug.cpp | 95 ++- libraries/KernelDebug/src/KernelDebug.h | 23 + libraries/KernelDebug/src/armv7-m_asm.S | 144 ++-- libraries/MRI/library.properties | 2 +- .../MRI/src/architectures/armv7-m/armv7-m.h | 19 +- .../MRI/src/architectures/armv7-m/armv7-m.x | 613 ++++++++++++++---- .../MRI/src/architectures/armv7-m/debug_cm3.h | 3 + libraries/MRI/src/core/buffer.c | 36 +- libraries/MRI/src/core/buffer.h | 50 +- libraries/MRI/src/core/cmd_file.c | 2 +- libraries/MRI/src/core/cmd_memory.c | 15 +- libraries/MRI/src/core/cmd_query.c | 15 +- libraries/MRI/src/core/cmd_registers.c | 2 +- libraries/MRI/src/core/cmd_step.c | 13 +- libraries/MRI/src/core/cmd_thread.c | 2 +- libraries/MRI/src/core/cmd_vcont.c | 14 +- libraries/MRI/src/core/context.c | 4 +- libraries/MRI/src/core/core.h | 16 +- libraries/MRI/src/core/fileio.h | 62 +- libraries/MRI/src/core/gdb_console.c | 22 +- libraries/MRI/src/core/gdb_console.h | 10 +- libraries/MRI/src/core/libc.c | 141 ++++ libraries/MRI/src/core/libc.h | 35 + libraries/MRI/src/core/memory.c | 50 +- libraries/MRI/src/core/mri.c | 103 +-- libraries/MRI/src/core/mri.h | 3 +- libraries/MRI/src/core/packet.c | 120 ++-- libraries/MRI/src/core/packet.h | 12 +- libraries/MRI/src/core/platforms.h | 13 +- libraries/MRI/src/core/semihost.h | 5 +- .../MRI/src/core/{posix4win.h => signal.h} | 18 +- libraries/MRI/src/core/token.c | 12 +- libraries/MRI/src/core/version.h | 6 +- .../MRI/src/semihost/newlib/newlib_stubs.S | 140 ++++ .../MRI/src/semihost/newlib/newlib_stubs.h | 36 + .../MRI/src/semihost/newlib/semihost_newlib.c | 187 ++++++ libraries/MRI/src/semihost/semihost.c | 72 ++ libraries/MRI/src/variants/Nano_33_BLE.h | 27 + libraries/MRI/src/variants/Portenta_H7.h | 44 ++ libraries/MRI/src/variants/mri_variant.h | 27 + .../examples/ThreadDebug/ThreadDebug.ino | 10 +- libraries/ThreadDebug/library.properties | 2 +- libraries/ThreadDebug/src/ThreadDebug.cpp | 156 +++-- libraries/ThreadDebug/src/ThreadDebug.h | 31 +- libraries/ThreadDebug/src/ThreadDebug_asm.S | 2 +- 46 files changed, 1906 insertions(+), 510 deletions(-) create mode 100644 libraries/MRI/src/core/libc.c create mode 100644 libraries/MRI/src/core/libc.h rename libraries/MRI/src/core/{posix4win.h => signal.h} (82%) create mode 100644 libraries/MRI/src/semihost/newlib/newlib_stubs.S create mode 100644 libraries/MRI/src/semihost/newlib/newlib_stubs.h create mode 100644 libraries/MRI/src/semihost/newlib/semihost_newlib.c create mode 100644 libraries/MRI/src/semihost/semihost.c create mode 100644 libraries/MRI/src/variants/Nano_33_BLE.h create mode 100644 libraries/MRI/src/variants/Portenta_H7.h create mode 100644 libraries/MRI/src/variants/mri_variant.h 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. */ From f1ee3cac189f79e193ee5711c6777eb8fa3fb23d Mon Sep 17 00:00:00 2001 From: agdl Date: Tue, 14 Mar 2023 14:35:32 +0100 Subject: [PATCH 2/2] added arduino pin number --- variants/PORTENTA_H7_M7/variant.cpp | 371 ++++++++++++++-------------- 1 file changed, 185 insertions(+), 186 deletions(-) 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