qemu-block
[Top][All Lists]
Advanced

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

Re: [PATCH 1/2] hw: m25p80: Add Block Protect and Top Bottom bits for wr


From: Cédric Le Goater
Subject: Re: [PATCH 1/2] hw: m25p80: Add Block Protect and Top Bottom bits for write protect
Date: Mon, 4 Jul 2022 22:50:12 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.10.0

On 6/27/22 20:52, Iris Chen wrote:
Signed-off-by: Iris Chen <irischenlj@fb.com>
---
  hw/block/m25p80.c | 74 +++++++++++++++++++++++++++++++++++++++--------
  1 file changed, 62 insertions(+), 12 deletions(-)

diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index 50b523e5b1..0156a70f5e 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -38,21 +38,19 @@
  #include "trace.h"
  #include "qom/object.h"
-/* Fields for FlashPartInfo->flags */
-
-/* erase capabilities */
-#define ER_4K 1
-#define ER_32K 2
-/* set to allow the page program command to write 0s back to 1. Useful for
- * modelling EEPROM with SPI flash command set
- */
-#define EEPROM 0x100
-
  /* 16 MiB max in 3 byte address mode */
  #define MAX_3BYTES_SIZE 0x1000000
-
  #define SPI_NOR_MAX_ID_LEN 6
+/* Fields for FlashPartInfo->flags */
+enum spi_nor_option_flags {
+    ER_4K                  = BIT(0),
+    ER_32K                 = BIT(1),
+    EEPROM                 = BIT(2),
+    SNOR_F_HAS_SR_TB       = BIT(3),
+    SNOR_F_HAS_SR_BP3_BIT6 = BIT(4),
+};
+
  typedef struct FlashPartInfo {
      const char *part_name;
      /*
@@ -253,7 +251,8 @@ static const FlashPartInfo known_devices[] = {
      { INFO("n25q512a11",  0x20bb20,      0,  64 << 10, 1024, ER_4K) },
      { INFO("n25q512a13",  0x20ba20,      0,  64 << 10, 1024, ER_4K) },
      { INFO("n25q128",     0x20ba18,      0,  64 << 10, 256, 0) },
-    { INFO("n25q256a",    0x20ba19,      0,  64 << 10, 512, ER_4K) },
+    { INFO("n25q256a",    0x20ba19,      0,  64 << 10, 512,
+           ER_4K | SNOR_F_HAS_SR_BP3_BIT6 | SNOR_F_HAS_SR_TB) },
      { INFO("n25q512a",    0x20ba20,      0,  64 << 10, 1024, ER_4K) },
      { INFO("n25q512ax3",  0x20ba20,  0x1000,  64 << 10, 1024, ER_4K) },
      { INFO("mt25ql512ab", 0x20ba20, 0x1044, 64 << 10, 1024, ER_4K | ER_32K) },
@@ -480,6 +479,11 @@ struct Flash {
      bool reset_enable;
      bool quad_enable;
      bool aai_enable;
+    bool block_protect0;
+    bool block_protect1;
+    bool block_protect2;
+    bool block_protect3;
+    bool top_bottom_bit;
      bool status_register_write_disabled;
      uint8_t ear;
@@ -630,6 +634,29 @@ void flash_write8(Flash *s, uint32_t addr, uint8_t data)
          qemu_log_mask(LOG_GUEST_ERROR, "M25P80: write with write protect!\n");
          return;
      }
+    uint32_t block_protect_value = (s->block_protect3 << 3) |
+                                   (s->block_protect2 << 2) |
+                                   (s->block_protect1 << 1) |
+                                   (s->block_protect0 << 0);
+
+     uint32_t num_protected_sectors = 1 << (block_protect_value - 1);

Something wrong will occur if all block_protect[0123] are zeroes.

C.

+     uint32_t sector = addr / s->pi->sector_size;
+
+     /* top_bottom_bit == 0 means TOP */
+    if (!s->top_bottom_bit) {
+        if (block_protect_value > 0 &&
+            s->pi->n_sectors <= sector + num_protected_sectors) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "M25P80: write with write protect!\n");
+            return;
+        }
+    } else {
+        if (block_protect_value > 0 && sector < num_protected_sectors) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "M25P80: write with write protect!\n");
+            return;
+        }
+    }
if ((prev ^ data) & data) {
          trace_m25p80_programming_zero_to_one(s, addr, prev, data);
@@ -728,6 +755,15 @@ static void complete_collecting_data(Flash *s)
          break;
      case WRSR:
          s->status_register_write_disabled = extract32(s->data[0], 7, 1);
+        s->block_protect0 = extract32(s->data[0], 2, 1);
+        s->block_protect1 = extract32(s->data[0], 3, 1);
+        s->block_protect2 = extract32(s->data[0], 4, 1);
+        if (s->pi->flags & SNOR_F_HAS_SR_TB) {
+            s->top_bottom_bit = extract32(s->data[0], 5, 1);
+        }
+        if (s->pi->flags & SNOR_F_HAS_SR_BP3_BIT6) {
+            s->block_protect3 = extract32(s->data[0], 6, 1);
+        }
switch (get_man(s)) {
          case MAN_SPANSION:
@@ -1213,6 +1249,15 @@ 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;
+        s->data[0] |= (!!s->block_protect0) << 2;
+        s->data[0] |= (!!s->block_protect1) << 3;
+        s->data[0] |= (!!s->block_protect2) << 4;
+        if (s->pi->flags & SNOR_F_HAS_SR_TB) {
+            s->data[0] |= (!!s->top_bottom_bit) << 5;
+        }
+        if (s->pi->flags & SNOR_F_HAS_SR_BP3_BIT6) {
+            s->data[0] |= (!!s->block_protect3) << 6;
+        }
if (get_man(s) == MAN_MACRONIX || get_man(s) == MAN_ISSI) {
              s->data[0] |= (!!s->quad_enable) << 6;
@@ -1553,6 +1598,11 @@ static void m25p80_reset(DeviceState *d)
s->wp_level = true;
      s->status_register_write_disabled = false;
+    s->block_protect0 = false;
+    s->block_protect1 = false;
+    s->block_protect2 = false;
+    s->block_protect3 = false;
+    s->top_bottom_bit = false;
reset_memory(s);
  }




reply via email to

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