On 2/4/10 2:18 AM, Carl-Daniel Hailfinger wrote:
On 04.02.2010 07:29, Sean Nelson wrote:
Locking infrastructure
Add lock-status command option.
Winbond W39V080FA has 64k lock blocks.
PMC Pm49FL004 has 64k lock blocks. Tested, but write/erase fails.
Hm. That's bad. Does the code work in an older revision (e.g. 0.9.1)?


The oldest revision I could compile was r714, but I still couldn't erase or write. Previous revisions had a "rdmsr" compile problem. The board may need a board enable.

+#define NUM_LOCKFUNCTIONS 3
Excessive? I'd say we restrict that to 2 (or maybe even 1) until there
is a need for more.



Semantics... if we have multiple lock printing functions, which result
do we trust?

Well...for example, the Winbond W39V080FA has two write protect status functions, one for #TBL/#WP and one for Block Lock status.
  {
        uint8_t *buf;
        unsigned long numbytes;
        FILE *image;
        int ret = 0;
        unsigned long size;

        size = flash->total_size * 1024;
        buf = (uint8_t *) calloc(size, sizeof(char));

+       unlock_flash(flash);
Bad idea. We don't want to unlock the flash so early, especially if
we're only planning to read.


Some of the chips have higher lock states like locking-out reading. Also, we would be calling unlock twice otherwise since we need to lock and unlock for erase/write. Some of the chipdrivers unlock, erase/write, and lock for each erase or write function.

+               print_lock_status_flash(flash);
+       }
+
        if (erase_it) {
                if (flash->tested&  TEST_BAD_ERASE) {
                        fprintf(stderr, "Erase is not working on this chip. ");
                        if (!force) {
                                fprintf(stderr, "Aborting.\n");
                                programmer_shutdown();
                                return 1;
                        } else {
                                fprintf(stderr, "Continuing anyway.\n");
                        }
                }
                if (erase_flash(flash)) {
                        emergency_help_message();
                        programmer_shutdown();
                        return 1;
                }
        } else if (read_it) {
                if (read_flash(flash, filename)) {
                        programmer_shutdown();
                        return 1;
                }
-       } else {
+       } else if (write_it | verify_it) {
This chance can die as well.
The only times the following code is used is for verifying and writing, I don't like using a simple else; but that's just my opinion.
                struct stat image_stat;

                if (flash->tested&  TEST_BAD_ERASE) {
                        fprintf(stderr, "Erase is not working on this chip "
                                "and erase is needed for write. ");
                        if (!force) {
                                fprintf(stderr, "Aborting.\n");
                                programmer_shutdown();
                                return 1;
                        } else {
                                fprintf(stderr, "Continuing anyway.\n");
                        }
                }
@@ -1196,26 +1382,28 @@ int doit(struct flashchip *flash, int force, char 
*filename, int read_it, int wr
                        return 1;
                }
                ret = flash->write(flash, buf);
                if (ret) {
                        fprintf(stderr, "FAILED!\n");
                        emergency_help_message();
                        programmer_shutdown();
                        return 1;
                } else {
                        printf("COMPLETE.\n");
                }
        }

+       lock_flash(flash);
We probably don't want this either. For starters, it means that a
previously unlocked chip will now be unusable for all older flashrom
versions.


I've removed it but older flashrom versions also did the same locking and 
unlock sequence for chipdrivers.

+
        if (verify_it) {
                /* Work around chips which need some time to calm down. */
                if (write_it)
                        programmer_delay(1000*1000);
                ret = verify_flash(flash, buf);
                /* If we tried to write, and verification now fails, we
                 * might have an emergency situation.
                 */
                if (ret&&  write_it)
                        emergency_help_message();
        }

        programmer_shutdown();
diff --git a/jedec.c b/jedec.c
index 055e910..2002fd6 100644
--- a/jedec.c
+++ b/jedec.c
@@ -485,13 +485,33 @@ int erase_block_jedec(struct flashchip *flash, unsigned 
int page, unsigned int s
        int mask;

        mask = getaddrmask(flash);
        return erase_block_jedec_common(flash, page, size, mask);
  }

  int erase_chip_jedec(struct flashchip *flash)
  {
        int mask;

        mask = getaddrmask(flash);
        return erase_chip_jedec_common(flash, mask);
  }
+
+int unlock_block_jedec(struct flashchip *flash, unsigned int block)
+{
+       chip_writeb(0, flash->virtual_registers + block + 2);
+       return 0;
+}
+
+int lock_block_jedec(struct flashchip *flash, unsigned int block)
+{
+       chip_writeb(1, flash->virtual_registers + block + 2);
+       return 0;
+}
+
+int lock_status_block_jedec(struct flashchip *flash, unsigned int block)
+{
+       int lock;
+       lock = chip_readb(flash->virtual_registers + block + 2);
+       return lock&  0x7;
+}
+
I've expanded the lock_status_* functions so themselves print the status.
Assuming there are multiple lock functions, which one is correct? If
they all have the same results anyway, there's no point in having more
than one set of lock functions. If they may have differing results,
either something is totally broken or there are different types of locks
(and then we'd have to lock and unlock _all_ of them, not just the first
one that is successful).

There is another conceptual problem. How do you differentiate between
- temporary reversible software locks
- temporary irreversible software locks (irreversible until next reset etc.)
- permanent software locks (write-once for the whole chip lifetime)
- unchangeable hardware locks (WP#, BPL#)
- locks which lock locks (once that "master" lock is set, other locks
may not be changed)
- read locks (i.e. chip region will return 0xff)
- write locks

All of the above exists in some flash chips supported by flashrom.
I just considered the general case with multiple lock states. Non-SPI is only being considered in this patch. The Lock functions can/should deal with the different lock concepts. You are more than welcome to take my patch and extend it, I only wrote this patch as a starting point for us and was actually expecting you and Uwe to expand on it. From what I could gleam from the chipdrivers and datasheets is we can condense the lock code into my defined lock/unlock/status functions.
Regards,
Carl-Daniel

~ Sean Nelson
diff --git a/chipdrivers.h b/chipdrivers.h
index c5062ca..fb9b1e8 100644
--- a/chipdrivers.h
+++ b/chipdrivers.h
@@ -79,26 +79,29 @@ int write_en29f002a(struct flashchip *flash, uint8_t *buf);
 uint8_t oddparity(uint8_t val);
 void toggle_ready_jedec(chipaddr dst);
 void data_polling_jedec(chipaddr dst, uint8_t data);
 int write_byte_program_jedec(chipaddr bios, uint8_t *src,
                             chipaddr dst);
 int probe_jedec(struct flashchip *flash);
 int erase_chip_jedec(struct flashchip *flash);
 int write_jedec(struct flashchip *flash, uint8_t *buf);
 int write_jedec_1(struct flashchip *flash, uint8_t *buf);
 int erase_sector_jedec(struct flashchip *flash, unsigned int page, unsigned 
int pagesize);
 int erase_block_jedec(struct flashchip *flash, unsigned int page, unsigned int 
blocksize);
 int erase_chip_block_jedec(struct flashchip *flash, unsigned int page, 
unsigned int blocksize);
 int write_sector_jedec_common(struct flashchip *flash, uint8_t *src, chipaddr 
dst, unsigned int page_size, unsigned int mask);
+int lock_status_block_jedec(struct flashchip *flash, unsigned int blockaddr);
+int unlock_block_jedec(struct flashchip *flash, unsigned int blockaddr);
+int lock_block_jedec(struct flashchip *flash, unsigned int blockaddr);
 
 /* m29f002.c */
 int erase_m29f002(struct flashchip *flash);
 int write_m29f002t(struct flashchip *flash, uint8_t *buf);
 int write_m29f002b(struct flashchip *flash, uint8_t *buf);
 
 /* m29f400bt.c */
 int probe_m29f400bt(struct flashchip *flash);
 int erase_m29f400bt(struct flashchip *flash);
 int block_erase_m29f400bt(struct flashchip *flash, unsigned int start, 
unsigned int len);
 int block_erase_chip_m29f400bt(struct flashchip *flash, unsigned int start, 
unsigned int len);
 int write_m29f400bt(struct flashchip *flash, uint8_t *buf);
 int write_coreboot_m29f400bt(struct flashchip *flash, uint8_t *buf);
diff --git a/flash.h b/flash.h
index d8f02bb..cd27e60 100644
--- a/flash.h
+++ b/flash.h
@@ -142,26 +142,30 @@ enum chipbustype {
 };
 
 /*
  * How many different contiguous runs of erase blocks with one size each do
  * we have for a given erase function?
  */
 #define NUM_ERASEREGIONS 5
 
 /*
  * How many different erase functions do we have per chip?
  */
 #define NUM_ERASEFUNCTIONS 5
 
+/* How many different lock segments can a chip have? */
+#define NUM_LOCKREGIONS 4
+#define NUM_LOCKFUNCTIONS 2
+
 #define FEATURE_REGISTERMAP    (1 << 0)
 #define FEATURE_BYTEWRITES     (1 << 1)
 #define FEATURE_LONG_RESET     (0 << 4)
 #define FEATURE_SHORT_RESET    (1 << 4)
 #define FEATURE_EITHER_RESET   FEATURE_LONG_RESET
 #define FEATURE_ADDR_FULL      (0 << 2)
 #define FEATURE_ADDR_MASK      (3 << 2)
 #define FEATURE_ADDR_2AA       (1 << 2)
 #define FEATURE_ADDR_AAA       (2 << 2)
 #define FEATURE_ADDR_SHIFTED   0
 
 struct flashchip {
        const char *vendor;
@@ -195,26 +199,41 @@ struct flashchip {
 
        /*
         * Erase blocks and associated erase function. Any chip erase function
         * is stored as chip-sized virtual block together with said function.
         */
        struct block_eraser {
                struct eraseblock{
                        unsigned int size; /* Eraseblock size */
                        unsigned int count; /* Number of contiguous blocks with 
that size */
                } eraseblocks[NUM_ERASEREGIONS];
                int (*block_erase) (struct flashchip *flash, unsigned int 
blockaddr, unsigned int blocklen);
        } block_erasers[NUM_ERASEFUNCTIONS];
 
+       /*
+        * Lock blocks and associated locking related functions. Lock blocks
+        * are usually uniform blocks with three functions for locking,
+        * unlocking, and lock status.
+        */
+       struct block_locker {
+               struct lockblock {
+                       unsigned int size; /* Lock block size; 64k or 32k */
+                       unsigned int count; /* Number of contiguous blocks */
+               } lockblocks[NUM_LOCKREGIONS];
+               int (*lock) (struct flashchip *flash, unsigned int block);
+               int (*unlock) (struct flashchip *flash, unsigned int block);
+               int (*lock_status) (struct flashchip *flash, unsigned int 
block);
+       } block_lockers[NUM_LOCKFUNCTIONS];
+
        int (*write) (struct flashchip *flash, uint8_t *buf);
        int (*read) (struct flashchip *flash, uint8_t *buf, int start, int len);
 
        /* Some flash devices have an additional register space. */
        chipaddr virtual_memory;
        chipaddr virtual_registers;
 };
 
 #define TEST_UNTESTED  0
 
 #define TEST_OK_PROBE  (1 << 0)
 #define TEST_OK_READ   (1 << 1)
 #define TEST_OK_ERASE  (1 << 2)
@@ -516,26 +535,29 @@ int erase_flash(struct flashchip *flash);
 struct flashchip *probe_flash(struct flashchip *first_flash, int force);
 int read_flash(struct flashchip *flash, char *filename);
 void check_chip_supported(struct flashchip *flash);
 int check_max_decode(enum chipbustype buses, uint32_t size);
 int min(int a, int b);
 int max(int a, int b);
 char *extract_param(char **haystack, char *needle, char *delim);
 int check_erased_range(struct flashchip *flash, int start, int len);
 int verify_range(struct flashchip *flash, uint8_t *cmpbuf, int start, int len, 
char *message);
 char *strcat_realloc(char *dest, const char *src);
 void print_version(void);
 int selfcheck(void);
 int doit(struct flashchip *flash, int force, char *filename, int read_it, int 
write_it, int erase_it, int verify_it);
+int unlock_flash(struct flashchip *flash);
+int lock_flash(struct flashchip *flash);
+int print_lock_status_flash(struct flashchip *flash);
 
 #define OK 0
 #define NT 1    /* Not tested */
 
 /* cli_output.c */
 int print(int type, const char *fmt, ...);
 #define MSG_ERROR      0
 #define MSG_INFO       1
 #define MSG_DEBUG      2
 #define MSG_BARF       3
 #define msg_gerr(...)  print(MSG_ERROR, __VA_ARGS__)   /* general errors */
 #define msg_perr(...)  print(MSG_ERROR, __VA_ARGS__)   /* programmer errors */
 #define msg_cerr(...)  print(MSG_ERROR, __VA_ARGS__)   /* chip errors */
diff --git a/flashchips.c b/flashchips.c
index f66b95a..174dce6 100644
--- a/flashchips.c
+++ b/flashchips.c
@@ -3425,27 +3425,36 @@ struct flashchip flashchips[] = {
                .block_erasers  =
                {
                        {
                                .eraseblocks = { {4 * 1024, 64} },
                                .block_erase = erase_sector_jedec,
                        }, {
                                .eraseblocks = { {16 * 1024, 16} },
                                .block_erase = erase_block_jedec,
                        }, {
                                .eraseblocks = { {256 * 1024, 1} },
                                .block_erase = erase_chip_block_jedec,
                        }
                },
-               .write          = write_49fl00x,
+               .block_lockers =
+               {
+                       {
+                               .lockblocks = { {64 * 1024, 8} },
+                               .lock = lock_block_jedec,
+                               .unlock = unlock_block_jedec,
+                               .lock_status = lock_status_block_jedec,
+                       },
+               },
+               .write          = write_jedec_1,
                .read           = read_memmapped,
        },
 
        {
                .vendor         = "PMC",
                .name           = "Pm49FL004",
                .bustype        = CHIP_BUSTYPE_LPC | CHIP_BUSTYPE_FWH, /* A/A 
Mux*/
                .manufacture_id = PMC_ID_NOPREFIX,
                .model_id       = PMC_49FL004,
                .total_size     = 512,
                .page_size      = 64 * 1024,
                .feature_bits   = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
                .tested         = TEST_UNTESTED,
@@ -3455,27 +3464,36 @@ struct flashchip flashchips[] = {
                .block_erasers  =
                {
                        {
                                .eraseblocks = { {4 * 1024, 128} },
                                .block_erase = erase_sector_jedec,
                        }, {
                                .eraseblocks = { {64 * 1024, 8} },
                                .block_erase = erase_block_jedec,
                        }, {
                                .eraseblocks = { {512 * 1024, 1} },
                                .block_erase = erase_chip_block_jedec,
                        }
                },
-               .write          = write_49fl00x,
+               .block_lockers =
+               {
+                       {
+                               .lockblocks = { {64 * 1024, 8} },
+                               .lock = lock_block_jedec,
+                               .unlock = unlock_block_jedec,
+                               .lock_status = lock_status_block_jedec,
+                       },
+               },
+               .write          = write_jedec_1,
                .read           = read_memmapped,
        },
 
        {
                .vendor         = "Sanyo",
                .name           = "LF25FW203A",
                .bustype        = CHIP_BUSTYPE_SPI,
                .manufacture_id = SANYO_ID,
                .model_id       = SANYO_LE25FW203A,
                .total_size     = 2048,
                .page_size      = 256,
                .tested         = TEST_UNTESTED,
                .probe          = probe_spi_rdid,
@@ -6120,26 +6138,40 @@ struct flashchip flashchips[] = {
                .probe          = probe_jedec,
                .probe_timing   = TIMING_FIXME,
                .erase          = NULL, /* Was erase_winbond_fwhub */
                .block_erasers  =
                {
                        {
                                .eraseblocks = { {64 * 1024, 16}, },
                                .block_erase = erase_sector_jedec,
                        }, {
                                .eraseblocks = { {1024 * 1024, 1} },
                                .block_erase = erase_chip_block_jedec,
                        }
                },
+               .block_lockers =
+               {
+                       { /* block lock functions */
+                               .lockblocks = { {64 * 1024, 16} },
+                               .lock = lock_block_jedec,
+                               .unlock = unlock_block_jedec,
+                               .lock_status = lock_status_block_jedec,
+                       }, { /* #TBL / #WP status */
+                               .lockblocks = { {512 * 1024, 1} }, /* dummy 
block */
+                               .lock = NULL,
+                               .unlock = NULL,
+                               .lock_status = lock_status_chip_jedec,
+                       }
+               },
                .write          = write_jedec_1,
                .read           = read_memmapped,
        },
 
        {
                .vendor         = "Winbond",
                .name           = "W39V080FA (dual mode)",
                .bustype        = CHIP_BUSTYPE_FWH,
                .manufacture_id = WINBOND_ID,
                .model_id       = W_39V080FA_DM,
                .total_size     = 512,
                .page_size      = 64 * 1024,
                .feature_bits   = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
@@ -6147,26 +6179,40 @@ struct flashchip flashchips[] = {
                .probe          = probe_jedec,
                .probe_timing   = TIMING_FIXME,
                .erase          = NULL, /* Was erase_winbond_fwhub */
                .block_erasers  =
                {
                        {
                                .eraseblocks = { {64 * 1024, 8}, },
                                .block_erase = erase_sector_jedec,
                        }, {
                                .eraseblocks = { {512 * 1024, 1} },
                                .block_erase = erase_chip_block_jedec,
                        }
                },
+               .block_lockers =
+               {
+                       { /* block lock functions */
+                               .lockblocks = { {64 * 1024, 8} },
+                               .lock = lock_block_jedec,
+                               .unlock = unlock_block_jedec,
+                               .lock_status = lock_status_block_jedec,
+                       }, { /* #TBL / #WP status */
+                               .lockblocks = { {512 * 1024, 1} }, /* dummy 
block */
+                               .lock = NULL,
+                               .unlock = NULL,
+                               .lock_status = lock_status_chip_jedec,
+                       }
+               },
                .write          = write_jedec_1,
                .read           = read_memmapped,
        },
 
        {
                .vendor         = "Atmel",
                .name           = "unknown Atmel SPI chip",
                .bustype        = CHIP_BUSTYPE_SPI,
                .manufacture_id = ATMEL_ID,
                .model_id       = GENERIC_DEVICE_ID,
                .total_size     = 0,
                .page_size      = 256,
                .tested         = TEST_BAD_PREW,
diff --git a/flashrom.c b/flashrom.c
index 326f725..1d5439a 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -795,26 +795,28 @@ struct flashchip *probe_flash(struct flashchip 
*first_flash, int force)
                        break;
 
 notfound:
                programmer_unmap_flash_region((void *)flash->virtual_memory, 
size);
        }
 
        if (!flash || !flash->name)
                return NULL;
 
        printf("Found chip \"%s %s\" (%d KB, %s) at physical address 0x%lx.\n",
               flash->vendor, flash->name, flash->total_size,
               flashbuses_to_text(flash->bustype), base);
 
+       print_lock_status_flash(flash);
+
        return flash;
 }
 
 int verify_flash(struct flashchip *flash, uint8_t *buf)
 {
        int ret;
        int total_size = flash->total_size * 1024;
 
        printf("Verifying flash... ");
 
        ret = verify_range(flash, buf, 0, total_size, NULL);
 
        if (!ret)
@@ -984,26 +986,213 @@ int erase_flash(struct flashchip *flash)
        if (!found) {
                fprintf(stderr, "ERROR: flashrom has no erase function for this 
flash chip.\n");
                return 1;
        }
 
        if (ret) {
                fprintf(stderr, "FAILED!\n");
        } else {
                printf("SUCCESS.\n");
        }
        return ret;
 }
 
+int unlock_flash(struct flashchip *flash)
+{
+       int i, j, k, ret = 0, found = 0;
+       unsigned int start;
+
+       printf("Unlocking flash chip... ");
+       for (k = 0; k < NUM_LOCKFUNCTIONS; k++) {
+               unsigned int done = 0;
+               struct block_locker locker = flash->block_lockers[k];
+
+               printf_debug("Looking at blockwise unlock function %i... ", k);
+               if (!locker.unlock && !locker.lockblocks[0].count) {
+                       printf_debug("not defined. "
+                               "Looking for another unlock function.\n");
+                       continue;
+               }
+               if (!locker.unlock && locker.lockblocks[0].count) {
+                       printf_debug("lockblock layout is known, but no "
+                               "matching block unlock function found. "
+                               "Looking for another unlock function.\n");
+                       continue;
+               }
+               if (locker.unlock && !locker.lockblocks[0].count) {
+                       printf_debug("block unlock function found, but "
+                               "lockblock layout is unknown. "
+                               "Looking for another unlock function.\n");
+                       continue;
+               }
+               found = 1;
+               printf_debug("trying... ");
+               for (i = 0; i < NUM_LOCKREGIONS; i++) {
+                       /* count==0 for all automatically initialized array
+                        * members so the loop below won't be executed for them.
+                        */
+                       for (j = 0; j < locker.lockblocks[i].count; j++) {
+                               start = done + locker.lockblocks[i].size * j;
+                               ret = locker.unlock(flash, start);
+                               printf_debug("0x%06x, ", start);
+                               if (ret)
+                                       break;
+                       }
+                       if (ret)
+                               break;
+                       done += locker.lockblocks[i].count *
+                               locker.lockblocks[i].size;
+               }
+               printf_debug("\n");
+               /* If everything is OK, don't try another unlock function. */
+               if (!ret)
+                       break;
+       }
+       if (!found) {
+               fprintf(stderr, "ERROR: flashrom has no unlock function for 
this flash chip.\n");
+               return 1;
+       }
+
+       if (ret) {
+               fprintf(stderr, "FAILED!\n");
+       } else {
+               printf("SUCCESS.\n");
+       }
+       return ret;
+}
+
+int lock_flash(struct flashchip *flash)
+{
+       int i, j, k, ret = 0, found = 0;
+       unsigned int start;
+
+       printf("Locking flash chip... ");
+       for (k = 0; k < NUM_LOCKFUNCTIONS; k++) {
+               unsigned int done = 0;
+               struct block_locker locker = flash->block_lockers[k];
+
+               printf_debug("Looking at blockwise lock function %i... ", k);
+               if (!locker.lock && !locker.lockblocks[0].count) {
+                       printf_debug("not defined. "
+                               "Looking for another lock function.\n");
+                       continue;
+               }
+               if (!locker.lock && locker.lockblocks[0].count) {
+                       printf_debug("lockblock layout is known, but no "
+                               "matching block lock function found. "
+                               "Looking for another lock function.\n");
+                       continue;
+               }
+               if (locker.lock && !locker.lockblocks[0].count) {
+                       printf_debug("block lock function found, but "
+                               "lockblock layout is unknown. "
+                               "Looking for another lock function.\n");
+                       continue;
+               }
+               found = 1;
+               printf_debug("trying... ");
+               for (i = 0; i < NUM_LOCKREGIONS; i++) {
+                       /* count==0 for all automatically initialized array
+                        * members so the loop below won't be executed for them.
+                        */
+                       for (j = 0; j < locker.lockblocks[i].count; j++) {
+                               start = done + locker.lockblocks[i].size * j;
+                               ret = locker.lock(flash, start);
+                               printf_debug("0x%06x, ", start);
+                               if (ret)
+                                       break;
+                       }
+                       if (ret)
+                               break;
+                       done += locker.lockblocks[i].count *
+                               locker.lockblocks[i].size;
+               }
+               printf_debug("\n");
+               /* If everything is OK, don't try another lock function. */
+               if (!ret)
+                       break;
+       }
+       if (!found) {
+               fprintf(stderr, "ERROR: flashrom has no lock function for this 
flash chip.\n");
+               return 1;
+       }
+
+       if (ret) {
+               fprintf(stderr, "FAILED!\n");
+       } else {
+               printf("SUCCESS.\n");
+       }
+       return ret;
+}
+
+int print_lock_status_flash(struct flashchip *flash)
+{
+       int i, j, k, ret = 0, found = 0;
+       unsigned int start, lock_stat = 0;
+
+       printf("Printing Lock Status for flash chip... ");
+       for (k = 0; k < NUM_LOCKFUNCTIONS; k++) {
+               unsigned int done = 0;
+               struct block_locker locker = flash->block_lockers[k];
+
+               printf_debug("Looking at blockwise lock_status function %i... 
", k);
+               if (!locker.lock_status && !locker.lockblocks[0].count) {
+                       printf_debug("not defined. "
+                               "Looking for another lock_status function.\n");
+                       continue;
+               }
+               if (!locker.lock_status && locker.lockblocks[0].count) {
+                       printf_debug("lockblock layout is known, but no "
+                               "matching block lock_status function found. "
+                               "Looking for another lock_status function.\n");
+                       continue;
+               }
+               if (locker.lock_status && !locker.lockblocks[0].count) {
+                       printf_debug("block lock_status function found, but "
+                               "lockblock layout is unknown. "
+                               "Looking for another lock_status function.\n");
+                       continue;
+               }
+               found = 1;
+               printf("trying... ");
+               for (i = 0; i < NUM_LOCKREGIONS; i++) {
+                       /* count==0 for all automatically initialized array
+                        * members so the loop below won't be executed for them.
+                        */
+                       for (j = 0; j < locker.lockblocks[i].count; j++) {
+                               start = done + locker.lockblocks[i].size * j;
+                               ret = locker.lock_status(flash, start);
+                       }
+                       done += locker.lockblocks[i].count *
+                               locker.lockblocks[i].size;
+                       if (ret) {
+                               break;
+                       }
+               }
+               printf("\n");
+       }
+       if (!found) {
+               fprintf(stderr, "WARNING: flashrom has no lock_status function 
for this flash chip.\n");
+               return 1;
+       }
+
+       if (ret) {
+               fprintf(stderr, "FAILED!\n");
+       } else {
+               printf("SUCCESS.\n");
+       }
+       return ret;
+}
+
 void emergency_help_message(void)
 {
        fprintf(stderr, "Your flash chip is in an unknown state.\n"
                "Get help on IRC at irc.freenode.net (channel #flashrom) or\n"
                "mail [email protected]!\n--------------------"
                "-----------------------------------------------------------\n"
                "DO NOT REBOOT OR POWEROFF!\n");
 }
 
 /* The way to go if you want a delimited list of programmers*/
 void list_programmers(char *delim)
 {
        enum programmer p;
@@ -1099,26 +1288,28 @@ int main(int argc, char *argv[])
  * but right now it allows us to split off the CLI code.
  */
 int doit(struct flashchip *flash, int force, char *filename, int read_it, int 
write_it, int erase_it, int verify_it)
 {
        uint8_t *buf;
        unsigned long numbytes;
        FILE *image;
        int ret = 0;
        unsigned long size;
 
        size = flash->total_size * 1024;
        buf = (uint8_t *) calloc(size, sizeof(char));
 
+       unlock_flash(flash);
+
        if (erase_it) {
                if (flash->tested & TEST_BAD_ERASE) {
                        fprintf(stderr, "Erase is not working on this chip. ");
                        if (!force) {
                                fprintf(stderr, "Aborting.\n");
                                programmer_shutdown();
                                return 1;
                        } else {
                                fprintf(stderr, "Continuing anyway.\n");
                        }
                }
                if (erase_flash(flash)) {
                        emergency_help_message();
diff --git a/jedec.c b/jedec.c
index 055e910..6b857bf 100644
--- a/jedec.c
+++ b/jedec.c
@@ -485,13 +485,113 @@ int erase_block_jedec(struct flashchip *flash, unsigned 
int page, unsigned int s
        int mask;
 
        mask = getaddrmask(flash);
        return erase_block_jedec_common(flash, page, size, mask);
 }
 
 int erase_chip_jedec(struct flashchip *flash)
 {
        int mask;
 
        mask = getaddrmask(flash);
        return erase_chip_jedec_common(flash, mask);
 }
+
+int unlock_block_jedec(struct flashchip *flash, unsigned int blockaddr)
+{
+       chip_writeb(0, flash->virtual_registers + blockaddr + 2);
+       return 0;
+}
+
+int lock_block_jedec(struct flashchip *flash, unsigned int blockaddr)
+{
+       chip_writeb(1, flash->virtual_registers + blockaddr + 2);
+       return 0;
+}
+
+int lock_status_block_jedec(struct flashchip *flash, unsigned int blockaddr)
+{
+       chipaddr wrprotect = flash->virtual_registers + offset + 2;
+       uint8_t locking;
+
+       printf_debug("Trying to unlock block @0x%08x = 0x%02x\n", offset,
+                    chip_readb(wrprotect));
+
+       locking = chip_readb(wrprotect);
+       switch (locking & 0x7) {
+       case 0:
+               printf_debug("Full Access.\n");
+               return 0;
+       case 1:
+               printf_debug("Write Lock (Default State).\n");
+               chip_writeb(0, wrprotect);
+               return 0;
+       case 2:
+               printf_debug("Locked Open (Full Access, Lock Down).\n");
+               return 0;
+       case 3:
+               fprintf(stderr, "Error: Write Lock, Locked Down.\n");
+               return -1;
+       case 4:
+               printf_debug("Read Lock.\n");
+               chip_writeb(0, wrprotect);
+               return 0;
+       case 5:
+               printf_debug("Read/Write Lock.\n");
+               chip_writeb(0, wrprotect);
+               return 0;
+       case 6:
+               fprintf(stderr, "Error: Read Lock, Locked Down.\n");
+               return -1;
+       case 7:
+               fprintf(stderr, "Error: Read/Write Lock, Locked Down.\n");
+               return -1;
+       }
+
+       /* We will never reach this point, but GCC doesn't know */
+       return -1;
+}
+
+int lock_status_chip_jedec(struct flashchip *flash, unsigned int blockaddr)
+{
+       int i, total_size = flash->total_size * 1024;
+       chipaddr bios = flash->virtual_memory;
+       uint8_t locking;
+       int mask;
+       
+       mask = getaddrmask(flash);
+       /* Are there any hardware restrictions that we can't overcome? 
+        * If flashrom fail here, someone's got to check all those GPIOs.
+        */
+
+       /* Product Identification Entry */
+       chip_writeb(0xAA, bios + (0x5555 & mask));
+       chip_writeb(0x55, bios + (0x2AAA & mask));
+       chip_writeb(0x90, bios + (0x5555 & mask));
+       programmer_delay(10);
+
+       /* Read Hardware Lock Bits */
+       locking = chip_readb(bios + 0xffff2);
+
+       /* Product Identification Exit */
+       chip_writeb(0xAA, bios + (0x5555 & mask));
+       chip_writeb(0x55, bios + (0x2AAA & mask));
+       chip_writeb(0xF0, bios + (0x5555 & mask));
+       programmer_delay(10);
+
+       printf_debug("Lockout bits:\n");
+
+       if (locking & (1 << 2))
+               fprintf(stderr, "Error: hardware bootblock locking (#TBL).\n");
+       else
+               printf_debug("No hardware bootblock locking (good!)\n");
+
+       if (locking & (1 << 3))
+               fprintf(stderr, "Error: hardware block locking (#WP).\n");
+       else
+               printf_debug("No hardware block locking (good!)\n");
+
+       if (locking & ((1 << 2) | (1 << 3)))
+               return -1;
+
+       return 0;
+}
\ No newline at end of file
_______________________________________________
flashrom mailing list
[email protected]
http://www.flashrom.org/mailman/listinfo/flashrom

Reply via email to