[U-Boot] [PATCH 0/5] sf: Add support for status register protect

Many SPI NOR flash devices support status register protection through one or two status register protection bits. Protection of the status register is essential in defending the device from rogue software which may attempt to modify block protection bits in order to make malicious modifications to the data stored in flash. This patch series adds status register protect support for STMICRO, SST, Winbond and Spansion devices and also implements an sf sub-command to set the used protection method.
George McCollister (5): sf: Add status register protection mechanism sf: Add status register protect for STMICRO, SST sf: Use stm_lock/unlock for Spansion and Winbond sf: Add status register protect for Winbond sf: Add sr-protect sub-command
cmd/sf.c | 28 ++++++++++++ drivers/mtd/spi/sf_internal.h | 2 + drivers/mtd/spi/spi_flash.c | 103 +++++++++++++++++++++++++++++++++++++++++- include/spi_flash.h | 17 +++++++ 4 files changed, 149 insertions(+), 1 deletion(-)

Many SPI NOR flash devices support status register protection through one or two status register protection bits. Status register protection enables protection of block protect and other bits from manipulation.
So far, four different status register protection methods have been observed:
Software - Writes to the status register are blocked until a write enable bit is set by software. Hardware - Writes to the status register are blocked while a pin is in a certain state. Power - Writes to the status register are blocked until the next power-down. One Time Program - Writes to the status register are permanently blocked.
Signed-off-by: George McCollister george.mccollister@gmail.com --- include/spi_flash.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
diff --git a/include/spi_flash.h b/include/spi_flash.h index be2fe3f..d1f63c7 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -26,6 +26,13 @@ # define CONFIG_SF_DEFAULT_BUS 0 #endif
+enum srp_method { + SRP_SOFTWARE, + SRP_HARDWARE, + SRP_POWER, + SRP_OTP, +}; + struct spi_slave;
/** @@ -89,6 +96,7 @@ struct spi_flash { int (*flash_lock)(struct spi_flash *flash, u32 ofs, size_t len); int (*flash_unlock)(struct spi_flash *flash, u32 ofs, size_t len); int (*flash_is_locked)(struct spi_flash *flash, u32 ofs, size_t len); + int (*sr_protect)(struct spi_flash *flash, enum srp_method method); #ifndef CONFIG_DM_SPI_FLASH /* * These are not strictly needed for driver model, but keep them here @@ -239,4 +247,13 @@ static inline int spi_flash_protect(struct spi_flash *flash, u32 ofs, u32 len, return flash->flash_unlock(flash, ofs, len); }
+static inline int spi_flash_sr_protect(struct spi_flash *flash, + enum srp_method method) +{ + if (!flash->sr_protect) + return -EOPNOTSUPP; + + return flash->sr_protect(flash, method); +} + #endif /* _SPI_FLASH_H_ */

On Tue, Oct 11, 2016 at 2:57 AM, George McCollister george.mccollister@gmail.com wrote:
Many SPI NOR flash devices support status register protection through one or two status register protection bits. Status register protection enables protection of block protect and other bits from manipulation.
So far, four different status register protection methods have been observed:
Software - Writes to the status register are blocked until a write enable bit is set by software. Hardware - Writes to the status register are blocked while a pin is in a certain state. Power - Writes to the status register are blocked until the next power-down. One Time Program - Writes to the status register are permanently blocked.
Signed-off-by: George McCollister george.mccollister@gmail.com
include/spi_flash.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

STMICRO parts such as M25PX64 and SST parts such as SST26VF032B support a single status register protect bit. When set this bit cause writes to the status register to be blocked when the write protect signal is low.
Implement sr_protect for these devices.
Signed-off-by: George McCollister george.mccollister@gmail.com --- drivers/mtd/spi/sf_internal.h | 1 + drivers/mtd/spi/spi_flash.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+)
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index cde4cfb..1b576e8 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -81,6 +81,7 @@ enum spi_nor_option_flags { #define SR_BP0 BIT(2) /* Block protect 0 */ #define SR_BP1 BIT(3) /* Block protect 1 */ #define SR_BP2 BIT(4) /* Block protect 2 */ +#define SR_SRP0 BIT(7) /* Status register protect 0 */
/* Flash timeout values */ #define SPI_FLASH_PROG_TIMEOUT (2 * CONFIG_SYS_HZ) diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index 7f6e9ae..0e33901 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -837,6 +837,40 @@ int stm_unlock(struct spi_flash *flash, u32 ofs, size_t len)
return 0; } + +/* + * Set status register protection method for parts with one protection bit + * + * Returns negative on errors, 0 on success. + */ +int stm_sr_protect(struct spi_flash *flash, enum srp_method method) +{ + uint8_t status_old, status_new; + u8 mask = SR_SRP0; + u8 val; + int ret; + + ret = read_sr(flash, &status_old); + if (ret < 0) + return ret; + + switch (method) { + case SRP_SOFTWARE: + val = 0; + break; + case SRP_HARDWARE: + val = SR_SRP0; + break; + default: + return -EOPNOTSUPP; + } + + status_new = (status_old & ~mask) | val; + + write_sr(flash, status_new); + + return 0; +} #endif
@@ -1125,6 +1159,7 @@ int spi_flash_scan(struct spi_flash *flash) flash->flash_lock = stm_lock; flash->flash_unlock = stm_unlock; flash->flash_is_locked = stm_is_locked; + flash->sr_protect = stm_sr_protect; #endif break; default:

On Tue, Oct 11, 2016 at 2:57 AM, George McCollister george.mccollister@gmail.com wrote:
STMICRO parts such as M25PX64 and SST parts such as SST26VF032B support a single status register protect bit. When set this bit cause writes to the status register to be blocked when the write protect signal is low.
Implement sr_protect for these devices.
Signed-off-by: George McCollister george.mccollister@gmail.com
drivers/mtd/spi/sf_internal.h | 1 + drivers/mtd/spi/spi_flash.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

Spansion parts such as S25FL128S and Winbond parts such as W25Q64FV support the block protection mechanism implemented as stm_lock() and stm_unlock(). Use stm_lock() and stm_unlock() for Spansion and Winbond devices.
Signed-off-by: George McCollister george.mccollister@gmail.com --- drivers/mtd/spi/spi_flash.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index 0e33901..392146b 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -664,7 +664,8 @@ int sst_write_bp(struct spi_flash *flash, u32 offset, size_t len, } #endif
-#if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST) +#if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST) || \ + defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) static void stm_get_locked_range(struct spi_flash *flash, u8 sr, loff_t *ofs, u64 *len) { @@ -1160,8 +1161,16 @@ int spi_flash_scan(struct spi_flash *flash) flash->flash_unlock = stm_unlock; flash->flash_is_locked = stm_is_locked; flash->sr_protect = stm_sr_protect; + break; #endif +#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) + case SPI_FLASH_CFI_MFR_SPANSION: + case SPI_FLASH_CFI_MFR_WINBOND: + flash->flash_lock = stm_lock; + flash->flash_unlock = stm_unlock; + flash->flash_is_locked = stm_is_locked; break; +#endif default: debug("SF: Lock ops not supported for %02x flash\n", idcode[0]); }

On Tue, Oct 11, 2016 at 2:57 AM, George McCollister george.mccollister@gmail.com wrote:
Spansion parts such as S25FL128S and Winbond parts such as W25Q64FV support the block protection mechanism implemented as stm_lock() and stm_unlock(). Use stm_lock() and stm_unlock() for Spansion and Winbond devices.
Signed-off-by: George McCollister george.mccollister@gmail.com
drivers/mtd/spi/spi_flash.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

Winbond parts such as W25Q64FV and Spansion parts such as S25FL128S support two status register protection bits. Implement sr_protect for Winbond and Spansion devices.
------------------------------------------------------- | SRP1 | SRP0 | Method | Description | -------------------------|----------------------------- | 0 | 0 | Software | Blocked until write enable | | 0 | 1 | Hardware | Blocked if WP pin is low | | 1 | 0 | Power | Blocked until power down | | 1 | 1 | OTP | Blocked permanently | -------------------------------------------------------
Not all devices support OTP.
Signed-off-by: George McCollister george.mccollister@gmail.com --- drivers/mtd/spi/sf_internal.h | 1 + drivers/mtd/spi/spi_flash.c | 57 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+)
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 1b576e8..7a97fc4 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -82,6 +82,7 @@ enum spi_nor_option_flags { #define SR_BP1 BIT(3) /* Block protect 1 */ #define SR_BP2 BIT(4) /* Block protect 2 */ #define SR_SRP0 BIT(7) /* Status register protect 0 */ +#define SR_SRP1 BIT(0) /* Status register protect 1 */
/* Flash timeout values */ #define SPI_FLASH_PROG_TIMEOUT (2 * CONFIG_SYS_HZ) diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index 392146b..80e67e6 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -874,6 +874,62 @@ int stm_sr_protect(struct spi_flash *flash, enum srp_method method) } #endif
+#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) +/* + * Set status register protection method for parts with two protection bits + * + * Returns negative on errors, 0 on success. + */ +int winbond_sr_protect(struct spi_flash *flash, enum srp_method method) +{ + u8 status_old[2], status_new[2]; + u8 mask[2] = {SR_SRP0, SR_SRP1}; + u8 val[2]; + u8 cmd; + int ret; + + ret = read_sr(flash, &status_old[0]); + if (ret < 0) + return ret; + + ret = read_cr(flash, &status_old[1]); + if (ret < 0) + return ret; + + switch (method) { + case SRP_SOFTWARE: + val[0] = 0; + val[1] = 0; + break; + case SRP_HARDWARE: + val[0] = SR_SRP0; + val[1] = 0; + break; + case SRP_POWER: + val[0] = 0; + val[1] = SR_SRP1; + break; + case SRP_OTP: + val[0] = SR_SRP0; + val[1] = SR_SRP1; + break; + default: + return -EOPNOTSUPP; + } + + status_new[0] = (status_old[0] & ~mask[0]) | val[0]; + status_new[1] = (status_old[1] & ~mask[1]) | val[1]; + + cmd = CMD_WRITE_STATUS; + ret = spi_flash_write_common(flash, &cmd, 1, &status_new, 2); + if (ret) { + debug("SF: fail to write status register\n"); + return ret; + } + + return 0; +} +#endif
#ifdef CONFIG_SPI_FLASH_MACRONIX static int macronix_quad_enable(struct spi_flash *flash) @@ -1169,6 +1225,7 @@ int spi_flash_scan(struct spi_flash *flash) flash->flash_lock = stm_lock; flash->flash_unlock = stm_unlock; flash->flash_is_locked = stm_is_locked; + flash->sr_protect = winbond_sr_protect; break; #endif default:

On Tue, Oct 11, 2016 at 2:58 AM, George McCollister george.mccollister@gmail.com wrote:
Winbond parts such as W25Q64FV and Spansion parts such as S25FL128S support two status register protection bits. Implement sr_protect for Winbond and Spansion devices.
| SRP1 | SRP0 | Method | Description | -------------------------|----------------------------- | 0 | 0 | Software | Blocked until write enable | | 0 | 1 | Hardware | Blocked if WP pin is low | | 1 | 0 | Power | Blocked until power down | | 1 | 1 | OTP | Blocked permanently |
Not all devices support OTP.
Signed-off-by: George McCollister george.mccollister@gmail.com
drivers/mtd/spi/sf_internal.h | 1 + drivers/mtd/spi/spi_flash.c | 57 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

Add an sf sub-command named sr-protect which allows the status register protection method to be changed.
Valid settings are software, hardware, power and otp.
Signed-off-by: George McCollister george.mccollister@gmail.com --- cmd/sf.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
diff --git a/cmd/sf.c b/cmd/sf.c index 65b117f..1a42bf6 100644 --- a/cmd/sf.c +++ b/cmd/sf.c @@ -380,6 +380,30 @@ static int do_spi_protect(int argc, char * const argv[]) return ret == 0 ? 0 : 1; }
+static int do_spi_sr_protect(int argc, char * const argv[]) +{ + int ret; + enum srp_method method; + + if (argc != 2) + return -1; + + if (strcmp(argv[1], "software") == 0) + method = SRP_SOFTWARE; + else if (strcmp(argv[1], "hardware") == 0) + method = SRP_HARDWARE; + else if (strcmp(argv[1], "power") == 0) + method = SRP_POWER; + else if (strcmp(argv[1], "otp") == 0) + method = SRP_OTP; + else + return -1; /* Unknown parameter */ + + ret = spi_flash_sr_protect(flash, method); + + return ret == 0 ? 0 : 1; +} + #ifdef CONFIG_CMD_SF_TEST enum { STAGE_ERASE, @@ -574,6 +598,8 @@ static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int argc, ret = do_spi_flash_erase(argc, argv); else if (strcmp(cmd, "protect") == 0) ret = do_spi_protect(argc, argv); + else if (strcmp(cmd, "sr-protect") == 0) + ret = do_spi_sr_protect(argc, argv); #ifdef CONFIG_CMD_SF_TEST else if (!strcmp(cmd, "test")) ret = do_spi_flash_test(argc, argv); @@ -615,5 +641,7 @@ U_BOOT_CMD( " or to start of mtd `partition'\n" "sf protect lock/unlock sector len - protect/unprotect 'len' bytes starting\n" " at address 'sector'\n" + "sf sr-protect method - set status register protect method to\n" + " software, hardware, power or otp\n" SF_TEST_HELP );

On Tue, Oct 11, 2016 at 2:58 AM, George McCollister george.mccollister@gmail.com wrote:
Add an sf sub-command named sr-protect which allows the status register protection method to be changed.
Valid settings are software, hardware, power and otp.
Signed-off-by: George McCollister george.mccollister@gmail.com
cmd/sf.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Mon, Oct 10, 2016 at 1:57 PM, George McCollister george.mccollister@gmail.com wrote:
Many SPI NOR flash devices support status register protection through one or two status register protection bits. Protection of the status register is essential in defending the device from rogue software which may attempt to modify block protection bits in order to make malicious modifications to the data stored in flash. This patch series adds status register protect support for STMICRO, SST, Winbond and Spansion devices and also implements an sf sub-command to set the used protection method.
George McCollister (5): sf: Add status register protection mechanism sf: Add status register protect for STMICRO, SST sf: Use stm_lock/unlock for Spansion and Winbond sf: Add status register protect for Winbond sf: Add sr-protect sub-command
cmd/sf.c | 28 ++++++++++++ drivers/mtd/spi/sf_internal.h | 2 + drivers/mtd/spi/spi_flash.c | 103 +++++++++++++++++++++++++++++++++++++++++- include/spi_flash.h | 17 +++++++ 4 files changed, 149 insertions(+), 1 deletion(-)
-- 2.9.3
Jagan,
I think get_maintainer.pl may have given me an old email address for you and you may have missed it on the mailing list. Either way if you get a chance I'd like hear what you think. I'm not sure which tree/branch you're working with (u-boot-spi master?) but if you need it rebased just let me know.
Thanks, George

On Fri, Oct 28, 2016 at 10:36 PM, George McCollister george.mccollister@gmail.com wrote:
On Mon, Oct 10, 2016 at 1:57 PM, George McCollister george.mccollister@gmail.com wrote:
Many SPI NOR flash devices support status register protection through one or two status register protection bits. Protection of the status register is essential in defending the device from rogue software which may attempt to modify block protection bits in order to make malicious modifications to the data stored in flash. This patch series adds status register protect support for STMICRO, SST, Winbond and Spansion devices and also implements an sf sub-command to set the used protection method.
George McCollister (5): sf: Add status register protection mechanism sf: Add status register protect for STMICRO, SST sf: Use stm_lock/unlock for Spansion and Winbond sf: Add status register protect for Winbond sf: Add sr-protect sub-command
cmd/sf.c | 28 ++++++++++++ drivers/mtd/spi/sf_internal.h | 2 + drivers/mtd/spi/spi_flash.c | 103 +++++++++++++++++++++++++++++++++++++++++- include/spi_flash.h | 17 +++++++ 4 files changed, 149 insertions(+), 1 deletion(-)
-- 2.9.3
Jagan,
I think get_maintainer.pl may have given me an old email address for you and you may have missed it on the mailing list. Either way if you get a chance I'd like hear what you think. I'm not sure which tree/branch you're working with (u-boot-spi master?) but if you need it rebased just let me know.
But this still active. about the patches please wait for some time will get back to you.
thanks!
participants (3)
-
Bin Meng
-
George McCollister
-
Jagan Teki