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