qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v2 1/2] hw: m25p80: add WP# pin and SRWD bit for write protec


From: Dan Zhang
Subject: Re: [PATCH v2 1/2] hw: m25p80: add WP# pin and SRWD bit for write protection
Date: Mon, 13 Jun 2022 23:19:14 -0700

On Mon, Jun 13, 2022 at 10:45:34PM -0700, Dan Zhang wrote:
> Just find out how to use mutt to reply all in the thread.
> repeat the previous comments. Add STATE_HIZ to handle decode_new_command
> aborting gracefully. 
> 
> On Thu, Jun 09, 2022 at 08:06:00PM +0000, Peter Delevoryas wrote:
> > 
> > 
> > > On Jun 9, 2022, at 12:22 PM, Francisco Iglesias 
> > > <frasse.iglesias@gmail.com> wrote:
> > > 
> > > Hi Iris,
> > > 
> > > Looks good some, a couple of comments below.
> > > 
> > > On [2022 Jun 08] Wed 20:13:19, Iris Chen wrote:
> > >> From: Iris Chen <irischenlj@gmail.com>
> > >> 
> > >> Signed-off-by: Iris Chen <irischenlj@gmail.com>
> > >> ---
> > >> Addressed all comments from V1. The biggest change: removed 
> > >> object_class_property_add.
> > >> 
> > >> hw/block/m25p80.c             | 37 +++++++++++++++++++++++++++++++++++
> > >> tests/qtest/aspeed_smc-test.c |  2 ++
> > >> 2 files changed, 39 insertions(+)
> > >> 
> > >> diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
> > >> index 81ba3da4df..1a20bd55d4 100644
> > >> --- a/hw/block/m25p80.c
> > >> +++ b/hw/block/m25p80.c
> > >> @@ -27,12 +27,14 @@
> > >> #include "hw/qdev-properties.h"
> > >> #include "hw/qdev-properties-system.h"
> > >> #include "hw/ssi/ssi.h"
> > >> +#include "hw/irq.h"
> > >> #include "migration/vmstate.h"
> > >> #include "qemu/bitops.h"
> > >> #include "qemu/log.h"
> > >> #include "qemu/module.h"
> > >> #include "qemu/error-report.h"
> > >> #include "qapi/error.h"
> > >> +#include "qapi/visitor.h"
> > >> #include "trace.h"
> > >> #include "qom/object.h"
> > >> 
> > >> @@ -472,11 +474,13 @@ struct Flash {
> > >>     uint8_t spansion_cr2v;
> > >>     uint8_t spansion_cr3v;
> > >>     uint8_t spansion_cr4v;
> > >> +    bool wp_level;
> > >>     bool write_enable;
> > >>     bool four_bytes_address_mode;
> > >>     bool reset_enable;
> > >>     bool quad_enable;
> > >>     bool aai_enable;
> > >> +    bool status_register_write_disabled;
> > >>     uint8_t ear;
> > >> 
> > >>     int64_t dirty_page;
> > >> @@ -723,6 +727,21 @@ static void complete_collecting_data(Flash *s)
> > >>         flash_erase(s, s->cur_addr, s->cmd_in_progress);
> > >>         break;
> > >>     case WRSR:
> > >> +        /*
> > >> +         * If WP# is low and status_register_write_disabled is high,
> > >> +         * status register writes are disabled.
> > >> +         * This is also called "hardware protected mode" (HPM). All 
> > >> other
> > >> +         * combinations of the two states are called "software 
> > >> protected mode"
> > >> +         * (SPM), and status register writes are permitted.
> > >> +         */
> > >> +        if ((s->wp_level == 0 && s->status_register_write_disabled)
> > >> +            || !s->write_enable) {
> > > 
> > > 'write_enable' needs to be true in 'decode_new_cmd' when issueing the WRSR
> > > command, otherwise the state machinery will not advance to this function
> > > (meaning that above check for !s->write_enable will never hit as far as I 
> > > can
> > > tell). A suggestion is to move the check for wp_level and
> > > status_reg_wr_disabled into 'decode_new_cmd' to for keeping it consistent.
> > 
> > Oh good catch! Yes actually, in our fork, we also removed the write_enable
> > guard in decode_new_cmd. We either need both checks in decode_new_cmd,
> > or both checks in complete_collecting_data.
> > 
> > I think we had some difficulty deciding whether to block command decoding,
> > or to decode and ignore the command if restrictions are enabled.
> > 
> > The reason being that, in the qtest, the WRSR command code gets ignored, and
> > then the subsequent write data gets interpreted as some random command code.
> > We had elected to decode and ignore the command, but I think the
> > datasheet actually describes that the command won’t be decoded successfully,
> > so you’re probably right, we should put this logic in decode_new_cmd.
> > 
> > Most likely, the qtest will also need to be modified to reset the transfer
> > state machine after a blocked write command. I can’t remember if
> > exiting and re-entering user mode is sufficient for that, but something
> > like that is probably possible.
> > 
> > Thanks for catching this!
> > Peter
> > 
> 
> I am proposing add a CMDState: STATE_HIZ to handle command decode fail
> situation. When decode_new_command need abort the decoding and ignore
> following
> on input bytes of this transaction, set the state to STATE_HIZ.
> And m25p80_transfer8() will ignore all the following on byte when in
> this state.
> 
> This is to simulating the real device operation behavior
> i.e. Macronix MX66L1G45G data sheet section 8 DEVICE OPERATION described
> ```
> 2. When an incorrect command is written to this device, it enters
> standby mode and stays in standby mode until the next CS# falling edge.
> In standby mode, This device's SO pin should be High-Z.
> ``` 
If don't want to consider WRSR command when HPM activated is "incorrect
command" and enter into standby mode, then according to data sheet in WRSR 
section
```
The WRSR instruction cannot be executed once the Hardware Protected Mode (HPM) 
is entered.
```
the best place to check HPM is before the command execution in function
complete_collecting_data(). This can help avoiding decode the WRSR input
data as new command.

BTW, maybe STATE_STANDBY is better than STATE_HIZ, much easy to
understand.
> BRs
> Dan Zhang
> > > 
> > >> +            qemu_log_mask(LOG_GUEST_ERROR,
> > >> +                          "M25P80: Status register write is 
> > >> disabled!\n");
> > >> +            break;
> > >> +        }
> > >> +        s->status_register_write_disabled = extract32(s->data[0], 7, 1);
> > >> +
> > >>         switch (get_man(s)) {
> > >>         case MAN_SPANSION:
> > >>             s->quad_enable = !!(s->data[1] & 0x02);
> > >> @@ -1195,6 +1214,8 @@ static void decode_new_cmd(Flash *s, uint32_t 
> > >> value)
> > >> 
> > >>     case RDSR:
> > >>         s->data[0] = (!!s->write_enable) << 1;
> > >> +        s->data[0] |= (!!s->status_register_write_disabled) << 7;
> > >> +
> > >>         if (get_man(s) == MAN_MACRONIX || get_man(s) == MAN_ISSI) {
> > >>             s->data[0] |= (!!s->quad_enable) << 6;
> > >>         }
> > >> @@ -1484,6 +1505,14 @@ static uint32_t m25p80_transfer8(SSIPeripheral 
> > >> *ss, uint32_t tx)
> > >>     return r;
> > >> }
> > >> 
> > >> +static void m25p80_write_protect_pin_irq_handler(void *opaque, int n, 
> > >> int level)
> > >> +{
> > >> +    Flash *s = M25P80(opaque);
> > >> +    /* WP# is just a single pin. */
> > >> +    assert(n == 0);
> > >> +    s->wp_level = !!level;
> > >> +}
> > >> +
> > >> static void m25p80_realize(SSIPeripheral *ss, Error **errp)
> > >> {
> > >>     Flash *s = M25P80(ss);
> > >> @@ -1515,12 +1544,18 @@ static void m25p80_realize(SSIPeripheral *ss, 
> > >> Error **errp)
> > >>         s->storage = blk_blockalign(NULL, s->size);
> > >>         memset(s->storage, 0xFF, s->size);
> > >>     }
> > >> +
> > >> +    qdev_init_gpio_in_named(DEVICE(s),
> > >> +                            m25p80_write_protect_pin_irq_handler, 
> > >> "WP#", 1);
> > >> }
> > >> 
> > >> static void m25p80_reset(DeviceState *d)
> > >> {
> > >>     Flash *s = M25P80(d);
> > >> 
> > >> +    s->wp_level = true;
> > >> +    s->status_register_write_disabled = false;
> > >> +
> > >>     reset_memory(s);
> > >> }
> > >> 
> > >> @@ -1601,6 +1636,8 @@ static const VMStateDescription vmstate_m25p80 = {
> > >>         VMSTATE_UINT8(needed_bytes, Flash),
> > >>         VMSTATE_UINT8(cmd_in_progress, Flash),
> > >>         VMSTATE_UINT32(cur_addr, Flash),
> > >> +        VMSTATE_BOOL(wp_level, Flash),
> > >> +        VMSTATE_BOOL(status_register_write_disabled, Flash),
> > > 
> > > Above needs to be added through a subsection, you can see commit 
> > > 465ef47abe3
> > > for an example an also read about this in docs/devel/migration.rst.
> > > 
> > > Thank you,
> > > Best regads,
> > > Francisco Iglesias
> > > 
> > > 
> > >>         VMSTATE_BOOL(write_enable, Flash),
> > >>         VMSTATE_BOOL(reset_enable, Flash),
> > >>         VMSTATE_UINT8(ear, Flash),
> > >> diff --git a/tests/qtest/aspeed_smc-test.c 
> > >> b/tests/qtest/aspeed_smc-test.c
> > >> index ec233315e6..c5d97d4410 100644
> > >> --- a/tests/qtest/aspeed_smc-test.c
> > >> +++ b/tests/qtest/aspeed_smc-test.c
> > >> @@ -56,7 +56,9 @@ enum {
> > >>     BULK_ERASE = 0xc7,
> > >>     READ = 0x03,
> > >>     PP = 0x02,
> > >> +    WRSR = 0x1,
> > >>     WREN = 0x6,
> > >> +    SRWD = 0x80,
> > >>     RESET_ENABLE = 0x66,
> > >>     RESET_MEMORY = 0x99,
> > >>     EN_4BYTE_ADDR = 0xB7,
> > >> -- 
> > >> 2.30.2
> > >> 
> > >> 
> > 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]