* [Qemu-devel] [PATCH v5 0/5] hw/block/pflash_cfi01: Add DeviceReset() handler @ 2019-07-15 12:13 Philippe Mathieu-Daudé 2019-07-15 12:13 ` [Qemu-devel] [PATCH v5 1/5] hw/block/pflash_cfi01: Removed an unused timer Philippe Mathieu-Daudé ` (4 more replies) 0 siblings, 5 replies; 11+ messages in thread From: Philippe Mathieu-Daudé @ 2019-07-15 12:13 UTC (permalink / raw) To: qemu-devel, Dr . David Alan Gilbert Cc: Kevin Wolf, Peter Maydell, Philippe Mathieu-Daudé, qemu-block, Max Reitz Last attempt before sending pull request for rc1. The pflash device lacks a reset() function. When a machine is resetted, the flash might be in an inconsistent state, leading to unexpected behavior: https://bugzilla.redhat.com/show_bug.cgi?id=1678713 Resolve this issue by adding a DeviceReset() handler. Fix also two minor issues, and clean a bit the codebase. Since v1: https://lists.gnu.org/archive/html/qemu-devel/2019-05/msg00962.html - addressed Laszlo review comments Since v2: https://lists.gnu.org/archive/html/qemu-devel/2019-07/msg00395.html - consider migration (Laszlo, Peter) Since v3: https://lists.gnu.org/archive/html/qemu-devel/2019-07/msg01668.html - more reliable migration (Dave) - dropped patches 6-9 not required for next release Since v4: https://lists.gnu.org/archive/html/qemu-devel/2019-07/msg02785.html - document why using READ_ARRAY value 0x00 for migration is safe $ git backport-diff -u v4 Key: [----] : patches are identical [####] : number of functional differences between upstream/downstream patch [down] : patch is downstream-only The flags [FC] indicate (F)unctional and (C)ontextual differences, respectively 001/5:[----] [--] 'hw/block/pflash_cfi01: Removed an unused timer' 002/5:[----] [--] 'hw/block/pflash_cfi01: Use the correct READ_ARRAY value' 003/5:[----] [--] 'hw/block/pflash_cfi01: Extract pflash_mode_read_array()' 004/5:[----] [--] 'hw/block/pflash_cfi01: Start state machine as READY to accept commands' 005/5:[----] [--] 'hw/block/pflash_cfi01: Add the DeviceReset() handler' Regards, Phil. Philippe Mathieu-Daudé (5): hw/block/pflash_cfi01: Removed an unused timer hw/block/pflash_cfi01: Use the correct READ_ARRAY value hw/block/pflash_cfi01: Extract pflash_mode_read_array() hw/block/pflash_cfi01: Start state machine as READY to accept commands hw/block/pflash_cfi01: Add the DeviceReset() handler hw/block/pflash_cfi01.c | 109 +++++++++++++++++++++++++++------------- hw/block/trace-events | 1 + 2 files changed, 75 insertions(+), 35 deletions(-) -- 2.20.1 ^ permalink raw reply [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH v5 1/5] hw/block/pflash_cfi01: Removed an unused timer 2019-07-15 12:13 [Qemu-devel] [PATCH v5 0/5] hw/block/pflash_cfi01: Add DeviceReset() handler Philippe Mathieu-Daudé @ 2019-07-15 12:13 ` Philippe Mathieu-Daudé 2019-07-15 12:13 ` [Qemu-devel] [PATCH v5 2/5] hw/block/pflash_cfi01: Use the correct READ_ARRAY value Philippe Mathieu-Daudé ` (3 subsequent siblings) 4 siblings, 0 replies; 11+ messages in thread From: Philippe Mathieu-Daudé @ 2019-07-15 12:13 UTC (permalink / raw) To: qemu-devel, Dr . David Alan Gilbert Cc: Kevin Wolf, Peter Maydell, qemu-block, Laszlo Ersek, Max Reitz, Alistair Francis, Wei Yang, Philippe Mathieu-Daudé The 'CFI02' NOR flash was introduced in commit 29133e9a0fff, with timing modelled. One year later, the CFI01 model was introduced (commit 05ee37ebf630) based on the CFI02 model. As noted in the header, "It does not support timings". 12 years later, we never had to model the device timings. Time to remove the unused timer, we can still add it back if required. Suggested-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Wei Yang <richardw.yang@linux.intel.com> Reviewed-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Regression-tested-by: Laszlo Ersek <lersek@redhat.com> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com> --- v2: Fixed commit description (Laszlo) --- hw/block/pflash_cfi01.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index db4a246b22..9e34fd4e82 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -42,7 +42,6 @@ #include "hw/block/flash.h" #include "sysemu/block-backend.h" #include "qapi/error.h" -#include "qemu/timer.h" #include "qemu/bitops.h" #include "qemu/error-report.h" #include "qemu/host-utils.h" @@ -90,7 +89,6 @@ struct PFlashCFI01 { uint8_t cfi_table[0x52]; uint64_t counter; unsigned int writeblock_size; - QEMUTimer *timer; MemoryRegion mem; char *name; void *storage; @@ -114,18 +112,6 @@ static const VMStateDescription vmstate_pflash = { } }; -static void pflash_timer (void *opaque) -{ - PFlashCFI01 *pfl = opaque; - - trace_pflash_timer_expired(pfl->cmd); - /* Reset flash */ - pfl->status ^= 0x80; - memory_region_rom_device_set_romd(&pfl->mem, true); - pfl->wcycle = 0; - pfl->cmd = 0; -} - /* Perform a CFI query based on the bank width of the flash. * If this code is called we know we have a device_width set for * this flash. @@ -774,7 +760,6 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) pfl->max_device_width = pfl->device_width; } - pfl->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pflash_timer, pfl); pfl->wcycle = 0; pfl->cmd = 0; pfl->status = 0; -- 2.20.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH v5 2/5] hw/block/pflash_cfi01: Use the correct READ_ARRAY value 2019-07-15 12:13 [Qemu-devel] [PATCH v5 0/5] hw/block/pflash_cfi01: Add DeviceReset() handler Philippe Mathieu-Daudé 2019-07-15 12:13 ` [Qemu-devel] [PATCH v5 1/5] hw/block/pflash_cfi01: Removed an unused timer Philippe Mathieu-Daudé @ 2019-07-15 12:13 ` Philippe Mathieu-Daudé 2019-07-16 12:25 ` Markus Armbruster 2019-07-15 12:13 ` [Qemu-devel] [PATCH v5 3/5] hw/block/pflash_cfi01: Extract pflash_mode_read_array() Philippe Mathieu-Daudé ` (2 subsequent siblings) 4 siblings, 1 reply; 11+ messages in thread From: Philippe Mathieu-Daudé @ 2019-07-15 12:13 UTC (permalink / raw) To: qemu-devel, Dr . David Alan Gilbert Cc: Kevin Wolf, Peter Maydell, qemu-block, Philippe Mathieu-Daudé, Laszlo Ersek, Max Reitz, Alistair Francis, John Snow In the document [*] the "Read Array Flowchart", the READ_ARRAY command has a value of 0xff. Use the correct value in the pflash model. There is no change of behavior in the guest, because: - when the guest were sending 0xFF, the reset_flash label was setting the command value as 0x00 - 0x00 was used internally for READ_ARRAY To keep migration with older versions behaving correctly, we decide to always migrate the READ_ARRAY as 0x00. If the CFI open standard decide to assign a new command of value 0x00, this model is flawed because it uses this value internally. If a guest eventually requires this new CFI feature, a different model will be required (or this same model but breaking backward migration). So it is safe to keep migrating READ_ARRAY as 0x00. [*] "Common Flash Interface (CFI) and Command Sets" (Intel Application Note 646) Appendix B "Basic Command Set" Reviewed-by: John Snow <jsnow@redhat.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Regression-tested-by: Laszlo Ersek <lersek@redhat.com> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com> --- v3: Handle migrating the 'cmd' field. v4: Handle migrating to older QEMU (Dave) v5: Add a paragraph about why this model is flawed due to historically using READ_ARRAY as 0x00 (Dave, Peter). Since Laszlo stated he did not test migration [*], I'm keeping his test tag, because the change with v2 has no impact in the tests he ran. Likewise I'm keeping John and Alistair tags, but I'd like an extra review for the migration change, thanks! [*] https://lists.gnu.org/archive/html/qemu-devel/2019-07/msg00679.html --- hw/block/pflash_cfi01.c | 57 ++++++++++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index 9e34fd4e82..85bb2132c0 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -96,6 +96,37 @@ struct PFlashCFI01 { bool old_multiple_chip_handling; }; +static int pflash_pre_save(void *opaque) +{ + PFlashCFI01 *s = opaque; + + /* + * Previous to QEMU v4.1 an incorrect value of 0x00 was used for the + * READ_ARRAY command. To preserve migrating to these older version, + * always migrate the READ_ARRAY command as 0x00. + */ + if (s->cmd == 0xff) { + s->cmd = 0x00; + } + + return 0; +} + +static int pflash_post_save(void *opaque) +{ + PFlashCFI01 *s = opaque; + + /* + * If migration failed, the guest will continue to run. + * Restore the correct READ_ARRAY value. + */ + if (s->cmd == 0x00) { + s->cmd = 0xff; + } + + return 0; +} + static int pflash_post_load(void *opaque, int version_id); static const VMStateDescription vmstate_pflash = { @@ -103,6 +134,8 @@ static const VMStateDescription vmstate_pflash = { .version_id = 1, .minimum_version_id = 1, .post_load = pflash_post_load, + .pre_save = pflash_pre_save, + .post_save = pflash_post_save, .fields = (VMStateField[]) { VMSTATE_UINT8(wcycle, PFlashCFI01), VMSTATE_UINT8(cmd, PFlashCFI01), @@ -277,10 +310,9 @@ static uint32_t pflash_read(PFlashCFI01 *pfl, hwaddr offset, /* This should never happen : reset state & treat it as a read */ DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd); pfl->wcycle = 0; - pfl->cmd = 0; + pfl->cmd = 0xff; /* fall through to read code */ - case 0x00: - /* Flash area read */ + case 0xff: /* Read Array */ ret = pflash_data_read(pfl, offset, width, be); break; case 0x10: /* Single byte program */ @@ -448,8 +480,6 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, case 0: /* read mode */ switch (cmd) { - case 0x00: /* ??? */ - goto reset_flash; case 0x10: /* Single Byte Program */ case 0x40: /* Single Byte Program */ DPRINTF("%s: Single Byte Program\n", __func__); @@ -526,7 +556,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, if (cmd == 0xd0) { /* confirm */ pfl->wcycle = 0; pfl->status |= 0x80; - } else if (cmd == 0xff) { /* read array mode */ + } else if (cmd == 0xff) { /* Read Array */ goto reset_flash; } else goto error_flash; @@ -553,7 +583,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, } else if (cmd == 0x01) { pfl->wcycle = 0; pfl->status |= 0x80; - } else if (cmd == 0xff) { + } else if (cmd == 0xff) { /* read array mode */ goto reset_flash; } else { DPRINTF("%s: Unknown (un)locking command\n", __func__); @@ -645,7 +675,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, trace_pflash_reset(); memory_region_rom_device_set_romd(&pfl->mem, true); pfl->wcycle = 0; - pfl->cmd = 0; + pfl->cmd = 0xff; } @@ -761,7 +791,7 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) } pfl->wcycle = 0; - pfl->cmd = 0; + pfl->cmd = 0xff; pfl->status = 0; /* Hardcoded CFI table */ /* Standard "QRY" string */ @@ -1001,5 +1031,14 @@ static int pflash_post_load(void *opaque, int version_id) pfl->vmstate = qemu_add_vm_change_state_handler(postload_update_cb, pfl); } + + /* + * Previous to QEMU v4.1 an incorrect value of 0x00 was used for the + * READ_ARRAY command. + */ + if (pfl->cmd == 0x00) { + pfl->cmd = 0xff; + } + return 0; } -- 2.20.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH v5 2/5] hw/block/pflash_cfi01: Use the correct READ_ARRAY value 2019-07-15 12:13 ` [Qemu-devel] [PATCH v5 2/5] hw/block/pflash_cfi01: Use the correct READ_ARRAY value Philippe Mathieu-Daudé @ 2019-07-16 12:25 ` Markus Armbruster 2019-07-16 14:04 ` Dr. David Alan Gilbert 0 siblings, 1 reply; 11+ messages in thread From: Markus Armbruster @ 2019-07-16 12:25 UTC (permalink / raw) To: Philippe Mathieu-Daudé Cc: Kevin Wolf, Peter Maydell, qemu-block, John Snow, qemu-devel, Dr . David Alan Gilbert, Alistair Francis, Max Reitz, Laszlo Ersek Philippe asked me to have a look at this one, so here goes. Philippe Mathieu-Daudé <philmd@redhat.com> writes: > In the document [*] the "Read Array Flowchart", the READ_ARRAY > command has a value of 0xff. > > Use the correct value in the pflash model. > > There is no change of behavior in the guest, because: > - when the guest were sending 0xFF, the reset_flash label > was setting the command value as 0x00 > - 0x00 was used internally for READ_ARRAY *Groan* Is this cleanup, or does it fix an observable bug? > To keep migration with older versions behaving correctly, we > decide to always migrate the READ_ARRAY as 0x00. > > If the CFI open standard decide to assign a new command of value > 0x00, this model is flawed because it uses this value internally. > If a guest eventually requires this new CFI feature, a different > model will be required (or this same model but breaking backward > migration). So it is safe to keep migrating READ_ARRAY as 0x00. We could perhaps keep migration working for "benign" device states, with judicious use of subsections. We'll cross that bridge when we get to it. > [*] "Common Flash Interface (CFI) and Command Sets" > (Intel Application Note 646) > Appendix B "Basic Command Set" > > Reviewed-by: John Snow <jsnow@redhat.com> > Reviewed-by: Alistair Francis <alistair.francis@wdc.com> > Regression-tested-by: Laszlo Ersek <lersek@redhat.com> > Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com> > --- > v3: Handle migrating the 'cmd' field. > v4: Handle migrating to older QEMU (Dave) > v5: Add a paragraph about why this model is flawed due to > historically using READ_ARRAY as 0x00 (Dave, Peter). > > Since Laszlo stated he did not test migration [*], I'm keeping his > test tag, because the change with v2 has no impact in the tests > he ran. > > Likewise I'm keeping John and Alistair tags, but I'd like an extra > review for the migration change, thanks! > > [*] https://lists.gnu.org/archive/html/qemu-devel/2019-07/msg00679.html > --- > hw/block/pflash_cfi01.c | 57 ++++++++++++++++++++++++++++++++++------- > 1 file changed, 48 insertions(+), 9 deletions(-) > > diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c > index 9e34fd4e82..85bb2132c0 100644 > --- a/hw/block/pflash_cfi01.c > +++ b/hw/block/pflash_cfi01.c > @@ -96,6 +96,37 @@ struct PFlashCFI01 { > bool old_multiple_chip_handling; > }; > > +static int pflash_pre_save(void *opaque) > +{ > + PFlashCFI01 *s = opaque; > + > + /* > + * Previous to QEMU v4.1 an incorrect value of 0x00 was used for the > + * READ_ARRAY command. To preserve migrating to these older version, > + * always migrate the READ_ARRAY command as 0x00. > + */ > + if (s->cmd == 0xff) { > + s->cmd = 0x00; > + } > + > + return 0; > +} > + > +static int pflash_post_save(void *opaque) > +{ > + PFlashCFI01 *s = opaque; > + > + /* > + * If migration failed, the guest will continue to run. > + * Restore the correct READ_ARRAY value. > + */ > + if (s->cmd == 0x00) { > + s->cmd = 0xff; > + } > + > + return 0; > +} Uh, this gives me a queasy feeling. Perhaps David can assuage it. I figure the intent is to migrate PFlashCFI01 member @cmd value 0xFF as 0x00, for migration compatibility to and from older versions. You do this by monkey-patching it to 0x00 before migration, and to 0xFF afterwards. On the incoming side, you replace 0x00 by 0xFF, in pflash_post_load() below. Questions: * Can anything but the code that sends @cmd see the temporary 0x00 value between pflash_pre_save() and pflash_post_save() * Consider the matrix source \in { old, new } x dest \in { old, new } x @cmd on source in { 0x00, 0xFF }. What does migration put into @cmd on dest? Eight cases: source @cmd -> wire -> dest @cmd old 0x00 -> 0x00 -> old 0x00 (1) new 0xFF (2) old 0xFF -> 0xFF -> old 0xFF (3) new 0xFF (4) new 0x00 -> 0x00 -> old 0x00 (5) new 0xFF (6) new 0xFF -> 0x00 -> old 0x00 (7) new 0xFF (8) Old -> old (cases 1 and 3) is unaffected by this patch. New -> new leaves 0xFF unchanged (8). It changes 0x00 to 0xFF (6). Uh-oh. Can this happen? Rephrasing the question: can @cmd ever be 0x00 with this patch applied? Old -> new leaves 0xFF unchanged (4). It changes 0x00 to 0xFF (2), which I think is intentional. New -> old leaves 0x00 unchanged (5). It changes 0xFF to 0x00 (7), which I think is intentional. Old -> new -> old leaves 0x00 unchanged. Good. It changes 0xFF to 0x00. Uh-oh. Can @cmd ever be 0xFF before this patch? New -> old -> new leaves 0xFF unchanged. Good. It changes 0x00 to 0xFF. Same uh-oh as for new -> new. > + > static int pflash_post_load(void *opaque, int version_id); > > static const VMStateDescription vmstate_pflash = { > @@ -103,6 +134,8 @@ static const VMStateDescription vmstate_pflash = { > .version_id = 1, > .minimum_version_id = 1, > .post_load = pflash_post_load, > + .pre_save = pflash_pre_save, > + .post_save = pflash_post_save, > .fields = (VMStateField[]) { > VMSTATE_UINT8(wcycle, PFlashCFI01), > VMSTATE_UINT8(cmd, PFlashCFI01), > @@ -277,10 +310,9 @@ static uint32_t pflash_read(PFlashCFI01 *pfl, hwaddr offset, > /* This should never happen : reset state & treat it as a read */ > DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd); > pfl->wcycle = 0; > - pfl->cmd = 0; > + pfl->cmd = 0xff; > /* fall through to read code */ > - case 0x00: > - /* Flash area read */ > + case 0xff: /* Read Array */ > ret = pflash_data_read(pfl, offset, width, be); > break; On 0xFF, we no longer zap pfl->wcycle and pfl->cmd. On 0x00, we do. We zap pfl->cmd to 0xFF instead of 0x00. Same below after label error_flash and reset_flash. Related: initialization to 0xFF instead of 0x00 in pflash_cfi01_realize(). I *guess* these changes together ensure pfl->cmd can't become 0x00. Correct? > case 0x10: /* Single byte program */ > @@ -448,8 +480,6 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, > case 0: > /* read mode */ > switch (cmd) { > - case 0x00: /* ??? */ > - goto reset_flash; On 0x00, we now use default: goto error_flash. Can this happen? > case 0x10: /* Single Byte Program */ > case 0x40: /* Single Byte Program */ > DPRINTF("%s: Single Byte Program\n", __func__); > @@ -526,7 +556,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, > if (cmd == 0xd0) { /* confirm */ > pfl->wcycle = 0; > pfl->status |= 0x80; > - } else if (cmd == 0xff) { /* read array mode */ > + } else if (cmd == 0xff) { /* Read Array */ > goto reset_flash; > } else > goto error_flash; > @@ -553,7 +583,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, > } else if (cmd == 0x01) { > pfl->wcycle = 0; > pfl->status |= 0x80; > - } else if (cmd == 0xff) { > + } else if (cmd == 0xff) { /* read array mode */ Your new comment is phrased the way you corrected in the previous hunk. Intentional? > goto reset_flash; > } else { > DPRINTF("%s: Unknown (un)locking command\n", __func__); > @@ -645,7 +675,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, error_flash: qemu_log_mask(LOG_UNIMP, "%s: Unimplemented flash cmd sequence " "(offset " TARGET_FMT_plx ", wcycle 0x%x cmd 0x%x value 0x%x)" "\n", __func__, offset, pfl->wcycle, pfl->cmd, value); reset_flash: > trace_pflash_reset(); > memory_region_rom_device_set_romd(&pfl->mem, true); > pfl->wcycle = 0; > - pfl->cmd = 0; > + pfl->cmd = 0xff; > } > > > @@ -761,7 +791,7 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) > } > > pfl->wcycle = 0; > - pfl->cmd = 0; > + pfl->cmd = 0xff; > pfl->status = 0; > /* Hardcoded CFI table */ > /* Standard "QRY" string */ > @@ -1001,5 +1031,14 @@ static int pflash_post_load(void *opaque, int version_id) > pfl->vmstate = qemu_add_vm_change_state_handler(postload_update_cb, > pfl); > } > + > + /* > + * Previous to QEMU v4.1 an incorrect value of 0x00 was used for the > + * READ_ARRAY command. > + */ > + if (pfl->cmd == 0x00) { > + pfl->cmd = 0xff; > + } > + > return 0; > } ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH v5 2/5] hw/block/pflash_cfi01: Use the correct READ_ARRAY value 2019-07-16 12:25 ` Markus Armbruster @ 2019-07-16 14:04 ` Dr. David Alan Gilbert 2019-07-16 15:12 ` Markus Armbruster 0 siblings, 1 reply; 11+ messages in thread From: Dr. David Alan Gilbert @ 2019-07-16 14:04 UTC (permalink / raw) To: Markus Armbruster Cc: Kevin Wolf, Peter Maydell, qemu-block, Laszlo Ersek, qemu-devel, Max Reitz, John Snow, Alistair Francis, Philippe Mathieu-Daudé * Markus Armbruster (armbru@redhat.com) wrote: > Philippe asked me to have a look at this one, so here goes. > > Philippe Mathieu-Daudé <philmd@redhat.com> writes: > > > In the document [*] the "Read Array Flowchart", the READ_ARRAY > > command has a value of 0xff. > > > > Use the correct value in the pflash model. > > > > There is no change of behavior in the guest, because: > > - when the guest were sending 0xFF, the reset_flash label > > was setting the command value as 0x00 > > - 0x00 was used internally for READ_ARRAY > > *Groan* > > Is this cleanup, or does it fix an observable bug? > > > To keep migration with older versions behaving correctly, we > > decide to always migrate the READ_ARRAY as 0x00. > > > > If the CFI open standard decide to assign a new command of value > > 0x00, this model is flawed because it uses this value internally. > > If a guest eventually requires this new CFI feature, a different > > model will be required (or this same model but breaking backward > > migration). So it is safe to keep migrating READ_ARRAY as 0x00. > > We could perhaps keep migration working for "benign" device states, with > judicious use of subsections. We'll cross that bridge when we get to > it. > > > [*] "Common Flash Interface (CFI) and Command Sets" > > (Intel Application Note 646) > > Appendix B "Basic Command Set" > > > > Reviewed-by: John Snow <jsnow@redhat.com> > > Reviewed-by: Alistair Francis <alistair.francis@wdc.com> > > Regression-tested-by: Laszlo Ersek <lersek@redhat.com> > > Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com> > > --- > > v3: Handle migrating the 'cmd' field. > > v4: Handle migrating to older QEMU (Dave) > > v5: Add a paragraph about why this model is flawed due to > > historically using READ_ARRAY as 0x00 (Dave, Peter). > > > > Since Laszlo stated he did not test migration [*], I'm keeping his > > test tag, because the change with v2 has no impact in the tests > > he ran. > > > > Likewise I'm keeping John and Alistair tags, but I'd like an extra > > review for the migration change, thanks! > > > > [*] https://lists.gnu.org/archive/html/qemu-devel/2019-07/msg00679.html > > --- > > hw/block/pflash_cfi01.c | 57 ++++++++++++++++++++++++++++++++++------- > > 1 file changed, 48 insertions(+), 9 deletions(-) > > > > diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c > > index 9e34fd4e82..85bb2132c0 100644 > > --- a/hw/block/pflash_cfi01.c > > +++ b/hw/block/pflash_cfi01.c > > @@ -96,6 +96,37 @@ struct PFlashCFI01 { > > bool old_multiple_chip_handling; > > }; > > > > +static int pflash_pre_save(void *opaque) > > +{ > > + PFlashCFI01 *s = opaque; > > + > > + /* > > + * Previous to QEMU v4.1 an incorrect value of 0x00 was used for the > > + * READ_ARRAY command. To preserve migrating to these older version, > > + * always migrate the READ_ARRAY command as 0x00. > > + */ > > + if (s->cmd == 0xff) { > > + s->cmd = 0x00; > > + } > > + > > + return 0; > > +} > > + > > +static int pflash_post_save(void *opaque) > > +{ > > + PFlashCFI01 *s = opaque; > > + > > + /* > > + * If migration failed, the guest will continue to run. > > + * Restore the correct READ_ARRAY value. > > + */ > > + if (s->cmd == 0x00) { > > + s->cmd = 0xff; > > + } > > + > > + return 0; > > +} > > Uh, this gives me a queasy feeling. Perhaps David can assuage it. See the previous 4 versions of discussion.... > I figure the intent is to migrate PFlashCFI01 member @cmd value 0xFF as > 0x00, for migration compatibility to and from older versions. > > You do this by monkey-patching it to 0x00 before migration, and to 0xFF > afterwards. On the incoming side, you replace 0x00 by 0xFF, in > pflash_post_load() below. > > Questions: > > * Can anything but the code that sends @cmd see the temporary 0x00 value > between pflash_pre_save() and pflash_post_save() It is the same pflash data structure; but all CPUs are stopped and we're just walking the list of devices serialising them; so no nothing should be seeing that value. (There is another way to do this, which is to produce a temporary structure at this point, populate the temporary structure and migrate that) Dave > * Consider the matrix source \in { old, new } x dest \in { old, new } x > @cmd on source in { 0x00, 0xFF }. What does migration put into @cmd > on dest? Eight cases: > > source @cmd -> wire -> dest @cmd > old 0x00 -> 0x00 -> old 0x00 (1) > new 0xFF (2) > old 0xFF -> 0xFF -> old 0xFF (3) > new 0xFF (4) > new 0x00 -> 0x00 -> old 0x00 (5) > new 0xFF (6) > new 0xFF -> 0x00 -> old 0x00 (7) > new 0xFF (8) > > Old -> old (cases 1 and 3) is unaffected by this patch. > > New -> new leaves 0xFF unchanged (8). It changes 0x00 to 0xFF (6). > Uh-oh. Can this happen? Rephrasing the question: can @cmd ever be > 0x00 with this patch applied? > > Old -> new leaves 0xFF unchanged (4). It changes 0x00 to 0xFF (2), > which I think is intentional. > > New -> old leaves 0x00 unchanged (5). It changes 0xFF to 0x00 (7), > which I think is intentional. > > Old -> new -> old leaves 0x00 unchanged. Good. It changes 0xFF to > 0x00. Uh-oh. Can @cmd ever be 0xFF before this patch? > > New -> old -> new leaves 0xFF unchanged. Good. It changes 0x00 to > 0xFF. Same uh-oh as for new -> new. > > > + > > static int pflash_post_load(void *opaque, int version_id); > > > > static const VMStateDescription vmstate_pflash = { > > @@ -103,6 +134,8 @@ static const VMStateDescription vmstate_pflash = { > > .version_id = 1, > > .minimum_version_id = 1, > > .post_load = pflash_post_load, > > + .pre_save = pflash_pre_save, > > + .post_save = pflash_post_save, > > .fields = (VMStateField[]) { > > VMSTATE_UINT8(wcycle, PFlashCFI01), > > VMSTATE_UINT8(cmd, PFlashCFI01), > > @@ -277,10 +310,9 @@ static uint32_t pflash_read(PFlashCFI01 *pfl, hwaddr offset, > > /* This should never happen : reset state & treat it as a read */ > > DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd); > > pfl->wcycle = 0; > > - pfl->cmd = 0; > > + pfl->cmd = 0xff; > > /* fall through to read code */ > > - case 0x00: > > - /* Flash area read */ > > + case 0xff: /* Read Array */ > > ret = pflash_data_read(pfl, offset, width, be); > > break; > > On 0xFF, we no longer zap pfl->wcycle and pfl->cmd. > > On 0x00, we do. > > We zap pfl->cmd to 0xFF instead of 0x00. Same below after label > error_flash and reset_flash. Related: initialization to 0xFF instead of > 0x00 in pflash_cfi01_realize(). I *guess* these changes together ensure > pfl->cmd can't become 0x00. Correct? > > > case 0x10: /* Single byte program */ > > @@ -448,8 +480,6 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, > > case 0: > > /* read mode */ > > switch (cmd) { > > - case 0x00: /* ??? */ > > - goto reset_flash; > > On 0x00, we now use default: goto error_flash. Can this happen? > > > case 0x10: /* Single Byte Program */ > > case 0x40: /* Single Byte Program */ > > DPRINTF("%s: Single Byte Program\n", __func__); > > @@ -526,7 +556,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, > > if (cmd == 0xd0) { /* confirm */ > > pfl->wcycle = 0; > > pfl->status |= 0x80; > > - } else if (cmd == 0xff) { /* read array mode */ > > + } else if (cmd == 0xff) { /* Read Array */ > > goto reset_flash; > > } else > > goto error_flash; > > @@ -553,7 +583,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, > > } else if (cmd == 0x01) { > > pfl->wcycle = 0; > > pfl->status |= 0x80; > > - } else if (cmd == 0xff) { > > + } else if (cmd == 0xff) { /* read array mode */ > > Your new comment is phrased the way you corrected in the previous hunk. > Intentional? > > > goto reset_flash; > > } else { > > DPRINTF("%s: Unknown (un)locking command\n", __func__); > > @@ -645,7 +675,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, > error_flash: > qemu_log_mask(LOG_UNIMP, "%s: Unimplemented flash cmd sequence " > "(offset " TARGET_FMT_plx ", wcycle 0x%x cmd 0x%x value 0x%x)" > "\n", __func__, offset, pfl->wcycle, pfl->cmd, value); > > reset_flash: > > trace_pflash_reset(); > > memory_region_rom_device_set_romd(&pfl->mem, true); > > pfl->wcycle = 0; > > - pfl->cmd = 0; > > + pfl->cmd = 0xff; > > } > > > > > > @@ -761,7 +791,7 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) > > } > > > > pfl->wcycle = 0; > > - pfl->cmd = 0; > > + pfl->cmd = 0xff; > > pfl->status = 0; > > /* Hardcoded CFI table */ > > /* Standard "QRY" string */ > > @@ -1001,5 +1031,14 @@ static int pflash_post_load(void *opaque, int version_id) > > pfl->vmstate = qemu_add_vm_change_state_handler(postload_update_cb, > > pfl); > > } > > + > > + /* > > + * Previous to QEMU v4.1 an incorrect value of 0x00 was used for the > > + * READ_ARRAY command. > > + */ > > + if (pfl->cmd == 0x00) { > > + pfl->cmd = 0xff; > > + } > > + > > return 0; > > } -- Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH v5 2/5] hw/block/pflash_cfi01: Use the correct READ_ARRAY value 2019-07-16 14:04 ` Dr. David Alan Gilbert @ 2019-07-16 15:12 ` Markus Armbruster 2019-07-29 16:21 ` Philippe Mathieu-Daudé 0 siblings, 1 reply; 11+ messages in thread From: Markus Armbruster @ 2019-07-16 15:12 UTC (permalink / raw) To: Dr. David Alan Gilbert Cc: Kevin Wolf, Peter Maydell, qemu-block, John Snow, Philippe Mathieu-Daudé, qemu-devel, Max Reitz, Alistair Francis, Laszlo Ersek "Dr. David Alan Gilbert" <dgilbert@redhat.com> writes: > * Markus Armbruster (armbru@redhat.com) wrote: >> Philippe asked me to have a look at this one, so here goes. >> >> Philippe Mathieu-Daudé <philmd@redhat.com> writes: >> >> > In the document [*] the "Read Array Flowchart", the READ_ARRAY >> > command has a value of 0xff. >> > >> > Use the correct value in the pflash model. >> > >> > There is no change of behavior in the guest, because: >> > - when the guest were sending 0xFF, the reset_flash label >> > was setting the command value as 0x00 >> > - 0x00 was used internally for READ_ARRAY >> >> *Groan* >> >> Is this cleanup, or does it fix an observable bug? >> >> > To keep migration with older versions behaving correctly, we >> > decide to always migrate the READ_ARRAY as 0x00. >> > >> > If the CFI open standard decide to assign a new command of value >> > 0x00, this model is flawed because it uses this value internally. >> > If a guest eventually requires this new CFI feature, a different >> > model will be required (or this same model but breaking backward >> > migration). So it is safe to keep migrating READ_ARRAY as 0x00. >> >> We could perhaps keep migration working for "benign" device states, with >> judicious use of subsections. We'll cross that bridge when we get to >> it. >> >> > [*] "Common Flash Interface (CFI) and Command Sets" >> > (Intel Application Note 646) >> > Appendix B "Basic Command Set" >> > >> > Reviewed-by: John Snow <jsnow@redhat.com> >> > Reviewed-by: Alistair Francis <alistair.francis@wdc.com> >> > Regression-tested-by: Laszlo Ersek <lersek@redhat.com> >> > Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com> >> > --- >> > v3: Handle migrating the 'cmd' field. >> > v4: Handle migrating to older QEMU (Dave) >> > v5: Add a paragraph about why this model is flawed due to >> > historically using READ_ARRAY as 0x00 (Dave, Peter). >> > >> > Since Laszlo stated he did not test migration [*], I'm keeping his >> > test tag, because the change with v2 has no impact in the tests >> > he ran. >> > >> > Likewise I'm keeping John and Alistair tags, but I'd like an extra >> > review for the migration change, thanks! >> > >> > [*] https://lists.gnu.org/archive/html/qemu-devel/2019-07/msg00679.html >> > --- >> > hw/block/pflash_cfi01.c | 57 ++++++++++++++++++++++++++++++++++------- >> > 1 file changed, 48 insertions(+), 9 deletions(-) >> > >> > diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c >> > index 9e34fd4e82..85bb2132c0 100644 >> > --- a/hw/block/pflash_cfi01.c >> > +++ b/hw/block/pflash_cfi01.c >> > @@ -96,6 +96,37 @@ struct PFlashCFI01 { >> > bool old_multiple_chip_handling; >> > }; >> > >> > +static int pflash_pre_save(void *opaque) >> > +{ >> > + PFlashCFI01 *s = opaque; >> > + >> > + /* >> > + * Previous to QEMU v4.1 an incorrect value of 0x00 was used for the >> > + * READ_ARRAY command. To preserve migrating to these older version, >> > + * always migrate the READ_ARRAY command as 0x00. >> > + */ >> > + if (s->cmd == 0xff) { >> > + s->cmd = 0x00; >> > + } >> > + >> > + return 0; >> > +} >> > + >> > +static int pflash_post_save(void *opaque) >> > +{ >> > + PFlashCFI01 *s = opaque; >> > + >> > + /* >> > + * If migration failed, the guest will continue to run. >> > + * Restore the correct READ_ARRAY value. >> > + */ >> > + if (s->cmd == 0x00) { >> > + s->cmd = 0xff; >> > + } >> > + >> > + return 0; >> > +} >> >> Uh, this gives me a queasy feeling. Perhaps David can assuage it. > > See the previous 4 versions of discussion.... Jumped in at v5; sorry about that. >> I figure the intent is to migrate PFlashCFI01 member @cmd value 0xFF as >> 0x00, for migration compatibility to and from older versions. >> >> You do this by monkey-patching it to 0x00 before migration, and to 0xFF >> afterwards. On the incoming side, you replace 0x00 by 0xFF, in >> pflash_post_load() below. >> >> Questions: >> >> * Can anything but the code that sends @cmd see the temporary 0x00 value >> between pflash_pre_save() and pflash_post_save() > > It is the same pflash data structure; but all CPUs are stopped and we're > just walking the list of devices serialising them; so no nothing should > be seeing that value. Sounds good. > (There is another way to do this, which is to produce a temporary > structure at this point, populate the temporary structure and migrate > that) Not necessary. The uh-ohs below still need assuaging, not necessarily yours. > Dave > >> * Consider the matrix source \in { old, new } x dest \in { old, new } x >> @cmd on source in { 0x00, 0xFF }. What does migration put into @cmd >> on dest? Eight cases: >> >> source @cmd -> wire -> dest @cmd >> old 0x00 -> 0x00 -> old 0x00 (1) >> new 0xFF (2) >> old 0xFF -> 0xFF -> old 0xFF (3) >> new 0xFF (4) >> new 0x00 -> 0x00 -> old 0x00 (5) >> new 0xFF (6) >> new 0xFF -> 0x00 -> old 0x00 (7) >> new 0xFF (8) >> >> Old -> old (cases 1 and 3) is unaffected by this patch. >> >> New -> new leaves 0xFF unchanged (8). It changes 0x00 to 0xFF (6). >> Uh-oh. Can this happen? Rephrasing the question: can @cmd ever be >> 0x00 with this patch applied? >> >> Old -> new leaves 0xFF unchanged (4). It changes 0x00 to 0xFF (2), >> which I think is intentional. >> >> New -> old leaves 0x00 unchanged (5). It changes 0xFF to 0x00 (7), >> which I think is intentional. >> >> Old -> new -> old leaves 0x00 unchanged. Good. It changes 0xFF to >> 0x00. Uh-oh. Can @cmd ever be 0xFF before this patch? >> >> New -> old -> new leaves 0xFF unchanged. Good. It changes 0x00 to >> 0xFF. Same uh-oh as for new -> new. >> >> > + >> > static int pflash_post_load(void *opaque, int version_id); >> > >> > static const VMStateDescription vmstate_pflash = { >> > @@ -103,6 +134,8 @@ static const VMStateDescription vmstate_pflash = { >> > .version_id = 1, >> > .minimum_version_id = 1, >> > .post_load = pflash_post_load, >> > + .pre_save = pflash_pre_save, >> > + .post_save = pflash_post_save, >> > .fields = (VMStateField[]) { >> > VMSTATE_UINT8(wcycle, PFlashCFI01), >> > VMSTATE_UINT8(cmd, PFlashCFI01), >> > @@ -277,10 +310,9 @@ static uint32_t pflash_read(PFlashCFI01 *pfl, hwaddr offset, >> > /* This should never happen : reset state & treat it as a read */ >> > DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd); >> > pfl->wcycle = 0; >> > - pfl->cmd = 0; >> > + pfl->cmd = 0xff; >> > /* fall through to read code */ >> > - case 0x00: >> > - /* Flash area read */ >> > + case 0xff: /* Read Array */ >> > ret = pflash_data_read(pfl, offset, width, be); >> > break; >> >> On 0xFF, we no longer zap pfl->wcycle and pfl->cmd. >> >> On 0x00, we do. >> >> We zap pfl->cmd to 0xFF instead of 0x00. Same below after label >> error_flash and reset_flash. Related: initialization to 0xFF instead of >> 0x00 in pflash_cfi01_realize(). I *guess* these changes together ensure >> pfl->cmd can't become 0x00. Correct? >> >> > case 0x10: /* Single byte program */ >> > @@ -448,8 +480,6 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, >> > case 0: >> > /* read mode */ >> > switch (cmd) { >> > - case 0x00: /* ??? */ >> > - goto reset_flash; >> >> On 0x00, we now use default: goto error_flash. Can this happen? >> >> > case 0x10: /* Single Byte Program */ >> > case 0x40: /* Single Byte Program */ >> > DPRINTF("%s: Single Byte Program\n", __func__); >> > @@ -526,7 +556,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, >> > if (cmd == 0xd0) { /* confirm */ >> > pfl->wcycle = 0; >> > pfl->status |= 0x80; >> > - } else if (cmd == 0xff) { /* read array mode */ >> > + } else if (cmd == 0xff) { /* Read Array */ >> > goto reset_flash; >> > } else >> > goto error_flash; >> > @@ -553,7 +583,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, >> > } else if (cmd == 0x01) { >> > pfl->wcycle = 0; >> > pfl->status |= 0x80; >> > - } else if (cmd == 0xff) { >> > + } else if (cmd == 0xff) { /* read array mode */ >> >> Your new comment is phrased the way you corrected in the previous hunk. >> Intentional? >> >> > goto reset_flash; >> > } else { >> > DPRINTF("%s: Unknown (un)locking command\n", __func__); >> > @@ -645,7 +675,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, >> error_flash: >> qemu_log_mask(LOG_UNIMP, "%s: Unimplemented flash cmd sequence " >> "(offset " TARGET_FMT_plx ", wcycle 0x%x cmd 0x%x value 0x%x)" >> "\n", __func__, offset, pfl->wcycle, pfl->cmd, value); >> >> reset_flash: >> > trace_pflash_reset(); >> > memory_region_rom_device_set_romd(&pfl->mem, true); >> > pfl->wcycle = 0; >> > - pfl->cmd = 0; >> > + pfl->cmd = 0xff; >> > } >> > >> > >> > @@ -761,7 +791,7 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) >> > } >> > >> > pfl->wcycle = 0; >> > - pfl->cmd = 0; >> > + pfl->cmd = 0xff; >> > pfl->status = 0; >> > /* Hardcoded CFI table */ >> > /* Standard "QRY" string */ >> > @@ -1001,5 +1031,14 @@ static int pflash_post_load(void *opaque, int version_id) >> > pfl->vmstate = qemu_add_vm_change_state_handler(postload_update_cb, >> > pfl); >> > } >> > + >> > + /* >> > + * Previous to QEMU v4.1 an incorrect value of 0x00 was used for the >> > + * READ_ARRAY command. >> > + */ >> > + if (pfl->cmd == 0x00) { >> > + pfl->cmd = 0xff; >> > + } >> > + >> > return 0; >> > } > -- > Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH v5 2/5] hw/block/pflash_cfi01: Use the correct READ_ARRAY value 2019-07-16 15:12 ` Markus Armbruster @ 2019-07-29 16:21 ` Philippe Mathieu-Daudé 2019-07-31 12:22 ` Markus Armbruster 0 siblings, 1 reply; 11+ messages in thread From: Philippe Mathieu-Daudé @ 2019-07-29 16:21 UTC (permalink / raw) To: Markus Armbruster, Dr. David Alan Gilbert Cc: Kevin Wolf, Peter Maydell, qemu-block, John Snow, qemu-devel, Max Reitz, Alistair Francis, Laszlo Ersek Hi Markus. On 7/16/19 5:12 PM, Markus Armbruster wrote: > "Dr. David Alan Gilbert" <dgilbert@redhat.com> writes: > >> * Markus Armbruster (armbru@redhat.com) wrote: >>> Philippe asked me to have a look at this one, so here goes. Thanks a lot for your careful analysis. I got scared the uh-oh you raised would get this series or rework of it still refused for the release, so I went for a quick-and-dirty bugfix. Since this bugfix got merged (as commit 3a283507c0347), I can now think again about how to properly fix this (if it is fixable...). >>> Philippe Mathieu-Daudé <philmd@redhat.com> writes: >>> >>>> In the document [*] the "Read Array Flowchart", the READ_ARRAY >>>> command has a value of 0xff. >>>> >>>> Use the correct value in the pflash model. >>>> >>>> There is no change of behavior in the guest, because: >>>> - when the guest were sending 0xFF, the reset_flash label >>>> was setting the command value as 0x00 >>>> - 0x00 was used internally for READ_ARRAY >>> >>> *Groan* >>> >>> Is this cleanup, or does it fix an observable bug? Well it depends where you stand. I have a few patches on top of this adding trace events (4.2 material) and while debugging it was not making sense with the CFI specs. 1/ The guest writes 0xFF to go in READ_ARRAY mode, the model report a warning and take the switch default case which calls pflash_reset(), which happens to set the flash in READ_ARRAY. 2/ Then a later series adds the CFI specs timings (like the CFI02 model), because it would useful to test the UEFI Capsule Update feature with real-time behavior. For the 'Virt' pflash, the timing is disabled. Now running a non-Virt pflash, it becomes very slow because each time the guest goes into READ_ARRAY mode, the reset delay (which is the longest) occurs. Talking with Laszlo, I figured for 1/ instead of fixing the model, I can display 0x00 as 0xFF and ignore the pflash_reset() when the caller is not system_reset(). Dirty again. For 2/ it is not that easy, it will depends if there is more interest from the UEFI community (Intel parallel NOR flashes are used on x86 and aarch64 UEFI platforms). If we justify 1/ and 2/ are not important, then it is simply a cleanup. >>>> To keep migration with older versions behaving correctly, we >>>> decide to always migrate the READ_ARRAY as 0x00. >>>> >>>> If the CFI open standard decide to assign a new command of value >>>> 0x00, this model is flawed because it uses this value internally. >>>> If a guest eventually requires this new CFI feature, a different >>>> model will be required (or this same model but breaking backward >>>> migration). So it is safe to keep migrating READ_ARRAY as 0x00. >>> >>> We could perhaps keep migration working for "benign" device states, with >>> judicious use of subsections. We'll cross that bridge when we get to >>> it. >>> >>>> [*] "Common Flash Interface (CFI) and Command Sets" >>>> (Intel Application Note 646) >>>> Appendix B "Basic Command Set" >>>> >>>> Reviewed-by: John Snow <jsnow@redhat.com> >>>> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> >>>> Regression-tested-by: Laszlo Ersek <lersek@redhat.com> >>>> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com> >>>> --- >>>> v3: Handle migrating the 'cmd' field. >>>> v4: Handle migrating to older QEMU (Dave) >>>> v5: Add a paragraph about why this model is flawed due to >>>> historically using READ_ARRAY as 0x00 (Dave, Peter). >>>> >>>> Since Laszlo stated he did not test migration [*], I'm keeping his >>>> test tag, because the change with v2 has no impact in the tests >>>> he ran. >>>> >>>> Likewise I'm keeping John and Alistair tags, but I'd like an extra >>>> review for the migration change, thanks! >>>> >>>> [*] https://lists.gnu.org/archive/html/qemu-devel/2019-07/msg00679.html >>>> --- >>>> hw/block/pflash_cfi01.c | 57 ++++++++++++++++++++++++++++++++++------- >>>> 1 file changed, 48 insertions(+), 9 deletions(-) >>>> >>>> diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c >>>> index 9e34fd4e82..85bb2132c0 100644 >>>> --- a/hw/block/pflash_cfi01.c >>>> +++ b/hw/block/pflash_cfi01.c >>>> @@ -96,6 +96,37 @@ struct PFlashCFI01 { >>>> bool old_multiple_chip_handling; >>>> }; >>>> >>>> +static int pflash_pre_save(void *opaque) >>>> +{ >>>> + PFlashCFI01 *s = opaque; >>>> + >>>> + /* >>>> + * Previous to QEMU v4.1 an incorrect value of 0x00 was used for the >>>> + * READ_ARRAY command. To preserve migrating to these older version, >>>> + * always migrate the READ_ARRAY command as 0x00. >>>> + */ >>>> + if (s->cmd == 0xff) { >>>> + s->cmd = 0x00; >>>> + } >>>> + >>>> + return 0; >>>> +} >>>> + >>>> +static int pflash_post_save(void *opaque) >>>> +{ >>>> + PFlashCFI01 *s = opaque; >>>> + >>>> + /* >>>> + * If migration failed, the guest will continue to run. >>>> + * Restore the correct READ_ARRAY value. >>>> + */ >>>> + if (s->cmd == 0x00) { >>>> + s->cmd = 0xff; >>>> + } >>>> + >>>> + return 0; >>>> +} >>> >>> Uh, this gives me a queasy feeling. Perhaps David can assuage it. >> >> See the previous 4 versions of discussion.... > > Jumped in at v5; sorry about that. > >>> I figure the intent is to migrate PFlashCFI01 member @cmd value 0xFF as >>> 0x00, for migration compatibility to and from older versions. >>> >>> You do this by monkey-patching it to 0x00 before migration, and to 0xFF >>> afterwards. On the incoming side, you replace 0x00 by 0xFF, in >>> pflash_post_load() below. >>> >>> Questions: >>> >>> * Can anything but the code that sends @cmd see the temporary 0x00 value >>> between pflash_pre_save() and pflash_post_save() >> >> It is the same pflash data structure; but all CPUs are stopped and we're >> just walking the list of devices serialising them; so no nothing should >> be seeing that value. > > Sounds good. > >> (There is another way to do this, which is to produce a temporary >> structure at this point, populate the temporary structure and migrate >> that) > > Not necessary. > > The uh-ohs below still need assuaging, not necessarily yours. > >> Dave >> >>> * Consider the matrix source \in { old, new } x dest \in { old, new } x >>> @cmd on source in { 0x00, 0xFF }. What does migration put into @cmd >>> on dest? Eight cases: >>> >>> source @cmd -> wire -> dest @cmd >>> old 0x00 -> 0x00 -> old 0x00 (1) >>> new 0xFF (2) >>> old 0xFF -> 0xFF -> old 0xFF (3) >>> new 0xFF (4) >>> new 0x00 -> 0x00 -> old 0x00 (5) >>> new 0xFF (6) >>> new 0xFF -> 0x00 -> old 0x00 (7) >>> new 0xFF (8) >>> >>> Old -> old (cases 1 and 3) is unaffected by this patch. >>> >>> New -> new leaves 0xFF unchanged (8). It changes 0x00 to 0xFF (6). >>> Uh-oh. Can this happen? Rephrasing the question: can @cmd ever be >>> 0x00 with this patch applied? 0x00 is not in the spec (but as suggested Peter Maydell, the spec can eventually assign the value in the future [*]). So no guests use it. This value is only set: - when the (old) model is initialized, without any access to the guest - if the guest wrote an incorrect value, hitting the switch default case. The guest can not read this value (value internal to the state machine). So answer: Yes :( [*] However the spec has a way to announce supported features to the guest. >>> >>> Old -> new leaves 0xFF unchanged (4). It changes 0x00 to 0xFF (2), >>> which I think is intentional. >>> >>> New -> old leaves 0x00 unchanged (5). It changes 0xFF to 0x00 (7), >>> which I think is intentional. >>> >>> Old -> new -> old leaves 0x00 unchanged. Good. It changes 0xFF to >>> 0x00. Uh-oh. Can @cmd ever be 0xFF before this patch? I understand the full question as "Can @cmd ever be 0xFF [in Old] before this patch?". Answer: No, neither the guest nor the state machine can set @cmd to 0xFF in Old. >>> >>> New -> old -> new leaves 0xFF unchanged. Good. It changes 0x00 to >>> 0xFF. Same uh-oh as for new -> new. "Same uh-oh", do you mean "Can @cmd ever be 0x00 [in New] before this patch?"? Same answer: No, neither the guest nor the state machine can set @cmd to 0x00 in New. >>> >>>> + >>>> static int pflash_post_load(void *opaque, int version_id); >>>> >>>> static const VMStateDescription vmstate_pflash = { >>>> @@ -103,6 +134,8 @@ static const VMStateDescription vmstate_pflash = { >>>> .version_id = 1, >>>> .minimum_version_id = 1, >>>> .post_load = pflash_post_load, >>>> + .pre_save = pflash_pre_save, >>>> + .post_save = pflash_post_save, >>>> .fields = (VMStateField[]) { >>>> VMSTATE_UINT8(wcycle, PFlashCFI01), >>>> VMSTATE_UINT8(cmd, PFlashCFI01), >>>> @@ -277,10 +310,9 @@ static uint32_t pflash_read(PFlashCFI01 *pfl, hwaddr offset, >>>> /* This should never happen : reset state & treat it as a read */ >>>> DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd); >>>> pfl->wcycle = 0; >>>> - pfl->cmd = 0; >>>> + pfl->cmd = 0xff; >>>> /* fall through to read code */ >>>> - case 0x00: >>>> - /* Flash area read */ >>>> + case 0xff: /* Read Array */ >>>> ret = pflash_data_read(pfl, offset, width, be); >>>> break; >>> >>> On 0xFF, we no longer zap pfl->wcycle and pfl->cmd. We have 2 ways to set @cmd=0xFF. - Write 0xFF, write an invalid command, finish a multicycle operation (wcycle returns to 0): pflash_write() goto reset_flash, then calls memory_region_rom_device_set_romd(). set wcycle=0, cmd=READ_ARRAY. Next read() will be in ROMD mode, we won't reach pflash_read(). - if next access is write, we'll enter the same pflash_write(). - The /* This should never happen */ comment in pflash_read(). It might happens migrating? So we migrated crap, the guest wants to read, the crap defaults to READ_ARRAY in I/O mode. Wrong in many ways, not sure what the guest expects there, probably not ARRAY data. Anyway, we stay in this READ_ARRAY I/O mode until the guest eventually does a write access. Wrong. The case "The state machine set 0xff, let the device in I/O mode" so we expect to answer to a read() with READ_ARRAY is wrong too, the device should already be in ROMD mode. >>> >>> On 0x00, we do. Because we have no idea how we got there... Neither what we should do. >>> >>> We zap pfl->cmd to 0xFF instead of 0x00. Same below after label >>> error_flash and reset_flash. Related: initialization to 0xFF instead of >>> 0x00 in pflash_cfi01_realize(). I *guess* these changes together ensure >>> pfl->cmd can't become 0x00. Correct? >>> >>>> case 0x10: /* Single byte program */ >>>> @@ -448,8 +480,6 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, >>>> case 0: >>>> /* read mode */ >>>> switch (cmd) { >>>> - case 0x00: /* ??? */ >>>> - goto reset_flash; >>> >>> On 0x00, we now use default: goto error_flash. Can this happen? This could happen if the the guest is writing crap, so we correctly report this as an error. >>> >>>> case 0x10: /* Single Byte Program */ >>>> case 0x40: /* Single Byte Program */ >>>> DPRINTF("%s: Single Byte Program\n", __func__); >>>> @@ -526,7 +556,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, >>>> if (cmd == 0xd0) { /* confirm */ >>>> pfl->wcycle = 0; >>>> pfl->status |= 0x80; >>>> - } else if (cmd == 0xff) { /* read array mode */ >>>> + } else if (cmd == 0xff) { /* Read Array */ >>>> goto reset_flash; >>>> } else >>>> goto error_flash; >>>> @@ -553,7 +583,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, >>>> } else if (cmd == 0x01) { >>>> pfl->wcycle = 0; >>>> pfl->status |= 0x80; >>>> - } else if (cmd == 0xff) { >>>> + } else if (cmd == 0xff) { /* read array mode */ >>> >>> Your new comment is phrased the way you corrected in the previous hunk. >>> Intentional? No :/ Too many rebases. >>> >>>> goto reset_flash; >>>> } else { >>>> DPRINTF("%s: Unknown (un)locking command\n", __func__); >>>> @@ -645,7 +675,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, >>> error_flash: >>> qemu_log_mask(LOG_UNIMP, "%s: Unimplemented flash cmd sequence " >>> "(offset " TARGET_FMT_plx ", wcycle 0x%x cmd 0x%x value 0x%x)" >>> "\n", __func__, offset, pfl->wcycle, pfl->cmd, value); >>> >>> reset_flash: >>>> trace_pflash_reset(); >>>> memory_region_rom_device_set_romd(&pfl->mem, true); >>>> pfl->wcycle = 0; >>>> - pfl->cmd = 0; >>>> + pfl->cmd = 0xff; >>>> } >>>> >>>> >>>> @@ -761,7 +791,7 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) >>>> } >>>> >>>> pfl->wcycle = 0; >>>> - pfl->cmd = 0; >>>> + pfl->cmd = 0xff; >>>> pfl->status = 0; >>>> /* Hardcoded CFI table */ >>>> /* Standard "QRY" string */ >>>> @@ -1001,5 +1031,14 @@ static int pflash_post_load(void *opaque, int version_id) >>>> pfl->vmstate = qemu_add_vm_change_state_handler(postload_update_cb, >>>> pfl); >>>> } >>>> + >>>> + /* >>>> + * Previous to QEMU v4.1 an incorrect value of 0x00 was used for the >>>> + * READ_ARRAY command. >>>> + */ >>>> + if (pfl->cmd == 0x00) { >>>> + pfl->cmd = 0xff; >>>> + } >>>> + >>>> return 0; >>>> } >> -- >> Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH v5 2/5] hw/block/pflash_cfi01: Use the correct READ_ARRAY value 2019-07-29 16:21 ` Philippe Mathieu-Daudé @ 2019-07-31 12:22 ` Markus Armbruster 0 siblings, 0 replies; 11+ messages in thread From: Markus Armbruster @ 2019-07-31 12:22 UTC (permalink / raw) To: Philippe Mathieu-Daudé Cc: Kevin Wolf, Peter Maydell, qemu-block, Laszlo Ersek, Dr. David Alan Gilbert, qemu-devel, Alistair Francis, Max Reitz, John Snow Philippe Mathieu-Daudé <philmd@redhat.com> writes: > Hi Markus. > > On 7/16/19 5:12 PM, Markus Armbruster wrote: >> "Dr. David Alan Gilbert" <dgilbert@redhat.com> writes: >> >>> * Markus Armbruster (armbru@redhat.com) wrote: >>>> Philippe asked me to have a look at this one, so here goes. > > Thanks a lot for your careful analysis. > > I got scared the uh-oh you raised would get this series or rework of it > still refused for the release, so I went for a quick-and-dirty bugfix. This close to the release, minimal bug fix now and cleanup later makes lots of sense. > Since this bugfix got merged (as commit 3a283507c0347), I can now think > again about how to properly fix this (if it is fixable...). > >>>> Philippe Mathieu-Daudé <philmd@redhat.com> writes: >>>> >>>>> In the document [*] the "Read Array Flowchart", the READ_ARRAY >>>>> command has a value of 0xff. >>>>> >>>>> Use the correct value in the pflash model. >>>>> >>>>> There is no change of behavior in the guest, because: >>>>> - when the guest were sending 0xFF, the reset_flash label >>>>> was setting the command value as 0x00 >>>>> - 0x00 was used internally for READ_ARRAY >>>> >>>> *Groan* >>>> >>>> Is this cleanup, or does it fix an observable bug? > > Well it depends where you stand. > > I have a few patches on top of this adding trace events (4.2 material) > and while debugging it was not making sense with the CFI specs. > > 1/ The guest writes 0xFF to go in READ_ARRAY mode, the model report a > warning and take the switch default case which calls pflash_reset(), > which happens to set the flash in READ_ARRAY. This one, in pflash_write()? switch (pfl->wcycle) { case 0: ... ---> case 0xff: /* Read array mode */ DPRINTF("%s: Read array mode\n", __func__); goto reset_flash; ... } return; ... reset_flash: trace_pflash_reset(); memory_region_rom_device_set_romd(&pfl->mem, true); pfl->wcycle = 0; pfl->cmd = 0; I can't see a warning here. Let's ignore the tracepoint. Is the memory_region_rom_device_set_romd() appropriate for READ_ARRAY? pfl->wcycle = 0 is a no-op. pfl->cmd = 0 is part of the "use 0 instead 0f 0xFF to represent READ_ARRAY state" madness. By the way, use of tracing and DPRINTF() in the same .c is an anti-pattern. Care to convert the remaining DPRINTF() into tracepoints? Feel free to delete useless ones, if any. > 2/ Then a later series adds the CFI specs timings (like the CFI02 > model), because it would useful to test the UEFI Capsule Update feature > with real-time behavior. For the 'Virt' pflash, the timing is disabled. > Now running a non-Virt pflash, it becomes very slow because each time > the guest goes into READ_ARRAY mode, the reset delay (which is the > longest) occurs. Feels like a latent bug. Adding timing turns it into a real one. > Talking with Laszlo, I figured for 1/ instead of fixing the model, I can > display 0x00 as 0xFF and ignore the pflash_reset() when the caller is > not system_reset(). Dirty again. > > For 2/ it is not that easy, it will depends if there is more interest > from the UEFI community (Intel parallel NOR flashes are used on x86 and > aarch64 UEFI platforms). > > If we justify 1/ and 2/ are not important, then it is simply a cleanup. If it's a bug fix, have the commit message explain the bug. If it's just cleanup, heave the commit message say so. >>>>> To keep migration with older versions behaving correctly, we >>>>> decide to always migrate the READ_ARRAY as 0x00. >>>>> >>>>> If the CFI open standard decide to assign a new command of value >>>>> 0x00, this model is flawed because it uses this value internally. >>>>> If a guest eventually requires this new CFI feature, a different >>>>> model will be required (or this same model but breaking backward >>>>> migration). So it is safe to keep migrating READ_ARRAY as 0x00. >>>> >>>> We could perhaps keep migration working for "benign" device states, with >>>> judicious use of subsections. We'll cross that bridge when we get to >>>> it. >>>> >>>>> [*] "Common Flash Interface (CFI) and Command Sets" >>>>> (Intel Application Note 646) >>>>> Appendix B "Basic Command Set" >>>>> >>>>> Reviewed-by: John Snow <jsnow@redhat.com> >>>>> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> >>>>> Regression-tested-by: Laszlo Ersek <lersek@redhat.com> >>>>> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com> >>>>> --- >>>>> v3: Handle migrating the 'cmd' field. >>>>> v4: Handle migrating to older QEMU (Dave) >>>>> v5: Add a paragraph about why this model is flawed due to >>>>> historically using READ_ARRAY as 0x00 (Dave, Peter). >>>>> >>>>> Since Laszlo stated he did not test migration [*], I'm keeping his >>>>> test tag, because the change with v2 has no impact in the tests >>>>> he ran. >>>>> >>>>> Likewise I'm keeping John and Alistair tags, but I'd like an extra >>>>> review for the migration change, thanks! >>>>> >>>>> [*] https://lists.gnu.org/archive/html/qemu-devel/2019-07/msg00679.html >>>>> --- >>>>> hw/block/pflash_cfi01.c | 57 ++++++++++++++++++++++++++++++++++------- >>>>> 1 file changed, 48 insertions(+), 9 deletions(-) >>>>> >>>>> diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c >>>>> index 9e34fd4e82..85bb2132c0 100644 >>>>> --- a/hw/block/pflash_cfi01.c >>>>> +++ b/hw/block/pflash_cfi01.c >>>>> @@ -96,6 +96,37 @@ struct PFlashCFI01 { >>>>> bool old_multiple_chip_handling; >>>>> }; >>>>> >>>>> +static int pflash_pre_save(void *opaque) >>>>> +{ >>>>> + PFlashCFI01 *s = opaque; >>>>> + >>>>> + /* >>>>> + * Previous to QEMU v4.1 an incorrect value of 0x00 was used for the >>>>> + * READ_ARRAY command. To preserve migrating to these older version, >>>>> + * always migrate the READ_ARRAY command as 0x00. >>>>> + */ >>>>> + if (s->cmd == 0xff) { >>>>> + s->cmd = 0x00; >>>>> + } >>>>> + >>>>> + return 0; >>>>> +} >>>>> + >>>>> +static int pflash_post_save(void *opaque) >>>>> +{ >>>>> + PFlashCFI01 *s = opaque; >>>>> + >>>>> + /* >>>>> + * If migration failed, the guest will continue to run. >>>>> + * Restore the correct READ_ARRAY value. >>>>> + */ >>>>> + if (s->cmd == 0x00) { >>>>> + s->cmd = 0xff; >>>>> + } >>>>> + >>>>> + return 0; >>>>> +} >>>> >>>> Uh, this gives me a queasy feeling. Perhaps David can assuage it. >>> >>> See the previous 4 versions of discussion.... >> >> Jumped in at v5; sorry about that. >> >>>> I figure the intent is to migrate PFlashCFI01 member @cmd value 0xFF as >>>> 0x00, for migration compatibility to and from older versions. >>>> >>>> You do this by monkey-patching it to 0x00 before migration, and to 0xFF >>>> afterwards. On the incoming side, you replace 0x00 by 0xFF, in >>>> pflash_post_load() below. >>>> >>>> Questions: >>>> >>>> * Can anything but the code that sends @cmd see the temporary 0x00 value >>>> between pflash_pre_save() and pflash_post_save() >>> >>> It is the same pflash data structure; but all CPUs are stopped and we're >>> just walking the list of devices serialising them; so no nothing should >>> be seeing that value. >> >> Sounds good. >> >>> (There is another way to do this, which is to produce a temporary >>> structure at this point, populate the temporary structure and migrate >>> that) >> >> Not necessary. >> >> The uh-ohs below still need assuaging, not necessarily yours. >> >>> Dave >>> >>>> * Consider the matrix source \in { old, new } x dest \in { old, new } x >>>> @cmd on source in { 0x00, 0xFF }. What does migration put into @cmd >>>> on dest? Eight cases: >>>> >>>> source @cmd -> wire -> dest @cmd >>>> old 0x00 -> 0x00 -> old 0x00 (1) >>>> new 0xFF (2) >>>> old 0xFF -> 0xFF -> old 0xFF (3) >>>> new 0xFF (4) >>>> new 0x00 -> 0x00 -> old 0x00 (5) >>>> new 0xFF (6) >>>> new 0xFF -> 0x00 -> old 0x00 (7) >>>> new 0xFF (8) >>>> >>>> Old -> old (cases 1 and 3) is unaffected by this patch. >>>> >>>> New -> new leaves 0xFF unchanged (8). It changes 0x00 to 0xFF (6). >>>> Uh-oh. Can this happen? Rephrasing the question: can @cmd ever be >>>> 0x00 with this patch applied? > > 0x00 is not in the spec (but as suggested Peter Maydell, the spec can > eventually assign the value in the future [*]). So no guests use it. > This value is only set: > - when the (old) model is initialized, without any access to the guest > - if the guest wrote an incorrect value, hitting the switch default case. > The guest can not read this value (value internal to the state machine). > > So answer: Yes :( Could zero @cmd be avoided? > [*] However the spec has a way to announce supported features to the guest. > >>>> >>>> Old -> new leaves 0xFF unchanged (4). It changes 0x00 to 0xFF (2), >>>> which I think is intentional. >>>> >>>> New -> old leaves 0x00 unchanged (5). It changes 0xFF to 0x00 (7), >>>> which I think is intentional. >>>> >>>> Old -> new -> old leaves 0x00 unchanged. Good. It changes 0xFF to >>>> 0x00. Uh-oh. Can @cmd ever be 0xFF before this patch? > > I understand the full question as "Can @cmd ever be 0xFF [in Old] before > this patch?". > > Answer: No, neither the guest nor the state machine can set @cmd to 0xFF > in Old. Good. >>>> >>>> New -> old -> new leaves 0xFF unchanged. Good. It changes 0x00 to >>>> 0xFF. Same uh-oh as for new -> new. > > "Same uh-oh", do you mean "Can @cmd ever be 0x00 [in New] before this > patch?"? Uh, isn't "[in New] before this patch" is a contradiction? Old = QEMU before this patch New = QEMU with this patch applied New -> old -> new = migrate from QEMU with the patch to QEMU without the patch, then migrate again to QEMU with the patch. If @cmd can be 0x00 initially, then the first migration is (5), and @cmd remains 0x00. The second migration is (2), and @cmd becomes 0xFF. The two migrations together change device state, which could be bad. > Same answer: No, neither the guest nor the state machine can set @cmd to > 0x00 in New. I'm afraid you gave a different answer to the same question above: "Yes :(". >>>> >>>>> + >>>>> static int pflash_post_load(void *opaque, int version_id); >>>>> >>>>> static const VMStateDescription vmstate_pflash = { >>>>> @@ -103,6 +134,8 @@ static const VMStateDescription vmstate_pflash = { >>>>> .version_id = 1, >>>>> .minimum_version_id = 1, >>>>> .post_load = pflash_post_load, >>>>> + .pre_save = pflash_pre_save, >>>>> + .post_save = pflash_post_save, >>>>> .fields = (VMStateField[]) { >>>>> VMSTATE_UINT8(wcycle, PFlashCFI01), >>>>> VMSTATE_UINT8(cmd, PFlashCFI01), >>>>> @@ -277,10 +310,9 @@ static uint32_t pflash_read(PFlashCFI01 *pfl, hwaddr offset, >>>>> /* This should never happen : reset state & treat it as a read */ >>>>> DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd); >>>>> pfl->wcycle = 0; >>>>> - pfl->cmd = 0; >>>>> + pfl->cmd = 0xff; >>>>> /* fall through to read code */ >>>>> - case 0x00: >>>>> - /* Flash area read */ >>>>> + case 0xff: /* Read Array */ >>>>> ret = pflash_data_read(pfl, offset, width, be); >>>>> break; >>>> >>>> On 0xFF, we no longer zap pfl->wcycle and pfl->cmd. > > We have 2 ways to set @cmd=0xFF. > > - Write 0xFF, write an invalid command, > finish a multicycle operation (wcycle returns to 0): > > pflash_write() goto reset_flash, then calls > memory_region_rom_device_set_romd(). set wcycle=0, cmd=READ_ARRAY. > > Next read() will be in ROMD mode, we won't reach pflash_read(). > > - if next access is write, we'll enter the same pflash_write(). > > - The /* This should never happen */ comment in pflash_read(). > > It might happens migrating? So we migrated crap, the guest wants to > read, the crap defaults to READ_ARRAY in I/O mode. Wrong in many ways, > not sure what the guest expects there, probably not ARRAY data. > Anyway, we stay in this READ_ARRAY I/O mode until the guest eventually > does a write access. Wrong. > > The case "The state machine set 0xff, let the device in I/O mode" so we > expect to answer to a read() with READ_ARRAY is wrong too, the device > should already be in ROMD mode. > >>>> >>>> On 0x00, we do. > > Because we have no idea how we got there... Neither what we should do. The part I actually understand here is "this device model is wrong in so many ways". Is this device model fixable with reasonable effort? Would starting over be easier? >>>> >>>> We zap pfl->cmd to 0xFF instead of 0x00. Same below after label >>>> error_flash and reset_flash. Related: initialization to 0xFF instead of >>>> 0x00 in pflash_cfi01_realize(). I *guess* these changes together ensure >>>> pfl->cmd can't become 0x00. Correct? >>>> >>>>> case 0x10: /* Single byte program */ >>>>> @@ -448,8 +480,6 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, >>>>> case 0: >>>>> /* read mode */ >>>>> switch (cmd) { >>>>> - case 0x00: /* ??? */ >>>>> - goto reset_flash; >>>> >>>> On 0x00, we now use default: goto error_flash. Can this happen? > > This could happen if the the guest is writing crap, so we correctly > report this as an error. A bug fix of sorts. >>>> >>>>> case 0x10: /* Single Byte Program */ >>>>> case 0x40: /* Single Byte Program */ >>>>> DPRINTF("%s: Single Byte Program\n", __func__); >>>>> @@ -526,7 +556,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, >>>>> if (cmd == 0xd0) { /* confirm */ >>>>> pfl->wcycle = 0; >>>>> pfl->status |= 0x80; >>>>> - } else if (cmd == 0xff) { /* read array mode */ >>>>> + } else if (cmd == 0xff) { /* Read Array */ >>>>> goto reset_flash; >>>>> } else >>>>> goto error_flash; >>>>> @@ -553,7 +583,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, >>>>> } else if (cmd == 0x01) { >>>>> pfl->wcycle = 0; >>>>> pfl->status |= 0x80; >>>>> - } else if (cmd == 0xff) { >>>>> + } else if (cmd == 0xff) { /* read array mode */ >>>> >>>> Your new comment is phrased the way you corrected in the previous hunk. >>>> Intentional? > > No :/ Too many rebases. Easy enough to clean up :) >>>> >>>>> goto reset_flash; >>>>> } else { >>>>> DPRINTF("%s: Unknown (un)locking command\n", __func__); >>>>> @@ -645,7 +675,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, >>>> error_flash: >>>> qemu_log_mask(LOG_UNIMP, "%s: Unimplemented flash cmd sequence " >>>> "(offset " TARGET_FMT_plx ", wcycle 0x%x cmd 0x%x value 0x%x)" >>>> "\n", __func__, offset, pfl->wcycle, pfl->cmd, value); >>>> >>>> reset_flash: >>>>> trace_pflash_reset(); >>>>> memory_region_rom_device_set_romd(&pfl->mem, true); >>>>> pfl->wcycle = 0; >>>>> - pfl->cmd = 0; >>>>> + pfl->cmd = 0xff; >>>>> } >>>>> >>>>> >>>>> @@ -761,7 +791,7 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) >>>>> } >>>>> >>>>> pfl->wcycle = 0; >>>>> - pfl->cmd = 0; >>>>> + pfl->cmd = 0xff; >>>>> pfl->status = 0; >>>>> /* Hardcoded CFI table */ >>>>> /* Standard "QRY" string */ >>>>> @@ -1001,5 +1031,14 @@ static int pflash_post_load(void *opaque, int version_id) >>>>> pfl->vmstate = qemu_add_vm_change_state_handler(postload_update_cb, >>>>> pfl); >>>>> } >>>>> + >>>>> + /* >>>>> + * Previous to QEMU v4.1 an incorrect value of 0x00 was used for the >>>>> + * READ_ARRAY command. >>>>> + */ >>>>> + if (pfl->cmd == 0x00) { >>>>> + pfl->cmd = 0xff; >>>>> + } >>>>> + >>>>> return 0; >>>>> } >>> -- >>> Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK ^ permalink raw reply [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH v5 3/5] hw/block/pflash_cfi01: Extract pflash_mode_read_array() 2019-07-15 12:13 [Qemu-devel] [PATCH v5 0/5] hw/block/pflash_cfi01: Add DeviceReset() handler Philippe Mathieu-Daudé 2019-07-15 12:13 ` [Qemu-devel] [PATCH v5 1/5] hw/block/pflash_cfi01: Removed an unused timer Philippe Mathieu-Daudé 2019-07-15 12:13 ` [Qemu-devel] [PATCH v5 2/5] hw/block/pflash_cfi01: Use the correct READ_ARRAY value Philippe Mathieu-Daudé @ 2019-07-15 12:13 ` Philippe Mathieu-Daudé 2019-07-15 12:13 ` [Qemu-devel] [PATCH v5 4/5] hw/block/pflash_cfi01: Start state machine as READY to accept commands Philippe Mathieu-Daudé 2019-07-15 12:13 ` [Qemu-devel] [PATCH v5 5/5] hw/block/pflash_cfi01: Add the DeviceReset() handler Philippe Mathieu-Daudé 4 siblings, 0 replies; 11+ messages in thread From: Philippe Mathieu-Daudé @ 2019-07-15 12:13 UTC (permalink / raw) To: qemu-devel, Dr . David Alan Gilbert Cc: Kevin Wolf, Peter Maydell, qemu-block, Philippe Mathieu-Daudé, Laszlo Ersek, Max Reitz, Alistair Francis, John Snow The same pattern is used when setting the flash in READ_ARRAY mode: - Set the state machine command to READ_ARRAY - Reset the write_cycle counter - Reset the memory region in ROMD Refactor the current code by extracting this pattern. It is used twice: - On a write access (on command failure, error, or explicitly asked) - When the device is initialized. Here the ROMD mode is hidden by the memory_region_init_rom_device() call. Rename the 'reset_flash' as 'mode_read_array' to make explicit we do not reset the device, we simply set its internal state machine in the READ_ARRAY mode. We do not reset the status register error bits, as a device reset would do. Reviewed-by: John Snow <jsnow@redhat.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Regression-tested-by: Laszlo Ersek <lersek@redhat.com> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com> --- hw/block/pflash_cfi01.c | 36 ++++++++++++++++++++---------------- hw/block/trace-events | 1 + 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index 85bb2132c0..6c3fefcd2d 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -145,6 +145,14 @@ static const VMStateDescription vmstate_pflash = { } }; +static void pflash_mode_read_array(PFlashCFI01 *pfl) +{ + trace_pflash_mode_read_array(); + pfl->cmd = 0xff; /* Read Array */ + pfl->wcycle = 0; + memory_region_rom_device_set_romd(&pfl->mem, true); +} + /* Perform a CFI query based on the bank width of the flash. * If this code is called we know we have a device_width set for * this flash. @@ -502,7 +510,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, case 0x50: /* Clear status bits */ DPRINTF("%s: Clear status bits\n", __func__); pfl->status = 0x0; - goto reset_flash; + goto mode_read_array; case 0x60: /* Block (un)lock */ DPRINTF("%s: Block unlock\n", __func__); break; @@ -527,10 +535,10 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, break; case 0xf0: /* Probe for AMD flash */ DPRINTF("%s: Probe for AMD flash\n", __func__); - goto reset_flash; + goto mode_read_array; case 0xff: /* Read array mode */ DPRINTF("%s: Read array mode\n", __func__); - goto reset_flash; + goto mode_read_array; default: goto error_flash; } @@ -557,7 +565,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, pfl->wcycle = 0; pfl->status |= 0x80; } else if (cmd == 0xff) { /* Read Array */ - goto reset_flash; + goto mode_read_array; } else goto error_flash; @@ -584,15 +592,15 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, pfl->wcycle = 0; pfl->status |= 0x80; } else if (cmd == 0xff) { /* read array mode */ - goto reset_flash; + goto mode_read_array; } else { DPRINTF("%s: Unknown (un)locking command\n", __func__); - goto reset_flash; + goto mode_read_array; } break; case 0x98: if (cmd == 0xff) { - goto reset_flash; + goto mode_read_array; } else { DPRINTF("%s: leaving query mode\n", __func__); } @@ -652,7 +660,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, " the data is already written to storage!\n" "Flash device reset into READ mode.\n", __func__); - goto reset_flash; + goto mode_read_array; } break; default: @@ -662,7 +670,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, default: /* Should never happen */ DPRINTF("%s: invalid write state\n", __func__); - goto reset_flash; + goto mode_read_array; } return; @@ -671,11 +679,8 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset, "(offset " TARGET_FMT_plx ", wcycle 0x%x cmd 0x%x value 0x%x)" "\n", __func__, offset, pfl->wcycle, pfl->cmd, value); - reset_flash: - trace_pflash_reset(); - memory_region_rom_device_set_romd(&pfl->mem, true); - pfl->wcycle = 0; - pfl->cmd = 0xff; + mode_read_array: + pflash_mode_read_array(pfl); } @@ -790,8 +795,7 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) pfl->max_device_width = pfl->device_width; } - pfl->wcycle = 0; - pfl->cmd = 0xff; + pflash_mode_read_array(pfl); pfl->status = 0; /* Hardcoded CFI table */ /* Standard "QRY" string */ diff --git a/hw/block/trace-events b/hw/block/trace-events index 13d1b21dd4..91a8a106c0 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -7,6 +7,7 @@ fdc_ioport_write(uint8_t reg, uint8_t value) "write reg 0x%02x val 0x%02x" # pflash_cfi02.c # pflash_cfi01.c pflash_reset(void) "reset" +pflash_mode_read_array(void) "mode: read array" pflash_timer_expired(uint8_t cmd) "command 0x%02x done" pflash_io_read(uint64_t offset, int width, int fmt_width, uint32_t value, uint8_t cmd, uint8_t wcycle) "offset:0x%04"PRIx64" width:%d value:0x%0*x cmd:0x%02x wcycle:%u" pflash_io_write(uint64_t offset, int width, int fmt_width, uint32_t value, uint8_t wcycle) "offset:0x%04"PRIx64" width:%d value:0x%0*x wcycle:%u" -- 2.20.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH v5 4/5] hw/block/pflash_cfi01: Start state machine as READY to accept commands 2019-07-15 12:13 [Qemu-devel] [PATCH v5 0/5] hw/block/pflash_cfi01: Add DeviceReset() handler Philippe Mathieu-Daudé ` (2 preceding siblings ...) 2019-07-15 12:13 ` [Qemu-devel] [PATCH v5 3/5] hw/block/pflash_cfi01: Extract pflash_mode_read_array() Philippe Mathieu-Daudé @ 2019-07-15 12:13 ` Philippe Mathieu-Daudé 2019-07-15 12:13 ` [Qemu-devel] [PATCH v5 5/5] hw/block/pflash_cfi01: Add the DeviceReset() handler Philippe Mathieu-Daudé 4 siblings, 0 replies; 11+ messages in thread From: Philippe Mathieu-Daudé @ 2019-07-15 12:13 UTC (permalink / raw) To: qemu-devel, Dr . David Alan Gilbert Cc: Kevin Wolf, Peter Maydell, qemu-block, Philippe Mathieu-Daudé, Laszlo Ersek, Max Reitz, Alistair Francis, John Snow When the state machine is ready to accept command, the bit 7 of the status register (SR) is set to 1. The guest polls the status register and check this bit before writting command to the internal 'Write State Machine' (WSM). Set SR.7 bit to 1 when the device is created. There is no migration impact by this change. Reference: Read Array Flowchart "Common Flash Interface (CFI) and Command Sets" (Intel Application Note 646) Appendix B "Basic Command Set" Reviewed-by: John Snow <jsnow@redhat.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Regression-tested-by: Laszlo Ersek <lersek@redhat.com> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com> --- v3: Added migration comment. --- hw/block/pflash_cfi01.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index 6c3fefcd2d..aa2126f6dc 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -796,7 +796,7 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) } pflash_mode_read_array(pfl); - pfl->status = 0; + pfl->status = 0x80; /* WSM ready */ /* Hardcoded CFI table */ /* Standard "QRY" string */ pfl->cfi_table[0x10] = 'Q'; -- 2.20.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH v5 5/5] hw/block/pflash_cfi01: Add the DeviceReset() handler 2019-07-15 12:13 [Qemu-devel] [PATCH v5 0/5] hw/block/pflash_cfi01: Add DeviceReset() handler Philippe Mathieu-Daudé ` (3 preceding siblings ...) 2019-07-15 12:13 ` [Qemu-devel] [PATCH v5 4/5] hw/block/pflash_cfi01: Start state machine as READY to accept commands Philippe Mathieu-Daudé @ 2019-07-15 12:13 ` Philippe Mathieu-Daudé 4 siblings, 0 replies; 11+ messages in thread From: Philippe Mathieu-Daudé @ 2019-07-15 12:13 UTC (permalink / raw) To: qemu-devel, Dr . David Alan Gilbert Cc: Kevin Wolf, Peter Maydell, qemu-block, Laszlo Ersek, Max Reitz, John Snow, Alistair Francis, Philippe Mathieu-Daudé A "system reset" sets the device state machine in READ_ARRAY mode and, after some delay, set the SR.7 READY bit. We do not model timings, so we set the SR.7 bit directly. The TYPE_DEVICE interface provides a DeviceReset handler. This pflash device is a subclass of TYPE_SYS_BUS_DEVICE (which is a subclass of TYPE_DEVICE). SYS_BUS devices are automatically plugged into the 'main system bus', which is the root of the qbus tree. Devices in the qbus tree are guaranteed to have their reset() handler called after realize() and before we try to run the guest. To avoid incoherent states when the machine resets (see but report below), factor out the reset code into pflash_cfi01_system_reset, and register the method as a device reset callback. Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1678713 Reported-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: John Snow <jsnow@redhat.com> Regression-tested-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com> --- v3: reword description --- hw/block/pflash_cfi01.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index aa2126f6dc..dd2ace92a8 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -795,8 +795,6 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) pfl->max_device_width = pfl->device_width; } - pflash_mode_read_array(pfl); - pfl->status = 0x80; /* WSM ready */ /* Hardcoded CFI table */ /* Standard "QRY" string */ pfl->cfi_table[0x10] = 'Q'; @@ -884,6 +882,18 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp) pfl->cfi_table[0x3f] = 0x01; /* Number of protection fields */ } +static void pflash_cfi01_system_reset(DeviceState *dev) +{ + PFlashCFI01 *pfl = PFLASH_CFI01(dev); + + pflash_mode_read_array(pfl); + /* + * The WSM ready timer occurs at most 150ns after system reset. + * This model deliberately ignores this delay. + */ + pfl->status = 0x80; +} + static Property pflash_cfi01_properties[] = { DEFINE_PROP_DRIVE("drive", PFlashCFI01, blk), /* num-blocks is the number of blocks actually visible to the guest, @@ -928,6 +938,7 @@ static void pflash_cfi01_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + dc->reset = pflash_cfi01_system_reset; dc->realize = pflash_cfi01_realize; dc->props = pflash_cfi01_properties; dc->vmsd = &vmstate_pflash; -- 2.20.1 ^ permalink raw reply related [flat|nested] 11+ messages in thread
end of thread, other threads:[~2019-07-31 12:23 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2019-07-15 12:13 [Qemu-devel] [PATCH v5 0/5] hw/block/pflash_cfi01: Add DeviceReset() handler Philippe Mathieu-Daudé 2019-07-15 12:13 ` [Qemu-devel] [PATCH v5 1/5] hw/block/pflash_cfi01: Removed an unused timer Philippe Mathieu-Daudé 2019-07-15 12:13 ` [Qemu-devel] [PATCH v5 2/5] hw/block/pflash_cfi01: Use the correct READ_ARRAY value Philippe Mathieu-Daudé 2019-07-16 12:25 ` Markus Armbruster 2019-07-16 14:04 ` Dr. David Alan Gilbert 2019-07-16 15:12 ` Markus Armbruster 2019-07-29 16:21 ` Philippe Mathieu-Daudé 2019-07-31 12:22 ` Markus Armbruster 2019-07-15 12:13 ` [Qemu-devel] [PATCH v5 3/5] hw/block/pflash_cfi01: Extract pflash_mode_read_array() Philippe Mathieu-Daudé 2019-07-15 12:13 ` [Qemu-devel] [PATCH v5 4/5] hw/block/pflash_cfi01: Start state machine as READY to accept commands Philippe Mathieu-Daudé 2019-07-15 12:13 ` [Qemu-devel] [PATCH v5 5/5] hw/block/pflash_cfi01: Add the DeviceReset() handler Philippe Mathieu-Daudé
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).