Anastasia Klimchuk has submitted this change. ( https://review.coreboot.org/c/flashrom/+/66212 )
(
9 is the latest approved patch-set. No files were changed between the latest approved patch-set and the submitted one. )Change subject: writeprotect_ranges.c: add more range functions ......................................................................
writeprotect_ranges.c: add more range functions
Not all chips follow the same pattern. There are differences in how CMP bit is treated or in block size used.
Change-Id: Ied7b27be2ee2426af8f473432e2b01a290de2365 Signed-off-by: Sergii Dmytruk sergii.dmytruk@3mdeb.com Reviewed-on: https://review.coreboot.org/c/flashrom/+/66212 Reviewed-by: Nikolai Artemiev nartemiev@google.com Reviewed-by: Anastasia Klimchuk aklm@chromium.org Tested-by: build bot (Jenkins) no-reply@coreboot.org --- M include/chipdrivers.h M include/flash.h M writeprotect.c M writeprotect_ranges.c 4 files changed, 90 insertions(+), 12 deletions(-)
Approvals: build bot (Jenkins): Verified Nikolai Artemiev: Looks good to me, but someone else must approve Anastasia Klimchuk: Looks good to me, approved
diff --git a/include/chipdrivers.h b/include/chipdrivers.h index 3b07afe..34e3af8 100644 --- a/include/chipdrivers.h +++ b/include/chipdrivers.h @@ -216,5 +216,8 @@
/* writeprotect_ranges.c */ void decode_range_spi25(size_t *start, size_t *len, const struct wp_bits *, size_t chip_len); +void decode_range_spi25_64k_block(size_t *start, size_t *len, const struct wp_bits *, size_t chip_len); +void decode_range_spi25_bit_cmp(size_t *start, size_t *len, const struct wp_bits *, size_t chip_len); +void decode_range_spi25_2x_block(size_t *start, size_t *len, const struct wp_bits *, size_t chip_len);
#endif /* !__CHIPDRIVERS_H__ */ diff --git a/include/flash.h b/include/flash.h index 23222c7..b4b56fe 100644 --- a/include/flash.h +++ b/include/flash.h @@ -224,8 +224,11 @@ struct wp_bits;
enum decode_range_func { - NO_DECODE_RANGE_FUNC = 0, /* 0 indicates no range decode funciton is set. */ + NO_DECODE_RANGE_FUNC = 0, /* 0 indicates no range decode function is set. */ DECODE_RANGE_SPI25 = 1, + DECODE_RANGE_SPI25_64K_BLOCK = 2, + DECODE_RANGE_SPI25_BIT_CMP = 3, + DECODE_RANGE_SPI25_2X_BLOCK = 4, }; typedef void (decode_range_func_t)(size_t *start, size_t *len, const struct wp_bits *, size_t chip_len);
diff --git a/writeprotect.c b/writeprotect.c index 1ac0c1a..38ac997 100644 --- a/writeprotect.c +++ b/writeprotect.c @@ -211,6 +211,9 @@ { switch (chip->decode_range) { case DECODE_RANGE_SPI25: return &decode_range_spi25; + case DECODE_RANGE_SPI25_64K_BLOCK: return &decode_range_spi25_64k_block; + case DECODE_RANGE_SPI25_BIT_CMP: return &decode_range_spi25_bit_cmp; + case DECODE_RANGE_SPI25_2X_BLOCK: return &decode_range_spi25_2x_block; /* default: total function, 0 indicates no decode range function set. */ case NO_DECODE_RANGE_FUNC: return NULL; }; diff --git a/writeprotect_ranges.c b/writeprotect_ranges.c index dacce32..45678f2 100644 --- a/writeprotect_ranges.c +++ b/writeprotect_ranges.c @@ -17,11 +17,11 @@ #include "writeprotect.h" #include "chipdrivers.h"
-/* - * Protection range calculation that works with many common SPI flash chips. - */ -void decode_range_spi25(size_t *start, size_t *len, const struct wp_bits *bits, size_t chip_len) +static void decode_range_generic(size_t *start, size_t *len, const struct wp_bits *bits, size_t chip_len, + bool fixed_block_len, bool apply_cmp_to_bp, int coeff_offset) { + const bool cmp = bits->cmp_bit_present && bits->cmp == 1; + /* Interpret BP bits as an integer */ size_t bp = 0; size_t bp_max = 0; @@ -31,6 +31,15 @@ bp_max |= 1 << i; }
+ /* + * Most chips: the CMP bit only negates the range. + * + * Some MX chips: the CMP bit negates the BP bits and the range. + * (CMP bit is often the MSB BP bit in such chips.) + */ + if (cmp && apply_cmp_to_bp) + bp ^= bp_max; + if (bp == 0) { /* Special case: all BP bits are 0 => no write protection */ *len = 0; @@ -40,14 +49,14 @@ } else { /* * Usual case: the BP bits encode a coefficient in the form - * `coeff = 2 ** (bp - 1)`. + * `coeff = 2 ** (bp - offset)` where `offset == 1`. * * The range's length is given by multiplying the coefficient * by a base unit, usually a 4K sector or a 64K block. */
- size_t coeff = 1 << (bp - 1); - size_t max_coeff = 1 << (bp_max - 2); + size_t coeff = 1 << (bp - coeff_offset); + size_t max_coeff = 1 << (bp_max - coeff_offset - 1);
size_t sector_len = 4 * KiB; size_t default_block_len = 64 * KiB; @@ -62,14 +71,19 @@ } else { /* * SEC=0 or is not present, protect blocks. - * + */ + size_t block_len = default_block_len; + + /* * With very large chips, the 'block' size can be * larger than 64K. This occurs when a larger block * size is needed so that half the chip can be * protected by the maximum possible coefficient. */ - size_t min_block_len = chip_len / 2 / max_coeff; - size_t block_len = max(min_block_len, default_block_len); + if (!fixed_block_len) { + size_t min_block_len = chip_len / 2 / max_coeff; + block_len = max(min_block_len, default_block_len); + }
*len = min(block_len * coeff, chip_len); } @@ -79,7 +93,7 @@ bool protect_top = bits->tb_bit_present ? (bits->tb == 0) : 1;
/* Apply CMP bit */ - if (bits->cmp_bit_present && bits->cmp == 1) { + if (cmp) { *len = chip_len - *len; protect_top = !protect_top; } @@ -90,3 +104,41 @@ else *start = 0; } + +/* + * Protection range calculation that works with many common SPI flash chips. + */ +void decode_range_spi25(size_t *start, size_t *len, const struct wp_bits *bits, size_t chip_len) +{ + decode_range_generic(start, len, bits, chip_len, + /*fixed_block_len=*/false, /*apply_cmp_to_bp=*/false, /*coeff_offset=*/1); +} + +/* + * Do not adjust block size to be able to fill half of the chip. + */ +void decode_range_spi25_64k_block(size_t *start, size_t *len, const struct wp_bits *bits, size_t chip_len) +{ + decode_range_generic(start, len, bits, chip_len, + /*fixed_block_len=*/true, /*apply_cmp_to_bp=*/false, /*coeff_offset=*/1); +} + +/* + * Inverts BP bits when CMP is set and treats all ones in BP bits as a request to protect whole chip regardless + * of the CMP bit. + */ +void decode_range_spi25_bit_cmp(size_t *start, size_t *len, const struct wp_bits *bits, size_t chip_len) +{ + decode_range_generic(start, len, bits, chip_len, + /*fixed_block_len=*/false, /*apply_cmp_to_bp=*/true, /*coeff_offset=*/1); +} + +/* + * This multiplies coefficient by 2. To be used with chips which have more BP bits than needed, such that the + * most significant BP bit effectively acts as "protect whole chip" flag. + */ +void decode_range_spi25_2x_block(size_t *start, size_t *len, const struct wp_bits *bits, size_t chip_len) +{ + decode_range_generic(start, len, bits, chip_len, + /*fixed_block_len=*/false, /*apply_cmp_to_bp=*/false, /*coeff_offset=*/0); +}