qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

memory.c (12511B)


      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)))
     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 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 
     57 static 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 
     77 static inline uint8_t get_byte(int index, bool neg)
     78 {
     79     return neg ? (0xff << (index % 7)) : (0xff >> ((index % 6) + 1));
     80 }
     81 
     82 static 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  */
    101 static 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 
    110 static 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 
    130 static 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 
    151 static 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 
    176 static 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 
    201 static 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 
    242 static 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 */
    297 read_ufn read_ufns[] = { read_test_data_u16,
    298                          read_test_data_u32,
    299                          read_test_data_u64 };
    300 
    301 bool 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 
    320 static 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 
    341 static 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 
    368 static 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 
    393 static 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  */
    425 read_sfn read_sfns[] = { read_test_data_s8,
    426                          read_test_data_s16,
    427                          read_test_data_s32 };
    428 
    429 bool 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 
    449 init_ufn init_ufns[] = { init_test_data_u8,
    450                          init_test_data_u16,
    451                          init_test_data_u32,
    452                          init_test_data_u64 };
    453 
    454 int 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 }