diff mbox series

[2/2] mtd: parsers: add TP-Link SafeLoader partitions table parser

Message ID 20221011100333.32536-2-zajec5@gmail.com
State Superseded
Headers show
Series [1/2] dt-bindings: mtd: partitions: add TP-Link SafeLoader layout | expand

Commit Message

Rafał Miłecki Oct. 11, 2022, 10:03 a.m. UTC
From: Rafał Miłecki <rafal@milecki.pl>

This parser deals with most TP-Link home routers. It reads info about
partitions and registers them in the MTD subsystem.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
---
 drivers/mtd/parsers/Kconfig             |  15 +++
 drivers/mtd/parsers/Makefile            |   1 +
 drivers/mtd/parsers/tplink_safeloader.c | 150 ++++++++++++++++++++++++
 3 files changed, 166 insertions(+)
 create mode 100644 drivers/mtd/parsers/tplink_safeloader.c

Comments

kernel test robot Oct. 11, 2022, 12:55 p.m. UTC | #1
Hi Rafał,

I love your patch! Perhaps something to improve:

[auto build test WARNING on mtd/mtd/next]
[also build test WARNING on mtd/mtd/fixes robh/for-next linus/master v6.0 next-20221011]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Rafa-Mi-ecki/dt-bindings-mtd-partitions-add-TP-Link-SafeLoader-layout/20221011-180628
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git mtd/next
config: alpha-allyesconfig
compiler: alpha-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/d674742894485372607b3b6bc17bf515712559ea
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Rafa-Mi-ecki/dt-bindings-mtd-partitions-add-TP-Link-SafeLoader-layout/20221011-180628
        git checkout d674742894485372607b3b6bc17bf515712559ea
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=alpha SHELL=/bin/bash drivers/mtd/parsers/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/mtd/parsers/tplink_safeloader.c: In function 'mtd_parser_tplink_safeloader_read_table':
   drivers/mtd/parsers/tplink_safeloader.c:37:65: error: passing argument 3 of 'of_property_read_u32' from incompatible pointer type [-Werror=incompatible-pointer-types]
      37 |         if (of_property_read_u32(np, "partitions-table-offset", &offset)) {
         |                                                                 ^~~~~~~
         |                                                                 |
         |                                                                 size_t * {aka long unsigned int *}
   In file included from include/linux/mtd/mtd.h:14,
                    from drivers/mtd/parsers/tplink_safeloader.c:8:
   include/linux/of.h:1310:45: note: expected 'u32 *' {aka 'unsigned int *'} but argument is of type 'size_t *' {aka 'long unsigned int *'}
    1310 |                                        u32 *out_value)
         |                                        ~~~~~^~~~~~~~~
   drivers/mtd/parsers/tplink_safeloader.c: In function 'mtd_parser_tplink_safeloader_parse':
>> drivers/mtd/parsers/tplink_safeloader.c:99:75: warning: format '%n' expects argument of type 'int *', but argument 6 has type 'size_t *' {aka 'long unsigned int *'} [-Wformat=]
      99 |              sscanf(buf + offset, "partition %64s base 0x%llx size 0x%llx%n\n",
         |                                                                          ~^
         |                                                                           |
         |                                                                           int *
         |                                                                          %ln
     100 |                     name, &parts[idx].offset, &parts[idx].size, &bytes) == 3;
         |                                                                 ~~~~~~     
         |                                                                 |
         |                                                                 size_t * {aka long unsigned int *}
   cc1: some warnings being treated as errors


vim +99 drivers/mtd/parsers/tplink_safeloader.c

    72	
    73	static int mtd_parser_tplink_safeloader_parse(struct mtd_info *mtd,
    74						      const struct mtd_partition **pparts,
    75						      struct mtd_part_parser_data *data)
    76	{
    77		struct mtd_partition *parts;
    78		char name[65];
    79		size_t offset;
    80		size_t bytes;
    81		char *buf;
    82		int idx;
    83		int err;
    84	
    85		parts = kcalloc(TPLINK_SAFELOADER_MAX_PARTS, sizeof(*parts), GFP_KERNEL);
    86		if (!parts) {
    87			err = -ENOMEM;
    88			goto err_out;
    89		}
    90	
    91		buf = mtd_parser_tplink_safeloader_read_table(mtd);
    92		if (!buf) {
    93			err = -ENOENT;
    94			goto err_out;
    95		}
    96	
    97		for (idx = 0, offset = TPLINK_SAFELOADER_DATA_OFFSET;
    98		     idx < TPLINK_SAFELOADER_MAX_PARTS &&
  > 99		     sscanf(buf + offset, "partition %64s base 0x%llx size 0x%llx%n\n",
   100			    name, &parts[idx].offset, &parts[idx].size, &bytes) == 3;
   101		     idx++, offset += bytes + 1) {
   102			parts[idx].name = kstrdup(name, GFP_KERNEL);
   103			if (!parts[idx].name) {
   104				err = -ENOMEM;
   105				goto err_free;
   106			}
   107		}
   108	
   109		if (idx == TPLINK_SAFELOADER_MAX_PARTS)
   110			pr_warn("Reached maximum number of partitions!\n");
   111	
   112		kfree(buf);
   113	
   114		*pparts = parts;
   115	
   116		return idx;
   117	
   118	err_free:
   119		for (idx -= 1; idx >= 0; idx--)
   120			kfree(parts[idx].name);
   121	err_out:
   122		return err;
   123	};
   124
diff mbox series

Patch

diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig
index aaa06050c9bc..c258ba2a3a6f 100644
--- a/drivers/mtd/parsers/Kconfig
+++ b/drivers/mtd/parsers/Kconfig
@@ -123,6 +123,21 @@  config MTD_AFS_PARTS
 	  for your particular device. It won't happen automatically. The
 	  'physmap' map driver (CONFIG_MTD_PHYSMAP) does this, for example.
 
+config MTD_PARSER_TPLINK_SAFELOADER
+	tristate "TP-Link Safeloader partitions parser"
+	depends on MTD && (ARCH_BCM_5301X || ATH79 || SOC_MT7620 || SOC_MT7621 || COMPILE_TEST)
+	help
+	  TP-Link home routers use flash partitions to store various data. Info
+	  about flash space layout is stored in a partitions table using a
+	  custom ASCII-based format.
+
+	  That format was first found in devices with SafeLoader bootloader and
+	  was named after it. Later it was adapted to CFE and U-Boot
+	  bootloaders.
+
+	  This driver reads partitions table, parses it and creates MTD
+	  partitions.
+
 config MTD_PARSER_TRX
 	tristate "Parser for TRX format partitions"
 	depends on MTD && (BCM47XX || ARCH_BCM_5301X || ARCH_MEDIATEK || RALINK || COMPILE_TEST)
diff --git a/drivers/mtd/parsers/Makefile b/drivers/mtd/parsers/Makefile
index 23fa4de4016f..0e70b621a1d8 100644
--- a/drivers/mtd/parsers/Makefile
+++ b/drivers/mtd/parsers/Makefile
@@ -10,6 +10,7 @@  ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908)	+= ofpart_bcm4908.o
 ofpart-$(CONFIG_MTD_OF_PARTS_LINKSYS_NS)+= ofpart_linksys_ns.o
 obj-$(CONFIG_MTD_PARSER_IMAGETAG)	+= parser_imagetag.o
 obj-$(CONFIG_MTD_AFS_PARTS)		+= afs.o
+obj-$(CONFIG_MTD_PARSER_TPLINK_SAFELOADER)	+= tplink_safeloader.o
 obj-$(CONFIG_MTD_PARSER_TRX)		+= parser_trx.o
 obj-$(CONFIG_MTD_SERCOMM_PARTS)		+= scpart.o
 obj-$(CONFIG_MTD_SHARPSL_PARTS)		+= sharpslpart.o
diff --git a/drivers/mtd/parsers/tplink_safeloader.c b/drivers/mtd/parsers/tplink_safeloader.c
new file mode 100644
index 000000000000..7317d1faabbb
--- /dev/null
+++ b/drivers/mtd/parsers/tplink_safeloader.c
@@ -0,0 +1,150 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright © 2022 Rafał Miłecki <rafal@milecki.pl>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+#define TPLINK_SAFELOADER_DATA_OFFSET		4
+#define TPLINK_SAFELOADER_MAX_PARTS		32
+
+struct safeloader_cmn_header {
+	__be32 size;
+	uint32_t unused;
+} __packed;
+
+static void *mtd_parser_tplink_safeloader_read_table(struct mtd_info *mtd)
+{
+	struct safeloader_cmn_header hdr;
+	struct device_node *np;
+	size_t bytes_read;
+	size_t offset;
+	size_t size;
+	char *buf;
+	int err;
+
+	np = mtd_get_of_node(mtd);
+	if (mtd_is_partition(mtd))
+		of_node_get(np);
+	else
+		np = of_get_child_by_name(np, "partitions");
+
+	if (of_property_read_u32(np, "partitions-table-offset", &offset)) {
+		pr_err("Failed to get partitions table offset\n");
+		goto err_put;
+	}
+
+	err = mtd_read(mtd, offset, sizeof(hdr), &bytes_read, (uint8_t *)&hdr);
+	if (err && !mtd_is_bitflip(err)) {
+		pr_err("Failed to read from %s at 0x%zx\n", mtd->name, offset);
+		goto err_put;
+	}
+
+	size = be32_to_cpu(hdr.size);
+
+	buf = kmalloc(size + 1, GFP_KERNEL);
+	if (!buf)
+		goto err_put;
+
+	err = mtd_read(mtd, offset + sizeof(hdr), size, &bytes_read, buf);
+	if (err && !mtd_is_bitflip(err)) {
+		pr_err("Failed to read from %s at 0x%zx\n", mtd->name, offset + sizeof(hdr));
+		goto err_kfree;
+	}
+
+	buf[size - 1] = '\0';
+
+	of_node_put(np);
+
+	return buf;
+
+err_kfree:
+	kfree(buf);
+err_put:
+	of_node_put(np);
+	return NULL;
+}
+
+static int mtd_parser_tplink_safeloader_parse(struct mtd_info *mtd,
+					      const struct mtd_partition **pparts,
+					      struct mtd_part_parser_data *data)
+{
+	struct mtd_partition *parts;
+	char name[65];
+	size_t offset;
+	size_t bytes;
+	char *buf;
+	int idx;
+	int err;
+
+	parts = kcalloc(TPLINK_SAFELOADER_MAX_PARTS, sizeof(*parts), GFP_KERNEL);
+	if (!parts) {
+		err = -ENOMEM;
+		goto err_out;
+	}
+
+	buf = mtd_parser_tplink_safeloader_read_table(mtd);
+	if (!buf) {
+		err = -ENOENT;
+		goto err_out;
+	}
+
+	for (idx = 0, offset = TPLINK_SAFELOADER_DATA_OFFSET;
+	     idx < TPLINK_SAFELOADER_MAX_PARTS &&
+	     sscanf(buf + offset, "partition %64s base 0x%llx size 0x%llx%n\n",
+		    name, &parts[idx].offset, &parts[idx].size, &bytes) == 3;
+	     idx++, offset += bytes + 1) {
+		parts[idx].name = kstrdup(name, GFP_KERNEL);
+		if (!parts[idx].name) {
+			err = -ENOMEM;
+			goto err_free;
+		}
+	}
+
+	if (idx == TPLINK_SAFELOADER_MAX_PARTS)
+		pr_warn("Reached maximum number of partitions!\n");
+
+	kfree(buf);
+
+	*pparts = parts;
+
+	return idx;
+
+err_free:
+	for (idx -= 1; idx >= 0; idx--)
+		kfree(parts[idx].name);
+err_out:
+	return err;
+};
+
+static void mtd_parser_tplink_safeloader_cleanup(const struct mtd_partition *pparts,
+						 int nr_parts)
+{
+	int i;
+
+	for (i = 0; i < nr_parts; i++)
+		kfree(pparts[i].name);
+
+	kfree(pparts);
+}
+
+static const struct of_device_id mtd_parser_tplink_safeloader_of_match_table[] = {
+	{ .compatible = "tplink,safeloader-partitions" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mtd_parser_tplink_safeloader_of_match_table);
+
+static struct mtd_part_parser mtd_parser_tplink_safeloader = {
+	.parse_fn = mtd_parser_tplink_safeloader_parse,
+	.cleanup = mtd_parser_tplink_safeloader_cleanup,
+	.name = "tplink-safeloader",
+	.of_match_table = mtd_parser_tplink_safeloader_of_match_table,
+};
+module_mtd_part_parser(mtd_parser_tplink_safeloader);
+
+MODULE_LICENSE("GPL");