David Hendricks would like Brian Norris to review this change.

View Change

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

To view, visit change 22504. To unsubscribe, visit settings.

Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ifed2ad510a70fe1944f93f48e411769977afb5ca
Gerrit-Change-Number: 22504
Gerrit-PatchSet: 1
Gerrit-Owner: David Hendricks <david.hendricks@gmail.com>
Gerrit-Reviewer: Brian Norris <briannorris@chromium.org>