summaryrefslogtreecommitdiff
path: root/src/mtd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mtd.c')
-rw-r--r--src/mtd.c385
1 files changed, 385 insertions, 0 deletions
diff --git a/src/mtd.c b/src/mtd.c
new file mode 100644
index 000000000..532f9fe5d
--- /dev/null
+++ b/src/mtd.c
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2012 Mike Frysinger <vapier@gentoo.org>
+ * Copyright (c) 2012-2018 The strace developers.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "defs.h"
+
+#ifdef HAVE_STRUCT_MTD_WRITE_REQ
+
+# include DEF_MPERS_TYPE(struct_mtd_oob_buf)
+
+# include <linux/ioctl.h>
+# include <mtd/mtd-abi.h>
+
+typedef struct mtd_oob_buf struct_mtd_oob_buf;
+
+#endif /* HAVE_STRUCT_MTD_WRITE_REQ */
+
+#include MPERS_DEFS
+
+#ifdef HAVE_STRUCT_MTD_WRITE_REQ
+
+# include "xlat/mtd_mode_options.h"
+# include "xlat/mtd_file_mode_options.h"
+# include "xlat/mtd_type_options.h"
+# include "xlat/mtd_flags_options.h"
+# include "xlat/mtd_otp_options.h"
+# include "xlat/mtd_nandecc_options.h"
+
+static void
+decode_erase_info_user(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+ struct erase_info_user einfo;
+
+ tprints(", ");
+ if (umove_or_printaddr(tcp, addr, &einfo))
+ return;
+
+ tprint_struct_begin();
+ PRINT_FIELD_X(einfo, start);
+ tprint_struct_next();
+ PRINT_FIELD_X(einfo, length);
+ tprint_struct_end();
+}
+
+static void
+decode_erase_info_user64(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+ struct erase_info_user64 einfo64;
+
+ tprints(", ");
+ if (umove_or_printaddr(tcp, addr, &einfo64))
+ return;
+
+ tprint_struct_begin();
+ PRINT_FIELD_X(einfo64, start);
+ tprint_struct_next();
+ PRINT_FIELD_X(einfo64, length);
+ tprint_struct_end();
+}
+
+static void
+decode_mtd_oob_buf(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+ struct_mtd_oob_buf mbuf;
+
+ tprints(", ");
+ if (umove_or_printaddr(tcp, addr, &mbuf))
+ return;
+ tprint_struct_begin();
+ PRINT_FIELD_X(mbuf, start);
+ tprint_struct_next();
+ PRINT_FIELD_X(mbuf, length);
+ tprint_struct_next();
+ PRINT_FIELD_PTR(mbuf, ptr);
+ tprint_struct_end();
+}
+
+static void
+decode_mtd_oob_buf64(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+ struct mtd_oob_buf64 mbuf64;
+
+ tprints(", ");
+ if (umove_or_printaddr(tcp, addr, &mbuf64))
+ return;
+
+ tprint_struct_begin();
+ PRINT_FIELD_X(mbuf64, start);
+ tprint_struct_next();
+ PRINT_FIELD_X(mbuf64, length);
+ tprint_struct_next();
+ PRINT_FIELD_ADDR64(mbuf64, usr_ptr);
+ tprint_struct_end();
+}
+
+static void
+decode_otp_info(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+ struct otp_info oinfo;
+
+ tprints(", ");
+ if (umove_or_printaddr(tcp, addr, &oinfo))
+ return;
+
+ tprint_struct_begin();
+ PRINT_FIELD_X(oinfo, start);
+ tprint_struct_next();
+ PRINT_FIELD_X(oinfo, length);
+ tprint_struct_next();
+ PRINT_FIELD_U(oinfo, locked);
+ tprint_struct_end();
+}
+
+static void
+decode_otp_select(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+ unsigned int i;
+
+ tprints(", ");
+ if (umove_or_printaddr(tcp, addr, &i))
+ return;
+
+ tprints("[");
+ printxval(mtd_otp_options, i, "MTD_OTP_???");
+ tprints("]");
+}
+
+static void
+decode_mtd_write_req(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+ struct mtd_write_req mreq;
+
+ tprints(", ");
+ if (umove_or_printaddr(tcp, addr, &mreq))
+ return;
+
+ tprint_struct_begin();
+ PRINT_FIELD_X(mreq, start);
+ tprint_struct_next();
+ PRINT_FIELD_X(mreq, len);
+ tprint_struct_next();
+ PRINT_FIELD_X(mreq, ooblen);
+ tprint_struct_next();
+ PRINT_FIELD_ADDR64(mreq, usr_data);
+ tprint_struct_next();
+ PRINT_FIELD_ADDR64(mreq, usr_oob);
+ tprint_struct_next();
+ PRINT_FIELD_XVAL(mreq, mode, mtd_mode_options, "MTD_OPS_???");
+ tprint_struct_end();
+}
+
+static void
+decode_mtd_info_user(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+ struct mtd_info_user minfo;
+
+ tprints(", ");
+ if (umove_or_printaddr(tcp, addr, &minfo))
+ return;
+
+ tprint_struct_begin();
+ PRINT_FIELD_XVAL(minfo, type, mtd_type_options, "MTD_???");
+ tprint_struct_next();
+ PRINT_FIELD_FLAGS(minfo, flags, mtd_flags_options, "MTD_???");
+ tprint_struct_next();
+ PRINT_FIELD_X(minfo, size);
+ tprint_struct_next();
+ PRINT_FIELD_X(minfo, erasesize);
+ tprint_struct_next();
+ PRINT_FIELD_X(minfo, writesize);
+ tprint_struct_next();
+ PRINT_FIELD_X(minfo, oobsize);
+ tprint_struct_next();
+ PRINT_FIELD_X(minfo, padding);
+ tprint_struct_end();
+}
+
+static bool
+print_xint32x2_array_member(struct tcb *tcp, void *elem_buf, size_t elem_size,
+ void *data)
+{
+ print_local_array_ex(tcp, elem_buf, 2, sizeof(int),
+ print_xint32_array_member, NULL, 0, NULL, NULL);
+ return true;
+}
+
+static void
+decode_nand_oobinfo(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+ struct nand_oobinfo ninfo;
+
+ tprints(", ");
+ if (umove_or_printaddr(tcp, addr, &ninfo))
+ return;
+
+ tprint_struct_begin();
+ PRINT_FIELD_XVAL(ninfo, useecc, mtd_nandecc_options, "MTD_NANDECC_???");
+ tprint_struct_next();
+ PRINT_FIELD_X(ninfo, eccbytes);
+ tprint_struct_next();
+ PRINT_FIELD_ARRAY(ninfo, oobfree, tcp, print_xint32x2_array_member);
+ tprint_struct_next();
+ PRINT_FIELD_ARRAY(ninfo, eccpos, tcp, print_xint32_array_member);
+ tprint_struct_end();
+}
+
+static bool
+print_nand_oobfree_array_member(struct tcb *tcp, void *elem_buf,
+ size_t elem_size, void *data)
+{
+ const struct nand_oobfree *p = elem_buf;
+ tprint_struct_begin();
+ PRINT_FIELD_X(*p, offset);
+ tprint_struct_next();
+ PRINT_FIELD_X(*p, length);
+ tprint_struct_end();
+ return true;
+}
+
+static void
+decode_nand_ecclayout_user(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+ struct nand_ecclayout_user nlay;
+
+ tprints(", ");
+ if (umove_or_printaddr(tcp, addr, &nlay))
+ return;
+
+ tprint_struct_begin();
+ PRINT_FIELD_X(nlay, eccbytes);
+ tprint_struct_next();
+ PRINT_FIELD_ARRAY(nlay, eccpos, tcp, print_xint32_array_member);
+ tprint_struct_next();
+ PRINT_FIELD_X(nlay, oobavail);
+ tprint_struct_next();
+ PRINT_FIELD_ARRAY(nlay, oobfree, tcp, print_nand_oobfree_array_member);
+ tprint_struct_end();
+}
+
+static void
+decode_mtd_ecc_stats(struct tcb *const tcp, const kernel_ulong_t addr)
+{
+ struct mtd_ecc_stats es;
+
+ tprints(", ");
+ if (umove_or_printaddr(tcp, addr, &es))
+ return;
+
+ tprint_struct_begin();
+ PRINT_FIELD_X(es, corrected);
+ tprint_struct_next();
+ PRINT_FIELD_X(es, failed);
+ tprint_struct_next();
+ PRINT_FIELD_X(es, badblocks);
+ tprint_struct_next();
+ PRINT_FIELD_X(es, bbtblocks);
+ tprint_struct_end();
+}
+
+MPERS_PRINTER_DECL(int, mtd_ioctl, struct tcb *const tcp,
+ const unsigned int code, const kernel_ulong_t arg)
+{
+ switch (code) {
+ case MEMERASE:
+ case MEMLOCK:
+ case MEMUNLOCK:
+ case MEMISLOCKED:
+ decode_erase_info_user(tcp, arg);
+ break;
+
+ case MEMERASE64:
+ decode_erase_info_user64(tcp, arg);
+ break;
+
+ case MEMWRITEOOB:
+ case MEMREADOOB:
+ decode_mtd_oob_buf(tcp, arg);
+ break;
+
+ case MEMWRITEOOB64:
+ case MEMREADOOB64:
+ decode_mtd_oob_buf64(tcp, arg);
+ break;
+
+ case MEMWRITE:
+ decode_mtd_write_req(tcp, arg);
+ break;
+
+ case OTPGETREGIONINFO:
+ if (entering(tcp))
+ return 0;
+ ATTRIBUTE_FALLTHROUGH;
+ case OTPLOCK:
+ decode_otp_info(tcp, arg);
+ break;
+
+ case OTPSELECT:
+ decode_otp_select(tcp, arg);
+ break;
+
+ case MTDFILEMODE:
+ tprints(", ");
+ printxval64(mtd_file_mode_options, arg, "MTD_FILE_MODE_???");
+ break;
+
+ case MEMGETBADBLOCK:
+ case MEMSETBADBLOCK:
+ tprints(", ");
+ printnum_int64(tcp, arg, "%" PRIu64);
+ break;
+
+ case MEMGETINFO:
+ if (entering(tcp))
+ return 0;
+ decode_mtd_info_user(tcp, arg);
+ break;
+
+ case MEMGETOOBSEL:
+ if (entering(tcp))
+ return 0;
+ decode_nand_oobinfo(tcp, arg);
+ break;
+
+ case ECCGETLAYOUT:
+ if (entering(tcp))
+ return 0;
+ decode_nand_ecclayout_user(tcp, arg);
+ break;
+
+ case ECCGETSTATS:
+ if (entering(tcp))
+ return 0;
+ decode_mtd_ecc_stats(tcp, arg);
+ break;
+
+ case OTPGETREGIONCOUNT:
+ if (entering(tcp))
+ return 0;
+ tprints(", ");
+ printnum_int(tcp, arg, "%u");
+ break;
+
+ case MEMGETREGIONCOUNT:
+ if (entering(tcp))
+ return 0;
+ tprints(", ");
+ printnum_int(tcp, arg, "%d");
+ break;
+
+ case MEMGETREGIONINFO:
+ if (entering(tcp)) {
+ struct region_info_user rinfo;
+
+ tprints(", ");
+ if (umove_or_printaddr(tcp, arg, &rinfo))
+ break;
+ tprint_struct_begin();
+ PRINT_FIELD_X(rinfo, regionindex);
+ return 0;
+ } else {
+ struct region_info_user rinfo;
+
+ if (!syserror(tcp) && !umove(tcp, arg, &rinfo)) {
+ tprint_struct_next();
+ PRINT_FIELD_X(rinfo, offset);
+ tprint_struct_next();
+ PRINT_FIELD_X(rinfo, erasesize);
+ tprint_struct_next();
+ PRINT_FIELD_X(rinfo, numblocks);
+ }
+ tprint_struct_end();
+ break;
+ }
+
+ default:
+ return RVAL_DECODED;
+ }
+
+ return RVAL_IOCTL_DECODED;
+}
+
+#endif /* HAVE_STRUCT_MTD_WRITE_REQ */