diff --git a/Marlin/src/gcode/calibrate/M100.cpp b/Marlin/src/gcode/calibrate/M100.cpp index c2121f52d1..eed7800976 100644 --- a/Marlin/src/gcode/calibrate/M100.cpp +++ b/Marlin/src/gcode/calibrate/M100.cpp @@ -50,7 +50,7 @@ * * Also, there are two support functions that can be called from a developer's C code. * - * uint16_t check_for_free_memory_corruption(PGM_P const ptr); + * uint16_t check_for_free_memory_corruption(PGM_P const free_memory_start); * void M100_dump_routine(PGM_P const title, const char *start, const char *end); * * Initial version by Roxy-3D @@ -60,16 +60,57 @@ #define TEST_BYTE ((char) 0xE5) -extern char* __brkval; -extern size_t __heap_start, __heap_end, __flp; -extern char __bss_end; +#if defined(__AVR__) || IS_32BIT_TEENSY + + extern char __bss_end; + char* end_bss = &__bss_end; + char* free_memory_start = end_bss; + + + char* free_memory_end = 0; + char* stacklimit = 0; + char* heaplimit = 0; + + #define MEMORY_END_CORRECTION 0 + +#elif defined(TARGET_LPC1768) + + extern char __bss_end__; + extern char __StackLimit; + extern char __HeapLimit; + + char* end_bss = &__bss_end__; + char* stacklimit = &__StackLimit; + char* heaplimit = &__HeapLimit ; + + #define MEMORY_END_CORRECTION 0x200 + + char* free_memory_start = heaplimit; + char* free_memory_end = stacklimit - MEMORY_END_CORRECTION; + + +#elif defined(__SAM3X8E__) + + extern char _ebss; + + char* end_bss = &_ebss; + + char* free_memory_start = end_bss; + + char* free_memory_end = 0; + char* stacklimit = 0; + char* heaplimit = 0; + + #define MEMORY_END_CORRECTION 0x10000 // need to stay well below 0x20080000 or M100 F crashes + +#else + #error "M100 - unsupported CPU" +#endif // // Utility functions // -#define END_OF_HEAP() (__brkval ? __brkval : &__bss_end) - // Location of a variable on its stack frame. Returns a value above // the stack (once the function returns to the caller). char* top_of_stack() { @@ -78,9 +119,9 @@ char* top_of_stack() { } // Count the number of test bytes at the specified location. -inline int32_t count_test_bytes(const char * const ptr) { +inline int32_t count_test_bytes(const char * const start_free_memory) { for (uint32_t i = 0; i < 32000; i++) - if (char(ptr[i]) != TEST_BYTE) + if (char(start_free_memory[i]) != TEST_BYTE) return i - 1; return -1; @@ -93,35 +134,35 @@ inline int32_t count_test_bytes(const char * const ptr) { #if ENABLED(M100_FREE_MEMORY_DUMPER) /** * M100 D - * Dump the free memory block from __brkval to the stack pointer. + * Dump the free memory block from brkval to the stack pointer. * malloc() eats memory from the start of the block and the stack grows * up from the bottom of the block. Solid test bytes indicate nothing has * used that memory yet. There should not be anything but test bytes within * the block. If so, it may indicate memory corruption due to a bad pointer. * Unexpected bytes are flagged in the right column. */ - inline void dump_free_memory(const char *ptr, const char *sp) { + inline void dump_free_memory(const char *start_free_memory, const char *end_free_memory) { // // Start and end the dump on a nice 16 byte boundary // (even though the values are not 16-byte aligned). // - ptr = (char*)((ptr_int_t)((uint32_t)ptr & 0xFFFFFFF0)); // Align to 16-byte boundary - sp = (char*)((ptr_int_t)((uint32_t)sp | 0x0000000F)); // Align sp to the 15th byte (at or above sp) + start_free_memory = (char*)((ptr_int_t)((uint32_t)start_free_memory & 0xFFFFFFF0)); // Align to 16-byte boundary + end_free_memory = (char*)((ptr_int_t)((uint32_t)end_free_memory | 0x0000000F)); // Align end_free_memory to the 15th byte (at or above end_free_memory) // Dump command main loop - while (ptr < sp) { - print_hex_address(ptr); // Print the address + while (start_free_memory < end_free_memory) { + print_hex_address(start_free_memory); // Print the address SERIAL_CHAR(':'); for (uint8_t i = 0; i < 16; i++) { // and 16 data bytes if (i == 8) SERIAL_CHAR('-'); - print_hex_byte(ptr[i]); + print_hex_byte(start_free_memory[i]); SERIAL_CHAR(' '); } serial_delay(25); SERIAL_CHAR('|'); // Point out non test bytes for (uint8_t i = 0; i < 16; i++) { - char ccc = (char)ptr[i]; // cast to char before automatically casting to char on assignment, in case the compiler is broken - if (&ptr[i] >= (const char*)command_queue && &ptr[i] < (const char*)(command_queue + sizeof(command_queue))) { // Print out ASCII in the command buffer area + char ccc = (char)start_free_memory[i]; // cast to char before automatically casting to char on assignment, in case the compiler is broken + if (&start_free_memory[i] >= (const char*)command_queue && &start_free_memory[i] < (const char*)(command_queue + sizeof(command_queue))) { // Print out ASCII in the command buffer area if (!WITHIN(ccc, ' ', 0x7E)) ccc = ' '; } else { // If not in the command buffer area, flag bytes that don't match the test byte @@ -130,7 +171,7 @@ inline int32_t count_test_bytes(const char * const ptr) { SERIAL_CHAR(ccc); } SERIAL_EOL(); - ptr += 16; + start_free_memory += 16; serial_delay(25); idle(); } @@ -143,7 +184,7 @@ inline int32_t count_test_bytes(const char * const ptr) { // Round the start and end locations to produce full lines of output // start = (char*)((ptr_int_t)((uint32_t)start & 0xFFFFFFF0)); // Align to 16-byte boundary - end = (char*)((ptr_int_t)((uint32_t)end | 0x0000000F)); // Align sp to the 15th byte (at or above sp) + end = (char*)((ptr_int_t)((uint32_t)end | 0x0000000F)); // Align end_free_memory to the 15th byte (at or above end_free_memory) dump_free_memory(start, end); } @@ -152,17 +193,15 @@ inline int32_t count_test_bytes(const char * const ptr) { inline int check_for_free_memory_corruption(PGM_P const title) { serialprintPGM(title); - char *ptr = END_OF_HEAP(), *sp = top_of_stack(); - int n = sp - ptr; + char *start_free_memory = free_memory_start, *end_free_memory = free_memory_end; + int n = end_free_memory - start_free_memory; SERIAL_ECHOPAIR("\nfmc() n=", n); - SERIAL_ECHOPAIR("\n&__brkval: ", hex_address(&__brkval)); - SERIAL_ECHOPAIR("=", hex_address(__brkval)); - SERIAL_ECHOPAIR("\n__bss_end: ", hex_address(&__bss_end)); - SERIAL_ECHOPAIR(" sp=", hex_address(sp)); + SERIAL_ECHOPAIR("\nfree_memory_start=", hex_address(free_memory_start)); + SERIAL_ECHOLNPAIR(" end_free_memory=", hex_address(end_free_memory)); - if (sp < ptr) { - SERIAL_ECHOPGM(" sp < Heap "); + if (end_free_memory < start_free_memory) { + SERIAL_ECHOPGM(" end_free_memory < Heap "); // SET_INPUT_PULLUP(63); // if the developer has a switch wired up to their controller board // safe_delay(5); // this code can be enabled to pause the display as soon as the // while ( READ(63)) // malfunction is detected. It is currently defaulting to a switch @@ -172,29 +211,29 @@ inline int check_for_free_memory_corruption(PGM_P const title) { // idle(); serial_delay(20); #if ENABLED(M100_FREE_MEMORY_DUMPER) - M100_dump_routine(PSTR(" Memory corruption detected with sp 8) { // SERIAL_ECHOPAIR("Found ", j); - // SERIAL_ECHOLNPAIR(" bytes free at ", hex_address(ptr + i)); + // SERIAL_ECHOLNPAIR(" bytes free at ", hex_address(start_free_memory + i)); i += j; block_cnt++; SERIAL_ECHOPAIR(" (", block_cnt); SERIAL_ECHOPAIR(") found=", j); - SERIAL_ECHOPGM(" "); + SERIAL_ECHOLNPGM(" "); } } } SERIAL_ECHOPAIR(" block_found=", block_cnt); - if (block_cnt != 1 || __brkval != nullptr) + if (block_cnt != 1) SERIAL_ECHOLNPGM("\nMemory Corruption detected in free memory area."); if (block_cnt == 0) // Make sure the special case of no free blocks shows up as an @@ -215,12 +254,12 @@ inline int check_for_free_memory_corruption(PGM_P const title) { * Return the number of free bytes in the memory pool, * with other vital statistics defining the pool. */ -inline void free_memory_pool_report(char * const ptr, const int32_t size) { +inline void free_memory_pool_report(char * const start_free_memory, const int32_t size) { int32_t max_cnt = -1, block_cnt = 0; char *max_addr = nullptr; // Find the longest block of test bytes in the buffer for (int32_t i = 0; i < size; i++) { - char *addr = ptr + i; + char *addr = start_free_memory + i; if (*addr == TEST_BYTE) { const int32_t j = count_test_bytes(addr); if (j > 8) { @@ -249,14 +288,14 @@ inline void free_memory_pool_report(char * const ptr, const int32_t size) { * Corrupt locations in the free memory pool and report the corrupt addresses. * This is useful to check the correctness of the M100 D and the M100 F commands. */ - inline void corrupt_free_memory(char *ptr, const uint32_t size) { - ptr += 8; - const uint32_t near_top = top_of_stack() - ptr - 250, // -250 to avoid interrupt activity that's altered the stack. + inline void corrupt_free_memory(char *start_free_memory, const uint32_t size) { + start_free_memory += 8; + const uint32_t near_top = top_of_stack() - start_free_memory - 250, // -250 to avoid interrupt activity that's altered the stack. j = near_top / (size + 1); SERIAL_ECHOLNPGM("Corrupting free memory block.\n"); for (uint32_t i = 1; i <= size; i++) { - char * const addr = ptr + i * j; + char * const addr = start_free_memory + i * j; *addr = i; SERIAL_ECHOPAIR("\nCorrupting address: ", hex_address(addr)); } @@ -268,7 +307,7 @@ inline void free_memory_pool_report(char * const ptr, const int32_t size) { * M100 I * Init memory for the M100 tests. (Automatically applied on the first M100.) */ -inline void init_free_memory(char *ptr, int32_t size) { +inline void init_free_memory(char *start_free_memory, int32_t size) { SERIAL_ECHOLNPGM("Initializing free memory block.\n\n"); size -= 250; // -250 to avoid interrupt activity that's altered the stack. @@ -277,17 +316,17 @@ inline void init_free_memory(char *ptr, int32_t size) { return; } - ptr += 8; // move a few bytes away from the heap just because we don't want + start_free_memory += 8; // move a few bytes away from the heap just because we don't want // to be altering memory that close to it. - memset(ptr, TEST_BYTE, size); + memset(start_free_memory, TEST_BYTE, size); SERIAL_ECHO(size); SERIAL_ECHOLNPGM(" bytes of memory initialized.\n"); for (int32_t i = 0; i < size; i++) { - if (ptr[i] != TEST_BYTE) { - SERIAL_ECHOPAIR("? address : ", hex_address(ptr + i)); - SERIAL_ECHOLNPAIR("=", hex_byte(ptr[i])); + if (start_free_memory[i] != TEST_BYTE) { + SERIAL_ECHOPAIR("? address : ", hex_address(start_free_memory + i)); + SERIAL_ECHOLNPAIR("=", hex_byte(start_free_memory[i])); SERIAL_EOL(); } } @@ -297,33 +336,36 @@ inline void init_free_memory(char *ptr, int32_t size) { * M100: Free Memory Check */ void GcodeSuite::M100() { - SERIAL_ECHOPAIR("\n__brkval : ", hex_address(__brkval)); - SERIAL_ECHOPAIR("\n__bss_end : ", hex_address(&__bss_end)); - char *ptr = END_OF_HEAP(), *sp = top_of_stack(); - - SERIAL_ECHOPAIR("\nstart of free space : ", hex_address(ptr)); - SERIAL_ECHOLNPAIR("\nStack Pointer : ", hex_address(sp)); + char *sp = top_of_stack(); + if (!free_memory_end) free_memory_end = sp - MEMORY_END_CORRECTION; + SERIAL_ECHOPAIR("\nbss_end : ", hex_address(end_bss)); + if (heaplimit) SERIAL_ECHOPAIR("\n__heaplimit : ", hex_address(heaplimit )); + SERIAL_ECHOPAIR("\nfree_memory_start : ", hex_address(free_memory_start)); + if (stacklimit) SERIAL_ECHOPAIR("\n__stacklimit : ", hex_address(stacklimit)); + SERIAL_ECHOPAIR("\nfree_memory_end : ", hex_address(free_memory_end )); + if (MEMORY_END_CORRECTION) SERIAL_ECHOPAIR("\nMEMORY_END_CORRECTION: ", MEMORY_END_CORRECTION ); + SERIAL_ECHOLNPAIR("\nStack Pointer : ", hex_address(sp)); // Always init on the first invocation of M100 static bool m100_not_initialized = true; if (m100_not_initialized || parser.seen('I')) { m100_not_initialized = false; - init_free_memory(ptr, sp - ptr); + init_free_memory(free_memory_start, free_memory_end - free_memory_start); } #if ENABLED(M100_FREE_MEMORY_DUMPER) if (parser.seen('D')) - return dump_free_memory(ptr, sp); + return dump_free_memory(free_memory_start, free_memory_end); #endif if (parser.seen('F')) - return free_memory_pool_report(ptr, sp - ptr); + return free_memory_pool_report(free_memory_start, free_memory_end - free_memory_start); #if ENABLED(M100_FREE_MEMORY_CORRUPTOR) if (parser.seen('C')) - return corrupt_free_memory(ptr, parser.value_int()); + return corrupt_free_memory(free_memory_start, parser.value_int()); #endif }