qemu/tests/tcg/multiarch/system/memory.c
<<
>>
Prefs
   1/*
   2 * Memory Test
   3 *
   4 * This is intended to test the softmmu 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 (softmmu) 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)))
  29static uint8_t test_data[TEST_SIZE];
  30
  31typedef void (*init_ufn) (int offset);
  32typedef bool (*read_ufn) (int offset);
  33typedef bool (*read_sfn) (int offset, bool nf);
  34
  35static 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
  60static 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
  80static inline uint8_t get_byte(int index, bool neg)
  81{
  82    return neg ? (0xff << (index % 7)) : (0xff >> ((index % 6) + 1));
  83}
  84
  85static 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 */
 104static 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
 113static 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
 133static 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
 155static 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
 180static 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
 205static 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
 246static 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 */
 301read_ufn read_ufns[] = { read_test_data_u16,
 302                         read_test_data_u32,
 303                         read_test_data_u64 };
 304
 305bool 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
 324static 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
 345static 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
 372static 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
 405static 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 */
 444read_sfn read_sfns[] = { read_test_data_s8,
 445                         read_test_data_s16,
 446                         read_test_data_s32 };
 447
 448bool 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
 468init_ufn init_ufns[] = { init_test_data_u8,
 469                         init_test_data_u16,
 470                         init_test_data_u32,
 471                         init_test_data_u64 };
 472
 473int 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