mtd_debug.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. /*
  2. * Copyright (c) 2d3D, Inc.
  3. * Written by Abraham vd Merwe <abraham@2d3d.co.za>
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the name of the author nor the names of other contributors
  15. * may be used to endorse or promote products derived from this software
  16. * without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  19. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  20. * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  21. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  22. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  23. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  24. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  25. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  26. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  27. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. */
  29. #define PROGRAM_NAME "mtd_debug"
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <errno.h>
  33. #include <string.h>
  34. #include <unistd.h>
  35. #include <sys/ioctl.h>
  36. #include <sys/types.h>
  37. #include <sys/stat.h>
  38. #include <fcntl.h>
  39. #include <mtd/mtd-user.h>
  40. #include "common.h"
  41. /*
  42. * MEMGETINFO
  43. */
  44. static int getmeminfo(int fd, struct mtd_info_user *mtd)
  45. {
  46. return ioctl(fd, MEMGETINFO, mtd);
  47. }
  48. /*
  49. * MEMERASE
  50. */
  51. static int memerase(int fd, struct erase_info_user *erase)
  52. {
  53. return ioctl(fd, MEMERASE, erase);
  54. }
  55. /*
  56. * MEMGETREGIONCOUNT
  57. * MEMGETREGIONINFO
  58. */
  59. static int getregions(int fd, struct region_info_user *regions, int *n)
  60. {
  61. int i, err;
  62. err = ioctl(fd, MEMGETREGIONCOUNT, n);
  63. if (err)
  64. return err;
  65. for (i = 0; i < *n; i++) {
  66. regions[i].regionindex = i;
  67. err = ioctl(fd, MEMGETREGIONINFO, &regions[i]);
  68. if (err)
  69. return err;
  70. }
  71. return 0;
  72. }
  73. static int erase_flash(int fd, u_int32_t offset, u_int32_t bytes)
  74. {
  75. int err;
  76. struct erase_info_user erase;
  77. erase.start = offset;
  78. erase.length = bytes;
  79. err = memerase(fd, &erase);
  80. if (err < 0) {
  81. perror("MEMERASE");
  82. return 1;
  83. }
  84. fprintf(stderr, "Erased %d bytes from address 0x%.8x in flash\n", bytes, offset);
  85. return 0;
  86. }
  87. static void printsize(u_int32_t x)
  88. {
  89. int i;
  90. static const char *flags = "KMGT";
  91. printf("%u ", x);
  92. for (i = 0; x >= 1024 && flags[i] != '\0'; i++)
  93. x /= 1024;
  94. i--;
  95. if (i >= 0)
  96. printf("(%u%c)", x, flags[i]);
  97. }
  98. static int flash_to_file(int fd, off_t offset, size_t len, const char *filename)
  99. {
  100. u_int8_t *buf = NULL;
  101. int outfd, err;
  102. int size = len * sizeof(u_int8_t);
  103. int n = len;
  104. if (offset != lseek(fd, offset, SEEK_SET)) {
  105. perror("lseek()");
  106. return 1;
  107. }
  108. outfd = creat(filename, 0666);
  109. if (outfd < 0) {
  110. perror("creat()");
  111. return 1;
  112. }
  113. retry:
  114. if ((buf = (u_int8_t *) malloc(size)) == NULL) {
  115. #define BUF_SIZE (64 * 1024 * sizeof(u_int8_t))
  116. fprintf(stderr, "%s: malloc(%#x)\n", __func__, size);
  117. if (size != BUF_SIZE) {
  118. size = BUF_SIZE;
  119. fprintf(stderr, "%s: trying buffer size %#x\n", __func__, size);
  120. goto retry;
  121. }
  122. perror("malloc()");
  123. goto fail;
  124. }
  125. do {
  126. if (n <= size)
  127. size = n;
  128. err = read(fd, buf, size);
  129. if (err < 0) {
  130. fprintf(stderr, "%s: read, size %#x, n %#x\n", __func__, size, n);
  131. perror("read()");
  132. goto fail;
  133. }
  134. if (err < size) {
  135. fprintf(stderr, "%s: short read, requested %#x, read %#x\n", __func__, size, err);
  136. }
  137. err = write(outfd, buf, err);
  138. if (err < 0) {
  139. fprintf(stderr, "%s: write, size %#x, n %#x\n", __func__, size, n);
  140. perror("write()");
  141. goto fail;
  142. }
  143. if (err != size) {
  144. fprintf(stderr, "Couldn't copy entire buffer to %s. (%d/%d bytes copied)\n", filename, err, size);
  145. goto fail;
  146. }
  147. n -= size;
  148. } while (n > 0);
  149. if (buf != NULL)
  150. free(buf);
  151. close(outfd);
  152. printf("Copied %zu bytes from address 0x%.8llx in flash to %s\n", len, (unsigned long long)offset, filename);
  153. return 0;
  154. fail:
  155. close(outfd);
  156. free(buf);
  157. return 1;
  158. }
  159. static int file_to_flash(int fd, off_t offset, u_int32_t len,
  160. const char *filename)
  161. {
  162. u_int8_t *buf = NULL;
  163. FILE *fp;
  164. int err;
  165. int size = len * sizeof(u_int8_t);
  166. int n = len;
  167. if (offset != lseek(fd, offset, SEEK_SET)) {
  168. perror("lseek()");
  169. return 1;
  170. }
  171. if ((fp = fopen(filename, "r")) == NULL) {
  172. perror("fopen()");
  173. return 1;
  174. }
  175. retry:
  176. if ((buf = (u_int8_t *) malloc(size)) == NULL) {
  177. fprintf(stderr, "%s: malloc(%#x) failed\n", __func__, size);
  178. if (size != BUF_SIZE) {
  179. size = BUF_SIZE;
  180. fprintf(stderr, "%s: trying buffer size %#x\n", __func__, size);
  181. goto retry;
  182. }
  183. perror("malloc()");
  184. fclose(fp);
  185. return 1;
  186. }
  187. do {
  188. if (n <= size)
  189. size = n;
  190. if (fread(buf, size, 1, fp) != 1 || ferror(fp)) {
  191. fprintf(stderr, "%s: fread, size %#x, n %#x\n", __func__, size, n);
  192. perror("fread()");
  193. free(buf);
  194. fclose(fp);
  195. return 1;
  196. }
  197. err = write(fd, buf, size);
  198. if (err < 0) {
  199. fprintf(stderr, "%s: write, size %#x, n %#x\n", __func__, size, n);
  200. perror("write()");
  201. free(buf);
  202. fclose(fp);
  203. return 1;
  204. }
  205. n -= size;
  206. } while (n > 0);
  207. if (buf != NULL)
  208. free(buf);
  209. fclose(fp);
  210. printf("Copied %d bytes from %s to address 0x%.8llx in flash\n", len, filename, (unsigned long long)offset);
  211. return 0;
  212. }
  213. static int showinfo(int fd)
  214. {
  215. int i, err, n;
  216. struct mtd_info_user mtd;
  217. static struct region_info_user region[1024];
  218. err = getmeminfo(fd, &mtd);
  219. if (err < 0) {
  220. perror("MEMGETINFO");
  221. return 1;
  222. }
  223. err = getregions(fd, region, &n);
  224. if (err < 0) {
  225. perror("MEMGETREGIONCOUNT");
  226. return 1;
  227. }
  228. printf("mtd.type = ");
  229. switch (mtd.type) {
  230. case MTD_ABSENT:
  231. printf("MTD_ABSENT");
  232. break;
  233. case MTD_RAM:
  234. printf("MTD_RAM");
  235. break;
  236. case MTD_ROM:
  237. printf("MTD_ROM");
  238. break;
  239. case MTD_NORFLASH:
  240. printf("MTD_NORFLASH");
  241. break;
  242. case MTD_NANDFLASH:
  243. printf("MTD_NANDFLASH");
  244. break;
  245. case MTD_MLCNANDFLASH:
  246. printf("MTD_MLCNANDFLASH");
  247. break;
  248. case MTD_DATAFLASH:
  249. printf("MTD_DATAFLASH");
  250. break;
  251. case MTD_UBIVOLUME:
  252. printf("MTD_UBIVOLUME");
  253. break;
  254. default:
  255. printf("(unknown type - new MTD API maybe?)");
  256. }
  257. printf("\nmtd.flags = ");
  258. if (mtd.flags == MTD_CAP_ROM)
  259. printf("MTD_CAP_ROM");
  260. else if (mtd.flags == MTD_CAP_RAM)
  261. printf("MTD_CAP_RAM");
  262. else if (mtd.flags == MTD_CAP_NORFLASH)
  263. printf("MTD_CAP_NORFLASH");
  264. else if (mtd.flags == MTD_CAP_NANDFLASH)
  265. printf("MTD_CAP_NANDFLASH");
  266. else {
  267. int first = 1;
  268. static struct {
  269. const char *name;
  270. int value;
  271. } flags[] =
  272. {
  273. { "MTD_WRITEABLE", MTD_WRITEABLE },
  274. { "MTD_BIT_WRITEABLE", MTD_BIT_WRITEABLE },
  275. { "MTD_NO_ERASE", MTD_NO_ERASE },
  276. { "MTD_POWERUP_LOCK", MTD_POWERUP_LOCK },
  277. { NULL, -1 }
  278. };
  279. for (i = 0; flags[i].name != NULL; i++) {
  280. if (mtd.flags & flags[i].value) {
  281. if (first) {
  282. printf("%s", flags[i].name);
  283. first = 0;
  284. } else {
  285. printf(" | %s", flags[i].name);
  286. }
  287. }
  288. }
  289. }
  290. printf("\nmtd.size = ");
  291. printsize(mtd.size);
  292. printf("\nmtd.erasesize = ");
  293. printsize(mtd.erasesize);
  294. printf("\nmtd.writesize = ");
  295. printsize(mtd.writesize);
  296. printf("\nmtd.oobsize = ");
  297. printsize(mtd.oobsize);
  298. printf("\nregions = %d\n\n", n);
  299. for (i = 0; i < n; i++) {
  300. printf("region[%d].offset = 0x%.8x\n"
  301. "region[%d].erasesize = ",
  302. i, region[i].offset, i);
  303. printsize(region[i].erasesize);
  304. printf("\nregion[%d].numblocks = %d\n"
  305. "region[%d].regionindex = %d\n",
  306. i, region[i].numblocks,
  307. i, region[i].regionindex);
  308. }
  309. return 0;
  310. }
  311. static NORETURN void showusage(void)
  312. {
  313. fprintf(stderr, "usage: %1$s info <device>\n"
  314. " %1$s read <device> <offset> <len> <dest-filename>\n"
  315. " %1$s write <device> <offset> <len> <source-filename>\n"
  316. " %1$s erase <device> <offset> <len>\n",
  317. PROGRAM_NAME);
  318. exit(EXIT_FAILURE);
  319. }
  320. int main(int argc, char *argv[])
  321. {
  322. int err = 0, fd;
  323. int open_flag;
  324. enum {
  325. OPT_INFO,
  326. OPT_READ,
  327. OPT_WRITE,
  328. OPT_ERASE
  329. } option = OPT_INFO;
  330. /* parse command-line options */
  331. if (argc == 3 && !strcmp(argv[1], "info"))
  332. option = OPT_INFO;
  333. else if (argc == 6 && !strcmp(argv[1], "read"))
  334. option = OPT_READ;
  335. else if (argc == 6 && !strcmp(argv[1], "write"))
  336. option = OPT_WRITE;
  337. else if (argc == 5 && !strcmp(argv[1], "erase"))
  338. option = OPT_ERASE;
  339. else
  340. showusage();
  341. /* open device */
  342. open_flag = (option == OPT_INFO || option == OPT_READ) ? O_RDONLY : O_RDWR;
  343. if ((fd = open(argv[2], O_SYNC | open_flag)) < 0)
  344. errmsg_die("open()");
  345. switch (option) {
  346. case OPT_INFO:
  347. showinfo(fd);
  348. break;
  349. case OPT_READ:
  350. err = flash_to_file(fd, strtoll(argv[3], NULL, 0), strtoul(argv[4], NULL, 0), argv[5]);
  351. break;
  352. case OPT_WRITE:
  353. err = file_to_flash(fd, strtoll(argv[3], NULL, 0), strtoul(argv[4], NULL, 0), argv[5]);
  354. break;
  355. case OPT_ERASE:
  356. err = erase_flash(fd, strtoul(argv[3], NULL, 0), strtoul(argv[4], NULL, 0));
  357. break;
  358. }
  359. /* close device */
  360. if (close(fd) < 0)
  361. errmsg_die("close()");
  362. return err;
  363. }