summaryrefslogtreecommitdiff
path: root/misc-utils/flash_unlock.c
diff options
context:
space:
mode:
Diffstat (limited to 'misc-utils/flash_unlock.c')
-rw-r--r--misc-utils/flash_unlock.c220
1 files changed, 220 insertions, 0 deletions
diff --git a/misc-utils/flash_unlock.c b/misc-utils/flash_unlock.c
new file mode 100644
index 0000000..f51870a
--- /dev/null
+++ b/misc-utils/flash_unlock.c
@@ -0,0 +1,220 @@
+/*
+ * flash_{lock,unlock}
+ *
+ * utilities for locking/unlocking sectors of flash devices
+ */
+
+enum flash_lock_request {
+ REQUEST_LOCK,
+ REQUEST_UNLOCK,
+ REQUEST_ISLOCKED,
+};
+
+#ifndef PROGRAM_NAME
+#define PROGRAM_NAME "flash_unlock"
+#define DEFAULT_REQUEST REQUEST_UNLOCK
+#else
+#define DEFAULT_REQUEST REQUEST_LOCK
+#endif
+
+#include <getopt.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <string.h>
+
+#include "common.h"
+#include <mtd/mtd-user.h>
+
+static const char *flash_msg[] = {
+ [ REQUEST_LOCK ] = "lock",
+ [ REQUEST_UNLOCK ] = "unlock",
+ [ REQUEST_ISLOCKED ] = "check lock status",
+};
+
+static void usage(int status)
+{
+ fprintf(status ? stderr : stdout,
+ "Utility to lock, unlock, or check the lock status of the flash.\n"
+ "Default action: %s\n"
+ "\n"
+ "Usage: %s [options] [--] <mtd device> [offset [block count]]\n"
+ "\n"
+ "Options:\n"
+ " -h --help Display this help and exit\n"
+ " --version Display version information and exit\n"
+ " -i --islocked Check if flash region is locked\n"
+ " -l --lock Lock a region of flash\n"
+ " -u --unlock Unlock a region of flash\n"
+ "\n"
+ "If offset is not specified, it defaults to 0.\n"
+ "If block count is not specified, it defaults to all blocks.\n"
+ "A block count of -1 means all blocks.\n",
+ flash_msg[DEFAULT_REQUEST],
+ PROGRAM_NAME);
+ exit(status);
+}
+
+static const char short_opts[] = "hilu";
+static const struct option long_opts[] = {
+ { "help", no_argument, 0, 'h' },
+ { "islocked", no_argument, 0, 'i' },
+ { "lock", no_argument, 0, 'l' },
+ { "unlock", no_argument, 0, 'u' },
+ { "version", no_argument, 0, 'v' },
+ { NULL, 0, 0, 0 },
+};
+
+/* Program arguments */
+static const char *dev, *offs_s, *count_s;
+static enum flash_lock_request req = DEFAULT_REQUEST;
+
+static void process_args(int argc, char *argv[])
+{
+ int arg_idx;
+ int req_set = 0;
+
+ for (;;) {
+ int c;
+
+ c = getopt_long(argc, argv, short_opts, long_opts, NULL);
+ if (c == EOF)
+ break;
+
+ switch (c) {
+ case 'h':
+ usage(0);
+ break;
+ case 'i':
+ req = REQUEST_ISLOCKED;
+ req_set++;
+ break;
+ case 'l':
+ req = REQUEST_LOCK;
+ req_set++;
+ break;
+ case 'u':
+ req = REQUEST_UNLOCK;
+ req_set++;
+ break;
+ case 'v':
+ common_print_version();
+ exit(0);
+ default:
+ usage(1);
+ break;
+ }
+ }
+
+ if (req_set > 1) {
+ errmsg("cannot specify more than one lock/unlock/islocked option");
+ usage(1);
+ }
+
+ arg_idx = optind;
+
+ /* Sanity checks */
+ if (argc - arg_idx < 1) {
+ errmsg("too few arguments");
+ usage(1);
+ } else if (argc - arg_idx > 3) {
+ errmsg("too many arguments");
+ usage(1);
+ }
+
+ /* First non-option argument */
+ dev = argv[arg_idx++];
+
+ /* Second non-option argument */
+ if (arg_idx < argc)
+ offs_s = argv[arg_idx++];
+ else
+ offs_s = NULL;
+
+ /* Third non-option argument */
+ if (arg_idx < argc)
+ count_s = argv[arg_idx++];
+ else
+ count_s = NULL;
+
+}
+
+int main(int argc, char *argv[])
+{
+ int fd, request;
+ struct mtd_info_user mtdInfo;
+ struct erase_info_user mtdLockInfo;
+ long count;
+ int ret = 0;
+
+ process_args(argc, argv);
+
+ /* Get the device info to compare to command line sizes */
+ fd = open(dev, O_RDWR);
+ if (fd < 0)
+ sys_errmsg_die("could not open: %s", dev);
+
+ if (ioctl(fd, MEMGETINFO, &mtdInfo))
+ sys_errmsg_die("could not get mtd info: %s", dev);
+
+ /* Make sure user options are valid */
+ if (offs_s) {
+ mtdLockInfo.start = simple_strtol(offs_s, &ret);
+ if (ret)
+ errmsg_die("bad offset");
+ } else {
+ mtdLockInfo.start = 0;
+ }
+ if (mtdLockInfo.start >= mtdInfo.size)
+ errmsg_die("%#x is beyond device size %#x",
+ mtdLockInfo.start, mtdInfo.size);
+
+ if (count_s) {
+ count = simple_strtol(count_s, &ret);
+ if (ret)
+ errmsg_die("bad count");
+ if (count == -1)
+ mtdLockInfo.length = mtdInfo.size;
+ else
+ mtdLockInfo.length = mtdInfo.erasesize * count;
+ } else {
+ mtdLockInfo.length = mtdInfo.size;
+ }
+ if (mtdLockInfo.start + mtdLockInfo.length > mtdInfo.size)
+ errmsg_die("range is more than device supports: %#x + %#x > %#x",
+ mtdLockInfo.start, mtdLockInfo.length, mtdInfo.size);
+
+ /* Finally do the operation */
+ switch (req) {
+ case REQUEST_LOCK:
+ request = MEMLOCK;
+ break;
+ case REQUEST_UNLOCK:
+ request = MEMUNLOCK;
+ break;
+ case REQUEST_ISLOCKED:
+ request = MEMISLOCKED;
+ break;
+ default:
+ errmsg_die("unknown request type: %d", req);
+ break;
+ }
+ ret = ioctl(fd, request, &mtdLockInfo);
+ if (ret < 0)
+ sys_errmsg_die("could not %s device: %s\n",
+ flash_msg[req], dev);
+
+ if (req == REQUEST_ISLOCKED) {
+ printf("Device: %s\n", dev);
+ printf("Start: %#0x\n", mtdLockInfo.start);
+ printf("Len: %#0x\n", mtdLockInfo.length);
+ printf("Lock status: %s\n", ret ? "locked" : "unlocked");
+ printf("Return code: %d\n", ret);
+ }
+
+ return 0;
+}