Hello Brian Norris,
I'd like you to do a code review. Please visit
https://review.coreboot.org/22504
to review the following change.
Change subject: MTD write-protect support ......................................................................
MTD write-protect support
** WIP: Do not merge (yet) **
This adds MTD write protect functionality.
Caveats: - --wp-range and --wp-enable must be used simultaneously - --wp-disable will clear the chip's block protect range by default. If the user specifies a range using --wp-range in the same invocation to flashrom, then that range will be cleared instead.
BUG=chrome-os-partner:40208,chromium:523575 BRANCH=none TEST=needs testing.
Change-Id: Ifed2ad510a70fe1944f93f48e411769977afb5ca Signed-off-by: David Hendricks dhendrix@chromium.org Reviewed-on: https://chromium-review.googlesource.com/275381 Reviewed-by: Brian Norris briannorris@chromium.org --- M linux_mtd.c 1 file changed, 150 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/04/22504/1
diff --git a/linux_mtd.c b/linux_mtd.c index 064065f..d8d835d 100644 --- a/linux_mtd.c +++ b/linux_mtd.c @@ -34,6 +34,9 @@ #include "file.h" #include "flash.h" #include "programmer.h" +#if 0 +#include "writeprotect.h" +#endif
#define LINUX_DEV_ROOT "/dev" #define LINUX_MTD_SYSFS_ROOT "/sys/class/mtd" @@ -49,6 +52,10 @@ static unsigned long int mtd_total_size; static unsigned long int mtd_numeraseregions; static unsigned long int mtd_erasesize; /* only valid if numeraseregions is 0 */ + +#if 0 +static struct wp wp_mtd; /* forward declaration */ +#endif
/* read a string from a sysfs file and sanitize it */ static int read_sysfs_string(const char *filename, char *buf, int len) @@ -171,6 +178,9 @@ flash->chip->block_erasers[0].eraseblocks[0].size = mtd_erasesize; flash->chip->block_erasers[0].eraseblocks[0].count = mtd_total_size / mtd_erasesize; +#if 0 + flash->chip->wp = &wp_mtd; +#endif return 1; }
@@ -369,3 +379,143 @@ msg_pdbg("%s: %s\n", __func__, ret == 0 ? "success." : "failed."); return ret; } + +#if 0 +/* + * Write-protect functions. + */ +static int mtd_wp_list_ranges(const struct flashchip *flash) +{ + /* TODO: implement this */ + msg_perr("--wp-list is not currently implemented for MTD.\n"); + return 1; +} + +/* + * We only have MEMLOCK to enable write-protection for a particular block, + * so we need to do force the user to use --wp-range and --wp-enable + * command-line arguments simultaneously. (Fortunately, CrOS factory + * installer does this already). + * + * The --wp-range argument is processed first and will set these variables + * which --wp-enable will use afterward. + */ +static unsigned int wp_range_start; +static unsigned int wp_range_len; +static int wp_set_range_called = 0; + +static int mtd_wp_set_range(const struct flashchip *flash, + unsigned int start, unsigned int len) +{ + wp_range_start = start; + wp_range_len = len; + + wp_set_range_called = 1; + return 0; +} + +static int mtd_wp_enable_writeprotect(const struct flashchip *flash, enum wp_mode mode) +{ + struct erase_info_user entire_chip = { + .start = 0, + .length = mtd_total_size, + }; + struct erase_info_user desired_range = { + .start = wp_range_start, + .length = wp_range_len, + }; + + if (!wp_set_range_called) { + msg_perr("For MTD, --wp-range and --wp-enable must be " + "used simultaneously.\n"); + return 1; + } + + /* + * MTD handles write-protection additively, so whatever new range is + * specified is added to the range which is currently protected. To be + * consistent with flashrom behavior with other programmer interfaces, + * we need to disable the current write protection and then enable + * it for the desired range. + */ + if (ioctl(dev_fd, MEMUNLOCK, &entire_chip) == -1) { + msg_perr("%s: Failed to disable write-protection, ioctl: %s\n", + __func__, strerror(errno)); + return 1; + } + + if (ioctl(dev_fd, MEMLOCK, &desired_range) == -1) { + msg_perr("%s: Failed to enable write-protection, ioctl: %s\n", + __func__, strerror(errno)); + return 1; + } + + return 0; +} + +static int mtd_wp_disable_writeprotect(const struct flashchip *flash) +{ + struct erase_info_user erase_info; + + if (wp_set_range_called) { + erase_info.start = wp_range_start; + erase_info.length = wp_range_len; + } else { + erase_info.start = 0; + erase_info.length = mtd_total_size; + } + + if (ioctl(dev_fd, MEMUNLOCK, &erase_info) == -1) { + msg_perr("%s: ioctl: %s\n", __func__, strerror(errno)); + return 1; + } + + return 0; +} + +static int mtd_wp_status(const struct flashchip *flash) +{ + uint32_t start = 0, end = 0; + unsigned int u; + + /* For now, assume only one contiguous region can be locked (NOR) */ + /* FIXME: use flash struct members instead of raw MTD values here */ + for (u = 0; u < mtd_total_size / mtd_erasesize; u += mtd_erasesize) { + int rc; + struct erase_info_user erase_info = { + .start = u, + .length = mtd_erasesize, + }; + + rc = ioctl(dev_fd, MEMISLOCKED, &erase_info); + if (rc < 0) { + msg_perr("%s: ioctl: %s\n", __func__, strerror(errno)); + return 1; + } else if (rc == 1) { + if (!start) + start = erase_info.start; + } else if (rc == 0) { + if (start) + end = erase_info.start - 1; + } + + if (start && end) { + msg_pinfo("WP: write protect range: start=0x%08x, " + "len=0x%08x\n", start, end - start); + /* TODO: Replace this break with "start = end = 0" if + * we want to support non-contiguous locked regions */ + break; + } + } + + return 0; +} + +static struct wp wp_mtd = { + .list_ranges = mtd_wp_list_ranges, + .set_range = mtd_wp_set_range, + .enable = mtd_wp_enable_writeprotect, + .disable = mtd_wp_disable_writeprotect, + .wp_status = mtd_wp_status, +}; +#endif