|
@@ -38,6 +38,11 @@
|
38
|
38
|
* M100 C x Corrupts x locations within the free memory block. This is useful to check the
|
39
|
39
|
* correctness of the M100 F and M100 D commands.
|
40
|
40
|
*
|
|
41
|
+ * Also, there are two support functions that can be called from a developer's C code.
|
|
42
|
+ *
|
|
43
|
+ * uint16_t check_for_free_memory_corruption(char * const ptr);
|
|
44
|
+ * void M100_dump_free_memory(char *ptr, char *sp);
|
|
45
|
+ *
|
41
|
46
|
* Initial version by Roxy-3D
|
42
|
47
|
*/
|
43
|
48
|
#define M100_FREE_MEMORY_DUMPER // Enable for the `M110 D` Dump sub-command
|
|
@@ -47,7 +52,7 @@
|
47
|
52
|
|
48
|
53
|
#if ENABLED(M100_FREE_MEMORY_WATCHER)
|
49
|
54
|
|
50
|
|
-#define TEST_BYTE 0xE5
|
|
55
|
+#define TEST_BYTE ((uint8_t) 0xE5)
|
51
|
56
|
|
52
|
57
|
extern char* __brkval;
|
53
|
58
|
extern size_t __heap_start, __heap_end, __flp;
|
|
@@ -61,6 +66,7 @@ extern char __bss_end;
|
61
|
66
|
//
|
62
|
67
|
|
63
|
68
|
#define END_OF_HEAP() (__brkval ? __brkval : &__bss_end)
|
|
69
|
+int check_for_free_memory_corruption(char *title);
|
64
|
70
|
|
65
|
71
|
// Location of a variable on its stack frame. Returns a value above
|
66
|
72
|
// the stack (once the function returns to the caller).
|
|
@@ -70,7 +76,7 @@ char* top_of_stack() {
|
70
|
76
|
}
|
71
|
77
|
|
72
|
78
|
// Count the number of test bytes at the specified location.
|
73
|
|
-int16_t count_test_bytes(const char * const ptr) {
|
|
79
|
+int16_t count_test_bytes(const uint8_t * const ptr) {
|
74
|
80
|
for (uint16_t i = 0; i < 32000; i++)
|
75
|
81
|
if (ptr[i] != TEST_BYTE)
|
76
|
82
|
return i - 1;
|
|
@@ -78,27 +84,6 @@ int16_t count_test_bytes(const char * const ptr) {
|
78
|
84
|
return -1;
|
79
|
85
|
}
|
80
|
86
|
|
81
|
|
-// Return a count of free memory blocks.
|
82
|
|
-uint16_t free_memory_is_corrupted(char * const ptr, const uint16_t size) {
|
83
|
|
- // Find the longest block of test bytes in the given buffer
|
84
|
|
- uint16_t block_cnt = 0;
|
85
|
|
- for (uint16_t i = 0; i < size; i++) {
|
86
|
|
- if (ptr[i] == TEST_BYTE) {
|
87
|
|
- const uint16_t j = count_test_bytes(ptr + i);
|
88
|
|
- if (j > 8) {
|
89
|
|
- //SERIAL_ECHOPAIR("Found ", j);
|
90
|
|
- //SERIAL_ECHOLNPAIR(" bytes free at 0x", hex_word((uint16_t)ptr + i));
|
91
|
|
- i += j;
|
92
|
|
- block_cnt++;
|
93
|
|
- }
|
94
|
|
- }
|
95
|
|
- }
|
96
|
|
- //if (block_cnt > 1) {
|
97
|
|
- // SERIAL_ECHOLNPGM("\nMemory Corruption detected in free memory area.");
|
98
|
|
- // SERIAL_ECHOLNPAIR("\nLargest free block is ", max_cnt);
|
99
|
|
- //}
|
100
|
|
- return block_cnt;
|
101
|
|
-}
|
102
|
87
|
|
103
|
88
|
//
|
104
|
89
|
// M100 sub-commands
|
|
@@ -114,13 +99,13 @@ uint16_t free_memory_is_corrupted(char * const ptr, const uint16_t size) {
|
114
|
99
|
* the block. If so, it may indicate memory corruption due to a bad pointer.
|
115
|
100
|
* Unexpected bytes are flagged in the right column.
|
116
|
101
|
*/
|
117
|
|
- void dump_free_memory(char *ptr, char *sp) {
|
|
102
|
+ void dump_free_memory(uint8_t *ptr, uint8_t *sp) {
|
118
|
103
|
//
|
119
|
104
|
// Start and end the dump on a nice 16 byte boundary
|
120
|
105
|
// (even though the values are not 16-byte aligned).
|
121
|
106
|
//
|
122
|
|
- ptr = (char*)((uint16_t)ptr & 0xFFF0); // Align to 16-byte boundary
|
123
|
|
- sp = (char*)((uint16_t)sp | 0x000F); // Align sp to the 15th byte (at or above sp)
|
|
107
|
+ ptr = (uint8_t *)((uint16_t)ptr & 0xFFF0); // Align to 16-byte boundary
|
|
108
|
+ sp = (uint8_t *)((uint16_t)sp | 0x000F); // Align sp to the 15th byte (at or above sp)
|
124
|
109
|
|
125
|
110
|
// Dump command main loop
|
126
|
111
|
while (ptr < sp) {
|
|
@@ -131,14 +116,30 @@ uint16_t free_memory_is_corrupted(char * const ptr, const uint16_t size) {
|
131
|
116
|
print_hex_byte(ptr[i]);
|
132
|
117
|
SERIAL_CHAR(' ');
|
133
|
118
|
}
|
|
119
|
+ safe_delay(25);
|
134
|
120
|
SERIAL_CHAR('|'); // Point out non test bytes
|
135
|
121
|
for (uint8_t i = 0; i < 16; i++)
|
136
|
122
|
SERIAL_CHAR(ptr[i] == TEST_BYTE ? ' ' : '?');
|
137
|
123
|
SERIAL_EOL;
|
138
|
124
|
ptr += 16;
|
|
125
|
+ safe_delay(25);
|
139
|
126
|
idle();
|
140
|
127
|
}
|
141
|
128
|
}
|
|
129
|
+
|
|
130
|
+void M100_dump_routine( char *title, char *start, char *end) {
|
|
131
|
+unsigned char c;
|
|
132
|
+int i;
|
|
133
|
+
|
|
134
|
+//
|
|
135
|
+// Round the start and end locations to produce full lines of output
|
|
136
|
+//
|
|
137
|
+ start = (char*) ((uint16_t) start & 0xfff0);
|
|
138
|
+ end = (char*) ((uint16_t) end | 0x000f);
|
|
139
|
+
|
|
140
|
+ SERIAL_ECHOLN(title);
|
|
141
|
+ dump_free_memory( start, end );
|
|
142
|
+}
|
142
|
143
|
#endif // M100_FREE_MEMORY_DUMPER
|
143
|
144
|
|
144
|
145
|
/**
|
|
@@ -172,7 +173,7 @@ void free_memory_pool_report(const char * const ptr, const uint16_t size) {
|
172
|
173
|
SERIAL_ECHOPAIR("\nLargest free block is ", max_cnt);
|
173
|
174
|
SERIAL_ECHOLNPAIR(" bytes at 0x", hex_word((uint16_t)max_addr));
|
174
|
175
|
}
|
175
|
|
- SERIAL_ECHOLNPAIR("free_memory_is_corrupted() = ", free_memory_is_corrupted(ptr, size));
|
|
176
|
+ SERIAL_ECHOLNPAIR("check_for_free_memory_corruption() = ", check_for_free_memory_corruption("M100 F "));
|
176
|
177
|
}
|
177
|
178
|
|
178
|
179
|
#if ENABLED(M100_FREE_MEMORY_CORRUPTOR)
|
|
@@ -202,13 +203,17 @@ void free_memory_pool_report(const char * const ptr, const uint16_t size) {
|
202
|
203
|
* M100 I
|
203
|
204
|
* Init memory for the M100 tests. (Automatically applied on the first M100.)
|
204
|
205
|
*/
|
205
|
|
-void init_free_memory(char *ptr, int16_t size) {
|
|
206
|
+void init_free_memory(uint8_t *ptr, int16_t size) {
|
206
|
207
|
SERIAL_ECHOLNPGM("Initializing free memory block.\n\n");
|
207
|
208
|
|
208
|
209
|
size -= 250; // -250 to avoid interrupt activity that's altered the stack.
|
209
|
|
- if (size < 0) return;
|
|
210
|
+ if (size < 0) {
|
|
211
|
+ SERIAL_ECHOLNPGM("Unable to initialize.\n");
|
|
212
|
+ return;
|
|
213
|
+ }
|
210
|
214
|
|
211
|
|
- ptr += 8;
|
|
215
|
+ ptr += 8; // move a few bytes away from the heap just because we don't want
|
|
216
|
+ // to be altering memory that close to it.
|
212
|
217
|
memset(ptr, TEST_BYTE, size);
|
213
|
218
|
|
214
|
219
|
SERIAL_ECHO(size);
|
|
@@ -217,8 +222,7 @@ void init_free_memory(char *ptr, int16_t size) {
|
217
|
222
|
for (uint16_t i = 0; i < size; i++) {
|
218
|
223
|
if (ptr[i] != TEST_BYTE) {
|
219
|
224
|
SERIAL_ECHOPAIR("? address : 0x", hex_word((uint16_t)ptr + i));
|
220
|
|
- SERIAL_ECHOPAIR("=", hex_byte(ptr[i]));
|
221
|
|
- SERIAL_EOL; SERIAL_EOL;
|
|
225
|
+ SERIAL_ECHOLNPAIR("=", hex_byte(ptr[i]));
|
222
|
226
|
}
|
223
|
227
|
}
|
224
|
228
|
}
|
|
@@ -228,9 +232,9 @@ void init_free_memory(char *ptr, int16_t size) {
|
228
|
232
|
*/
|
229
|
233
|
void gcode_M100() {
|
230
|
234
|
SERIAL_ECHOPAIR("\n__brkval : 0x", hex_word((uint16_t)__brkval));
|
231
|
|
- SERIAL_ECHOPAIR("\n__bss_end : 0x", hex_word((uint16_t)&__bss_end));
|
|
235
|
+ SERIAL_ECHOPAIR("\n__bss_end: 0x", hex_word((uint16_t)&__bss_end));
|
232
|
236
|
|
233
|
|
- char *ptr = END_OF_HEAP(), *sp = top_of_stack();
|
|
237
|
+ uint8_t *ptr = END_OF_HEAP(), *sp = top_of_stack();
|
234
|
238
|
|
235
|
239
|
SERIAL_ECHOPAIR("\nstart of free space : 0x", hex_word((uint16_t)ptr));
|
236
|
240
|
SERIAL_ECHOLNPAIR("\nStack Pointer : 0x", hex_word((uint16_t)sp));
|
|
@@ -243,10 +247,8 @@ void gcode_M100() {
|
243
|
247
|
}
|
244
|
248
|
|
245
|
249
|
#if ENABLED(M100_FREE_MEMORY_DUMPER)
|
246
|
|
-
|
247
|
250
|
if (code_seen('D'))
|
248
|
251
|
return dump_free_memory(ptr, sp);
|
249
|
|
-
|
250
|
252
|
#endif
|
251
|
253
|
|
252
|
254
|
if (code_seen('F'))
|
|
@@ -260,4 +262,67 @@ void gcode_M100() {
|
260
|
262
|
#endif
|
261
|
263
|
}
|
262
|
264
|
|
|
265
|
+int check_for_free_memory_corruption(char *title) {
|
|
266
|
+ char *sp, *ptr;
|
|
267
|
+ int block_cnt = 0, i, j, n;
|
|
268
|
+
|
|
269
|
+ SERIAL_ECHO(title);
|
|
270
|
+
|
|
271
|
+ ptr = __brkval ? __brkval : &__bss_end;
|
|
272
|
+ sp = top_of_stack();
|
|
273
|
+
|
|
274
|
+ n = sp - ptr;
|
|
275
|
+ SERIAL_ECHOPAIR("\nfmc() n=", n);
|
|
276
|
+ SERIAL_ECHOPAIR("\n&__brkval: 0x", hex_word((uint16_t)&__brkval));
|
|
277
|
+ SERIAL_ECHOPAIR("=0x", hex_word((uint16_t)__brkval));
|
|
278
|
+ SERIAL_ECHOPAIR("\n__bss_end: 0x", hex_word((uint16_t)&__bss_end));
|
|
279
|
+ SERIAL_ECHOPAIR(" sp=", hex_word(sp));
|
|
280
|
+
|
|
281
|
+ if (sp < ptr) {
|
|
282
|
+ SERIAL_ECHOPGM(" sp < Heap ");
|
|
283
|
+// SET_INPUT_PULLUP(63); // if the developer has a switch wired up to their controller board
|
|
284
|
+// safe_delay(5); // this code can be enabled to pause the display as soon as the
|
|
285
|
+// while ( READ(63)) // malfunction is detected. It is currently defaulting to a switch
|
|
286
|
+// idle(); // being on pin-63 which is unassigend and available on most controller
|
|
287
|
+// safe_delay(20); // boards.
|
|
288
|
+// while ( !READ(63))
|
|
289
|
+// idle();
|
|
290
|
+ safe_delay(20);
|
|
291
|
+ M100_dump_routine( " Memory corruption detected with sp<Heap\n", (char *)0x1b80, 0x21ff );
|
|
292
|
+ }
|
|
293
|
+
|
|
294
|
+ // Scan through the range looking for the biggest block of 0xE5's we can find
|
|
295
|
+ for (i = 0; i < n; i++) {
|
|
296
|
+ if (*(ptr + i) == (char)0xe5) {
|
|
297
|
+ j = count_test_bytes(ptr + i);
|
|
298
|
+ if (j > 8) {
|
|
299
|
+// SERIAL_ECHOPAIR("Found ", j);
|
|
300
|
+// SERIAL_ECHOLNPAIR(" bytes free at 0x", hex_word((uint16_t)(ptr + i)));
|
|
301
|
+
|
|
302
|
+ i += j;
|
|
303
|
+ block_cnt++;
|
|
304
|
+ SERIAL_ECHOPAIR(" (", block_cnt);
|
|
305
|
+ SERIAL_ECHOPAIR(") found=", j);
|
|
306
|
+ SERIAL_ECHOPGM(" ");
|
|
307
|
+ }
|
|
308
|
+ }
|
|
309
|
+ }
|
|
310
|
+ SERIAL_ECHOPAIR(" block_found=", block_cnt);
|
|
311
|
+
|
|
312
|
+ if ((block_cnt!=1) || (__brkval != 0x0000))
|
|
313
|
+ SERIAL_ECHOLNPGM("\nMemory Corruption detected in free memory area.");
|
|
314
|
+
|
|
315
|
+ if ((block_cnt==0)) // Make sure the special case of no free blocks shows up as an
|
|
316
|
+ block_cnt = -1; // error to the calling code!
|
|
317
|
+
|
|
318
|
+ if (block_cnt==1) {
|
|
319
|
+ SERIAL_ECHOPGM(" return=0\n"); // if the block_cnt is 1, nothing has broken up the free memory
|
|
320
|
+ return 0; // area and it is appropriate to say 'no corruption'.
|
|
321
|
+ }
|
|
322
|
+ SERIAL_ECHOPGM(" return=true\n");
|
|
323
|
+ return block_cnt;
|
|
324
|
+ }
|
|
325
|
+
|
263
|
326
|
#endif // M100_FREE_MEMORY_WATCHER
|
|
327
|
+
|
|
328
|
+
|