qemu

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

pflash-cfi02-test.c (23658B)


      1 /*
      2  * QTest testcase for parallel flash with AMD command set
      3  *
      4  * Copyright (c) 2019 Stephen Checkoway
      5  *
      6  * This work is licensed under the terms of the GNU GPL, version 2 or later.
      7  * See the COPYING file in the top-level directory.
      8  */
      9 
     10 #include "qemu/osdep.h"
     11 #include "libqtest.h"
     12 
     13 /*
     14  * To test the pflash_cfi02 device, we run QEMU with the musicpal machine with
     15  * a pflash drive. This enables us to test some flash configurations, but not
     16  * all. In particular, we're limited to a 16-bit wide flash device.
     17  */
     18 
     19 #define MP_FLASH_SIZE_MAX (32 * 1024 * 1024)
     20 #define BASE_ADDR (0x100000000ULL - MP_FLASH_SIZE_MAX)
     21 
     22 #define UNIFORM_FLASH_SIZE (8 * 1024 * 1024)
     23 #define UNIFORM_FLASH_SECTOR_SIZE (64 * 1024)
     24 
     25 /* Use a newtype to keep flash addresses separate from byte addresses. */
     26 typedef struct {
     27     uint64_t addr;
     28 } faddr;
     29 #define FLASH_ADDR(x) ((faddr) { .addr = (x) })
     30 
     31 #define CFI_ADDR FLASH_ADDR(0x55)
     32 #define UNLOCK0_ADDR FLASH_ADDR(0x555)
     33 #define UNLOCK1_ADDR FLASH_ADDR(0x2AA)
     34 
     35 #define CFI_CMD 0x98
     36 #define UNLOCK0_CMD 0xAA
     37 #define UNLOCK1_CMD 0x55
     38 #define SECOND_UNLOCK_CMD 0x80
     39 #define AUTOSELECT_CMD 0x90
     40 #define RESET_CMD 0xF0
     41 #define PROGRAM_CMD 0xA0
     42 #define SECTOR_ERASE_CMD 0x30
     43 #define CHIP_ERASE_CMD 0x10
     44 #define UNLOCK_BYPASS_CMD 0x20
     45 #define UNLOCK_BYPASS_RESET_CMD 0x00
     46 #define ERASE_SUSPEND_CMD 0xB0
     47 #define ERASE_RESUME_CMD SECTOR_ERASE_CMD
     48 
     49 typedef struct {
     50     int bank_width;
     51 
     52     /* Nonuniform block size. */
     53     int nb_blocs[4];
     54     int sector_len[4];
     55 
     56     QTestState *qtest;
     57 } FlashConfig;
     58 
     59 static char *image_path;
     60 
     61 /*
     62  * The pflash implementation allows some parameters to be unspecified. We want
     63  * to test those configurations but we also need to know the real values in
     64  * our testing code. So after we launch qemu, we'll need a new FlashConfig
     65  * with the correct values filled in.
     66  */
     67 static FlashConfig expand_config_defaults(const FlashConfig *c)
     68 {
     69     FlashConfig ret = *c;
     70 
     71     if (ret.bank_width == 0) {
     72         ret.bank_width = 2;
     73     }
     74     if (ret.nb_blocs[0] == 0 && ret.sector_len[0] == 0) {
     75         ret.sector_len[0] = UNIFORM_FLASH_SECTOR_SIZE;
     76         ret.nb_blocs[0] = UNIFORM_FLASH_SIZE / UNIFORM_FLASH_SECTOR_SIZE;
     77     }
     78 
     79     /* XXX: Limitations of test harness. */
     80     assert(ret.bank_width == 2);
     81     return ret;
     82 }
     83 
     84 /*
     85  * Return a bit mask suitable for extracting the least significant
     86  * status/query response from an interleaved response.
     87  */
     88 static inline uint64_t device_mask(const FlashConfig *c)
     89 {
     90     return (uint64_t)-1;
     91 }
     92 
     93 /*
     94  * Return a bit mask exactly as long as the bank_width.
     95  */
     96 static inline uint64_t bank_mask(const FlashConfig *c)
     97 {
     98     if (c->bank_width == 8) {
     99         return (uint64_t)-1;
    100     }
    101     return (1ULL << (c->bank_width * 8)) - 1ULL;
    102 }
    103 
    104 static inline void flash_write(const FlashConfig *c, uint64_t byte_addr,
    105                                uint64_t data)
    106 {
    107     /* Sanity check our tests. */
    108     assert((data & ~bank_mask(c)) == 0);
    109     uint64_t addr = BASE_ADDR + byte_addr;
    110     switch (c->bank_width) {
    111     case 1:
    112         qtest_writeb(c->qtest, addr, data);
    113         break;
    114     case 2:
    115         qtest_writew(c->qtest, addr, data);
    116         break;
    117     case 4:
    118         qtest_writel(c->qtest, addr, data);
    119         break;
    120     case 8:
    121         qtest_writeq(c->qtest, addr, data);
    122         break;
    123     default:
    124         abort();
    125     }
    126 }
    127 
    128 static inline uint64_t flash_read(const FlashConfig *c, uint64_t byte_addr)
    129 {
    130     uint64_t addr = BASE_ADDR + byte_addr;
    131     switch (c->bank_width) {
    132     case 1:
    133         return qtest_readb(c->qtest, addr);
    134     case 2:
    135         return qtest_readw(c->qtest, addr);
    136     case 4:
    137         return qtest_readl(c->qtest, addr);
    138     case 8:
    139         return qtest_readq(c->qtest, addr);
    140     default:
    141         abort();
    142     }
    143 }
    144 
    145 /*
    146  * Convert a flash address expressed in the maximum width of the device as a
    147  * byte address.
    148  */
    149 static inline uint64_t as_byte_addr(const FlashConfig *c, faddr flash_addr)
    150 {
    151     /*
    152      * Command addresses are always given as addresses in the maximum
    153      * supported bus size for the flash chip. So an x8/x16 chip in x8 mode
    154      * uses addresses 0xAAA and 0x555 to unlock because the least significant
    155      * bit is ignored. (0x555 rather than 0x554 is traditional.)
    156      *
    157      * In general we need to multiply by the maximum device width.
    158      */
    159     return flash_addr.addr * c->bank_width;
    160 }
    161 
    162 /*
    163  * Return the command value or expected status replicated across all devices.
    164  */
    165 static inline uint64_t replicate(const FlashConfig *c, uint64_t data)
    166 {
    167     /* Sanity check our tests. */
    168     assert((data & ~device_mask(c)) == 0);
    169     return data;
    170 }
    171 
    172 static inline void flash_cmd(const FlashConfig *c, faddr cmd_addr,
    173                              uint8_t cmd)
    174 {
    175     flash_write(c, as_byte_addr(c, cmd_addr), replicate(c, cmd));
    176 }
    177 
    178 static inline uint64_t flash_query(const FlashConfig *c, faddr query_addr)
    179 {
    180     return flash_read(c, as_byte_addr(c, query_addr));
    181 }
    182 
    183 static inline uint64_t flash_query_1(const FlashConfig *c, faddr query_addr)
    184 {
    185     return flash_query(c, query_addr) & device_mask(c);
    186 }
    187 
    188 static void unlock(const FlashConfig *c)
    189 {
    190     flash_cmd(c, UNLOCK0_ADDR, UNLOCK0_CMD);
    191     flash_cmd(c, UNLOCK1_ADDR, UNLOCK1_CMD);
    192 }
    193 
    194 static void reset(const FlashConfig *c)
    195 {
    196     flash_cmd(c, FLASH_ADDR(0), RESET_CMD);
    197 }
    198 
    199 static void sector_erase(const FlashConfig *c, uint64_t byte_addr)
    200 {
    201     unlock(c);
    202     flash_cmd(c, UNLOCK0_ADDR, SECOND_UNLOCK_CMD);
    203     unlock(c);
    204     flash_write(c, byte_addr, replicate(c, SECTOR_ERASE_CMD));
    205 }
    206 
    207 static void wait_for_completion(const FlashConfig *c, uint64_t byte_addr)
    208 {
    209     /* If DQ6 is toggling, step the clock and ensure the toggle stops. */
    210     const uint64_t dq6 = replicate(c, 0x40);
    211     if ((flash_read(c, byte_addr) & dq6) ^ (flash_read(c, byte_addr) & dq6)) {
    212         /* Wait for erase or program to finish. */
    213         qtest_clock_step_next(c->qtest);
    214         /* Ensure that DQ6 has stopped toggling. */
    215         g_assert_cmphex(flash_read(c, byte_addr), ==, flash_read(c, byte_addr));
    216     }
    217 }
    218 
    219 static void bypass_program(const FlashConfig *c, uint64_t byte_addr,
    220                            uint16_t data)
    221 {
    222     flash_cmd(c, UNLOCK0_ADDR, PROGRAM_CMD);
    223     flash_write(c, byte_addr, data);
    224     /*
    225      * Data isn't valid until DQ6 stops toggling. We don't model this as
    226      * writes are immediate, but if this changes in the future, we can wait
    227      * until the program is complete.
    228      */
    229     wait_for_completion(c, byte_addr);
    230 }
    231 
    232 static void program(const FlashConfig *c, uint64_t byte_addr, uint16_t data)
    233 {
    234     unlock(c);
    235     bypass_program(c, byte_addr, data);
    236 }
    237 
    238 static void chip_erase(const FlashConfig *c)
    239 {
    240     unlock(c);
    241     flash_cmd(c, UNLOCK0_ADDR, SECOND_UNLOCK_CMD);
    242     unlock(c);
    243     flash_cmd(c, UNLOCK0_ADDR, CHIP_ERASE_CMD);
    244 }
    245 
    246 static void erase_suspend(const FlashConfig *c)
    247 {
    248     flash_cmd(c, FLASH_ADDR(0), ERASE_SUSPEND_CMD);
    249 }
    250 
    251 static void erase_resume(const FlashConfig *c)
    252 {
    253     flash_cmd(c, FLASH_ADDR(0), ERASE_RESUME_CMD);
    254 }
    255 
    256 /*
    257  * Test flash commands with a variety of device geometry.
    258  */
    259 static void test_geometry(const void *opaque)
    260 {
    261     const FlashConfig *config = opaque;
    262     QTestState *qtest;
    263     qtest = qtest_initf("-M musicpal"
    264                         " -drive if=pflash,file=%s,format=raw,copy-on-read=on"
    265                         /* Device geometry properties. */
    266                         " -global driver=cfi.pflash02,"
    267                         "property=num-blocks0,value=%d"
    268                         " -global driver=cfi.pflash02,"
    269                         "property=sector-length0,value=%d"
    270                         " -global driver=cfi.pflash02,"
    271                         "property=num-blocks1,value=%d"
    272                         " -global driver=cfi.pflash02,"
    273                         "property=sector-length1,value=%d"
    274                         " -global driver=cfi.pflash02,"
    275                         "property=num-blocks2,value=%d"
    276                         " -global driver=cfi.pflash02,"
    277                         "property=sector-length2,value=%d"
    278                         " -global driver=cfi.pflash02,"
    279                         "property=num-blocks3,value=%d"
    280                         " -global driver=cfi.pflash02,"
    281                         "property=sector-length3,value=%d",
    282                         image_path,
    283                         config->nb_blocs[0],
    284                         config->sector_len[0],
    285                         config->nb_blocs[1],
    286                         config->sector_len[1],
    287                         config->nb_blocs[2],
    288                         config->sector_len[2],
    289                         config->nb_blocs[3],
    290                         config->sector_len[3]);
    291     FlashConfig explicit_config = expand_config_defaults(config);
    292     explicit_config.qtest = qtest;
    293     const FlashConfig *c = &explicit_config;
    294 
    295     /* Check the IDs. */
    296     unlock(c);
    297     flash_cmd(c, UNLOCK0_ADDR, AUTOSELECT_CMD);
    298     g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
    299     if (c->bank_width >= 2) {
    300         /*
    301          * XXX: The ID returned by the musicpal flash chip is 16 bits which
    302          * wouldn't happen with an 8-bit device. It would probably be best to
    303          * prohibit addresses larger than the device width in pflash_cfi02.c,
    304          * but then we couldn't test smaller device widths at all.
    305          */
    306         g_assert_cmphex(flash_query(c, FLASH_ADDR(1)), ==,
    307                         replicate(c, 0x236D));
    308     }
    309     reset(c);
    310 
    311     /* Check the erase blocks. */
    312     flash_cmd(c, CFI_ADDR, CFI_CMD);
    313     g_assert_cmphex(flash_query(c, FLASH_ADDR(0x10)), ==, replicate(c, 'Q'));
    314     g_assert_cmphex(flash_query(c, FLASH_ADDR(0x11)), ==, replicate(c, 'R'));
    315     g_assert_cmphex(flash_query(c, FLASH_ADDR(0x12)), ==, replicate(c, 'Y'));
    316 
    317     /* Num erase regions. */
    318     int nb_erase_regions = flash_query_1(c, FLASH_ADDR(0x2C));
    319     g_assert_cmphex(nb_erase_regions, ==,
    320                     !!c->nb_blocs[0] + !!c->nb_blocs[1] + !!c->nb_blocs[2] +
    321                     !!c->nb_blocs[3]);
    322 
    323     /* Check device length. */
    324     uint32_t device_len = 1 << flash_query_1(c, FLASH_ADDR(0x27));
    325     g_assert_cmphex(device_len, ==, UNIFORM_FLASH_SIZE);
    326 
    327     /* Check that erase suspend to read/write is supported. */
    328     uint16_t pri = flash_query_1(c, FLASH_ADDR(0x15)) +
    329                    (flash_query_1(c, FLASH_ADDR(0x16)) << 8);
    330     g_assert_cmpint(pri, >=, 0x2D + 4 * nb_erase_regions);
    331     g_assert_cmpint(flash_query(c, FLASH_ADDR(pri + 0)), ==, replicate(c, 'P'));
    332     g_assert_cmpint(flash_query(c, FLASH_ADDR(pri + 1)), ==, replicate(c, 'R'));
    333     g_assert_cmpint(flash_query(c, FLASH_ADDR(pri + 2)), ==, replicate(c, 'I'));
    334     g_assert_cmpint(flash_query_1(c, FLASH_ADDR(pri + 6)), ==, 2); /* R/W */
    335     reset(c);
    336 
    337     const uint64_t dq7 = replicate(c, 0x80);
    338     const uint64_t dq6 = replicate(c, 0x40);
    339     const uint64_t dq3 = replicate(c, 0x08);
    340     const uint64_t dq2 = replicate(c, 0x04);
    341 
    342     uint64_t byte_addr = 0;
    343     for (int region = 0; region < nb_erase_regions; ++region) {
    344         uint64_t base = 0x2D + 4 * region;
    345         flash_cmd(c, CFI_ADDR, CFI_CMD);
    346         uint32_t nb_sectors = flash_query_1(c, FLASH_ADDR(base + 0)) +
    347                               (flash_query_1(c, FLASH_ADDR(base + 1)) << 8) + 1;
    348         uint32_t sector_len = (flash_query_1(c, FLASH_ADDR(base + 2)) << 8) +
    349                               (flash_query_1(c, FLASH_ADDR(base + 3)) << 16);
    350         g_assert_cmphex(nb_sectors, ==, c->nb_blocs[region]);
    351         g_assert_cmphex(sector_len, ==, c->sector_len[region]);
    352         reset(c);
    353 
    354         /* Erase and program sector. */
    355         for (uint32_t i = 0; i < nb_sectors; ++i) {
    356             sector_erase(c, byte_addr);
    357 
    358             /* Check that DQ3 is 0. */
    359             g_assert_cmphex(flash_read(c, byte_addr) & dq3, ==, 0);
    360             qtest_clock_step_next(c->qtest); /* Step over the 50 us timeout. */
    361 
    362             /* Check that DQ3 is 1. */
    363             uint64_t status0 = flash_read(c, byte_addr);
    364             g_assert_cmphex(status0 & dq3, ==, dq3);
    365 
    366             /* DQ7 is 0 during an erase. */
    367             g_assert_cmphex(status0 & dq7, ==, 0);
    368             uint64_t status1 = flash_read(c, byte_addr);
    369 
    370             /* DQ6 toggles during an erase. */
    371             g_assert_cmphex(status0 & dq6, ==, ~status1 & dq6);
    372 
    373             /* Wait for erase to complete. */
    374             wait_for_completion(c, byte_addr);
    375 
    376             /* Ensure DQ6 has stopped toggling. */
    377             g_assert_cmphex(flash_read(c, byte_addr), ==,
    378                             flash_read(c, byte_addr));
    379 
    380             /* Now the data should be valid. */
    381             g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
    382 
    383             /* Program a bit pattern. */
    384             program(c, byte_addr, 0x55);
    385             g_assert_cmphex(flash_read(c, byte_addr) & 0xFF, ==, 0x55);
    386             program(c, byte_addr, 0xA5);
    387             g_assert_cmphex(flash_read(c, byte_addr) & 0xFF, ==, 0x05);
    388             byte_addr += sector_len;
    389         }
    390     }
    391 
    392     /* Erase the chip. */
    393     chip_erase(c);
    394     /* Read toggle. */
    395     uint64_t status0 = flash_read(c, 0);
    396     /* DQ7 is 0 during an erase. */
    397     g_assert_cmphex(status0 & dq7, ==, 0);
    398     uint64_t status1 = flash_read(c, 0);
    399     /* DQ6 toggles during an erase. */
    400     g_assert_cmphex(status0 & dq6, ==, ~status1 & dq6);
    401     /* Wait for erase to complete. */
    402     qtest_clock_step_next(c->qtest);
    403     /* Ensure DQ6 has stopped toggling. */
    404     g_assert_cmphex(flash_read(c, 0), ==, flash_read(c, 0));
    405     /* Now the data should be valid. */
    406 
    407     for (int region = 0; region < nb_erase_regions; ++region) {
    408         for (uint32_t i = 0; i < c->nb_blocs[region]; ++i) {
    409             uint64_t byte_addr = (uint64_t)i * c->sector_len[region];
    410             g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
    411         }
    412     }
    413 
    414     /* Unlock bypass */
    415     unlock(c);
    416     flash_cmd(c, UNLOCK0_ADDR, UNLOCK_BYPASS_CMD);
    417     bypass_program(c, 0 * c->bank_width, 0x01);
    418     bypass_program(c, 1 * c->bank_width, 0x23);
    419     bypass_program(c, 2 * c->bank_width, 0x45);
    420     /*
    421      * Test that bypass programming, unlike normal programming can use any
    422      * address for the PROGRAM_CMD.
    423      */
    424     flash_cmd(c, FLASH_ADDR(3 * c->bank_width), PROGRAM_CMD);
    425     flash_write(c, 3 * c->bank_width, 0x67);
    426     wait_for_completion(c, 3 * c->bank_width);
    427     flash_cmd(c, FLASH_ADDR(0), UNLOCK_BYPASS_RESET_CMD);
    428     bypass_program(c, 4 * c->bank_width, 0x89); /* Should fail. */
    429     g_assert_cmphex(flash_read(c, 0 * c->bank_width), ==, 0x01);
    430     g_assert_cmphex(flash_read(c, 1 * c->bank_width), ==, 0x23);
    431     g_assert_cmphex(flash_read(c, 2 * c->bank_width), ==, 0x45);
    432     g_assert_cmphex(flash_read(c, 3 * c->bank_width), ==, 0x67);
    433     g_assert_cmphex(flash_read(c, 4 * c->bank_width), ==, bank_mask(c));
    434 
    435     /* Test ignored high order bits of address. */
    436     flash_cmd(c, FLASH_ADDR(0x5555), UNLOCK0_CMD);
    437     flash_cmd(c, FLASH_ADDR(0x2AAA), UNLOCK1_CMD);
    438     flash_cmd(c, FLASH_ADDR(0x5555), AUTOSELECT_CMD);
    439     g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
    440     reset(c);
    441 
    442     /*
    443      * Program a word on each sector, erase one or two sectors per region, and
    444      * verify that all of those, and only those, are erased.
    445      */
    446     byte_addr = 0;
    447     for (int region = 0; region < nb_erase_regions; ++region) {
    448         for (int i = 0; i < config->nb_blocs[region]; ++i) {
    449             program(c, byte_addr, 0);
    450             byte_addr += config->sector_len[region];
    451         }
    452     }
    453     unlock(c);
    454     flash_cmd(c, UNLOCK0_ADDR, SECOND_UNLOCK_CMD);
    455     unlock(c);
    456     byte_addr = 0;
    457     const uint64_t erase_cmd = replicate(c, SECTOR_ERASE_CMD);
    458     for (int region = 0; region < nb_erase_regions; ++region) {
    459         flash_write(c, byte_addr, erase_cmd);
    460         if (c->nb_blocs[region] > 1) {
    461             flash_write(c, byte_addr + c->sector_len[region], erase_cmd);
    462         }
    463         byte_addr += c->sector_len[region] * c->nb_blocs[region];
    464     }
    465 
    466     qtest_clock_step_next(c->qtest); /* Step over the 50 us timeout. */
    467     wait_for_completion(c, 0);
    468     byte_addr = 0;
    469     for (int region = 0; region < nb_erase_regions; ++region) {
    470         for (int i = 0; i < config->nb_blocs[region]; ++i) {
    471             if (i < 2) {
    472                 g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
    473             } else {
    474                 g_assert_cmphex(flash_read(c, byte_addr), ==, 0);
    475             }
    476             byte_addr += config->sector_len[region];
    477         }
    478     }
    479 
    480     /* Test erase suspend/resume during erase timeout. */
    481     sector_erase(c, 0);
    482     /*
    483      * Check that DQ 3 is 0 and DQ6 and DQ2 are toggling in the sector being
    484      * erased as well as in a sector not being erased.
    485      */
    486     byte_addr = c->sector_len[0];
    487     status0 = flash_read(c, 0);
    488     status1 = flash_read(c, 0);
    489     g_assert_cmpint(status0 & dq3, ==, 0);
    490     g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
    491     g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
    492     status0 = flash_read(c, byte_addr);
    493     status1 = flash_read(c, byte_addr);
    494     g_assert_cmpint(status0 & dq3, ==, 0);
    495     g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
    496     g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
    497 
    498     /*
    499      * Check that after suspending, DQ6 does not toggle but DQ2 does toggle in
    500      * an erase suspended sector but that neither toggle (we should be
    501      * getting data) in a sector not being erased.
    502      */
    503     erase_suspend(c);
    504     status0 = flash_read(c, 0);
    505     status1 = flash_read(c, 0);
    506     g_assert_cmpint(status0 & dq6, ==, status1 & dq6);
    507     g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
    508     g_assert_cmpint(flash_read(c, byte_addr), ==, flash_read(c, byte_addr));
    509 
    510     /* Check that after resuming, DQ3 is 1 and DQ6 and DQ2 toggle. */
    511     erase_resume(c);
    512     status0 = flash_read(c, 0);
    513     status1 = flash_read(c, 0);
    514     g_assert_cmpint(status0 & dq3, ==, dq3);
    515     g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
    516     g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
    517     status0 = flash_read(c, byte_addr);
    518     status1 = flash_read(c, byte_addr);
    519     g_assert_cmpint(status0 & dq3, ==, dq3);
    520     g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
    521     g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
    522     wait_for_completion(c, 0);
    523 
    524     /* Repeat this process but this time suspend after the timeout. */
    525     sector_erase(c, 0);
    526     qtest_clock_step_next(c->qtest);
    527     /*
    528      * Check that DQ 3 is 1 and DQ6 and DQ2 are toggling in the sector being
    529      * erased as well as in a sector not being erased.
    530      */
    531     byte_addr = c->sector_len[0];
    532     status0 = flash_read(c, 0);
    533     status1 = flash_read(c, 0);
    534     g_assert_cmpint(status0 & dq3, ==, dq3);
    535     g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
    536     g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
    537     status0 = flash_read(c, byte_addr);
    538     status1 = flash_read(c, byte_addr);
    539     g_assert_cmpint(status0 & dq3, ==, dq3);
    540     g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
    541     g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
    542 
    543     /*
    544      * Check that after suspending, DQ6 does not toggle but DQ2 does toggle in
    545      * an erase suspended sector but that neither toggle (we should be
    546      * getting data) in a sector not being erased.
    547      */
    548     erase_suspend(c);
    549     status0 = flash_read(c, 0);
    550     status1 = flash_read(c, 0);
    551     g_assert_cmpint(status0 & dq6, ==, status1 & dq6);
    552     g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
    553     g_assert_cmpint(flash_read(c, byte_addr), ==, flash_read(c, byte_addr));
    554 
    555     /* Check that after resuming, DQ3 is 1 and DQ6 and DQ2 toggle. */
    556     erase_resume(c);
    557     status0 = flash_read(c, 0);
    558     status1 = flash_read(c, 0);
    559     g_assert_cmpint(status0 & dq3, ==, dq3);
    560     g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
    561     g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
    562     status0 = flash_read(c, byte_addr);
    563     status1 = flash_read(c, byte_addr);
    564     g_assert_cmpint(status0 & dq3, ==, dq3);
    565     g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
    566     g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
    567     wait_for_completion(c, 0);
    568 
    569     qtest_quit(qtest);
    570 }
    571 
    572 /*
    573  * Test that
    574  * 1. enter autoselect mode;
    575  * 2. enter CFI mode; and then
    576  * 3. exit CFI mode
    577  * leaves the flash device in autoselect mode.
    578  */
    579 static void test_cfi_in_autoselect(const void *opaque)
    580 {
    581     const FlashConfig *config = opaque;
    582     QTestState *qtest;
    583     qtest = qtest_initf("-M musicpal"
    584                         " -drive if=pflash,file=%s,format=raw,copy-on-read=on",
    585                         image_path);
    586     FlashConfig explicit_config = expand_config_defaults(config);
    587     explicit_config.qtest = qtest;
    588     const FlashConfig *c = &explicit_config;
    589 
    590     /* 1. Enter autoselect. */
    591     unlock(c);
    592     flash_cmd(c, UNLOCK0_ADDR, AUTOSELECT_CMD);
    593     g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
    594 
    595     /* 2. Enter CFI. */
    596     flash_cmd(c, CFI_ADDR, CFI_CMD);
    597     g_assert_cmphex(flash_query(c, FLASH_ADDR(0x10)), ==, replicate(c, 'Q'));
    598     g_assert_cmphex(flash_query(c, FLASH_ADDR(0x11)), ==, replicate(c, 'R'));
    599     g_assert_cmphex(flash_query(c, FLASH_ADDR(0x12)), ==, replicate(c, 'Y'));
    600 
    601     /* 3. Exit CFI. */
    602     reset(c);
    603     g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
    604 
    605     qtest_quit(qtest);
    606 }
    607 
    608 static void cleanup(void *opaque)
    609 {
    610     unlink(image_path);
    611     g_free(image_path);
    612 }
    613 
    614 /*
    615  * XXX: Tests are limited to bank_width = 2 for now because that's what
    616  * hw/arm/musicpal.c has.
    617  */
    618 static const FlashConfig configuration[] = {
    619     /* One x16 device. */
    620     {
    621         .bank_width = 2,
    622     },
    623     /* Nonuniform sectors (top boot). */
    624     {
    625         .bank_width = 2,
    626         .nb_blocs = { 127, 1, 2, 1 },
    627         .sector_len = { 0x10000, 0x08000, 0x02000, 0x04000 },
    628     },
    629     /* Nonuniform sectors (bottom boot). */
    630     {
    631         .bank_width = 2,
    632         .nb_blocs = { 1, 2, 1, 127 },
    633         .sector_len = { 0x04000, 0x02000, 0x08000, 0x10000 },
    634     },
    635 };
    636 
    637 int main(int argc, char **argv)
    638 {
    639     GError *err = NULL;
    640     int fd = g_file_open_tmp("qtest.XXXXXX", &image_path, &err);
    641     g_assert_no_error(err);
    642 
    643     if (ftruncate(fd, UNIFORM_FLASH_SIZE) < 0) {
    644         int error_code = errno;
    645         close(fd);
    646         cleanup(NULL);
    647         g_printerr("Failed to truncate file %s to %u MB: %s\n", image_path,
    648                    UNIFORM_FLASH_SIZE, strerror(error_code));
    649         exit(EXIT_FAILURE);
    650     }
    651     close(fd);
    652 
    653     qtest_add_abrt_handler(cleanup, NULL);
    654     g_test_init(&argc, &argv, NULL);
    655 
    656     size_t nb_configurations = sizeof configuration / sizeof configuration[0];
    657     for (size_t i = 0; i < nb_configurations; ++i) {
    658         const FlashConfig *config = &configuration[i];
    659         char *path = g_strdup_printf("pflash-cfi02"
    660                                      "/geometry/%dx%x-%dx%x-%dx%x-%dx%x"
    661                                      "/%d",
    662                                      config->nb_blocs[0],
    663                                      config->sector_len[0],
    664                                      config->nb_blocs[1],
    665                                      config->sector_len[1],
    666                                      config->nb_blocs[2],
    667                                      config->sector_len[2],
    668                                      config->nb_blocs[3],
    669                                      config->sector_len[3],
    670                                      config->bank_width);
    671         qtest_add_data_func(path, config, test_geometry);
    672         g_free(path);
    673     }
    674 
    675     qtest_add_data_func("pflash-cfi02/cfi-in-autoselect", &configuration[0],
    676                         test_cfi_in_autoselect);
    677     int result = g_test_run();
    678     cleanup(NULL);
    679     return result;
    680 }