100-09-cmd-add-nmbm-command.patch 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. From 0af8d0aac77f4df4bc7dadbcdea5d9a16f5f3e45 Mon Sep 17 00:00:00 2001
  2. From: Weijie Gao <[email protected]>
  3. Date: Mon, 25 Jul 2022 10:44:57 +0800
  4. Subject: [PATCH 43/71] cmd: add nmbm command
  5. Add nmbm command for debugging, data operations and image-booting support
  6. Signed-off-by: Weijie Gao <[email protected]>
  7. ---
  8. cmd/Kconfig | 6 +
  9. cmd/Makefile | 1 +
  10. cmd/nmbm.c | 327 +++++++++++++++++++++++++++++++++++++++++++++++++++
  11. 3 files changed, 334 insertions(+)
  12. create mode 100644 cmd/nmbm.c
  13. --- a/cmd/Kconfig
  14. +++ b/cmd/Kconfig
  15. @@ -1392,6 +1392,12 @@ config CMD_NAND_TORTURE
  16. endif # CMD_NAND
  17. +config CMD_NMBM
  18. + depends on NMBM_MTD
  19. + bool "nmbm"
  20. + help
  21. + NAND mapping block management (NMBM) utility
  22. +
  23. config CMD_NVME
  24. bool "nvme"
  25. depends on NVME
  26. --- a/cmd/Makefile
  27. +++ b/cmd/Makefile
  28. @@ -127,6 +127,7 @@ obj-y += legacy-mtd-utils.o
  29. endif
  30. obj-$(CONFIG_CMD_MUX) += mux.o
  31. obj-$(CONFIG_CMD_NAND) += nand.o
  32. +obj-$(CONFIG_CMD_NMBM) += nmbm.o
  33. obj-$(CONFIG_CMD_NET) += net.o
  34. obj-$(CONFIG_CMD_NVEDIT_EFI) += nvedit_efi.o
  35. obj-$(CONFIG_CMD_ONENAND) += onenand.o
  36. --- /dev/null
  37. +++ b/cmd/nmbm.c
  38. @@ -0,0 +1,327 @@
  39. +// SPDX-License-Identifier: GPL-2.0
  40. +/*
  41. + * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
  42. + *
  43. + * Author: Weijie Gao <[email protected]>
  44. + */
  45. +
  46. +#include <command.h>
  47. +#include <image.h>
  48. +#include <stdbool.h>
  49. +#include <linux/types.h>
  50. +#include <linux/mtd/mtd.h>
  51. +#include <jffs2/load_kernel.h>
  52. +
  53. +#include <nmbm/nmbm-mtd.h>
  54. +
  55. +static int nmbm_parse_offset_size(struct mtd_info *mtd, char *off_str,
  56. + char *size_str, uint64_t *off,
  57. + uint64_t *size)
  58. +{
  59. + char *end;
  60. +
  61. + *off = simple_strtoull(off_str, &end, 16);
  62. + if (end == off_str) {
  63. + printf("Error: offset '%s' is invalid\n", off_str);
  64. + return -EINVAL;
  65. + }
  66. +
  67. + if (*off >= mtd->size) {
  68. + printf("Error: offset '0x%llx' is beyond the end of device\n",
  69. + *off);
  70. + return -EINVAL;
  71. + }
  72. +
  73. + *size = simple_strtoull(size_str, &end, 16);
  74. + if (end == off_str) {
  75. + printf("Error: size '%s' is invalid\n", off_str);
  76. + return -EINVAL;
  77. + }
  78. +
  79. + if (*off + *size > mtd->size) {
  80. + printf("Error: size '0x%llx' is too large\n", *size);
  81. + return -EINVAL;
  82. + }
  83. +
  84. + return 0;
  85. +}
  86. +
  87. +static int do_nmbm_erase(struct mtd_info *mtd, uint64_t offset, uint64_t size)
  88. +{
  89. + struct erase_info ei;
  90. + int ret;
  91. +
  92. + memset(&ei, 0, sizeof(ei));
  93. +
  94. + ei.mtd = mtd;
  95. + ei.addr = offset;
  96. + ei.len = size;
  97. +
  98. + printf("Erasing from 0x%llx, size 0x%llx ...\n", offset, size);
  99. +
  100. + ret = mtd_erase(mtd, &ei);
  101. +
  102. + if (!ret) {
  103. + printf("Succeeded\n");
  104. + return CMD_RET_SUCCESS;
  105. + }
  106. +
  107. + printf("Failed at 0x%llx\n", ei.fail_addr);
  108. +
  109. + return CMD_RET_FAILURE;
  110. +}
  111. +
  112. +static int do_nmbm_rw(int read, struct mtd_info *mtd, uintptr_t addr,
  113. + uint64_t offset, size_t size)
  114. +{
  115. + size_t retlen;
  116. + int ret;
  117. +
  118. + printf("%s 0x%llx, size 0x%zx\n", read ? "Reading from" : "Writing to",
  119. + offset, size);
  120. +
  121. + if (read)
  122. + ret = mtd_read(mtd, offset, size, &retlen, (void *)addr);
  123. + else
  124. + ret = mtd_write(mtd, offset, size, &retlen, (void *)addr);
  125. +
  126. + if (!ret) {
  127. + printf("Succeeded\n");
  128. + return CMD_RET_SUCCESS;
  129. + }
  130. +
  131. + printf("Failed at 0x%llx\n", offset + retlen);
  132. +
  133. + return CMD_RET_FAILURE;
  134. +}
  135. +
  136. +static int do_nmbm_mtd_boot(struct cmd_tbl *cmdtp, struct mtd_info *mtd,
  137. + int argc, char *const argv[])
  138. +{
  139. + bool print_image_contents = true;
  140. + uintptr_t loadaddr = image_load_addr;
  141. + char *end, *image_name;
  142. + const char *ep;
  143. + size_t retlen;
  144. + uint32_t size;
  145. + uint64_t off;
  146. + int ret;
  147. +
  148. +#if defined(CONFIG_CMD_MTDPARTS)
  149. + struct mtd_device *partdev;
  150. + struct mtd_info *partmtd;
  151. + struct part_info *part;
  152. + u8 pnum;
  153. +#endif
  154. +
  155. + ep = env_get("autostart");
  156. +
  157. + if (ep && !strcmp(ep, "yes"))
  158. + print_image_contents = false;
  159. +
  160. + if (argc == 2) {
  161. + loadaddr = simple_strtoul(argv[0], &end, 0);
  162. + if (*end || end == argv[0]) {
  163. + printf("'%s' is not a valid address\n", argv[0]);
  164. + return CMD_RET_FAILURE;
  165. + }
  166. +
  167. + argc--;
  168. + argv++;
  169. + }
  170. +
  171. + off = simple_strtoull(argv[0], &end, 0);
  172. + if (*end || end == argv[0]) {
  173. +#if defined(CONFIG_CMD_MTDPARTS)
  174. + ret = mtdparts_init();
  175. + if (ret)
  176. + return CMD_RET_FAILURE;
  177. +
  178. + ret = find_dev_and_part(argv[0], &partdev, &pnum, &part);
  179. + if (ret)
  180. + return CMD_RET_FAILURE;
  181. +
  182. + if (partdev->id->type != MTD_DEV_TYPE_NMBM) {
  183. + printf("'%s' is not a NMBM device partition\n",
  184. + argv[0]);
  185. + return CMD_RET_FAILURE;
  186. + }
  187. +
  188. + partmtd = nmbm_mtd_get_upper_by_index(partdev->id->num);
  189. +
  190. + if (partmtd != mtd) {
  191. + printf("'%s' does not belong to this device\n",
  192. + argv[0]);
  193. + return CMD_RET_FAILURE;
  194. + }
  195. +
  196. + off = part->offset;
  197. +#else
  198. + printf("'%s' is not a valid offset\n", argv[0]);
  199. + return CMD_RET_FAILURE;
  200. +#endif
  201. + }
  202. +
  203. + ret = mtd_read(mtd, off, sizeof(struct legacy_img_hdr), &retlen,
  204. + (void *)loadaddr);
  205. + if (ret || retlen != sizeof(struct legacy_img_hdr)) {
  206. + printf("Failed to read NMBM at offset 0x%08llx\n", off);
  207. + return CMD_RET_FAILURE;
  208. + }
  209. +
  210. + switch (genimg_get_format((void *)loadaddr)) {
  211. +#if defined(CONFIG_LEGACY_IMAGE_FORMAT)
  212. + case IMAGE_FORMAT_LEGACY:
  213. + size = image_get_image_size((struct legacy_img_hdr *)loadaddr);
  214. + image_name = "legacy";
  215. + break;
  216. +#endif
  217. +#if defined(CONFIG_FIT)
  218. + case IMAGE_FORMAT_FIT:
  219. + size = fit_get_size((const void *)loadaddr);
  220. + image_name = "FIT";
  221. + break;
  222. +#endif
  223. + default:
  224. + printf("Error: no Image found at offset 0x%08llx\n", off);
  225. + return CMD_RET_FAILURE;
  226. + }
  227. +
  228. + printf("Loading %s image at offset 0x%llx to memory 0x%08lx, size 0x%x ...\n",
  229. + image_name, off, loadaddr, size);
  230. +
  231. + ret = mtd_read(mtd, off, size, &retlen, (void *)loadaddr);
  232. + if (ret || retlen != size) {
  233. + printf("Error: Failed to load image at offset 0x%08llx\n",
  234. + off + retlen);
  235. + return CMD_RET_FAILURE;
  236. + }
  237. +
  238. + switch (genimg_get_format((void *)loadaddr)) {
  239. +#if defined(CONFIG_LEGACY_IMAGE_FORMAT)
  240. + case IMAGE_FORMAT_LEGACY:
  241. + if (print_image_contents)
  242. + image_print_contents((void *)loadaddr);
  243. + break;
  244. +#endif
  245. +#if defined(CONFIG_FIT)
  246. + case IMAGE_FORMAT_FIT:
  247. + if (print_image_contents)
  248. + fit_print_contents((void *)loadaddr);
  249. + break;
  250. +#endif
  251. + }
  252. +
  253. + image_load_addr = loadaddr;
  254. +
  255. + return bootm_maybe_autostart(cmdtp, "nmbm");
  256. +}
  257. +
  258. +static int do_nmbm(struct cmd_tbl *cmdtp, int flag, int argc,
  259. + char *const argv[])
  260. +{
  261. + struct mtd_info *mtd;
  262. + uint64_t offset, size;
  263. + char *end;
  264. + uintptr_t addr;
  265. + int ret, all = 0;
  266. +
  267. + if (argc == 1)
  268. + return CMD_RET_USAGE;
  269. +
  270. + if (!strcmp(argv[1], "list")) {
  271. + nmbm_mtd_list_devices();
  272. + return CMD_RET_SUCCESS;
  273. + }
  274. +
  275. + if (argc < 3)
  276. + return CMD_RET_USAGE;
  277. +
  278. + if (!strcmp(argv[2], "info"))
  279. + return !!nmbm_mtd_print_info(argv[1]);
  280. +
  281. + if (!strcmp(argv[2], "state"))
  282. + return !!nmbm_mtd_print_states(argv[1]);
  283. +
  284. + if (!strcmp(argv[2], "bad"))
  285. + return !!nmbm_mtd_print_bad_blocks(argv[1]);
  286. +
  287. + if (!strcmp(argv[2], "mapping")) {
  288. + if (argc >= 4) {
  289. + if (!strcmp(argv[3], "all"))
  290. + all = 1;
  291. + }
  292. +
  293. + return nmbm_mtd_print_mappings(argv[1], all);
  294. + }
  295. +
  296. + if (argc < 4)
  297. + return CMD_RET_USAGE;
  298. +
  299. + mtd = get_mtd_device_nm(argv[1]);
  300. + if (IS_ERR(mtd)) {
  301. + printf("Error: NMBM device '%s' not found\n", argv[1]);
  302. + return CMD_RET_FAILURE;
  303. + }
  304. +
  305. + if (mtd->type != MTD_DEV_TYPE_NMBM) {
  306. + printf("Error: '%s' is not a NMBM device\n", argv[1]);
  307. + return CMD_RET_FAILURE;
  308. + }
  309. +
  310. + if (!strcmp(argv[2], "boot"))
  311. + return do_nmbm_mtd_boot(cmdtp, mtd, argc - 3, argv + 3);
  312. +
  313. + if (argc < 5)
  314. + return CMD_RET_USAGE;
  315. +
  316. + if (!strcmp(argv[2], "erase")) {
  317. + ret = nmbm_parse_offset_size(mtd, argv[3], argv[4], &offset,
  318. + &size);
  319. + if (ret)
  320. + return CMD_RET_FAILURE;
  321. +
  322. + return do_nmbm_erase(mtd, offset, size);
  323. + }
  324. +
  325. + if (argc < 6)
  326. + return CMD_RET_USAGE;
  327. +
  328. + ret = nmbm_parse_offset_size(mtd, argv[4], argv[5], &offset, &size);
  329. + if (ret)
  330. + return CMD_RET_FAILURE;
  331. +
  332. + if (size > SIZE_MAX) {
  333. + printf("Error: size 0x%llx is too large\n", size);
  334. + return -EINVAL;
  335. + }
  336. +
  337. + addr = simple_strtoul(argv[3], &end, 16);
  338. + if (end == argv[3]) {
  339. + printf("Error: addr '%s' is invalid\n", argv[3]);
  340. + return -EINVAL;
  341. + }
  342. +
  343. + if (!strcmp(argv[2], "read"))
  344. + return do_nmbm_rw(1, mtd, addr, offset, (size_t)size);
  345. +
  346. + if (!strcmp(argv[2], "write"))
  347. + return do_nmbm_rw(0, mtd, addr, offset, (size_t)size);
  348. +
  349. + return CMD_RET_USAGE;
  350. +}
  351. +
  352. +U_BOOT_CMD(
  353. + nmbm, CONFIG_SYS_MAXARGS, 0, do_nmbm,
  354. + "NMBM utility commands",
  355. + "\n"
  356. + "nmbm list - List NMBM devices\n"
  357. + "nmbm <name> info - Display NMBM information\n"
  358. + "nmbm <name> state - Display block states\n"
  359. + "nmbm <name> bad - Display bad blocks\n"
  360. + "nmbm <name> boot <part | [loadaddr] offset> - Boot from NMBM\n"
  361. + "nmbm <name> mapping [all] - Display block mapping\n"
  362. + "nmbm <name> erase <offset> <size> - Erase blocks\n"
  363. + "nmbm <name> read <addr> <offset> <size> - Read data\n"
  364. + "nmbm <name> write <addr> <offset> <size> - Write data\n"
  365. +);