[flashrom] [RFC] [PATCH] Add ability to lock bootblock on Winbond Flash ROMs
David Hendricks
dhendrix at google.com
Wed Aug 24 02:12:27 CEST 2016
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/
On Tue, Aug 23, 2016 at 2:32 PM, Timothy Pearson <
tpearson at 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.
>
> 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 at flashrom.org
> https://www.flashrom.org/mailman/listinfo/flashrom
>
--
David Hendricks (dhendrix)
Systems Software Engineer, Google Inc.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.flashrom.org/pipermail/flashrom/attachments/20160823/efa1a02e/attachment.html>
More information about the flashrom
mailing list