summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEdward O'Callaghan <quasisec@google.com>2022-05-16 15:38:18 +1000
committerEdward O'Callaghan <quasisec@chromium.org>2022-06-21 03:38:49 +0000
commitf630a1623f84b452873e3fc69d608925d90fd85b (patch)
tree3656eb2d97bc0d869d0e6cb50abe3baa643beb7c
parentfac9fc28f5a6cadf7c94264f429faa597a2058ac (diff)
downloadflashrom-f630a1623f84b452873e3fc69d608925d90fd85b.tar.gz
flashrom-f630a1623f84b452873e3fc69d608925d90fd85b.tar.bz2
flashrom-f630a1623f84b452873e3fc69d608925d90fd85b.zip
writeprotect.c: Allow opaque masters to hook {read,write}_register()
Allow specialisation in opaque masters, such as ichspi hwseq, to write to status registers. Also update the dispatch logic in libflashrom to call wp code when status register access functions are provided by an opaque master. BUG=none BRANCH=none TEST=flashrom --wp-status on AMD and Intel DUTs Change-Id: I3ab0d7f5f48338c8ecb118a69651c203fbc516ac Signed-off-by: Edward O'Callaghan <quasisec@google.com> Signed-off-by: Nikolai Artemiev <nartemiev@google.com> Co-Authored-by: Nikolai Artemiev <nartemiev@google.com> Reviewed-on: https://review.coreboot.org/c/flashrom/+/64375 Reviewed-by: Anastasia Klimchuk <aklm@chromium.org> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
-rw-r--r--include/programmer.h8
-rw-r--r--include/writeprotect.h3
-rw-r--r--libflashrom.c18
-rw-r--r--writeprotect.c37
4 files changed, 53 insertions, 13 deletions
diff --git a/include/programmer.h b/include/programmer.h
index 5fb06260e..eaf4a983e 100644
--- a/include/programmer.h
+++ b/include/programmer.h
@@ -402,6 +402,14 @@ struct opaque_master {
int (*read) (struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
int (*write) (struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
int (*erase) (struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen);
+ /*
+ * Callbacks for accessing flash registers. An opaque programmer must
+ * provide these functions for writeprotect operations to be available,
+ * unless it provides custom wp operations instead.
+ */
+ int (*read_register)(const struct flashctx *flash, enum flash_reg reg, uint8_t *value);
+ int (*write_register)(const struct flashctx *flash, enum flash_reg reg, uint8_t value);
+ /* Callbacks for overiding default writeprotect operations with custom ones. */
enum flashrom_wp_result (*wp_write_cfg)(struct flashctx *, const struct flashrom_wp_cfg *);
enum flashrom_wp_result (*wp_read_cfg)(struct flashrom_wp_cfg *, struct flashctx *);
enum flashrom_wp_result (*wp_get_ranges)(struct flashrom_wp_ranges **, struct flashctx *);
diff --git a/include/writeprotect.h b/include/writeprotect.h
index e27403dcf..12926c4d3 100644
--- a/include/writeprotect.h
+++ b/include/writeprotect.h
@@ -86,4 +86,7 @@ enum flashrom_wp_result wp_read_cfg(struct flashrom_wp_cfg *, struct flashrom_fl
/* 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 *);
+/* Checks if writeprotect functions can be used with the current flash/programmer */
+bool wp_operations_available(struct flashrom_flashctx *);
+
#endif /* !__WRITEPROTECT_H__ */
diff --git a/libflashrom.c b/libflashrom.c
index 0c6613e94..3e28938c9 100644
--- a/libflashrom.c
+++ b/libflashrom.c
@@ -470,34 +470,34 @@ void flashrom_wp_get_range(size_t *start, size_t *len, const struct flashrom_wp_
enum flashrom_wp_result flashrom_wp_write_cfg(struct flashctx *flash, const struct flashrom_wp_cfg *cfg)
{
- if (flash->mst->buses_supported & BUS_SPI)
- return wp_write_cfg(flash, cfg);
-
if (flash->mst->buses_supported & BUS_PROG && flash->mst->opaque.wp_write_cfg)
return flash->mst->opaque.wp_write_cfg(flash, cfg);
+ if (wp_operations_available(flash))
+ return wp_write_cfg(flash, cfg);
+
return FLASHROM_WP_ERR_OTHER;
}
enum flashrom_wp_result flashrom_wp_read_cfg(struct flashrom_wp_cfg *cfg, struct flashctx *flash)
{
- if (flash->mst->buses_supported & BUS_SPI)
- return wp_read_cfg(cfg, flash);
-
if (flash->mst->buses_supported & BUS_PROG && flash->mst->opaque.wp_read_cfg)
return flash->mst->opaque.wp_read_cfg(cfg, flash);
+ if (wp_operations_available(flash))
+ return wp_read_cfg(cfg, flash);
+
return FLASHROM_WP_ERR_OTHER;
}
enum flashrom_wp_result flashrom_wp_get_available_ranges(struct flashrom_wp_ranges **list, struct flashrom_flashctx *flash)
{
- if (flash->mst->buses_supported & BUS_SPI)
- return wp_get_available_ranges(list, flash);
-
if (flash->mst->buses_supported & BUS_PROG && flash->mst->opaque.wp_get_ranges)
return flash->mst->opaque.wp_get_ranges(list, flash);
+ if (wp_operations_available(flash))
+ return wp_get_available_ranges(list, flash);
+
return FLASHROM_WP_ERR_OTHER;
}
diff --git a/writeprotect.c b/writeprotect.c
index 60d8ead1e..57d0f9bd6 100644
--- a/writeprotect.c
+++ b/writeprotect.c
@@ -23,13 +23,33 @@
#include "libflashrom.h"
#include "chipdrivers.h"
#include "writeprotect.h"
+#include "programmer.h"
+
+/*
+ * Allow specialisation in opaque masters, such as ichspi hwseq, to r/w to status registers.
+ */
+static int wp_write_register(const struct flashctx *flash, enum flash_reg reg, uint8_t value)
+{
+ if ((flash->mst->buses_supported & BUS_PROG) && flash->mst->opaque.write_register) {
+ return flash->mst->opaque.write_register(flash, reg, value);
+ }
+ return spi_write_register(flash, reg, value);
+}
+
+static int wp_read_register(const struct flashctx *flash, enum flash_reg reg, uint8_t *value)
+{
+ if ((flash->mst->buses_supported & BUS_PROG) && flash->mst->opaque.read_register) {
+ return flash->mst->opaque.read_register(flash, reg, value);
+ }
+ return spi_read_register(flash, reg, value);
+}
/** Read and extract a single bit from the chip's registers */
static enum flashrom_wp_result read_bit(uint8_t *value, bool *present, struct flashctx *flash, struct reg_bit_info bit)
{
*present = bit.reg != INVALID_REG;
if (*present) {
- if (spi_read_register(flash, bit.reg, value))
+ if (wp_read_register(flash, bit.reg, value))
return FLASHROM_WP_ERR_READ_FAILED;
*value = (*value >> bit.bit_index) & 1;
} else {
@@ -126,12 +146,12 @@ static enum flashrom_wp_result write_wp_bits(struct flashctx *flash, struct wp_b
continue;
uint8_t value;
- if (spi_read_register(flash, reg, &value))
+ if (wp_read_register(flash, reg, &value))
return FLASHROM_WP_ERR_READ_FAILED;
value = (value & ~write_masks[reg]) | (reg_values[reg] & write_masks[reg]);
- if (spi_write_register(flash, reg, value))
+ if (wp_write_register(flash, reg, value))
return FLASHROM_WP_ERR_WRITE_FAILED;
}
@@ -141,7 +161,7 @@ static enum flashrom_wp_result write_wp_bits(struct flashctx *flash, struct wp_b
continue;
uint8_t value;
- if (spi_read_register(flash, reg, &value))
+ if (wp_read_register(flash, reg, &value))
return FLASHROM_WP_ERR_READ_FAILED;
uint8_t actual = value & write_masks[reg];
@@ -407,6 +427,15 @@ static bool chip_supported(struct flashctx *flash)
return (flash->chip != NULL) && (flash->chip->decode_range != NULL);
}
+
+bool wp_operations_available(struct flashrom_flashctx *flash)
+{
+ return (flash->mst->buses_supported & BUS_SPI) ||
+ ((flash->mst->buses_supported & BUS_PROG) &&
+ flash->mst->opaque.read_register &&
+ flash->mst->opaque.write_register);
+}
+
enum flashrom_wp_result wp_read_cfg(struct flashrom_wp_cfg *cfg, struct flashctx *flash)
{
struct wp_bits bits;