Anastasia Klimchuk has submitted this change. ( https://review.coreboot.org/c/flashrom/+/58481 )
Change subject: libflashrom,writeprotect: add flashrom_wp_get_available_ranges()
......................................................................
libflashrom,writeprotect: add flashrom_wp_get_available_ranges()
Generate list of available ranges by enumerating all possible values
that range bits (BPx, TB, ...) can take and using the chip's range
decoding function to get the range that is selected by each one.
BUG=b:195381327,b:153800563
BRANCH=none
TEST=flashrom --wp-list
Change-Id: Id51f038f03305c8536d80313e52f77d27835f34d
Signed-off-by: Nikolai Artemiev <nartemiev(a)google.com>
Reviewed-on: https://review.coreboot.org/c/flashrom/+/58481
Tested-by: build bot (Jenkins) <no-reply(a)coreboot.org>
Reviewed-by: Nico Huber <nico.h(a)gmx.de>
---
M libflashrom.c
M libflashrom.h
M writeprotect.c
M writeprotect.h
4 files changed, 281 insertions(+), 0 deletions(-)
Approvals:
build bot (Jenkins): Verified
Nico Huber: Looks good to me, approved
diff --git a/libflashrom.c b/libflashrom.c
index f0b9cfd..f2288fe 100644
--- a/libflashrom.c
+++ b/libflashrom.c
@@ -747,4 +747,77 @@
return FLASHROM_WP_ERR_OTHER;
}
+/**
+ * @brief Get a list of protection ranges supported by the flash chip.
+ *
+ * @param[out] ranges Points to a pointer of type struct flashrom_wp_ranges
+ * that will be set if available ranges are found. Finding
+ * available ranges may not always be possible, even if the
+ * chip's protection range can be read or modified. *ranges
+ * must be freed using @ref flashrom_wp_ranges_free.
+ * @param[in] flash The flash context used to access the chip.
+ * @return 0 on success
+ * >0 on failure
+ */
+enum flashrom_wp_result flashrom_wp_get_available_ranges(struct flashrom_wp_ranges **list, struct flashrom_flashctx *flash)
+{
+ /*
+ * TODO: Call custom implementation if the programmer is opaque, as
+ * direct WP operations require SPI access. We actually can't implement
+ * this in linux_mtd right now, but we should adopt a proper generic
+ * architechure to match the read and write functions anyway.
+ */
+ if (flash->mst->buses_supported & BUS_SPI)
+ return wp_get_available_ranges(list, flash);
+
+ return FLASHROM_WP_ERR_OTHER;
+}
+
+/**
+ * @brief Get a number of protection ranges in a range list.
+ *
+ * @param[in] ranges The range list to get the count from.
+ * @return Number of ranges in the list.
+ */
+size_t flashrom_wp_ranges_get_count(const struct flashrom_wp_ranges *list)
+{
+ return list->count;
+}
+
+/**
+ * @brief Get a protection range from a range list.
+ *
+ * @param[out] start Points to a size_t to write the range's start to.
+ * @param[out] len Points to a size_t to write the range's length to.
+ * @param[in] ranges The range list to get the range from.
+ * @param[in] index Index of the range to get.
+ * @return 0 on success
+ * >0 on failure
+ */
+enum flashrom_wp_result flashrom_wp_ranges_get_range(size_t *start, size_t *len, const struct flashrom_wp_ranges *list, unsigned int index)
+{
+ if (index >= list->count)
+ return FLASHROM_WP_ERR_OTHER;
+
+ *start = list->ranges[index].start;
+ *len = list->ranges[index].len;
+
+ return 0;
+}
+
+/**
+ * @brief Free a WP range list.
+ *
+ * @param[out] cfg Pointer to the flashrom_wp_ranges to free.
+ */
+void flashrom_wp_ranges_release(struct flashrom_wp_ranges *list)
+{
+ if (!list)
+ return;
+
+ free(list->ranges);
+ free(list);
+}
+
+
/** @} */ /* end flashrom-wp */
diff --git a/libflashrom.h b/libflashrom.h
index 6d02d50..c9138da 100644
--- a/libflashrom.h
+++ b/libflashrom.h
@@ -137,6 +137,7 @@
FLASHROM_WP_MODE_PERMANENT
};
struct flashrom_wp_cfg;
+struct flashrom_wp_ranges;
enum flashrom_wp_result flashrom_wp_cfg_new(struct flashrom_wp_cfg **);
void flashrom_wp_cfg_release(struct flashrom_wp_cfg *);
@@ -148,4 +149,9 @@
enum flashrom_wp_result flashrom_wp_read_cfg(struct flashrom_wp_cfg *, struct flashrom_flashctx *);
enum flashrom_wp_result flashrom_wp_write_cfg(struct flashrom_flashctx *, const struct flashrom_wp_cfg *);
+enum flashrom_wp_result flashrom_wp_get_available_ranges(struct flashrom_wp_ranges **, struct flashrom_flashctx *);
+size_t flashrom_wp_ranges_get_count(const struct flashrom_wp_ranges *);
+enum flashrom_wp_result flashrom_wp_ranges_get_range(size_t *start, size_t *len, const struct flashrom_wp_ranges *, unsigned int index);
+void flashrom_wp_ranges_release(struct flashrom_wp_ranges *);
+
#endif /* !__LIBFLASHROM_H__ */
diff --git a/writeprotect.c b/writeprotect.c
index ca9d9ec..b619a24 100644
--- a/writeprotect.c
+++ b/writeprotect.c
@@ -158,6 +158,162 @@
return FLASHROM_WP_OK;
}
+/** Write protect bit values and the range they will activate. */
+struct wp_range_and_bits {
+ struct wp_bits bits;
+ struct wp_range range;
+};
+
+/**
+ * Comparator used for sorting ranges in get_ranges_and_wp_bits().
+ *
+ * Ranges are ordered by these attributes, in decreasing significance:
+ * (range length, range start, cmp bit, sec bit, tb bit, bp bits)
+ */
+static int compare_ranges(const void *aa, const void *bb)
+{
+ const struct wp_range_and_bits
+ *a = (const struct wp_range_and_bits *)aa,
+ *b = (const struct wp_range_and_bits *)bb;
+
+ int ord = 0;
+
+ if (ord == 0)
+ ord = a->range.len - b->range.len;
+
+ if (ord == 0)
+ ord = a->range.start - b->range.start;
+
+ if (ord == 0)
+ ord = a->bits.cmp - b->bits.cmp;
+
+ if (ord == 0)
+ ord = a->bits.sec - b->bits.sec;
+
+ if (ord == 0)
+ ord = a->bits.tb - b->bits.tb;
+
+ for (int i = a->bits.bp_bit_count - 1; i >= 0; i--) {
+ if (ord == 0)
+ ord = a->bits.bp[i] - b->bits.bp[i];
+ }
+
+ return ord;
+}
+
+static bool can_write_bit(const struct reg_bit_info bit)
+{
+ /*
+ * TODO: check if the programmer supports writing the register that the
+ * bit is in. For example, some chipsets may only allow SR1 to be
+ * written.
+ */
+
+ return bit.reg != INVALID_REG && bit.writability == RW;
+}
+
+/**
+ * Enumerate all protection ranges that the chip supports and that are able to
+ * be activated, given limitations such as OTP bits or programmer-enforced
+ * restrictions. Returns a list of deduplicated wp_range_and_bits structures.
+ *
+ * Allocates a buffer that must be freed by the caller with free().
+ */
+static enum flashrom_wp_result get_ranges_and_wp_bits(struct flashctx *flash, struct wp_bits bits, struct wp_range_and_bits **ranges, size_t *count)
+{
+ const struct reg_bit_map *reg_bits = &flash->chip->reg_bits;
+ /*
+ * Create a list of bits that affect the chip's protection range in
+ * range_bits. Each element is a pointer to a member of the wp_bits
+ * structure that will be modified.
+ *
+ * Some chips have range bits that cannot be changed (e.g. MX25L6473E
+ * has a one-time programmable TB bit). Rather than enumerating all
+ * possible values for unwritable bits, just read their values from the
+ * chip to ensure we only enumerate ranges that are actually available.
+ */
+ uint8_t *range_bits[ARRAY_SIZE(bits.bp) + 1 /* TB */ + 1 /* SEC */ + 1 /* CMP */];
+ size_t bit_count = 0;
+
+ for (size_t i = 0; i < ARRAY_SIZE(bits.bp); i++) {
+ if (can_write_bit(reg_bits->bp[i]))
+ range_bits[bit_count++] = &bits.bp[i];
+ }
+
+ if (can_write_bit(reg_bits->tb))
+ range_bits[bit_count++] = &bits.tb;
+
+ if (can_write_bit(reg_bits->sec))
+ range_bits[bit_count++] = &bits.sec;
+
+ if (can_write_bit(reg_bits->cmp))
+ range_bits[bit_count++] = &bits.cmp;
+
+ /* Allocate output buffer */
+ *count = 1 << bit_count;
+ *ranges = calloc(*count, sizeof(struct wp_range_and_bits));
+
+ for (size_t range_index = 0; range_index < *count; range_index++) {
+ /*
+ * Extract bits from the range index and assign them to members
+ * of the wp_bits structure. The loop bounds ensure that all
+ * bit combinations will be enumerated.
+ */
+ for (size_t i = 0; i < bit_count; i++)
+ *range_bits[i] = (range_index >> i) & 1;
+
+ struct wp_range_and_bits *output = &(*ranges)[range_index];
+
+ output->bits = bits;
+ enum flashrom_wp_result ret = get_wp_range(&output->range, flash, &bits);
+ if (ret != FLASHROM_WP_OK) {
+ free(*ranges);
+ return ret;
+ }
+
+ /* Debug: print range bits and range */
+ msg_gspew("Enumerated range: ");
+ if (bits.cmp_bit_present)
+ msg_gspew("CMP=%u ", bits.cmp);
+ if (bits.sec_bit_present)
+ msg_gspew("SEC=%u ", bits.sec);
+ if (bits.tb_bit_present)
+ msg_gspew("TB=%u ", bits.tb);
+ for (size_t i = 0; i < bits.bp_bit_count; i++) {
+ size_t j = bits.bp_bit_count - i - 1;
+ msg_gspew("BP%zu=%u ", j, bits.bp[j]);
+ }
+ msg_gspew(" start=0x%08zx length=0x%08zx ",
+ output->range.start, output->range.len);
+ }
+
+ /* Sort ranges. Ensures consistency if there are duplicate ranges. */
+ qsort(*ranges, *count, sizeof(struct wp_range_and_bits), compare_ranges);
+
+ /* Remove duplicates */
+ size_t output_index = 0;
+ struct wp_range *last_range = NULL;
+
+ for (size_t i = 0; i < *count; i++) {
+ bool different_to_last =
+ (last_range == NULL) ||
+ ((*ranges)[i].range.start != last_range->start) ||
+ ((*ranges)[i].range.len != last_range->len);
+
+ if (different_to_last) {
+ /* Move range to the next free position */
+ (*ranges)[output_index] = (*ranges)[i];
+ output_index++;
+ /* Keep track of last non-duplicate range */
+ last_range = &(*ranges)[i].range;
+ }
+ }
+ /* Reduce count to only include non-duplicate ranges */
+ *count = output_index;
+
+ return FLASHROM_WP_OK;
+}
+
static bool chip_supported(struct flashctx *flash)
{
return (flash->chip != NULL) && (flash->chip->decode_range != NULL);
@@ -218,4 +374,41 @@
return ret;
}
+enum flashrom_wp_result wp_get_available_ranges(struct flashrom_wp_ranges **list, struct flashrom_flashctx *flash)
+{
+ struct wp_bits bits;
+ struct wp_range_and_bits *range_pairs = NULL;
+ size_t count;
+
+ if (!chip_supported(flash))
+ return FLASHROM_WP_ERR_CHIP_UNSUPPORTED;
+
+ enum flashrom_wp_result ret = read_wp_bits(&bits, flash);
+ if (ret != FLASHROM_WP_OK)
+ return ret;
+
+ ret = get_ranges_and_wp_bits(flash, bits, &range_pairs, &count);
+ if (ret != FLASHROM_WP_OK)
+ return ret;
+
+ *list = calloc(1, sizeof(struct flashrom_wp_ranges));
+ struct wp_range *ranges = calloc(count, sizeof(struct wp_range));
+
+ if (!(*list) || !ranges) {
+ free(*list);
+ free(ranges);
+ ret = FLASHROM_WP_ERR_OTHER;
+ goto out;
+ }
+ (*list)->count = count;
+ (*list)->ranges = ranges;
+
+ for (size_t i = 0; i < count; i++)
+ ranges[i] = range_pairs[i].range;
+
+out:
+ free(range_pairs);
+ return ret;
+}
+
/** @} */ /* end flashrom-wp */
diff --git a/writeprotect.h b/writeprotect.h
index d54befa..e27403d 100644
--- a/writeprotect.h
+++ b/writeprotect.h
@@ -37,6 +37,12 @@
struct wp_range range;
};
+/* Collection of multiple write protection ranges. */
+struct flashrom_wp_ranges {
+ struct wp_range *ranges;
+ size_t count;
+};
+
/*
* Description of a chip's write protection configuration.
*
@@ -77,4 +83,7 @@
/* Read WP configuration from the chip */
enum flashrom_wp_result wp_read_cfg(struct flashrom_wp_cfg *, struct flashrom_flashctx *);
+/* Get a list of protection ranges supported by the chip */
+enum flashrom_wp_result wp_get_available_ranges(struct flashrom_wp_ranges **, struct flashrom_flashctx *);
+
#endif /* !__WRITEPROTECT_H__ */
58 is the latest approved patch-set.
No files were changed between the latest approved patch-set and the submitted one.
--
To view, visit https://review.coreboot.org/c/flashrom/+/58481
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-Change-Id: Id51f038f03305c8536d80313e52f77d27835f34d
Gerrit-Change-Number: 58481
Gerrit-PatchSet: 63
Gerrit-Owner: Nikolai Artemiev <nartemiev(a)google.com>
Gerrit-Reviewer: Anastasia Klimchuk <aklm(a)chromium.org>
Gerrit-Reviewer: Angel Pons <th3fanbus(a)gmail.com>
Gerrit-Reviewer: Edward O'Callaghan <quasisec(a)chromium.org>
Gerrit-Reviewer: Nico Huber <nico.h(a)gmx.de>
Gerrit-Reviewer: Sergii Dmytruk <sergii.dmytruk(a)3mdeb.com>
Gerrit-Reviewer: build bot (Jenkins) <no-reply(a)coreboot.org>
Gerrit-CC: Paul Menzel <paulepanter(a)mailbox.org>
Gerrit-MessageType: merged
Attention is currently required from: Edward O'Callaghan, Nikolai Artemiev, Anastasia Klimchuk.
Hello build bot (Jenkins), Edward O'Callaghan, Anastasia Klimchuk,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/flashrom/+/61897
to look at the new patch set (#27).
Change subject: libflashrom,linux_mtd: add linux_mtd writeprotect support
......................................................................
libflashrom,linux_mtd: add linux_mtd writeprotect support
BUG=b:182223106
BRANCH=none
TEST=make
Change-Id: I5c86e28cdec44bec49ba1d36f8ab62241b9b01da
Signed-off-by: Nikolai Artemiev <nartemiev(a)google.com>
---
M libflashrom.c
M linux_mtd.c
M programmer.h
3 files changed, 126 insertions(+), 16 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/97/61897/27
--
To view, visit https://review.coreboot.org/c/flashrom/+/61897
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-Change-Id: I5c86e28cdec44bec49ba1d36f8ab62241b9b01da
Gerrit-Change-Number: 61897
Gerrit-PatchSet: 27
Gerrit-Owner: Nikolai Artemiev <nartemiev(a)google.com>
Gerrit-Reviewer: Anastasia Klimchuk <aklm(a)chromium.org>
Gerrit-Reviewer: Edward O'Callaghan <quasisec(a)chromium.org>
Gerrit-Reviewer: build bot (Jenkins) <no-reply(a)coreboot.org>
Gerrit-CC: Paul Menzel <paulepanter(a)mailbox.org>
Gerrit-Attention: Edward O'Callaghan <quasisec(a)chromium.org>
Gerrit-Attention: Nikolai Artemiev <nartemiev(a)google.com>
Gerrit-Attention: Anastasia Klimchuk <aklm(a)chromium.org>
Gerrit-MessageType: newpatchset
Attention is currently required from: Nico Huber, Edward O'Callaghan, Nikolai Artemiev, Sergii Dmytruk.
Hello build bot (Jenkins), Nico Huber, Edward O'Callaghan, Angel Pons, Anastasia Klimchuk,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/flashrom/+/59528
to look at the new patch set (#59).
Change subject: spi25_statusreg: inline spi_write_register_flag()
......................................................................
spi25_statusreg: inline spi_write_register_flag()
Creating the entire SPI command that should be sent to the chip in
spi_write_register() is simpler than splitting it across two functions
that have to pass multiple parameters between them.
Additionally, having separate spi_write_register_flag() function
provided little benefit, as it was only ever called from
spi_write_register().
BUG=b:195381327,b:153800563
BRANCH=none
TEST=flashrom -{r,w,E}
Change-Id: I4996b0848d0ed09032bad2ab13ab1f40bbfc0304
Signed-off-by: Nikolai Artemiev <nartemiev(a)google.com>
---
M spi25_statusreg.c
1 file changed, 56 insertions(+), 70 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/28/59528/59
--
To view, visit https://review.coreboot.org/c/flashrom/+/59528
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-Change-Id: I4996b0848d0ed09032bad2ab13ab1f40bbfc0304
Gerrit-Change-Number: 59528
Gerrit-PatchSet: 59
Gerrit-Owner: Nikolai Artemiev <nartemiev(a)google.com>
Gerrit-Reviewer: Anastasia Klimchuk <aklm(a)chromium.org>
Gerrit-Reviewer: Angel Pons <th3fanbus(a)gmail.com>
Gerrit-Reviewer: Edward O'Callaghan <quasisec(a)chromium.org>
Gerrit-Reviewer: Nico Huber <nico.h(a)gmx.de>
Gerrit-Reviewer: build bot (Jenkins) <no-reply(a)coreboot.org>
Gerrit-CC: Paul Menzel <paulepanter(a)mailbox.org>
Gerrit-CC: Sergii Dmytruk <sergii.dmytruk(a)3mdeb.com>
Gerrit-Attention: Nico Huber <nico.h(a)gmx.de>
Gerrit-Attention: Edward O'Callaghan <quasisec(a)chromium.org>
Gerrit-Attention: Nikolai Artemiev <nartemiev(a)google.com>
Gerrit-Attention: Sergii Dmytruk <sergii.dmytruk(a)3mdeb.com>
Gerrit-MessageType: newpatchset