421-v6.2-mtd-parsers-add-TP-Link-SafeLoader-partitions-table-.patch 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. From aec4d5f5ffd0f0092bd9dc21ea90e0bc237d4b74 Mon Sep 17 00:00:00 2001
  2. From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <[email protected]>
  3. Date: Sat, 15 Oct 2022 11:29:50 +0200
  4. Subject: [PATCH] mtd: parsers: add TP-Link SafeLoader partitions table parser
  5. MIME-Version: 1.0
  6. Content-Type: text/plain; charset=UTF-8
  7. Content-Transfer-Encoding: 8bit
  8. This parser deals with most TP-Link home routers. It reads info about
  9. partitions and registers them in the MTD subsystem.
  10. Example from TP-Link Archer C5 V2:
  11. spi-nor spi0.0: s25fl128s1 (16384 Kbytes)
  12. 15 tplink-safeloader partitions found on MTD device spi0.0
  13. Creating 15 MTD partitions on "spi0.0":
  14. 0x000000000000-0x000000040000 : "fs-uboot"
  15. 0x000000040000-0x000000440000 : "os-image"
  16. 0x000000440000-0x000000e40000 : "rootfs"
  17. 0x000000e40000-0x000000e40200 : "default-mac"
  18. 0x000000e40200-0x000000e40400 : "pin"
  19. 0x000000e40400-0x000000e40600 : "product-info"
  20. 0x000000e50000-0x000000e60000 : "partition-table"
  21. 0x000000e60000-0x000000e60200 : "soft-version"
  22. 0x000000e61000-0x000000e70000 : "support-list"
  23. 0x000000e70000-0x000000e80000 : "profile"
  24. 0x000000e80000-0x000000e90000 : "default-config"
  25. 0x000000e90000-0x000000ee0000 : "user-config"
  26. 0x000000ee0000-0x000000fe0000 : "log"
  27. 0x000000fe0000-0x000000ff0000 : "radio_bk"
  28. 0x000000ff0000-0x000001000000 : "radio"
  29. Signed-off-by: Rafał Miłecki <[email protected]>
  30. Signed-off-by: Miquel Raynal <[email protected]>
  31. Link: https://lore.kernel.org/linux-mtd/[email protected]
  32. ---
  33. drivers/mtd/parsers/Kconfig | 15 +++
  34. drivers/mtd/parsers/Makefile | 1 +
  35. drivers/mtd/parsers/tplink_safeloader.c | 150 ++++++++++++++++++++++++
  36. 3 files changed, 166 insertions(+)
  37. create mode 100644 drivers/mtd/parsers/tplink_safeloader.c
  38. --- a/drivers/mtd/parsers/Kconfig
  39. +++ b/drivers/mtd/parsers/Kconfig
  40. @@ -113,6 +113,21 @@ config MTD_AFS_PARTS
  41. for your particular device. It won't happen automatically. The
  42. 'physmap' map driver (CONFIG_MTD_PHYSMAP) does this, for example.
  43. +config MTD_PARSER_TPLINK_SAFELOADER
  44. + tristate "TP-Link Safeloader partitions parser"
  45. + depends on MTD && (ARCH_BCM_5301X || ATH79 || SOC_MT7620 || SOC_MT7621 || COMPILE_TEST)
  46. + help
  47. + TP-Link home routers use flash partitions to store various data. Info
  48. + about flash space layout is stored in a partitions table using a
  49. + custom ASCII-based format.
  50. +
  51. + That format was first found in devices with SafeLoader bootloader and
  52. + was named after it. Later it was adapted to CFE and U-Boot
  53. + bootloaders.
  54. +
  55. + This driver reads partitions table, parses it and creates MTD
  56. + partitions.
  57. +
  58. config MTD_PARSER_TRX
  59. tristate "Parser for TRX format partitions"
  60. depends on MTD && (BCM47XX || ARCH_BCM_5301X || ARCH_MEDIATEK || RALINK || COMPILE_TEST)
  61. --- a/drivers/mtd/parsers/Makefile
  62. +++ b/drivers/mtd/parsers/Makefile
  63. @@ -9,6 +9,7 @@ ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) +=
  64. ofpart-$(CONFIG_MTD_OF_PARTS_LINKSYS_NS)+= ofpart_linksys_ns.o
  65. obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o
  66. obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
  67. +obj-$(CONFIG_MTD_PARSER_TPLINK_SAFELOADER) += tplink_safeloader.o
  68. obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o
  69. obj-$(CONFIG_MTD_SERCOMM_PARTS) += scpart.o
  70. obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o
  71. --- /dev/null
  72. +++ b/drivers/mtd/parsers/tplink_safeloader.c
  73. @@ -0,0 +1,150 @@
  74. +// SPDX-License-Identifier: GPL-2.0-only
  75. +/*
  76. + * Copyright © 2022 Rafał Miłecki <[email protected]>
  77. + */
  78. +
  79. +#include <linux/kernel.h>
  80. +#include <linux/module.h>
  81. +#include <linux/mtd/mtd.h>
  82. +#include <linux/mtd/partitions.h>
  83. +#include <linux/of.h>
  84. +#include <linux/slab.h>
  85. +
  86. +#define TPLINK_SAFELOADER_DATA_OFFSET 4
  87. +#define TPLINK_SAFELOADER_MAX_PARTS 32
  88. +
  89. +struct safeloader_cmn_header {
  90. + __be32 size;
  91. + uint32_t unused;
  92. +} __packed;
  93. +
  94. +static void *mtd_parser_tplink_safeloader_read_table(struct mtd_info *mtd)
  95. +{
  96. + struct safeloader_cmn_header hdr;
  97. + struct device_node *np;
  98. + size_t bytes_read;
  99. + size_t offset;
  100. + size_t size;
  101. + char *buf;
  102. + int err;
  103. +
  104. + np = mtd_get_of_node(mtd);
  105. + if (mtd_is_partition(mtd))
  106. + of_node_get(np);
  107. + else
  108. + np = of_get_child_by_name(np, "partitions");
  109. +
  110. + if (of_property_read_u32(np, "partitions-table-offset", (u32 *)&offset)) {
  111. + pr_err("Failed to get partitions table offset\n");
  112. + goto err_put;
  113. + }
  114. +
  115. + err = mtd_read(mtd, offset, sizeof(hdr), &bytes_read, (uint8_t *)&hdr);
  116. + if (err && !mtd_is_bitflip(err)) {
  117. + pr_err("Failed to read from %s at 0x%zx\n", mtd->name, offset);
  118. + goto err_put;
  119. + }
  120. +
  121. + size = be32_to_cpu(hdr.size);
  122. +
  123. + buf = kmalloc(size + 1, GFP_KERNEL);
  124. + if (!buf)
  125. + goto err_put;
  126. +
  127. + err = mtd_read(mtd, offset + sizeof(hdr), size, &bytes_read, buf);
  128. + if (err && !mtd_is_bitflip(err)) {
  129. + pr_err("Failed to read from %s at 0x%zx\n", mtd->name, offset + sizeof(hdr));
  130. + goto err_kfree;
  131. + }
  132. +
  133. + buf[size] = '\0';
  134. +
  135. + of_node_put(np);
  136. +
  137. + return buf;
  138. +
  139. +err_kfree:
  140. + kfree(buf);
  141. +err_put:
  142. + of_node_put(np);
  143. + return NULL;
  144. +}
  145. +
  146. +static int mtd_parser_tplink_safeloader_parse(struct mtd_info *mtd,
  147. + const struct mtd_partition **pparts,
  148. + struct mtd_part_parser_data *data)
  149. +{
  150. + struct mtd_partition *parts;
  151. + char name[65];
  152. + size_t offset;
  153. + size_t bytes;
  154. + char *buf;
  155. + int idx;
  156. + int err;
  157. +
  158. + parts = kcalloc(TPLINK_SAFELOADER_MAX_PARTS, sizeof(*parts), GFP_KERNEL);
  159. + if (!parts) {
  160. + err = -ENOMEM;
  161. + goto err_out;
  162. + }
  163. +
  164. + buf = mtd_parser_tplink_safeloader_read_table(mtd);
  165. + if (!buf) {
  166. + err = -ENOENT;
  167. + goto err_out;
  168. + }
  169. +
  170. + for (idx = 0, offset = TPLINK_SAFELOADER_DATA_OFFSET;
  171. + idx < TPLINK_SAFELOADER_MAX_PARTS &&
  172. + sscanf(buf + offset, "partition %64s base 0x%llx size 0x%llx%zn\n",
  173. + name, &parts[idx].offset, &parts[idx].size, &bytes) == 3;
  174. + idx++, offset += bytes + 1) {
  175. + parts[idx].name = kstrdup(name, GFP_KERNEL);
  176. + if (!parts[idx].name) {
  177. + err = -ENOMEM;
  178. + goto err_free;
  179. + }
  180. + }
  181. +
  182. + if (idx == TPLINK_SAFELOADER_MAX_PARTS)
  183. + pr_warn("Reached maximum number of partitions!\n");
  184. +
  185. + kfree(buf);
  186. +
  187. + *pparts = parts;
  188. +
  189. + return idx;
  190. +
  191. +err_free:
  192. + for (idx -= 1; idx >= 0; idx--)
  193. + kfree(parts[idx].name);
  194. +err_out:
  195. + return err;
  196. +};
  197. +
  198. +static void mtd_parser_tplink_safeloader_cleanup(const struct mtd_partition *pparts,
  199. + int nr_parts)
  200. +{
  201. + int i;
  202. +
  203. + for (i = 0; i < nr_parts; i++)
  204. + kfree(pparts[i].name);
  205. +
  206. + kfree(pparts);
  207. +}
  208. +
  209. +static const struct of_device_id mtd_parser_tplink_safeloader_of_match_table[] = {
  210. + { .compatible = "tplink,safeloader-partitions" },
  211. + {},
  212. +};
  213. +MODULE_DEVICE_TABLE(of, mtd_parser_tplink_safeloader_of_match_table);
  214. +
  215. +static struct mtd_part_parser mtd_parser_tplink_safeloader = {
  216. + .parse_fn = mtd_parser_tplink_safeloader_parse,
  217. + .cleanup = mtd_parser_tplink_safeloader_cleanup,
  218. + .name = "tplink-safeloader",
  219. + .of_match_table = mtd_parser_tplink_safeloader_of_match_table,
  220. +};
  221. +module_mtd_part_parser(mtd_parser_tplink_safeloader);
  222. +
  223. +MODULE_LICENSE("GPL");