Hello Timothy and David,
I have attached a patch that adds support for W25Q128BV and W25Q128FV chips (I noticed Timothy needed these chips;) so I added only these for now). This patch should be applied on top of all my most recent patches. Instead of downloading and locally applying all those patches and then applying the attached one, I recommend you clone my fork of flashrom (dev branch) from GitHub (https://github.com/hatimak/flashrom/tree/dev). I have already pushed the attached patch there ;)
Now, on how to use it. Once you compile and install it, have a look at the man page and the --help output. If you run --wp-list, you can see the access protection table. For you particular case you will need --wp-set-range start=0xfff000,len=4. This will lock the top 4kB of either or W25Q128BV or W25Q128FV. The man page will explain how you can set status register write protection if you need that. If it happens that you need OTP support for these chips, that is available as well :)
The CLI is arguably not the best, but this is a more general solution than what you sent. I hope this is sufficient and helps you out. Feel free to reach out for any comments/feedback/help over mail or IRC (hatim on #flashrom).
Thanks, Hatim
On Wednesday 24 August 2016 05:42 AM, David Hendricks wrote:
Hi Timothy, Check out Hatim's GSOC work for manipulating status register and write protect bits: https://patchwork.coreboot.org/patch/4471/ https://patchwork.coreboot.org/patch/4472/ https://patchwork.coreboot.org/patch/4469/ https://patchwork.coreboot.org/patch/4467/ https://patchwork.coreboot.org/patch/4468/ https://patchwork.coreboot.org/patch/4470/
There's also similar work done in Chromium.org fork of flashrom which might do what you need (--wp-enable command): https://chromium.googlesource.com/chromiumos/third_party/flashrom/
Thanks David for your reply :) Seeing my work being used and recommended feels extraordinarily happy ;)
On Tue, Aug 23, 2016 at 2:32 PM, Timothy Pearson <tpearson@raptorengineering.com mailto:tpearson@raptorengineering.com> wrote:
RFC PATCH TPM-enabled systems require an immutable (or at least very difficult to modify) CRTM, which can be provided via a locked bootblock sector. Add initial support for locking the upper 4K sector on Winbond Flash ROMs. Unlocking the sector after it has been locked requires hardware access to the write protect pin, satisfying the above requirements for many use cases. To use, pass the --lock flag to Flashrom. This flag can be used in isolation, or as part of a normal read / write / verify cycle.
Timothy, thanks for your patch :) Hope what I explained above is helpful to you. And I would gently point out that you forgot the "Signed-off-by" tag in your patch :)
Index: spi25_statusreg.c =================================================================== --- spi25_statusreg.c (revision 1955) +++ spi25_statusreg.c (working copy) @@ -123,6 +123,78 @@ return readarr[0]; } +static uint8_t spi_read_status_register_2(struct flashctx *flash) +{ + static const unsigned char cmd[JEDEC_RDSR_OUTSIZE] = { JEDEC_RDSR2 }; + /* FIXME: No workarounds for driver/hardware bugs in generic code. */ + unsigned char readarr[2]; /* JEDEC_RDSR2_INSIZE=1 but wbsio needs 2 */ + int ret; + + /* Read Status Register */ + ret = spi_send_command(flash, sizeof(cmd), sizeof(readarr), cmd, readarr); + if (ret) + msg_cerr("RDSR2 failed!\n"); + + return readarr[0]; +} + +/* Winbond sector protection enable that tries to set the status register bits given. */ +int spi_enable_sectorprotect_winbond(struct flashctx *flash, const uint8_t status_flags) +{ + uint8_t status, status2; + int result; + uint8_t lock_mask = 0x80; + uint8_t lock2_mask = 0x1; + + status = spi_read_status_register(flash); + status2 = spi_read_status_register_2(flash); + if ((status & lock_mask) != 0) { + msg_cdbg("\n\tNeed to disable the register lock first... "); + if ((status2 & lock2_mask) != 0) { + msg_cerr("Hardware protection is active, enabling write protection is impossible.\n"); + return 1; + } + /* All bits except the register lock bit (often called SPRL, SRWD, WPEN) are readonly. */ + result = spi_write_status_register(flash, status & ~lock_mask); + if (result) { + msg_cerr("spi_write_status_register failed.\n"); + return result; + } + status = spi_read_status_register(flash); + if ((status & lock_mask) != 0) { + msg_cerr("Unsetting lock bit(s) failed.\n"); + return 1; + } + msg_cdbg("done.\n"); + } + + /* Set requested protect bits */ + result = spi_write_status_register(flash, status | (status_flags << 2) ); + if (result) { + msg_cerr("spi_write_status_register failed.\n"); + return result; + } + status = spi_read_status_register(flash); + if ((status & (status_flags << 2)) != (status_flags << 2)) { + msg_cerr("Setting lock bit(s) failed.\n"); + return 1; + } + + /* Set lock bit */ + result = spi_write_status_register(flash, status | lock_mask); + if (result) { + msg_cerr("spi_write_status_register failed.\n"); + return result; + } + status = spi_read_status_register(flash); + if ((status & lock_mask) == 0) { + msg_cerr("Setting lock bit(s) failed.\n"); + return 1; + } + + return 0; +} + /* A generic block protection disable. * Tests if a protection is enabled with the block protection mask (bp_mask) and returns success otherwise. * Tests if the register bits are locked with the lock_mask (lock_mask). Index: flashrom.c =================================================================== --- flashrom.c (revision 1955) +++ flashrom.c (working copy) @@ -1977,7 +1977,7 @@ * Besides that, the function itself is a textbook example of abysmal code flow. */ int doit(struct flashctx *flash, int force, const char *filename, int read_it, - int write_it, int erase_it, int verify_it) + int write_it, int erase_it, int verify_it, int lock_it) { uint8_t *oldcontents; uint8_t *newcontents; @@ -2129,6 +2129,13 @@ msg_cinfo("VERIFIED.\n"); } + if (lock_it && flash->chip->lock) { + msg_cinfo("Locking upper 4K (bootblock)... "); + ret = flash->chip->lock(flash, 0x11); + if (!ret) + msg_cinfo("LOCKED.\n"); + } + out: free(oldcontents); free(newcontents); Index: cli_classic.c =================================================================== --- cli_classic.c (revision 1955) +++ cli_classic.c (working copy) @@ -49,6 +49,7 @@ " -r | --read <file> read flash and save to <file>\n" " -w | --write <file> write <file> to flash\n" " -v | --verify <file> verify flash against <file>\n" + " -u | --lock lock upper Flash region (typically the 4K bootblock)\n" " -E | --erase erase flash memory\n" " -V | --verbose more verbose output\n" " -c | --chip <chipname> probe only for specified flash chip\n" @@ -101,18 +102,19 @@ #if CONFIG_PRINT_WIKI == 1 int list_supported_wiki = 0; #endif - int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0; + int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0, lock_it = 0; int dont_verify_it = 0, list_supported = 0, operation_specified = 0; enum programmer prog = PROGRAMMER_INVALID; int ret = 0; - static const char optstring[] = "r:Rw:v:nVEfc:l:i:p:Lzho:"; + static const char optstring[] = "r:Rw:v:nuVEfc:l:i:p:Lzho:"; static const struct option long_options[] = { {"read", 1, NULL, 'r'}, {"write", 1, NULL, 'w'}, {"erase", 0, NULL, 'E'}, {"verify", 1, NULL, 'v'}, {"noverify", 0, NULL, 'n'}, + {"lock", 0, NULL, 'u'}, {"chip", 1, NULL, 'c'}, {"verbose", 0, NULL, 'V'}, {"force", 0, NULL, 'f'}, @@ -187,6 +189,9 @@ } dont_verify_it = 1; break; + case 'u': + lock_it = 1; + break; case 'c': chip_to_probe = strdup(optarg); break; @@ -522,7 +527,7 @@ goto out_shutdown; } - if (!(read_it | write_it | verify_it | erase_it)) { + if (!(read_it | write_it | verify_it | erase_it | lock_it)) { msg_ginfo("No operations were specified.\n"); goto out_shutdown; } @@ -542,7 +547,7 @@ * Give the chip time to settle. */ programmer_delay(100000); - ret |= doit(fill_flash, force, filename, read_it, write_it, erase_it, verify_it); + ret |= doit(fill_flash, force, filename, read_it, write_it, erase_it, verify_it, lock_it); unmap_flash(fill_flash); out_shutdown: Index: flashchips.c =================================================================== --- flashchips.c (revision 1955) +++ flashchips.c (working copy) @@ -14581,6 +14581,7 @@ }, .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */ .unlock = spi_disable_blockprotect, + .lock = spi_enable_sectorprotect_winbond, .write = spi_chip_write_256, .read = spi_chip_read, .voltage = {2700, 3600}, Index: chipdrivers.h =================================================================== --- chipdrivers.h (revision 1955) +++ chipdrivers.h (working copy) @@ -73,6 +73,7 @@ int spi_prettyprint_status_register_bp4_srwd(struct flashctx *flash); int spi_prettyprint_status_register_bp2_bpl(struct flashctx *flash); int spi_prettyprint_status_register_bp2_tb_bpl(struct flashctx *flash); +int spi_enable_sectorprotect_winbond(struct flashctx *flash, const uint8_t status_flags); int spi_disable_blockprotect(struct flashctx *flash); int spi_disable_blockprotect_bp1_srwd(struct flashctx *flash); int spi_disable_blockprotect_bp2_srwd(struct flashctx *flash); Index: flash.h =================================================================== --- flash.h (revision 1955) +++ flash.h (working copy) @@ -200,6 +200,7 @@ } block_erasers[NUM_ERASEFUNCTIONS]; int (*printlock) (struct flashctx *flash); + int (*lock) (struct flashctx *flash, const uint8_t status_flags); int (*unlock) (struct flashctx *flash); int (*write) (struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len); int (*read) (struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len); @@ -281,7 +282,7 @@ void print_banner(void); void list_programmers_linebreak(int startcol, int cols, int paren); int selfcheck(void); -int doit(struct flashctx *flash, int force, const char *filename, int read_it, int write_it, int erase_it, int verify_it); +int doit(struct flashctx *flash, int force, const char *filename, int read_it, int write_it, int erase_it, int verify_it, int lock_it); int read_buf_from_file(unsigned char *buf, unsigned long size, const char *filename); int write_buf_to_file(const unsigned char *buf, unsigned long size, const char *filename); Index: spi.h =================================================================== --- spi.h (revision 1955) +++ spi.h (working copy) @@ -121,6 +121,11 @@ #define JEDEC_RDSR_OUTSIZE 0x01 #define JEDEC_RDSR_INSIZE 0x01 +/* Read Status Register 2 */ +#define JEDEC_RDSR2 0x35 +#define JEDEC_RDSR2_OUTSIZE 0x01 +#define JEDEC_RDSR2_INSIZE 0x01 + /* Status Register Bits */ #define SPI_SR_WIP (0x01 << 0) #define SPI_SR_WEL (0x01 << 1) _______________________________________________ flashrom mailing list flashrom@flashrom.org <mailto:flashrom@flashrom.org> https://www.flashrom.org/mailman/listinfo/flashrom <https://www.flashrom.org/mailman/listinfo/flashrom>
-- David Hendricks (dhendrix) Systems Software Engineer, Google Inc.