cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

memory.c (12513B)


      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 <inttypes.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}