[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