|
@@ -50,7 +50,7 @@
|
50
|
50
|
*
|
51
|
51
|
* Also, there are two support functions that can be called from a developer's C code.
|
52
|
52
|
*
|
53
|
|
- * uint16_t check_for_free_memory_corruption(PGM_P const ptr);
|
|
53
|
+ * uint16_t check_for_free_memory_corruption(PGM_P const free_memory_start);
|
54
|
54
|
* void M100_dump_routine(PGM_P const title, const char *start, const char *end);
|
55
|
55
|
*
|
56
|
56
|
* Initial version by Roxy-3D
|
|
@@ -60,16 +60,57 @@
|
60
|
60
|
|
61
|
61
|
#define TEST_BYTE ((char) 0xE5)
|
62
|
62
|
|
63
|
|
-extern char* __brkval;
|
64
|
|
-extern size_t __heap_start, __heap_end, __flp;
|
65
|
|
-extern char __bss_end;
|
|
63
|
+#if defined(__AVR__) || IS_32BIT_TEENSY
|
|
64
|
+
|
|
65
|
+ extern char __bss_end;
|
|
66
|
+ char* end_bss = &__bss_end;
|
|
67
|
+ char* free_memory_start = end_bss;
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+ char* free_memory_end = 0;
|
|
71
|
+ char* stacklimit = 0;
|
|
72
|
+ char* heaplimit = 0;
|
|
73
|
+
|
|
74
|
+ #define MEMORY_END_CORRECTION 0
|
|
75
|
+
|
|
76
|
+#elif defined(TARGET_LPC1768)
|
|
77
|
+
|
|
78
|
+ extern char __bss_end__;
|
|
79
|
+ extern char __StackLimit;
|
|
80
|
+ extern char __HeapLimit;
|
|
81
|
+
|
|
82
|
+ char* end_bss = &__bss_end__;
|
|
83
|
+ char* stacklimit = &__StackLimit;
|
|
84
|
+ char* heaplimit = &__HeapLimit ;
|
|
85
|
+
|
|
86
|
+ #define MEMORY_END_CORRECTION 0x200
|
|
87
|
+
|
|
88
|
+ char* free_memory_start = heaplimit;
|
|
89
|
+ char* free_memory_end = stacklimit - MEMORY_END_CORRECTION;
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+#elif defined(__SAM3X8E__)
|
|
93
|
+
|
|
94
|
+ extern char _ebss;
|
|
95
|
+
|
|
96
|
+ char* end_bss = &_ebss;
|
|
97
|
+
|
|
98
|
+ char* free_memory_start = end_bss;
|
|
99
|
+
|
|
100
|
+ char* free_memory_end = 0;
|
|
101
|
+ char* stacklimit = 0;
|
|
102
|
+ char* heaplimit = 0;
|
|
103
|
+
|
|
104
|
+ #define MEMORY_END_CORRECTION 0x10000 // need to stay well below 0x20080000 or M100 F crashes
|
|
105
|
+
|
|
106
|
+#else
|
|
107
|
+ #error "M100 - unsupported CPU"
|
|
108
|
+#endif
|
66
|
109
|
|
67
|
110
|
//
|
68
|
111
|
// Utility functions
|
69
|
112
|
//
|
70
|
113
|
|
71
|
|
-#define END_OF_HEAP() (__brkval ? __brkval : &__bss_end)
|
72
|
|
-
|
73
|
114
|
// Location of a variable on its stack frame. Returns a value above
|
74
|
115
|
// the stack (once the function returns to the caller).
|
75
|
116
|
char* top_of_stack() {
|
|
@@ -78,9 +119,9 @@ char* top_of_stack() {
|
78
|
119
|
}
|
79
|
120
|
|
80
|
121
|
// Count the number of test bytes at the specified location.
|
81
|
|
-inline int32_t count_test_bytes(const char * const ptr) {
|
|
122
|
+inline int32_t count_test_bytes(const char * const start_free_memory) {
|
82
|
123
|
for (uint32_t i = 0; i < 32000; i++)
|
83
|
|
- if (char(ptr[i]) != TEST_BYTE)
|
|
124
|
+ if (char(start_free_memory[i]) != TEST_BYTE)
|
84
|
125
|
return i - 1;
|
85
|
126
|
|
86
|
127
|
return -1;
|
|
@@ -93,35 +134,35 @@ inline int32_t count_test_bytes(const char * const ptr) {
|
93
|
134
|
#if ENABLED(M100_FREE_MEMORY_DUMPER)
|
94
|
135
|
/**
|
95
|
136
|
* M100 D
|
96
|
|
- * Dump the free memory block from __brkval to the stack pointer.
|
|
137
|
+ * Dump the free memory block from brkval to the stack pointer.
|
97
|
138
|
* malloc() eats memory from the start of the block and the stack grows
|
98
|
139
|
* up from the bottom of the block. Solid test bytes indicate nothing has
|
99
|
140
|
* used that memory yet. There should not be anything but test bytes within
|
100
|
141
|
* the block. If so, it may indicate memory corruption due to a bad pointer.
|
101
|
142
|
* Unexpected bytes are flagged in the right column.
|
102
|
143
|
*/
|
103
|
|
- inline void dump_free_memory(const char *ptr, const char *sp) {
|
|
144
|
+ inline void dump_free_memory(const char *start_free_memory, const char *end_free_memory) {
|
104
|
145
|
//
|
105
|
146
|
// Start and end the dump on a nice 16 byte boundary
|
106
|
147
|
// (even though the values are not 16-byte aligned).
|
107
|
148
|
//
|
108
|
|
- ptr = (char*)((ptr_int_t)((uint32_t)ptr & 0xFFFFFFF0)); // Align to 16-byte boundary
|
109
|
|
- sp = (char*)((ptr_int_t)((uint32_t)sp | 0x0000000F)); // Align sp to the 15th byte (at or above sp)
|
|
149
|
+ start_free_memory = (char*)((ptr_int_t)((uint32_t)start_free_memory & 0xFFFFFFF0)); // Align to 16-byte boundary
|
|
150
|
+ 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)
|
110
|
151
|
|
111
|
152
|
// Dump command main loop
|
112
|
|
- while (ptr < sp) {
|
113
|
|
- print_hex_address(ptr); // Print the address
|
|
153
|
+ while (start_free_memory < end_free_memory) {
|
|
154
|
+ print_hex_address(start_free_memory); // Print the address
|
114
|
155
|
SERIAL_CHAR(':');
|
115
|
156
|
for (uint8_t i = 0; i < 16; i++) { // and 16 data bytes
|
116
|
157
|
if (i == 8) SERIAL_CHAR('-');
|
117
|
|
- print_hex_byte(ptr[i]);
|
|
158
|
+ print_hex_byte(start_free_memory[i]);
|
118
|
159
|
SERIAL_CHAR(' ');
|
119
|
160
|
}
|
120
|
161
|
serial_delay(25);
|
121
|
162
|
SERIAL_CHAR('|'); // Point out non test bytes
|
122
|
163
|
for (uint8_t i = 0; i < 16; i++) {
|
123
|
|
- char ccc = (char)ptr[i]; // cast to char before automatically casting to char on assignment, in case the compiler is broken
|
124
|
|
- if (&ptr[i] >= (const char*)command_queue && &ptr[i] < (const char*)(command_queue + sizeof(command_queue))) { // Print out ASCII in the command buffer area
|
|
164
|
+ char ccc = (char)start_free_memory[i]; // cast to char before automatically casting to char on assignment, in case the compiler is broken
|
|
165
|
+ 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
|
125
|
166
|
if (!WITHIN(ccc, ' ', 0x7E)) ccc = ' ';
|
126
|
167
|
}
|
127
|
168
|
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) {
|
130
|
171
|
SERIAL_CHAR(ccc);
|
131
|
172
|
}
|
132
|
173
|
SERIAL_EOL();
|
133
|
|
- ptr += 16;
|
|
174
|
+ start_free_memory += 16;
|
134
|
175
|
serial_delay(25);
|
135
|
176
|
idle();
|
136
|
177
|
}
|
|
@@ -143,7 +184,7 @@ inline int32_t count_test_bytes(const char * const ptr) {
|
143
|
184
|
// Round the start and end locations to produce full lines of output
|
144
|
185
|
//
|
145
|
186
|
start = (char*)((ptr_int_t)((uint32_t)start & 0xFFFFFFF0)); // Align to 16-byte boundary
|
146
|
|
- end = (char*)((ptr_int_t)((uint32_t)end | 0x0000000F)); // Align sp to the 15th byte (at or above sp)
|
|
187
|
+ end = (char*)((ptr_int_t)((uint32_t)end | 0x0000000F)); // Align end_free_memory to the 15th byte (at or above end_free_memory)
|
147
|
188
|
dump_free_memory(start, end);
|
148
|
189
|
}
|
149
|
190
|
|
|
@@ -152,17 +193,15 @@ inline int32_t count_test_bytes(const char * const ptr) {
|
152
|
193
|
inline int check_for_free_memory_corruption(PGM_P const title) {
|
153
|
194
|
serialprintPGM(title);
|
154
|
195
|
|
155
|
|
- char *ptr = END_OF_HEAP(), *sp = top_of_stack();
|
156
|
|
- int n = sp - ptr;
|
|
196
|
+ char *start_free_memory = free_memory_start, *end_free_memory = free_memory_end;
|
|
197
|
+ int n = end_free_memory - start_free_memory;
|
157
|
198
|
|
158
|
199
|
SERIAL_ECHOPAIR("\nfmc() n=", n);
|
159
|
|
- SERIAL_ECHOPAIR("\n&__brkval: ", hex_address(&__brkval));
|
160
|
|
- SERIAL_ECHOPAIR("=", hex_address(__brkval));
|
161
|
|
- SERIAL_ECHOPAIR("\n__bss_end: ", hex_address(&__bss_end));
|
162
|
|
- SERIAL_ECHOPAIR(" sp=", hex_address(sp));
|
|
200
|
+ SERIAL_ECHOPAIR("\nfree_memory_start=", hex_address(free_memory_start));
|
|
201
|
+ SERIAL_ECHOLNPAIR(" end_free_memory=", hex_address(end_free_memory));
|
163
|
202
|
|
164
|
|
- if (sp < ptr) {
|
165
|
|
- SERIAL_ECHOPGM(" sp < Heap ");
|
|
203
|
+ if (end_free_memory < start_free_memory) {
|
|
204
|
+ SERIAL_ECHOPGM(" end_free_memory < Heap ");
|
166
|
205
|
// SET_INPUT_PULLUP(63); // if the developer has a switch wired up to their controller board
|
167
|
206
|
// safe_delay(5); // this code can be enabled to pause the display as soon as the
|
168
|
207
|
// 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) {
|
172
|
211
|
// idle();
|
173
|
212
|
serial_delay(20);
|
174
|
213
|
#if ENABLED(M100_FREE_MEMORY_DUMPER)
|
175
|
|
- M100_dump_routine(PSTR(" Memory corruption detected with sp<Heap\n"), (char*)0x1B80, (char*)0x21FF);
|
|
214
|
+ M100_dump_routine(PSTR(" Memory corruption detected with end_free_memory<Heap\n"), (char*)0x1B80, (char*)0x21FF);
|
176
|
215
|
#endif
|
177
|
216
|
}
|
178
|
217
|
|
179
|
218
|
// Scan through the range looking for the biggest block of 0xE5's we can find
|
180
|
219
|
int block_cnt = 0;
|
181
|
220
|
for (int i = 0; i < n; i++) {
|
182
|
|
- if (ptr[i] == TEST_BYTE) {
|
183
|
|
- int32_t j = count_test_bytes(ptr + i);
|
|
221
|
+ if (start_free_memory[i] == TEST_BYTE) {
|
|
222
|
+ int32_t j = count_test_bytes(start_free_memory + i);
|
184
|
223
|
if (j > 8) {
|
185
|
224
|
// SERIAL_ECHOPAIR("Found ", j);
|
186
|
|
- // SERIAL_ECHOLNPAIR(" bytes free at ", hex_address(ptr + i));
|
|
225
|
+ // SERIAL_ECHOLNPAIR(" bytes free at ", hex_address(start_free_memory + i));
|
187
|
226
|
i += j;
|
188
|
227
|
block_cnt++;
|
189
|
228
|
SERIAL_ECHOPAIR(" (", block_cnt);
|
190
|
229
|
SERIAL_ECHOPAIR(") found=", j);
|
191
|
|
- SERIAL_ECHOPGM(" ");
|
|
230
|
+ SERIAL_ECHOLNPGM(" ");
|
192
|
231
|
}
|
193
|
232
|
}
|
194
|
233
|
}
|
195
|
234
|
SERIAL_ECHOPAIR(" block_found=", block_cnt);
|
196
|
235
|
|
197
|
|
- if (block_cnt != 1 || __brkval != nullptr)
|
|
236
|
+ if (block_cnt != 1)
|
198
|
237
|
SERIAL_ECHOLNPGM("\nMemory Corruption detected in free memory area.");
|
199
|
238
|
|
200
|
239
|
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) {
|
215
|
254
|
* Return the number of free bytes in the memory pool,
|
216
|
255
|
* with other vital statistics defining the pool.
|
217
|
256
|
*/
|
218
|
|
-inline void free_memory_pool_report(char * const ptr, const int32_t size) {
|
|
257
|
+inline void free_memory_pool_report(char * const start_free_memory, const int32_t size) {
|
219
|
258
|
int32_t max_cnt = -1, block_cnt = 0;
|
220
|
259
|
char *max_addr = nullptr;
|
221
|
260
|
// Find the longest block of test bytes in the buffer
|
222
|
261
|
for (int32_t i = 0; i < size; i++) {
|
223
|
|
- char *addr = ptr + i;
|
|
262
|
+ char *addr = start_free_memory + i;
|
224
|
263
|
if (*addr == TEST_BYTE) {
|
225
|
264
|
const int32_t j = count_test_bytes(addr);
|
226
|
265
|
if (j > 8) {
|
|
@@ -249,14 +288,14 @@ inline void free_memory_pool_report(char * const ptr, const int32_t size) {
|
249
|
288
|
* Corrupt <num> locations in the free memory pool and report the corrupt addresses.
|
250
|
289
|
* This is useful to check the correctness of the M100 D and the M100 F commands.
|
251
|
290
|
*/
|
252
|
|
- inline void corrupt_free_memory(char *ptr, const uint32_t size) {
|
253
|
|
- ptr += 8;
|
254
|
|
- const uint32_t near_top = top_of_stack() - ptr - 250, // -250 to avoid interrupt activity that's altered the stack.
|
|
291
|
+ inline void corrupt_free_memory(char *start_free_memory, const uint32_t size) {
|
|
292
|
+ start_free_memory += 8;
|
|
293
|
+ const uint32_t near_top = top_of_stack() - start_free_memory - 250, // -250 to avoid interrupt activity that's altered the stack.
|
255
|
294
|
j = near_top / (size + 1);
|
256
|
295
|
|
257
|
296
|
SERIAL_ECHOLNPGM("Corrupting free memory block.\n");
|
258
|
297
|
for (uint32_t i = 1; i <= size; i++) {
|
259
|
|
- char * const addr = ptr + i * j;
|
|
298
|
+ char * const addr = start_free_memory + i * j;
|
260
|
299
|
*addr = i;
|
261
|
300
|
SERIAL_ECHOPAIR("\nCorrupting address: ", hex_address(addr));
|
262
|
301
|
}
|
|
@@ -268,7 +307,7 @@ inline void free_memory_pool_report(char * const ptr, const int32_t size) {
|
268
|
307
|
* M100 I
|
269
|
308
|
* Init memory for the M100 tests. (Automatically applied on the first M100.)
|
270
|
309
|
*/
|
271
|
|
-inline void init_free_memory(char *ptr, int32_t size) {
|
|
310
|
+inline void init_free_memory(char *start_free_memory, int32_t size) {
|
272
|
311
|
SERIAL_ECHOLNPGM("Initializing free memory block.\n\n");
|
273
|
312
|
|
274
|
313
|
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) {
|
277
|
316
|
return;
|
278
|
317
|
}
|
279
|
318
|
|
280
|
|
- ptr += 8; // move a few bytes away from the heap just because we don't want
|
|
319
|
+ start_free_memory += 8; // move a few bytes away from the heap just because we don't want
|
281
|
320
|
// to be altering memory that close to it.
|
282
|
|
- memset(ptr, TEST_BYTE, size);
|
|
321
|
+ memset(start_free_memory, TEST_BYTE, size);
|
283
|
322
|
|
284
|
323
|
SERIAL_ECHO(size);
|
285
|
324
|
SERIAL_ECHOLNPGM(" bytes of memory initialized.\n");
|
286
|
325
|
|
287
|
326
|
for (int32_t i = 0; i < size; i++) {
|
288
|
|
- if (ptr[i] != TEST_BYTE) {
|
289
|
|
- SERIAL_ECHOPAIR("? address : ", hex_address(ptr + i));
|
290
|
|
- SERIAL_ECHOLNPAIR("=", hex_byte(ptr[i]));
|
|
327
|
+ if (start_free_memory[i] != TEST_BYTE) {
|
|
328
|
+ SERIAL_ECHOPAIR("? address : ", hex_address(start_free_memory + i));
|
|
329
|
+ SERIAL_ECHOLNPAIR("=", hex_byte(start_free_memory[i]));
|
291
|
330
|
SERIAL_EOL();
|
292
|
331
|
}
|
293
|
332
|
}
|
|
@@ -297,33 +336,36 @@ inline void init_free_memory(char *ptr, int32_t size) {
|
297
|
336
|
* M100: Free Memory Check
|
298
|
337
|
*/
|
299
|
338
|
void GcodeSuite::M100() {
|
300
|
|
- SERIAL_ECHOPAIR("\n__brkval : ", hex_address(__brkval));
|
301
|
|
- SERIAL_ECHOPAIR("\n__bss_end : ", hex_address(&__bss_end));
|
302
|
|
-
|
303
|
|
- char *ptr = END_OF_HEAP(), *sp = top_of_stack();
|
304
|
339
|
|
305
|
|
- SERIAL_ECHOPAIR("\nstart of free space : ", hex_address(ptr));
|
306
|
|
- SERIAL_ECHOLNPAIR("\nStack Pointer : ", hex_address(sp));
|
|
340
|
+ char *sp = top_of_stack();
|
|
341
|
+ if (!free_memory_end) free_memory_end = sp - MEMORY_END_CORRECTION;
|
|
342
|
+ SERIAL_ECHOPAIR("\nbss_end : ", hex_address(end_bss));
|
|
343
|
+ if (heaplimit) SERIAL_ECHOPAIR("\n__heaplimit : ", hex_address(heaplimit ));
|
|
344
|
+ SERIAL_ECHOPAIR("\nfree_memory_start : ", hex_address(free_memory_start));
|
|
345
|
+ if (stacklimit) SERIAL_ECHOPAIR("\n__stacklimit : ", hex_address(stacklimit));
|
|
346
|
+ SERIAL_ECHOPAIR("\nfree_memory_end : ", hex_address(free_memory_end ));
|
|
347
|
+ if (MEMORY_END_CORRECTION) SERIAL_ECHOPAIR("\nMEMORY_END_CORRECTION: ", MEMORY_END_CORRECTION );
|
|
348
|
+ SERIAL_ECHOLNPAIR("\nStack Pointer : ", hex_address(sp));
|
307
|
349
|
|
308
|
350
|
// Always init on the first invocation of M100
|
309
|
351
|
static bool m100_not_initialized = true;
|
310
|
352
|
if (m100_not_initialized || parser.seen('I')) {
|
311
|
353
|
m100_not_initialized = false;
|
312
|
|
- init_free_memory(ptr, sp - ptr);
|
|
354
|
+ init_free_memory(free_memory_start, free_memory_end - free_memory_start);
|
313
|
355
|
}
|
314
|
356
|
|
315
|
357
|
#if ENABLED(M100_FREE_MEMORY_DUMPER)
|
316
|
358
|
if (parser.seen('D'))
|
317
|
|
- return dump_free_memory(ptr, sp);
|
|
359
|
+ return dump_free_memory(free_memory_start, free_memory_end);
|
318
|
360
|
#endif
|
319
|
361
|
|
320
|
362
|
if (parser.seen('F'))
|
321
|
|
- return free_memory_pool_report(ptr, sp - ptr);
|
|
363
|
+ return free_memory_pool_report(free_memory_start, free_memory_end - free_memory_start);
|
322
|
364
|
|
323
|
365
|
#if ENABLED(M100_FREE_MEMORY_CORRUPTOR)
|
324
|
366
|
|
325
|
367
|
if (parser.seen('C'))
|
326
|
|
- return corrupt_free_memory(ptr, parser.value_int());
|
|
368
|
+ return corrupt_free_memory(free_memory_start, parser.value_int());
|
327
|
369
|
|
328
|
370
|
#endif
|
329
|
371
|
}
|