[PATCH 1/4] Nandsimctl initial commit
Daniel Walter
dwalter at sigma-star.at
Wed Aug 31 00:32:41 PDT 2016
From: Richard Weinberger <richard at nod.at>
Signed-off-by: Richard Weinberger <richard at nod.at>
Signed-off-by: Daniel Walter <dwalter at sigma-star.at>
---
Makefile | 2 +-
include/mtd/nandsim-user.h | 102 +++++++++++++++++
nand-utils/nandsimctl.c | 276 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 379 insertions(+), 1 deletion(-)
create mode 100644 include/mtd/nandsim-user.h
create mode 100644 nand-utils/nandsimctl.c
diff --git a/Makefile b/Makefile
index 977c9c5..1723e78 100644
--- a/Makefile
+++ b/Makefile
@@ -29,7 +29,7 @@ UBIFS_BINS = \
JFFSX_BINS = \
mkfs.jffs2 sumtool jffs2reader jffs2dump
NAND_BINS = \
- nanddump nandwrite nandtest nftldump nftl_format
+ nanddump nandwrite nandtest nftldump nftl_format nandsimctl
NOR_BINS = \
rfddump rfdformat
diff --git a/include/mtd/nandsim-user.h b/include/mtd/nandsim-user.h
new file mode 100644
index 0000000..0254b09
--- /dev/null
+++ b/include/mtd/nandsim-user.h
@@ -0,0 +1,102 @@
+#ifndef __NANDSIM_USER_H__
+#define __NANDSIM_USER_H__
+
+#include <linux/types.h>
+
+#define NANSIM_IOC_MAGIC 'n'
+
+#define NANDSIM_IOC_NEW_INSTANCE _IOW(NANSIM_IOC_MAGIC, 0, struct ns_new_instance_req)
+#define NANDSIM_IOC_DESTROY_INSTANCE _IOW(NANSIM_IOC_MAGIC, 1, struct ns_destroy_instance_req)
+
+#define NANDSIM_MAX_DEVICES 32
+#define NANDSIM_MAX_PARTS 32
+
+enum ns_backend_type {
+ NANDSIM_BACKEND_RAM = 0,
+ NANDSIM_BACKEND_CACHEFILE = 1,
+ NANDSIM_BACKEND_FILE = 2,
+ NANDSIM_BACKEND_MAX,
+};
+
+/**
+ * struct ns_new_instance_req - Create a new nandsim instance.
+ *
+ * @id_bytes: NAND ID of the simulated NAND chip
+ * @bus_width: bus width to emulate, either 8 or 16
+ * @bbt_mode: bad block table mode, 0 OOB, 1 BBT with marker in OOB,
+ * 2 BBT with marker in data area
+ * @no_oob: backing file contains no OOB data
+ * @bch_strength: instead of hamming ECC use BCH with given strength
+ * @parts_num: number of MTD partitions to create
+ * @parts: partition sizes in physical erase blocks, used then @parts_num > 0
+ * @backend: backend type, see @ns_backend_type
+ * @file_fd: file describtor of backend, only for @NANDSIM_BACKEND_CACHEFILE
+ * and @NANDSIM_BACKEND_FILE.
+ * @bitflips: maximum number of random bit flips per page
+ * @overridesize: specifies the NAND size overriding the ID bytes
+ * @access_delay: initial page access delay (microseconds)
+ * @program_delay: page programm delay (microseconds)
+ * @erase_delay: sector erase delay (milliseconds)
+ * @output_cycle: word output, from flash, time (nanoseconds)
+ * @input_cycle: word input, to flash, time (nanoseconds)
+ * @simelem_num: number of simulation elements appened to this
+ * data structure. see @ns_simelement_prop
+ *
+ * This struct is used with the @NANDSIM_IOC_NEW_INSTANCE ioctl command.
+ * It creates a new nandsim instance from the given parameter.
+ * The ioctl command returns in case of success the nandsim id of the new
+ * instance, in case of error a negative value.
+ *
+ * Not all fields in the struct have to be filled, if nandsim should
+ * use a default ignore the value, fill with 0.
+ * The only mandatory fields are @id_bytes and @bus_width.
+ * When @no_oob is non-zero @bch_strength cannot be used since
+ * @no_oob implies that no ECC is used.
+ */
+struct ns_new_instance_req {
+ __s8 id_bytes[8];
+
+ __s8 bus_width;
+ __s8 bbt_mode;
+ __s8 no_oob;
+ __s32 bch_strength;
+
+ __s8 parts_num;
+ __s32 parts[NANDSIM_MAX_PARTS];
+
+ __s8 backend;
+ __s32 file_fd;
+
+ __s32 bitflips;
+ __s32 overridesize;
+ __s32 access_delay;
+ __s32 program_delay;
+ __s32 erase_delay;
+ __s32 output_cycle;
+ __s32 input_cycle;
+
+ __s32 padding[4];
+
+ __s32 simelem_num;
+} __attribute__((packed));
+
+enum {
+ NANDSIM_SIMELEM_BADBLOCK = 0,
+ NANDSIM_SIMELEM_WEAKBLOCK,
+ NANDSIM_SIMELEM_WEAKPAGE,
+ NANDSIM_SIMELEM_GRAVEPAGE,
+};
+
+struct ns_simelement_prop {
+ __s8 elem_type;
+ __s32 elem_id;
+ __s32 elem_attr;
+ __s8 padding[7];
+} __attribute__((packed));
+
+struct ns_destroy_instance_req {
+ __s8 id;
+ __s8 padding[7];
+} __attribute__((packed));
+
+#endif /* __NANDSIM_USER_H__ */
diff --git a/nand-utils/nandsimctl.c b/nand-utils/nandsimctl.c
new file mode 100644
index 0000000..0f641ab
--- /dev/null
+++ b/nand-utils/nandsimctl.c
@@ -0,0 +1,276 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <mtd/nandsim-user.h>
+#include <getopt.h>
+#include <unistd.h>
+
+#define PROGRAM_NAME "nandsimctl"
+
+#include "common.h"
+
+#define TEMP_DIR "/tmp"
+#define NANDSIM_CTRL_DEV "/dev/nandsim_ctrl"
+
+enum action {
+ ACT_ATTACH = 0,
+ ACT_DETACH,
+ ACT_DETACH_ALL,
+};
+
+static const struct option long_options[] = {
+ { .name = "backend", .has_arg = 1, .flag = NULL, .val = 'b' },
+ { .name = "id", .has_arg = 1, .flag = NULL, .val = 'i' },
+ { .name = "detach", .has_arg = 1, .flag = NULL, .val = 'd' },
+ { .name = "detach-all", .has_arg = 0, .flag = NULL, .val = 'D' },
+ { .name = "no-oob", .has_arg = 0, .flag = NULL, .val = 'n' },
+ { NULL, 0, NULL, 0},
+};
+
+static int ctrl_fd;
+
+static struct {
+ int backend;
+ bool wide_addr;
+ int id[8];
+ char *backing_file;
+ bool no_oob;
+ enum action act;
+ int detach;
+ bool detach_all;
+} args = {
+ .backend = -1,
+ .detach = -1,
+ .wide_addr = false,
+ .id = {
+ [0] = 0x98,
+ [1] = 0x39,
+ [2 ... 7] = 0xff,
+ },
+ .backing_file = NULL,
+ .no_oob = false,
+};
+
+static int do_help(void)
+{
+ fprintf(stderr, "Help\n");
+ return 0;
+}
+
+static int parse_args(int argc, char *argv[])
+{
+ int key, error = 0;
+
+ for (;;) {
+ key = getopt_long(argc, argv, "b:i:h?rcfwod:D", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 'b':
+ if (args.backend != -1)
+ return errmsg("backend type already set!");
+
+ if (!strcmp(optarg, "ram"))
+ args.backend = NANDSIM_BACKEND_RAM;
+ else if (!strcmp(optarg, "cache"))
+ args.backend = NANDSIM_BACKEND_CACHEFILE;
+ else if (!strcmp(optarg, "file"))
+ args.backend = NANDSIM_BACKEND_FILE;
+ else
+ return errmsg("bad backend type: \"%s\"", optarg);
+ break;
+ case 'i':
+ {
+ int i;
+ int n = sscanf(optarg, "0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x",
+ &args.id[0], &args.id[1], &args.id[2], &args.id[3],
+ &args.id[4], &args.id[5], &args.id[6], &args.id[7]);
+ if (n < 1)
+ return errmsg("unable to parse id byte string!");
+
+ for (i = n; i < 8; i++)
+ args.id[i] = 0xff;
+ }
+ break;
+ case 'r':
+ if (args.backend != -1)
+ return errmsg("backend type already set!");
+
+ args.backend = NANDSIM_BACKEND_RAM;
+ break;
+ case 'c':
+ if (args.backend != -1)
+ return errmsg("backend type already set!");
+
+ args.backend = NANDSIM_BACKEND_CACHEFILE;
+ break;
+ case 'f':
+ if (args.backend != -1)
+ return errmsg("backend type already set!");
+
+ args.backend = NANDSIM_BACKEND_FILE;
+ break;
+ case 'w':
+ args.wide_addr = true;
+ break;
+ case 'n':
+ args.no_oob = true;
+ break;
+ case 'd':
+ args.detach = simple_strtoul(optarg, &error);
+ if (error)
+ return errmsg("unable to parse nandsim instance number");
+
+ if (args.detach < 0 || args.detach >= NANDSIM_MAX_DEVICES)
+ return errmsg("bad instance number to detach");
+ break;
+ case 'D':
+ args.detach_all = true;
+ break;
+ case '?':
+ return do_help();
+ break;
+ }
+ }
+
+ if (args.backend >= 0 && (args.detach >= 0 || args.detach_all))
+ return errmsg("you cannot attach and detach at the same time");
+
+ if (args.detach >= 0 && args.detach_all)
+ return errmsg("not sure whether you want to detach all instances or just one");
+
+ if (args.backend == NANDSIM_BACKEND_FILE) {
+ if (optind == argc)
+ return errmsg("no backing file specified!");
+
+ if (optind != argc - 1)
+ return errmsg("more than one backing file specified!");
+
+ args.backing_file = strdup(argv[optind]);
+ } else if (optind == argc - 1)
+ return errmsg("unknown parameter \"%s\"", argv[optind]);
+
+ if (args.detach >= 0)
+ args.act = ACT_DETACH;
+ else if (args.detach_all)
+ args.act = ACT_DETACH_ALL;
+ else
+ args.act = ACT_ATTACH;
+
+ return 0;
+}
+
+static int do_detach(int id)
+{
+ int ret;
+ struct ns_destroy_instance_req req;
+
+ req.id = id;
+ ret = ioctl(ctrl_fd, NANDSIM_IOC_DESTROY_INSTANCE, &req);
+ if (ret < 0 && errno != EBUSY)
+ return sys_errmsg("unable to destroy instance %i", id);
+
+ if (ret < 0)
+ warnmsg("instance %i is currently in use, cannot detach", id);
+
+ return 0;
+}
+
+static int do_detach_all(void)
+{
+ int i, ret;
+
+ for (i = 0; i < NANDSIM_MAX_DEVICES; i++) {
+ ret = do_detach(i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int get_temp_file_fd(void)
+{
+ int fd, ret;
+ char *tmpdir = NULL;
+
+#ifdef O_TMPFILE
+ fd = open(TEMP_DIR, O_CLOEXEC | O_RDWR | O_EXCL | O_TMPFILE, 0700);
+ if (fd == -1 && (errno != EINVAL && errno != EISDIR && errno != EOPNOTSUPP))
+ return sys_errmsg("Unable to open an temporary file");
+
+ if (fd >= 0)
+ return fd;
+#endif
+ tmpdir = xstrdup(TEMP_DIR "/nandsim-XXXXXX");
+ fd = mkstemp(tmpdir);
+ free(tmpdir);
+ if (fd == -1)
+ return sys_errmsg("unable to open an temporary file using mkstemp");
+
+ ret = unlink(tmpdir);
+ if (ret == -1)
+ return sys_errmsg("unable to unlink temporary file");
+
+ return fd;
+}
+
+static int do_attach(void)
+{
+ struct ns_new_instance_req req;
+ int i, ret, fd = 0;
+
+ if (args.backend == NANDSIM_BACKEND_CACHEFILE) {
+ fd = get_temp_file_fd();
+ if (fd < 0)
+ return fd;
+ } else if (args.backend == NANDSIM_BACKEND_FILE) {
+ fd = open(args.backing_file, O_RDWR | O_LARGEFILE | O_CLOEXEC);
+ if (fd == -1)
+ return sys_errmsg("unable to open \"%s\"", args.backing_file);
+ } else
+ args.backend = NANDSIM_BACKEND_RAM;
+
+ memset(&req, 0, sizeof(req));
+
+ req.backend = args.backend;
+ req.bus_width = args.wide_addr ? 16 : 8;
+ req.no_oob = !!args.no_oob;
+ for (i = 0; i < 8; i++)
+ req.id_bytes[i] = args.id[i] & 0xff;
+ req.file_fd = fd;
+
+ ret = ioctl(ctrl_fd, NANDSIM_IOC_NEW_INSTANCE, &req);
+ if (ret < 0) {
+ sys_errmsg("unable to create new nandsim instance");
+ return ret;
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+
+ ret = parse_args(argc, argv);
+ if (ret)
+ return -1;
+
+ ctrl_fd = open(NANDSIM_CTRL_DEV, O_RDWR | O_CLOEXEC);
+ if (ctrl_fd < 0)
+ return sys_errmsg("unable to open \"%s\"", NANDSIM_CTRL_DEV);
+
+ if (args.detach >= 0)
+ return do_detach(args.detach);
+ else if (args.detach_all)
+ return do_detach_all();
+ else
+ return do_attach();
+
+ return 0;
+}
--
2.8.3
More information about the linux-mtd
mailing list