nftldump.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. /*
  2. * nftldump.c: Dumping the content of NFTL partitions on a "Physical Disk"
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. *
  18. * ToDo:
  19. * 1. UnitSizeFactor != 0xFF cases
  20. * 2. test, test, and test !!!
  21. */
  22. #define PROGRAM_NAME "nftldump"
  23. #define _XOPEN_SOURCE 500 /* For pread */
  24. #include <unistd.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <sys/types.h>
  29. #include <fcntl.h>
  30. #include <sys/stat.h>
  31. #include <errno.h>
  32. #include <sys/ioctl.h>
  33. #include <asm/types.h>
  34. #include <mtd/mtd-user.h>
  35. #include <mtd/nftl-user.h>
  36. #include <mtd_swab.h>
  37. #include "common.h"
  38. static struct NFTLMediaHeader MedHead[2];
  39. static mtd_info_t meminfo;
  40. static struct nftl_oob oobbuf;
  41. static struct mtd_oob_buf oob = {0, 16, (unsigned char *)&oobbuf};
  42. static int fd, ofd = -1;;
  43. static int NumMedHeads;
  44. static unsigned char BadUnitTable[MAX_ERASE_ZONES];
  45. #define SWAP16(x) do { x = le16_to_cpu(x); } while(0)
  46. #define SWAP32(x) do { x = le32_to_cpu(x); } while(0)
  47. /* VUCtable, store the Erase Unit Number of the first Erase Unit in the chain */
  48. static unsigned short *VUCtable;
  49. /* FixMe: make this dynamic allocated */
  50. #define ERASESIZE 0x2000
  51. #define NUMVUNITS ((40*1024*1024) / ERASESIZE)
  52. static union nftl_uci UCItable[NUMVUNITS][3];
  53. static unsigned short nextEUN(unsigned short curEUN)
  54. {
  55. return UCItable[curEUN][0].a.ReplUnitNum;
  56. }
  57. static unsigned int find_media_headers(void)
  58. {
  59. int i;
  60. static unsigned long ofs = 0;
  61. NumMedHeads = 0;
  62. while (ofs < meminfo.size) {
  63. pread_nocheck(fd, &MedHead[NumMedHeads], sizeof(struct NFTLMediaHeader), ofs);
  64. if (!strncmp(MedHead[NumMedHeads].DataOrgID, "ANAND", 6)) {
  65. SWAP16(MedHead[NumMedHeads].NumEraseUnits);
  66. SWAP16(MedHead[NumMedHeads].FirstPhysicalEUN);
  67. SWAP32(MedHead[NumMedHeads].FormattedSize);
  68. if (NumMedHeads == 0) {
  69. printf("NFTL Media Header found at offset 0x%08lx:\n", ofs);
  70. printf("NumEraseUnits: %d\n",
  71. MedHead[NumMedHeads].NumEraseUnits);
  72. printf("FirstPhysicalEUN: %d\n",
  73. MedHead[NumMedHeads].FirstPhysicalEUN);
  74. printf("Formatted Size: %d\n",
  75. MedHead[NumMedHeads].FormattedSize);
  76. printf("UnitSizeFactor: 0x%x\n",
  77. MedHead[NumMedHeads].UnitSizeFactor);
  78. /* read BadUnitTable, I don't know why pread() does not work for
  79. larger (7680 bytes) chunks */
  80. for (i = 0; i < MAX_ERASE_ZONES; i += 512)
  81. pread_nocheck(fd, &BadUnitTable[i], 512, ofs + 512 + i);
  82. } else
  83. printf("Second NFTL Media Header found at offset 0x%08lx\n",ofs);
  84. NumMedHeads++;
  85. }
  86. ofs += meminfo.erasesize;
  87. if (NumMedHeads == 2) {
  88. if (strncmp((char *)&MedHead[0], (char *)&MedHead[1], sizeof(struct NFTLMediaHeader)) != 0) {
  89. printf("warning: NFTL Media Header is not consistent with "
  90. "Spare NFTL Media Header\n");
  91. }
  92. break;
  93. }
  94. }
  95. /* allocate Virtual Unit Chain table for this NFTL partition */
  96. VUCtable = calloc(MedHead[0].NumEraseUnits, sizeof(unsigned short));
  97. return NumMedHeads;
  98. }
  99. static void dump_erase_units(void)
  100. {
  101. int i, j;
  102. unsigned long ofs;
  103. for (i = MedHead[0].FirstPhysicalEUN; i < MedHead[0].FirstPhysicalEUN +
  104. MedHead[0].NumEraseUnits; i++) {
  105. /* For each Erase Unit */
  106. ofs = i * meminfo.erasesize;
  107. /* read the Unit Control Information */
  108. for (j = 0; j < 3; j++) {
  109. oob.start = ofs + (j * 512);
  110. if (ioctl(fd, MEMREADOOB, &oob))
  111. printf("MEMREADOOB at %lx: %s\n",
  112. (unsigned long) oob.start, strerror(errno));
  113. memcpy(&UCItable[i][j], &oobbuf.u, 8);
  114. }
  115. if (UCItable[i][1].b.EraseMark != cpu_to_le16(0x3c69)) {
  116. printf("EraseMark not present in unit %d: %x\n",
  117. i, UCItable[i][1].b.EraseMark);
  118. } else {
  119. /* a properly formatted unit */
  120. SWAP16(UCItable[i][0].a.VirtUnitNum);
  121. SWAP16(UCItable[i][0].a.ReplUnitNum);
  122. SWAP16(UCItable[i][0].a.SpareVirtUnitNum);
  123. SWAP16(UCItable[i][0].a.SpareReplUnitNum);
  124. SWAP32(UCItable[i][1].b.WearInfo);
  125. SWAP16(UCItable[i][1].b.EraseMark);
  126. SWAP16(UCItable[i][1].b.EraseMark1);
  127. SWAP16(UCItable[i][2].c.FoldMark);
  128. SWAP16(UCItable[i][2].c.FoldMark1);
  129. if (!(UCItable[i][0].a.VirtUnitNum & 0x8000)) {
  130. /* If this is the first in a chain, store the EUN in the VUC table */
  131. if (VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff]) {
  132. printf("Duplicate start of chain for VUC %d: "
  133. "Unit %d replaces Unit %d\n",
  134. UCItable[i][0].a.VirtUnitNum & 0x7fff,
  135. i, VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff]);
  136. }
  137. VUCtable[UCItable[i][0].a.VirtUnitNum & 0x7fff] = i;
  138. }
  139. }
  140. switch (BadUnitTable[i]) {
  141. case ZONE_BAD_ORIGINAL:
  142. printf("Unit %d is marked as ZONE_BAD_ORIGINAL\n", i);
  143. continue;
  144. case ZONE_BAD_MARKED:
  145. printf("Unit %d is marked as ZONE_BAD_MARKED\n", i);
  146. continue;
  147. }
  148. /* ZONE_GOOD */
  149. if (UCItable[i][0].a.VirtUnitNum == 0xffff)
  150. printf("Unit %d is free\n", i);
  151. else
  152. printf("Unit %d is in chain %d and %s a replacement\n", i,
  153. UCItable[i][0].a.VirtUnitNum & 0x7fff,
  154. UCItable[i][0].a.VirtUnitNum & 0x8000 ? "is" : "is not");
  155. }
  156. }
  157. static void dump_virtual_units(void)
  158. {
  159. int i, j;
  160. char readbuf[512];
  161. for (i = 0; i < (MedHead[0].FormattedSize / meminfo.erasesize); i++) {
  162. unsigned short curEUN = VUCtable[i];
  163. printf("Virtual Unit #%d: ", i);
  164. if (!curEUN) {
  165. printf("Not present\n");
  166. continue;
  167. }
  168. printf("%d", curEUN);
  169. /* walk through the Virtual Unit Chain */
  170. while ((curEUN = nextEUN(curEUN)) != 0xffff) {
  171. printf(", %d", curEUN & 0x7fff);
  172. }
  173. printf("\n");
  174. if (ofd != -1) {
  175. /* Actually write out the data */
  176. for (j = 0; j < meminfo.erasesize / 512; j++) {
  177. /* For each sector in the block */
  178. unsigned short lastgoodEUN = 0xffff, thisEUN = VUCtable[i];
  179. unsigned int status;
  180. if (thisEUN == 0xffff) thisEUN = 0;
  181. while (thisEUN && (thisEUN & 0x7fff) != 0x7fff) {
  182. oob.start = (thisEUN * ERASESIZE) + (j * 512);
  183. ioctl(fd, MEMREADOOB, &oob);
  184. status = oobbuf.b.Status | oobbuf.b.Status1;
  185. switch (status) {
  186. case SECTOR_FREE:
  187. /* This is still free. Don't look any more */
  188. thisEUN = 0;
  189. break;
  190. case SECTOR_USED:
  191. /* SECTOR_USED. This is a good one. */
  192. lastgoodEUN = thisEUN;
  193. break;
  194. }
  195. /* Find the next erase unit in this chain, if any */
  196. if (thisEUN)
  197. thisEUN = nextEUN(thisEUN) & 0x7fff;
  198. }
  199. if (lastgoodEUN == 0xffff)
  200. memset(readbuf, 0, 512);
  201. else
  202. pread_nocheck(fd, readbuf, 512,
  203. (lastgoodEUN * ERASESIZE) + (j * 512));
  204. write_nocheck(ofd, readbuf, 512);
  205. }
  206. }
  207. }
  208. }
  209. int main(int argc, char **argv)
  210. {
  211. if (argc < 2) {
  212. printf("Usage: %s <device> [<outfile>]\n", PROGRAM_NAME);
  213. exit(1);
  214. }
  215. fd = open(argv[1], O_RDONLY);
  216. if (fd == -1) {
  217. perror("open flash");
  218. exit (1);
  219. }
  220. if (argc > 2) {
  221. ofd = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, 0644);
  222. if (ofd == -1)
  223. perror ("open outfile");
  224. }
  225. /* get size information of the MTD device */
  226. if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
  227. perror("ioctl(MEMGETINFO)");
  228. close(fd);
  229. return 1;
  230. }
  231. while (find_media_headers() != 0) {
  232. dump_erase_units();
  233. dump_virtual_units();
  234. free(VUCtable);
  235. }
  236. exit(0);
  237. }