mtdsplit_mstc_boot.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * a mtdsplit parser using "bootnum" value in the "persist" partition
  4. * for the devices manufactured by MSTC (MitraStar Technology Corp.)
  5. */
  6. #include <linux/module.h>
  7. #include <linux/mtd/mtd.h>
  8. #include <linux/mtd/partitions.h>
  9. #include <linux/types.h>
  10. #include <linux/byteorder/generic.h>
  11. #include <linux/slab.h>
  12. #include <linux/libfdt.h>
  13. #include <linux/of_fdt.h>
  14. #include <dt-bindings/mtd/partitions/uimage.h>
  15. #include "mtdsplit.h"
  16. #define PERSIST_BOOTNUM_OFFSET 0x4
  17. #define NR_PARTS_MAX 2
  18. /*
  19. * Legacy format image header,
  20. * all data in network byte order (aka natural aka bigendian).
  21. */
  22. struct uimage_header {
  23. uint32_t ih_magic; /* Image Header Magic Number */
  24. uint32_t ih_hcrc; /* Image Header CRC Checksum */
  25. uint32_t ih_time; /* Image Creation Timestamp */
  26. uint32_t ih_size; /* Image Data Size */
  27. uint32_t ih_load; /* Data Load Address */
  28. uint32_t ih_ep; /* Entry Point Address */
  29. uint32_t ih_dcrc; /* Image Data CRC Checksum */
  30. uint8_t ih_os; /* Operating System */
  31. uint8_t ih_arch; /* CPU architecture */
  32. uint8_t ih_type; /* Image Type */
  33. uint8_t ih_comp; /* Compression Type */
  34. uint8_t ih_name[IH_NMLEN]; /* Image Name */
  35. };
  36. /* check whether the current mtd device is active or not */
  37. static int
  38. mstcboot_is_active(struct mtd_info *mtd, u32 *bootnum_dt)
  39. {
  40. struct device_node *np = mtd_get_of_node(mtd);
  41. struct device_node *persist_np;
  42. size_t retlen;
  43. u32 persist_offset;
  44. u_char bootnum;
  45. int ret;
  46. ret = of_property_read_u32(np, "mstc,bootnum", bootnum_dt);
  47. if (ret)
  48. return ret;
  49. persist_np = of_parse_phandle(np, "mstc,persist", 0);
  50. if (!persist_np)
  51. return -ENODATA;
  52. /* is "persist" under the same node? */
  53. if (persist_np->parent != np->parent) {
  54. of_node_put(persist_np);
  55. return -EINVAL;
  56. }
  57. ret = of_property_read_u32(persist_np, "reg", &persist_offset);
  58. of_node_put(persist_np);
  59. if (ret)
  60. return ret;
  61. ret = mtd_read(mtd->parent, persist_offset + PERSIST_BOOTNUM_OFFSET,
  62. 1, &retlen, &bootnum);
  63. if (ret)
  64. return ret;
  65. if (retlen != 1)
  66. return -EIO;
  67. return (bootnum == *bootnum_dt) ? 1 : 0;
  68. }
  69. /*
  70. * mainly for NOR devices that uses raw kernel and squashfs
  71. *
  72. * example:
  73. *
  74. * partition@5a0000 {
  75. * compatible = "mstc,boot";
  76. * label = "firmware1";
  77. * reg = <0x5a0000 0x3200000>;
  78. * mstc,bootnum = <1>;
  79. * mstc,persist = <&mtd_persist>;
  80. * };
  81. */
  82. static int
  83. mstcboot_parse_image_parts(struct mtd_info *mtd,
  84. const struct mtd_partition **pparts)
  85. {
  86. struct mtd_partition *parts;
  87. size_t retlen, kern_len = 0;
  88. size_t rootfs_offset;
  89. enum mtdsplit_part_type type;
  90. u_char buf[0x40];
  91. int ret, nr_parts = 1, index = 0;
  92. ret = mtd_read(mtd, 0, sizeof(struct uimage_header), &retlen, buf);
  93. if (ret)
  94. return ret;
  95. if (retlen != sizeof(struct uimage_header))
  96. return -EIO;
  97. if (be32_to_cpu(*(u32 *)buf) == OF_DT_HEADER) {
  98. /* Flattened Image Tree (FIT) */
  99. struct fdt_header *fdthdr = (void *)buf;
  100. kern_len = be32_to_cpu(fdthdr->totalsize);
  101. } else if (be32_to_cpu(*(u32 *)buf) == IH_MAGIC) {
  102. /* Legacy uImage */
  103. struct uimage_header *uimghdr = (void *)buf;
  104. kern_len = sizeof(*uimghdr) + be32_to_cpu(uimghdr->ih_size);
  105. }
  106. ret = mtd_find_rootfs_from(mtd, kern_len, mtd->size, &rootfs_offset, &type);
  107. if (ret) {
  108. pr_debug("no rootfs in \"%s\"\n", mtd->name);
  109. return ret;
  110. }
  111. if (kern_len > 0)
  112. nr_parts++;
  113. parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
  114. if (!parts)
  115. return -ENOMEM;
  116. if (kern_len) {
  117. parts[index].name = KERNEL_PART_NAME;
  118. parts[index].offset = 0;
  119. parts[index++].size = rootfs_offset;
  120. }
  121. parts[index].name = (type == MTDSPLIT_PART_TYPE_UBI)
  122. ? UBI_PART_NAME : ROOTFS_PART_NAME;
  123. parts[index].offset = rootfs_offset;
  124. parts[index].size = mtd->size - rootfs_offset;
  125. *pparts = parts;
  126. return nr_parts;
  127. }
  128. /*
  129. * mainly for NAND devices that uses raw-kernel and UBI and needs
  130. * splitted kernel/ubi partitions when sysupgrade
  131. *
  132. * example:
  133. *
  134. * partition@3c0000 {
  135. * compatible = "mstc,boot";
  136. * reg = <0x3c0000 0x3240000>;
  137. * label = "firmware1";
  138. * mstc,bootnum = <1>;
  139. * mstc,persist = <&mtd_persist>;
  140. * #address-cells = <1>;
  141. * #size-cells = <1>;
  142. *
  143. * partition@0 {
  144. * reg = <0x0 0x800000>;
  145. * label-base = "kernel";
  146. * };
  147. *
  148. * partition@800000 {
  149. * reg = <0x800000 0x2a40000>;
  150. * label-base = "ubi";
  151. * };
  152. };
  153. */
  154. static int
  155. mstcboot_parse_fixed_parts(struct mtd_info *mtd,
  156. const struct mtd_partition **pparts,
  157. int active, u32 bootnum_dt)
  158. {
  159. struct device_node *np = mtd_get_of_node(mtd);
  160. struct device_node *child;
  161. struct mtd_partition *parts;
  162. int ret, nr_parts, index = 0;
  163. nr_parts = of_get_child_count(np);
  164. if (nr_parts > NR_PARTS_MAX) {
  165. pr_err("too many partitions found!\n");
  166. return -EINVAL;
  167. }
  168. parts = kcalloc(nr_parts, sizeof(*parts), GFP_KERNEL);
  169. if (!parts)
  170. return -ENOMEM;
  171. for_each_child_of_node(np, child) {
  172. u32 reg[2];
  173. if (of_n_addr_cells(child) != 1 ||
  174. of_n_size_cells(child) != 1)
  175. {
  176. ret = -EINVAL;
  177. break;
  178. }
  179. ret = of_property_read_u32_array(child, "reg", reg, 2);
  180. if (ret)
  181. break;
  182. ret = of_property_read_string(child, "label-base",
  183. &parts[index].name);
  184. if (ret)
  185. break;
  186. if (!active) {
  187. parts[index].name = devm_kasprintf(&mtd->dev, GFP_KERNEL,
  188. "%s%u",
  189. parts[index].name, bootnum_dt);
  190. if (!parts[index].name) {
  191. ret = -ENOMEM;
  192. break;
  193. }
  194. }
  195. parts[index].offset = reg[0];
  196. parts[index].size = reg[1];
  197. index++;
  198. }
  199. of_node_put(child);
  200. if (ret)
  201. kfree(parts);
  202. else
  203. *pparts = parts;
  204. return ret ? ret : nr_parts;
  205. }
  206. static int
  207. mtdsplit_mstcboot_parse(struct mtd_info *mtd,
  208. const struct mtd_partition **pparts,
  209. struct mtd_part_parser_data *data)
  210. {
  211. struct device_node *np = mtd_get_of_node(mtd);
  212. u32 bootnum_dt;
  213. int ret;
  214. ret = mstcboot_is_active(mtd, &bootnum_dt);
  215. if (ret < 0)
  216. goto exit;
  217. if (of_get_child_count(np))
  218. ret = mstcboot_parse_fixed_parts(mtd, pparts, ret, bootnum_dt);
  219. else if (ret != 0)
  220. ret = mstcboot_parse_image_parts(mtd, pparts);
  221. exit:
  222. /*
  223. * return 0 when ret=-ENODEV, to prevent deletion of
  224. * parent mtd partitions on Linux 6.7 and later
  225. */
  226. return ret == -ENODEV ? 0 : ret;
  227. }
  228. static const struct of_device_id mtdsplit_mstcboot_of_match_table[] = {
  229. { .compatible = "mstc,boot" },
  230. {},
  231. };
  232. MODULE_DEVICE_TABLE(of, mtdsplit_mstcboot_of_match_table);
  233. static struct mtd_part_parser mtdsplit_mstcboot_parser = {
  234. .owner = THIS_MODULE,
  235. .name = "mstc-boot",
  236. .of_match_table = mtdsplit_mstcboot_of_match_table,
  237. .parse_fn = mtdsplit_mstcboot_parse,
  238. .type = MTD_PARSER_TYPE_FIRMWARE,
  239. };
  240. module_mtd_part_parser(mtdsplit_mstcboot_parser)