diff --git a/flash.h b/flash.h index e51b6d4c6..20db343ed 100644 --- a/flash.h +++ b/flash.h @@ -83,6 +83,7 @@ enum chipbustype { #define FEATURE_ADDR_SHIFTED (1 << 5) #define FEATURE_WRSR_EWSR (1 << 6) #define FEATURE_WRSR_WREN (1 << 7) +#define FEATURE_OTP (1 << 8) #define FEATURE_WRSR_EITHER (FEATURE_WRSR_EWSR | FEATURE_WRSR_WREN) struct flashctx; diff --git a/flashchips.c b/flashchips.c index ca1c57fce..c6bff8d97 100644 --- a/flashchips.c +++ b/flashchips.c @@ -1120,7 +1120,8 @@ const struct flashchip flashchips[] = { .model_id = AMIC_A25L032, .total_size = 4096, .page_size = 256, - .feature_bits = FEATURE_WRSR_WREN, + /* OTP: 64B total; read 0x4B, 0x48; write 0x42 */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP, .tested = TEST_UNTESTED, .probe = probe_spi_rdid, .probe_timing = TIMING_ZERO, @@ -1158,7 +1159,8 @@ const struct flashchip flashchips[] = { .model_id = AMIC_A25LQ032, .total_size = 4096, .page_size = 256, - .feature_bits = FEATURE_WRSR_WREN, + /* OTP: 64B total; read 0x4B, 0x48; write 0x42 */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP, .tested = TEST_UNTESTED, .probe = probe_spi_rdid, .probe_timing = TIMING_ZERO, @@ -1315,7 +1317,8 @@ const struct flashchip flashchips[] = { .model_id = ATMEL_AT25DF021, .total_size = 256, .page_size = 256, - .feature_bits = FEATURE_WRSR_WREN, + /* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP, .tested = TEST_UNTESTED, .probe = probe_spi_rdid, .probe_timing = TIMING_ZERO, @@ -1543,7 +1546,8 @@ const struct flashchip flashchips[] = { .model_id = ATMEL_AT25DF321A, .total_size = 4096, .page_size = 256, - .feature_bits = FEATURE_WRSR_WREN, + /* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP, .tested = TEST_OK_PROBE, .probe = probe_spi_rdid, .probe_timing = TIMING_ZERO, @@ -1619,7 +1623,8 @@ const struct flashchip flashchips[] = { .model_id = ATMEL_AT25DQ161, .total_size = 2048, .page_size = 256, - .feature_bits = FEATURE_WRSR_WREN, + /* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP, .tested = TEST_UNTESTED, .probe = probe_spi_rdid, .probe_timing = TIMING_ZERO, @@ -1657,7 +1662,8 @@ const struct flashchip flashchips[] = { .model_id = ATMEL_AT25F512B, .total_size = 64, .page_size = 256, - .feature_bits = FEATURE_WRSR_WREN, + /* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP, .tested = TEST_UNTESTED, .probe = probe_spi_rdid, .probe_timing = TIMING_ZERO, @@ -2168,6 +2174,8 @@ const struct flashchip flashchips[] = { .model_id = ATMEL_AT45DB321D, .total_size = 4096 /* Size can only be determined from status register */, .page_size = 512 /* Size can only be determined from status register */, + /* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */ + .feature_bits = FEATURE_OTP, .tested = TEST_BAD_READ, .probe = probe_spi_rdid, .probe_timing = TIMING_ZERO, @@ -3236,8 +3244,8 @@ const struct flashchip flashchips[] = { .model_id = EON_EN25Q40, .total_size = 512, .page_size = 256, - /* TODO: chip features 256-byte one-time programmable region */ - .feature_bits = FEATURE_WRSR_WREN, + /* OTP: 256B total; enter 0x3A */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP, .tested = TEST_UNTESTED, .probe = probe_spi_rdid, .probe_timing = TIMING_ZERO, @@ -3271,8 +3279,8 @@ const struct flashchip flashchips[] = { .model_id = EON_EN25Q80, .total_size = 1024, .page_size = 256, - /* TODO: chip features 256-byte one-time programmable region */ - .feature_bits = FEATURE_WRSR_WREN, + /* OTP: 256B total; enter 0x3A */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP, .tested = TEST_UNTESTED, .probe = probe_spi_rdid, .probe_timing = TIMING_ZERO, @@ -3308,9 +3316,8 @@ const struct flashchip flashchips[] = { .model_id = EON_EN25Q16, .total_size = 2048, .page_size = 256, - /* TODO: EN25D16 features 512-byte one-time programmable region, - * EN25Q16 features a 128-byte one-time programmable region */ - .feature_bits = FEATURE_WRSR_WREN, + /* OTP: D16 512B/Q16 128B total; enter 0x3A */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP, .tested = TEST_UNTESTED, .probe = probe_spi_rdid, .probe_timing = TIMING_ZERO, @@ -3348,8 +3355,8 @@ const struct flashchip flashchips[] = { .model_id = EON_EN25Q32, .total_size = 4096, .page_size = 256, - /* TODO: chip features 512-byte one-time programmable region */ - .feature_bits = FEATURE_WRSR_WREN, + /* OTP: 512B total; enter 0x3A */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP, .tested = TEST_UNTESTED, .probe = probe_spi_rdid, .probe_timing = TIMING_ZERO, @@ -3383,8 +3390,8 @@ const struct flashchip flashchips[] = { .model_id = EON_EN25Q64, .total_size = 8192, .page_size = 256, - /* TODO: chip features 512-byte one-time programmable region */ - .feature_bits = FEATURE_WRSR_WREN, + /* OTP: 512B total; enter 0x3A */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP, .tested = TEST_UNTESTED, .probe = probe_spi_rdid, .probe_timing = TIMING_ZERO, @@ -3418,8 +3425,8 @@ const struct flashchip flashchips[] = { .model_id = EON_EN25Q128, .total_size = 16384, .page_size = 256, - /* TODO: chip features 512-byte one-time programmable region */ - .feature_bits = FEATURE_WRSR_WREN, + /* OTP: 512B total; enter 0x3A */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP, .tested = TEST_UNTESTED, .probe = probe_spi_rdid, .probe_timing = TIMING_ZERO, @@ -3452,10 +3459,9 @@ const struct flashchip flashchips[] = { .model_id = EON_EN25QH16, .total_size = 2048, .page_size = 256, - /* TODO: chip features 512-byte one-time programmable region - * and supports SFDP. - */ - .feature_bits = FEATURE_WRSR_WREN, + /* supports SFDP */ + /* OTP: 512B total; enter 0x3A */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP, .tested = TEST_UNTESTED, .probe = probe_spi_rdid, .probe_timing = TIMING_ZERO, @@ -7092,6 +7098,8 @@ const struct flashchip flashchips[] = { .model_id = ST_M25PX16, .total_size = 2048, .page_size = 256, + /* OTP: 64B total; read 0x4B; write 0x42 */ + .feature_bits = FEATURE_OTP, .tested = TEST_OK_PREW, .probe = probe_spi_rdid, .probe_timing = TIMING_ZERO, @@ -7960,7 +7968,8 @@ const struct flashchip flashchips[] = { .model_id = WINBOND_NEX_W25Q80, .total_size = 1024, .page_size = 256, - .feature_bits = FEATURE_WRSR_WREN, + /* OTP: 1024B total, 256B reserved; read 0x48; write 0x42 */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP, .tested = TEST_OK_PREW, .probe = probe_spi_rdid, .probe_timing = TIMING_ZERO, @@ -7997,7 +8006,8 @@ const struct flashchip flashchips[] = { .model_id = WINBOND_NEX_W25Q16, .total_size = 2048, .page_size = 256, - .feature_bits = FEATURE_WRSR_WREN, + /* OTP: 1024B total, 256B reserved; read 0x48; write 0x42 */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP, .tested = TEST_OK_PREW, .probe = probe_spi_rdid, .probe_timing = TIMING_ZERO, @@ -8034,7 +8044,8 @@ const struct flashchip flashchips[] = { .model_id = WINBOND_NEX_W25Q32, .total_size = 4096, .page_size = 256, - .feature_bits = FEATURE_WRSR_WREN, + /* OTP: 1024B total, 256B reserved; read 0x48; write 0x42 */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP, .tested = TEST_OK_PREW, .probe = probe_spi_rdid, .probe_timing = TIMING_ZERO, @@ -8071,7 +8082,8 @@ const struct flashchip flashchips[] = { .model_id = WINBOND_NEX_W25Q64, .total_size = 8192, .page_size = 256, - .feature_bits = FEATURE_WRSR_WREN, + /* OTP: 1024B total, 256B reserved; read 0x48; write 0x42 */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP, .tested = TEST_OK_PREW, .probe = probe_spi_rdid, .probe_timing = TIMING_ZERO, @@ -8107,7 +8119,8 @@ const struct flashchip flashchips[] = { .model_id = WINBOND_NEX_W25Q128, .total_size = 16384, .page_size = 256, - .feature_bits = FEATURE_WRSR_WREN, + /* OTP: 1024B total, 256B reserved; read 0x48; write 0x42 */ + .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP, .tested = TEST_OK_PROBE, .probe = probe_spi_rdid, .probe_timing = TIMING_ZERO, diff --git a/flashrom.8 b/flashrom.8 index 2f23cb80c..e5f9a29ad 100644 --- a/flashrom.8 +++ b/flashrom.8 @@ -670,6 +670,19 @@ and flashrom will attempt to detect it and abort immediately for safety reasons. More information about flashrom on laptops is available from .sp .B " http://www.flashrom.org/Laptops" +.SS +One-time programmable (OTP) memory and unique IDs +.sp +Some flash chips contain OTP memory often denoted as "security registers". +They usually have a capacity in the range of some bytes to a few hundred +bytes and can be used to give devices unique IDs etc. flashrom is not able +to read or write these memories and may therefore not be able to duplicate a +chip completely. For chip types known to include OTP memories a warning is +printed when they are detected. +.sp +Similar to OTP memories are unique, factory programmed, unforgeable IDs. +They are not modifiable by the user at all. +.RE .SH LICENSE .B flashrom is covered by the GNU General Public License (GPL), version 2. Some files are diff --git a/flashrom.c b/flashrom.c index ee68344ec..a378e5103 100644 --- a/flashrom.c +++ b/flashrom.c @@ -1560,6 +1560,13 @@ int selfcheck(void) void check_chip_supported(const struct flashctx *flash) { + if (flash->feature_bits & FEATURE_OTP) { + msg_cdbg("This chip may contain one-time programmable memory. " + "flashrom cannot read\nand may never be able to write " + "it, hence it may not be able to completely\n" + "clone the contents of this chip (see man page for " + "details).\n"); + } if (TEST_OK_MASK != (flash->tested & TEST_OK_MASK)) { msg_cinfo("===\n"); if (flash->tested & TEST_BAD_MASK) {