xref: /qemu/tests/qtest/pflash-cfi02-test.c (revision 66997c42e02c84481fc162a5b7bd6ad6c643bae2)
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  }
681