Sergii Dmytruk has uploaded this change for review.

View Change

[RFC] dummyflasher: write protection for W25Q128FV

Start taking bits related to write protection into account.

Also add "wp" parameter for dummy programmer that sets state of WP pin.

Change-Id: I9fd1417f941186391bd213bd355530143c8f04a0
Signed-off-by: Sergii Dmytruk <sergii.dmytruk@3mdeb.com>
---
M dummyflasher.c
M flashrom.8.tmpl
2 files changed, 159 insertions(+), 18 deletions(-)

git pull ssh://review.coreboot.org:29418/flashrom refs/changes/74/59074/1
diff --git a/dummyflasher.c b/dummyflasher.c
index bb47c3c..f355d7e 100644
--- a/dummyflasher.c
+++ b/dummyflasher.c
@@ -25,6 +25,7 @@
#include "programmer.h"
#include "flashchips.h"
#include "spi.h"
+#include "writeprotect.h"

enum emu_chip {
EMULATE_NONE,
@@ -60,6 +61,11 @@
unsigned int spi_blacklist_size;
unsigned int spi_ignorelist_size;

+ bool wp; /* state of hardware write protection */
+ /* wp_start == wp_end when write-protection is disabled */
+ uint32_t wp_start;
+ uint32_t wp_end;
+
unsigned int spi_write_256_chunksize;
uint8_t *flashchip_contents;
};
@@ -166,7 +172,14 @@
uint8_t ro_bits = (status_reg == 1 ? SPI_SR_WEL | SPI_SR_WIP : 0);

if (data->emu_chip == EMULATE_WINBOND_W25Q128FV) {
- if (status_reg == 2) {
+ const bool srp0 = (data->emu_status >> 7);
+ const bool srp1 = (data->emu_status2 & 1);
+
+ const bool wp_active = (srp1 || (srp0 && data->wp));
+
+ if (wp_active) {
+ ro_bits = 0xff;
+ } else if (status_reg == 2) {
/* SUS1 (bit_7) and (R) (bit_2). */
ro_bits = 0x84;
/* Once any of the lock bits (LB[1..3]) are set, they
@@ -180,6 +193,81 @@
return ro_bits;
}

+static void update_write_protection(struct emu_data *data)
+{
+ if (data->emu_chip != EMULATE_WINBOND_W25Q128FV)
+ return;
+
+ const struct wp_chip_state wpst = {
+ .srp_bit_count = 2,
+ .srp = {data->emu_status >> 7, data->emu_status2 & 1},
+
+ .bp_bit_count = 3,
+ .bp =
+ {
+ (data->emu_status >> 2) & 1,
+ (data->emu_status >> 3) & 1,
+ (data->emu_status >> 4) & 1
+ },
+
+ .tb_bit_present = true,
+ .tb = (data->emu_status >> 5) & 1,
+
+ .sec_bit_present = true,
+ .sec = (data->emu_status >> 6) & 1,
+
+ .cmp_bit_present = true,
+ .cmp = (data->emu_status2 >> 6) & 1,
+ };
+
+ struct wp_range range = { .chip_len = data->emu_chip_size };
+ decode_range_w25(&wpst, &range);
+
+ data->wp_start = range.start;
+ data->wp_end = range.start + range.len;
+}
+
+/* Checks whether range intersects a write-protected area of the flash if one is
+ * defined. */
+static bool is_write_protected(const struct emu_data *data, uint32_t start, uint32_t len)
+{
+ if (len == 0)
+ return false;
+
+ if (start >= data->wp_start && start < data->wp_end)
+ return true;
+
+ const uint32_t last = start + len - 1;
+ return (last >= data->wp_start && last < data->wp_end);
+}
+
+/* Returns non-zero on error. */
+static int write_flash_part(struct emu_data *data, uint32_t start, uint32_t len, const uint8_t *buf)
+{
+ if (is_write_protected(data, start, len)) {
+ msg_perr("At least part of the write range is write protected!\n");
+ return 1;
+ }
+
+ memcpy(data->flashchip_contents + start, buf, len);
+ data->emu_modified = 1;
+ return 0;
+}
+
+/* Returns non-zero on error. */
+static int erase_flash_part(struct emu_data *data, uint32_t start, uint32_t len)
+{
+ if (is_write_protected(data, start, len)) {
+ msg_perr("At least part of the erase range is write protected!\n");
+ return 1;
+ }
+
+ /* XXX: should data->erase_to_zero be taken into account here? */
+ memset(data->flashchip_contents + start, 0xff, len);
+ data->emu_modified = 1;
+ return 0;
+}
+
static int emulate_spi_chip_response(unsigned int writecnt,
unsigned int readcnt,
const unsigned char *writearr,
@@ -358,6 +446,8 @@
msg_pdbg2("WRSR wrote 0x%02x%02x.\n", data->emu_status2, data->emu_status);
else
msg_pdbg2("WRSR wrote 0x%02x.\n", data->emu_status);
+
+ update_write_protection(data);
break;
case JEDEC_WRSR2:
if (data->emu_status_len < 2)
@@ -370,6 +460,8 @@
ro_bits = get_status_ro_bits(data, 2);
data->emu_status2 &= ro_bits;
data->emu_status2 |= (writearr[1] & ~ro_bits);
+
+ update_write_protection(data);
break;
case JEDEC_READ:
offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
@@ -397,8 +489,10 @@
msg_perr("Max BYTE PROGRAM size exceeded!\n");
return 1;
}
- memcpy(data->flashchip_contents + offs, writearr + 4, writecnt - 4);
- data->emu_modified = 1;
+ if (write_flash_part(data, offs, writecnt - 4, writearr + 4)) {
+ msg_perr("Failed to program flash!\n");
+ return 1;
+ }
break;
case JEDEC_BYTE_PROGRAM_4BA:
offs = writearr[1] << 24 | writearr[2] << 16 | writearr[3] << 8 | writearr[4];
@@ -412,8 +506,10 @@
msg_perr("Max BYTE PROGRAM size exceeded!\n");
return 1;
}
- memcpy(data->flashchip_contents + offs, writearr + 5, writecnt - 5);
- data->emu_modified = 1;
+ if (write_flash_part(data, offs, writecnt - 5, writearr + 5)) {
+ msg_perr("Failed to program flash!\n");
+ return 1;
+ }
break;
case JEDEC_AAI_WORD_PROGRAM:
if (!data->emu_max_aai_size)
@@ -434,7 +530,10 @@
writearr[3];
/* Truncate to emu_chip_size. */
aai_offs %= data->emu_chip_size;
- memcpy(data->flashchip_contents + aai_offs, writearr + 4, 2);
+ if (write_flash_part(data, aai_offs, 2, writearr + 4)) {
+ msg_perr("Failed to program flash!\n");
+ return 1;
+ }
aai_offs += 2;
} else {
if (writecnt < JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
@@ -447,10 +546,12 @@
"too long!\n");
return 1;
}
- memcpy(data->flashchip_contents + aai_offs, writearr + 1, 2);
+ if (write_flash_part(data, aai_offs, 2, writearr + 1)) {
+ msg_perr("Failed to program flash!\n");
+ return 1;
+ }
aai_offs += 2;
}
- data->emu_modified = 1;
break;
case JEDEC_WRDI:
if (data->emu_max_aai_size)
@@ -471,8 +572,10 @@
if (offs & (data->emu_jedec_se_size - 1))
msg_pdbg("Unaligned SECTOR ERASE 0x20: 0x%x\n", offs);
offs &= ~(data->emu_jedec_se_size - 1);
- memset(data->flashchip_contents + offs, 0xff, data->emu_jedec_se_size);
- data->emu_modified = 1;
+ if (erase_flash_part(data, offs, data->emu_jedec_se_size)) {
+ msg_perr("Failed to erase flash!\n");
+ return 1;
+ }
break;
case JEDEC_BE_52:
if (!data->emu_jedec_be_52_size)
@@ -489,8 +592,10 @@
if (offs & (data->emu_jedec_be_52_size - 1))
msg_pdbg("Unaligned BLOCK ERASE 0x52: 0x%x\n", offs);
offs &= ~(data->emu_jedec_be_52_size - 1);
- memset(data->flashchip_contents + offs, 0xff, data->emu_jedec_be_52_size);
- data->emu_modified = 1;
+ if (erase_flash_part(data, offs, data->emu_jedec_be_52_size)) {
+ msg_perr("Failed to erase flash!\n");
+ return 1;
+ }
break;
case JEDEC_BE_D8:
if (!data->emu_jedec_be_d8_size)
@@ -507,8 +612,10 @@
if (offs & (data->emu_jedec_be_d8_size - 1))
msg_pdbg("Unaligned BLOCK ERASE 0xd8: 0x%x\n", offs);
offs &= ~(data->emu_jedec_be_d8_size - 1);
- memset(data->flashchip_contents + offs, 0xff, data->emu_jedec_be_d8_size);
- data->emu_modified = 1;
+ if (erase_flash_part(data, offs, data->emu_jedec_be_d8_size)) {
+ msg_perr("Failed to erase flash!\n");
+ return 1;
+ }
break;
case JEDEC_CE_60:
if (!data->emu_jedec_ce_60_size)
@@ -523,8 +630,10 @@
}
/* JEDEC_CE_60_OUTSIZE is 1 (no address) -> no offset. */
/* emu_jedec_ce_60_size is emu_chip_size. */
- memset(data->flashchip_contents, 0xff, data->emu_jedec_ce_60_size);
- data->emu_modified = 1;
+ if (erase_flash_part(data, 0, data->emu_jedec_ce_60_size)) {
+ msg_perr("Failed to erase flash!\n");
+ return 1;
+ }
break;
case JEDEC_CE_C7:
if (!data->emu_jedec_ce_c7_size)
@@ -539,8 +648,10 @@
}
/* JEDEC_CE_C7_OUTSIZE is 1 (no address) -> no offset. */
/* emu_jedec_ce_c7_size is emu_chip_size. */
- memset(data->flashchip_contents, 0xff, data->emu_jedec_ce_c7_size);
- data->emu_modified = 1;
+ if (erase_flash_part(data, 0, data->emu_jedec_ce_c7_size)) {
+ msg_perr("Failed to erase flash!\n");
+ return 1;
+ }
break;
case JEDEC_SFDP:
if (data->emu_chip != EMULATE_MACRONIX_MX25L6436)
@@ -850,6 +961,21 @@
free(tmp);
}

+ tmp = extract_programmer_param("wp");
+ if (tmp) {
+ if (!strcmp(tmp, "yes")) {
+ msg_pdbg("Emulated chip will have WP enabled\n");
+ data->wp = true;
+ } else if (!strcmp(tmp, "no")) {
+ msg_pdbg("Emulated chip will have WP disabled\n");
+ } else {
+ msg_perr("wp can be \"yes\" or \"no\"\n");
+ free(tmp);
+ return 1;
+ }
+ free(tmp);
+ }
+
tmp = extract_programmer_param("emulate");
if (!tmp) {
msg_pdbg("Not emulating any flash chip.\n");
diff --git a/flashrom.8.tmpl b/flashrom.8.tmpl
index 989d677..000a67a 100644
--- a/flashrom.8.tmpl
+++ b/flashrom.8.tmpl
@@ -693,6 +693,8 @@
.sp
.RB "* Macronix " MX25L6436 " SPI flash chip (8192 kB, RDID, SFDP)"
.sp
+.RB "* Winbond " W25Q128FV " SPI flash chip (16384 kB, RDID)"
+.sp
.RB "* Dummy vendor " VARIABLE_SIZE " SPI flash chip (configurable size, page write)"
.sp
Example:
@@ -779,6 +781,19 @@
syntax where
.B content
is an 8-bit hexadecimal value.
+.sp
+.TP
+.B Write protection
+.sp
+Chips with emulated WP: W25Q128FV.
+.sp
+You can simulate state of hardware protection pin (WP) with the
+.sp
+.B " flashrom -p dummy:wp=state"
+.sp
+syntax where
+.B state
+is "yes" or "no" (default value).
.SS
.BR "nic3com" , " nicrealtek" , " nicnatsemi" , " nicintel", " nicintel_eeprom"\
, " nicintel_spi" , " gfxnvidia" , " ogp_spi" , " drkaiser" , " satasii"\

To view, visit change 59074. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-Change-Id: I9fd1417f941186391bd213bd355530143c8f04a0
Gerrit-Change-Number: 59074
Gerrit-PatchSet: 1
Gerrit-Owner: Sergii Dmytruk <sergii.dmytruk@3mdeb.com>
Gerrit-MessageType: newchange