1 /* 2 * Memory Test 3 * 4 * This is intended to test the system-mode code and ensure we properly 5 * behave across normal and unaligned accesses across several pages. 6 * We are not replicating memory tests for stuck bits and other 7 * hardware level failures but looking for issues with different size 8 * accesses when access is: 9 * 10 * - unaligned at various sizes (if -DCHECK_UNALIGNED set) 11 * - spanning a (system) page 12 * - sign extension when loading 13 */ 14 15 #include <stdint.h> 16 #include <stdbool.h> 17 #include <minilib.h> 18 19 #ifndef CHECK_UNALIGNED 20 # error "Target does not specify CHECK_UNALIGNED" 21 #endif 22 23 #define MEM_PAGE_SIZE 4096 /* nominal 4k "pages" */ 24 #define TEST_SIZE (MEM_PAGE_SIZE * 4) /* 4 pages */ 25 26 #define ARRAY_SIZE(x) ((sizeof(x) / sizeof((x)[0]))) 27 28 __attribute__((aligned(MEM_PAGE_SIZE))) 29 static uint8_t test_data[TEST_SIZE]; 30 31 typedef void (*init_ufn) (int offset); 32 typedef bool (*read_ufn) (int offset); 33 typedef bool (*read_sfn) (int offset, bool nf); 34 35 static void pdot(int count) 36 { 37 if (count % 128 == 0) { 38 ml_printf("."); 39 } 40 } 41 42 /* 43 * Helper macros for endian handling. 44 */ 45 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 46 #define BYTE_SHIFT(b, pos) (b << (pos * 8)) 47 #define BYTE_NEXT(b) ((b)++) 48 #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 49 #define BYTE_SHIFT(b, pos) (b << ((sizeof(b) - 1 - (pos)) * 8)) 50 #define BYTE_NEXT(b) (--(b)) 51 #else 52 #error Unsupported __BYTE_ORDER__ 53 #endif 54 55 /* 56 * Fill the data with ascending (for little-endian) or descending (for 57 * big-endian) value bytes. 58 */ 59 60 static void init_test_data_u8(int unused_offset) 61 { 62 uint8_t count = 0, *ptr = &test_data[0]; 63 int i; 64 (void)(unused_offset); 65 66 ml_printf("Filling test area with u8:"); 67 for (i = 0; i < TEST_SIZE; i++) { 68 *ptr++ = BYTE_NEXT(count); 69 pdot(i); 70 } 71 ml_printf("done\n"); 72 } 73 74 /* 75 * Fill the data with alternating positive and negative bytes. This 76 * should mean for reads larger than a byte all subsequent reads will 77 * stay either negative or positive. We never write 0. 78 */ 79 80 static inline uint8_t get_byte(int index, bool neg) 81 { 82 return neg ? (0xff << (index % 7)) : (0xff >> ((index % 6) + 1)); 83 } 84 85 static void init_test_data_s8(bool neg_first) 86 { 87 uint8_t top, bottom, *ptr = &test_data[0]; 88 int i; 89 90 ml_printf("Filling test area with s8 pairs (%s):", 91 neg_first ? "neg first" : "pos first"); 92 for (i = 0; i < TEST_SIZE / 2; i++) { 93 *ptr++ = get_byte(i, neg_first); 94 *ptr++ = get_byte(i, !neg_first); 95 pdot(i); 96 } 97 ml_printf("done\n"); 98 } 99 100 /* 101 * Zero the first few bytes of the test data in preparation for 102 * new offset values. 103 */ 104 static void reset_start_data(int offset) 105 { 106 uint32_t *ptr = (uint32_t *) &test_data[0]; 107 int i; 108 for (i = 0; i < offset; i++) { 109 *ptr++ = 0; 110 } 111 } 112 113 static void init_test_data_u16(int offset) 114 { 115 uint8_t count = 0; 116 uint16_t word, *ptr = (uint16_t *) &test_data[offset]; 117 const int max = (TEST_SIZE - offset) / sizeof(word); 118 int i; 119 120 ml_printf("Filling test area with u16 (offset %d, %p):", offset, ptr); 121 122 reset_start_data(offset); 123 124 for (i = 0; i < max; i++) { 125 uint16_t low = BYTE_NEXT(count), high = BYTE_NEXT(count); 126 word = BYTE_SHIFT(high, 1) | BYTE_SHIFT(low, 0); 127 *ptr++ = word; 128 pdot(i); 129 } 130 ml_printf("done @ %p\n", ptr); 131 } 132 133 static void init_test_data_u32(int offset) 134 { 135 uint8_t count = 0; 136 uint32_t word, *ptr = (uint32_t *) &test_data[offset]; 137 const int max = (TEST_SIZE - offset) / sizeof(word); 138 int i; 139 140 ml_printf("Filling test area with u32 (offset %d, %p):", offset, ptr); 141 142 reset_start_data(offset); 143 144 for (i = 0; i < max; i++) { 145 uint32_t b4 = BYTE_NEXT(count), b3 = BYTE_NEXT(count); 146 uint32_t b2 = BYTE_NEXT(count), b1 = BYTE_NEXT(count); 147 word = BYTE_SHIFT(b1, 3) | BYTE_SHIFT(b2, 2) | BYTE_SHIFT(b3, 1) | 148 BYTE_SHIFT(b4, 0); 149 *ptr++ = word; 150 pdot(i); 151 } 152 ml_printf("done @ %p\n", ptr); 153 } 154 155 static void init_test_data_u64(int offset) 156 { 157 uint8_t count = 0; 158 uint64_t word, *ptr = (uint64_t *) &test_data[offset]; 159 const int max = (TEST_SIZE - offset) / sizeof(word); 160 int i; 161 162 ml_printf("Filling test area with u64 (offset %d, %p):", offset, ptr); 163 164 reset_start_data(offset); 165 166 for (i = 0; i < max; i++) { 167 uint64_t b8 = BYTE_NEXT(count), b7 = BYTE_NEXT(count); 168 uint64_t b6 = BYTE_NEXT(count), b5 = BYTE_NEXT(count); 169 uint64_t b4 = BYTE_NEXT(count), b3 = BYTE_NEXT(count); 170 uint64_t b2 = BYTE_NEXT(count), b1 = BYTE_NEXT(count); 171 word = BYTE_SHIFT(b1, 7) | BYTE_SHIFT(b2, 6) | BYTE_SHIFT(b3, 5) | 172 BYTE_SHIFT(b4, 4) | BYTE_SHIFT(b5, 3) | BYTE_SHIFT(b6, 2) | 173 BYTE_SHIFT(b7, 1) | BYTE_SHIFT(b8, 0); 174 *ptr++ = word; 175 pdot(i); 176 } 177 ml_printf("done @ %p\n", ptr); 178 } 179 180 static bool read_test_data_u16(int offset) 181 { 182 uint16_t word, *ptr = (uint16_t *)&test_data[offset]; 183 int i; 184 const int max = (TEST_SIZE - offset) / sizeof(word); 185 186 ml_printf("Reading u16 from %#lx (offset %d):", ptr, offset); 187 188 for (i = 0; i < max; i++) { 189 uint8_t high, low; 190 word = *ptr++; 191 high = (word >> 8) & 0xff; 192 low = word & 0xff; 193 if (high < low && high != 0) { 194 ml_printf("Error %d < %d\n", high, low); 195 return false; 196 } else { 197 pdot(i); 198 } 199 200 } 201 ml_printf("done @ %p\n", ptr); 202 return true; 203 } 204 205 static bool read_test_data_u32(int offset) 206 { 207 uint32_t word, *ptr = (uint32_t *)&test_data[offset]; 208 int i; 209 const int max = (TEST_SIZE - offset) / sizeof(word); 210 211 ml_printf("Reading u32 from %#lx (offset %d):", ptr, offset); 212 213 for (i = 0; i < max; i++) { 214 uint8_t b1, b2, b3, b4; 215 int zeros = 0; 216 word = *ptr++; 217 218 b1 = word >> 24 & 0xff; 219 b2 = word >> 16 & 0xff; 220 b3 = word >> 8 & 0xff; 221 b4 = word & 0xff; 222 223 zeros += (b1 == 0 ? 1 : 0); 224 zeros += (b2 == 0 ? 1 : 0); 225 zeros += (b3 == 0 ? 1 : 0); 226 zeros += (b4 == 0 ? 1 : 0); 227 if (zeros > 1) { 228 ml_printf("Error @ %p, more zeros than expected: %d, %d, %d, %d", 229 ptr - 1, b1, b2, b3, b4); 230 return false; 231 } 232 233 if ((b1 < b2 && b1 != 0) || 234 (b2 < b3 && b2 != 0) || 235 (b3 < b4 && b3 != 0)) { 236 ml_printf("Error %d, %d, %d, %d", b1, b2, b3, b4); 237 return false; 238 } else { 239 pdot(i); 240 } 241 } 242 ml_printf("done @ %p\n", ptr); 243 return true; 244 } 245 246 static bool read_test_data_u64(int offset) 247 { 248 uint64_t word, *ptr = (uint64_t *)&test_data[offset]; 249 int i; 250 const int max = (TEST_SIZE - offset) / sizeof(word); 251 252 ml_printf("Reading u64 from %#lx (offset %d):", ptr, offset); 253 254 for (i = 0; i < max; i++) { 255 uint8_t b1, b2, b3, b4, b5, b6, b7, b8; 256 int zeros = 0; 257 word = *ptr++; 258 259 b1 = ((uint64_t) (word >> 56)) & 0xff; 260 b2 = ((uint64_t) (word >> 48)) & 0xff; 261 b3 = ((uint64_t) (word >> 40)) & 0xff; 262 b4 = (word >> 32) & 0xff; 263 b5 = (word >> 24) & 0xff; 264 b6 = (word >> 16) & 0xff; 265 b7 = (word >> 8) & 0xff; 266 b8 = (word >> 0) & 0xff; 267 268 zeros += (b1 == 0 ? 1 : 0); 269 zeros += (b2 == 0 ? 1 : 0); 270 zeros += (b3 == 0 ? 1 : 0); 271 zeros += (b4 == 0 ? 1 : 0); 272 zeros += (b5 == 0 ? 1 : 0); 273 zeros += (b6 == 0 ? 1 : 0); 274 zeros += (b7 == 0 ? 1 : 0); 275 zeros += (b8 == 0 ? 1 : 0); 276 if (zeros > 1) { 277 ml_printf("Error @ %p, more zeros than expected: %d, %d, %d, %d, %d, %d, %d, %d", 278 ptr - 1, b1, b2, b3, b4, b5, b6, b7, b8); 279 return false; 280 } 281 282 if ((b1 < b2 && b1 != 0) || 283 (b2 < b3 && b2 != 0) || 284 (b3 < b4 && b3 != 0) || 285 (b4 < b5 && b4 != 0) || 286 (b5 < b6 && b5 != 0) || 287 (b6 < b7 && b6 != 0) || 288 (b7 < b8 && b7 != 0)) { 289 ml_printf("Error %d, %d, %d, %d, %d, %d, %d, %d", 290 b1, b2, b3, b4, b5, b6, b7, b8); 291 return false; 292 } else { 293 pdot(i); 294 } 295 } 296 ml_printf("done @ %p\n", ptr); 297 return true; 298 } 299 300 /* Read the test data and verify at various offsets */ 301 read_ufn read_ufns[] = { read_test_data_u16, 302 read_test_data_u32, 303 read_test_data_u64 }; 304 305 bool do_unsigned_reads(int start_off) 306 { 307 int i; 308 bool ok = true; 309 310 for (i = 0; i < ARRAY_SIZE(read_ufns) && ok; i++) { 311 #if CHECK_UNALIGNED 312 int off; 313 for (off = start_off; off < 8 && ok; off++) { 314 ok = read_ufns[i](off); 315 } 316 #else 317 ok = read_ufns[i](start_off); 318 #endif 319 } 320 321 return ok; 322 } 323 324 static bool do_unsigned_test(init_ufn fn) 325 { 326 #if CHECK_UNALIGNED 327 bool ok = true; 328 int i; 329 for (i = 0; i < 8 && ok; i++) { 330 fn(i); 331 ok = do_unsigned_reads(i); 332 } 333 return ok; 334 #else 335 fn(0); 336 return do_unsigned_reads(0); 337 #endif 338 } 339 340 /* 341 * We need to ensure signed data is read into a larger data type to 342 * ensure that sign extension is working properly. 343 */ 344 345 static bool read_test_data_s8(int offset, bool neg_first) 346 { 347 int8_t *ptr = (int8_t *)&test_data[offset]; 348 int i; 349 const int max = (TEST_SIZE - offset) / 2; 350 351 ml_printf("Reading s8 pairs from %#lx (offset %d):", ptr, offset); 352 353 for (i = 0; i < max; i++) { 354 int16_t first, second; 355 bool ok; 356 first = *ptr++; 357 second = *ptr++; 358 359 if (neg_first && first < 0 && second > 0) { 360 pdot(i); 361 } else if (!neg_first && first > 0 && second < 0) { 362 pdot(i); 363 } else { 364 ml_printf("Error %d %c %d\n", first, neg_first ? '<' : '>', second); 365 return false; 366 } 367 } 368 ml_printf("done @ %p\n", ptr); 369 return true; 370 } 371 372 static bool read_test_data_s16(int offset, bool neg_first) 373 { 374 int16_t *ptr = (int16_t *)&test_data[offset]; 375 int i; 376 const int max = (TEST_SIZE - offset) / (sizeof(*ptr)); 377 378 ml_printf("Reading s16 from %#lx (offset %d, %s):", ptr, 379 offset, neg_first ? "neg" : "pos"); 380 381 /* 382 * If the first byte is negative, then the last byte is positive. 383 * Therefore the logic below must be flipped for big-endian. 384 */ 385 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 386 neg_first = !neg_first; 387 #endif 388 389 for (i = 0; i < max; i++) { 390 int32_t data = *ptr++; 391 392 if (neg_first && data < 0) { 393 pdot(i); 394 } else if (!neg_first && data > 0) { 395 pdot(i); 396 } else { 397 ml_printf("Error %d %c 0\n", data, neg_first ? '<' : '>'); 398 return false; 399 } 400 } 401 ml_printf("done @ %p\n", ptr); 402 return true; 403 } 404 405 static bool read_test_data_s32(int offset, bool neg_first) 406 { 407 int32_t *ptr = (int32_t *)&test_data[offset]; 408 int i; 409 const int max = (TEST_SIZE - offset) / (sizeof(int32_t)); 410 411 ml_printf("Reading s32 from %#lx (offset %d, %s):", 412 ptr, offset, neg_first ? "neg" : "pos"); 413 414 /* 415 * If the first byte is negative, then the last byte is positive. 416 * Therefore the logic below must be flipped for big-endian. 417 */ 418 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 419 neg_first = !neg_first; 420 #endif 421 422 for (i = 0; i < max; i++) { 423 int64_t data = *ptr++; 424 425 if (neg_first && data < 0) { 426 pdot(i); 427 } else if (!neg_first && data > 0) { 428 pdot(i); 429 } else { 430 ml_printf("Error %d %c 0\n", data, neg_first ? '<' : '>'); 431 return false; 432 } 433 } 434 ml_printf("done @ %p\n", ptr); 435 return true; 436 } 437 438 /* 439 * Read the test data and verify at various offsets 440 * 441 * For everything except bytes all our reads should be either positive 442 * or negative depending on what offset we are reading from. 443 */ 444 read_sfn read_sfns[] = { read_test_data_s8, 445 read_test_data_s16, 446 read_test_data_s32 }; 447 448 bool do_signed_reads(bool neg_first) 449 { 450 int i; 451 bool ok = true; 452 453 for (i = 0; i < ARRAY_SIZE(read_sfns) && ok; i++) { 454 #if CHECK_UNALIGNED 455 int off; 456 for (off = 0; off < 8 && ok; off++) { 457 bool nf = i == 0 ? neg_first ^ (off & 1) : !(neg_first ^ (off & 1)); 458 ok = read_sfns[i](off, nf); 459 } 460 #else 461 ok = read_sfns[i](0, i == 0 ? neg_first : !neg_first); 462 #endif 463 } 464 465 return ok; 466 } 467 468 init_ufn init_ufns[] = { init_test_data_u8, 469 init_test_data_u16, 470 init_test_data_u32, 471 init_test_data_u64 }; 472 473 int main(void) 474 { 475 int i; 476 bool ok = true; 477 478 /* Run through the unsigned tests first */ 479 for (i = 0; i < ARRAY_SIZE(init_ufns) && ok; i++) { 480 ok = do_unsigned_test(init_ufns[i]); 481 } 482 483 if (ok) { 484 init_test_data_s8(false); 485 ok = do_signed_reads(false); 486 } 487 488 if (ok) { 489 init_test_data_s8(true); 490 ok = do_signed_reads(true); 491 } 492 493 ml_printf("Test complete: %s\n", ok ? "PASSED" : "FAILED"); 494 return ok ? 0 : -1; 495 } 496