docfdisk.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /*
  2. * docfdisk.c: Modify INFTL partition tables
  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. #define PROGRAM_NAME "docfdisk"
  19. #define _XOPEN_SOURCE 500 /* for pread/pwrite */
  20. #include <unistd.h>
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <fcntl.h>
  24. #include <time.h>
  25. #include <sys/stat.h>
  26. #include <sys/ioctl.h>
  27. #include <sys/mount.h>
  28. #include <errno.h>
  29. #include <string.h>
  30. #include <asm/types.h>
  31. #include <mtd/mtd-user.h>
  32. #include <mtd/inftl-user.h>
  33. #include <mtd_swab.h>
  34. unsigned char *buf;
  35. mtd_info_t meminfo;
  36. erase_info_t erase;
  37. int fd;
  38. struct INFTLMediaHeader *mh;
  39. #define MAXSCAN 10
  40. static void show_header(int mhoffs) {
  41. int i, unitsize, numunits, bmbits, numpart;
  42. int start, end, num, nextunit;
  43. unsigned int flags;
  44. struct INFTLPartition *ip;
  45. bmbits = le32_to_cpu(mh->BlockMultiplierBits);
  46. printf(" bootRecordID = %s\n"
  47. " NoOfBootImageBlocks = %d\n"
  48. " NoOfBinaryPartitions = %d\n"
  49. " NoOfBDTLPartitions = %d\n"
  50. " BlockMultiplierBits = %d\n"
  51. " FormatFlags = %d\n"
  52. " OsakVersion = %d.%d.%d.%d\n"
  53. " PercentUsed = %d\n",
  54. mh->bootRecordID, le32_to_cpu(mh->NoOfBootImageBlocks),
  55. le32_to_cpu(mh->NoOfBinaryPartitions),
  56. le32_to_cpu(mh->NoOfBDTLPartitions),
  57. bmbits,
  58. le32_to_cpu(mh->FormatFlags),
  59. ((unsigned char *) &mh->OsakVersion)[0] & 0xf,
  60. ((unsigned char *) &mh->OsakVersion)[1] & 0xf,
  61. ((unsigned char *) &mh->OsakVersion)[2] & 0xf,
  62. ((unsigned char *) &mh->OsakVersion)[3] & 0xf,
  63. le32_to_cpu(mh->PercentUsed));
  64. numpart = le32_to_cpu(mh->NoOfBinaryPartitions) +
  65. le32_to_cpu(mh->NoOfBDTLPartitions);
  66. unitsize = meminfo.erasesize >> bmbits;
  67. numunits = meminfo.size / unitsize;
  68. nextunit = mhoffs / unitsize;
  69. nextunit++;
  70. printf("Unitsize is %d bytes. Device has %d units.\n",
  71. unitsize, numunits);
  72. if (numunits > 32768) {
  73. printf("WARNING: More than 32768 units! Unexpectedly small BlockMultiplierBits.\n");
  74. }
  75. if (bmbits && (numunits <= 16384)) {
  76. printf("NOTICE: Unexpectedly large BlockMultiplierBits.\n");
  77. }
  78. for (i = 0; i < 4; i++) {
  79. ip = &(mh->Partitions[i]);
  80. flags = le32_to_cpu(ip->flags);
  81. start = le32_to_cpu(ip->firstUnit);
  82. end = le32_to_cpu(ip->lastUnit);
  83. num = le32_to_cpu(ip->virtualUnits);
  84. if (start < nextunit) {
  85. printf("ERROR: Overlapping or misordered partitions!\n");
  86. }
  87. if (start > nextunit) {
  88. printf(" Unpartitioned space: %d bytes\n"
  89. " virtualUnits = %d\n"
  90. " firstUnit = %d\n"
  91. " lastUnit = %d\n",
  92. (start - nextunit) * unitsize, start - nextunit,
  93. nextunit, start - 1);
  94. }
  95. if (flags & INFTL_BINARY)
  96. printf(" Partition %d (BDK):", i+1);
  97. else
  98. printf(" Partition %d (BDTL):", i+1);
  99. printf(" %d bytes\n"
  100. " virtualUnits = %d\n"
  101. " firstUnit = %d\n"
  102. " lastUnit = %d\n"
  103. " flags = 0x%x\n"
  104. " spareUnits = %d\n",
  105. num * unitsize, num, start, end,
  106. le32_to_cpu(ip->flags), le32_to_cpu(ip->spareUnits));
  107. if (num > (1 + end - start)) {
  108. printf("ERROR: virtualUnits not consistent with first/lastUnit!\n");
  109. }
  110. end++;
  111. if (end > nextunit)
  112. nextunit = end;
  113. if (flags & INFTL_LAST)
  114. break;
  115. }
  116. if (i >= 4) {
  117. printf("Odd. Last partition was not marked with INFTL_LAST.\n");
  118. i--;
  119. }
  120. if ((i+1) != numpart) {
  121. printf("ERROR: Number of partitions != (NoOfBinaryPartitions + NoOfBDTLPartitions)\n");
  122. }
  123. if (nextunit > numunits) {
  124. printf("ERROR: Partitions appear to extend beyond end of device!\n");
  125. }
  126. if (nextunit < numunits) {
  127. printf(" Unpartitioned space: %d bytes\n"
  128. " virtualUnits = %d\n"
  129. " firstUnit = %d\n"
  130. " lastUnit = %d\n",
  131. (numunits - nextunit) * unitsize, numunits - nextunit,
  132. nextunit, numunits - 1);
  133. }
  134. }
  135. int main(int argc, char **argv)
  136. {
  137. int ret, i, mhblock, unitsize, block;
  138. unsigned int nblocks[4], npart;
  139. unsigned int totblocks;
  140. struct INFTLPartition *ip = NULL;
  141. unsigned char *oobbuf;
  142. struct mtd_oob_buf oob;
  143. char line[20];
  144. int mhoffs;
  145. struct INFTLMediaHeader *mh2;
  146. if (argc < 2) {
  147. printf(
  148. "Usage: %s <mtddevice> [<size1> [<size2> [<size3> [<size4]]]]\n"
  149. " Sizes are in device units (run with no sizes to show unitsize and current\n"
  150. " partitions). Last size = 0 means go to end of device.\n",
  151. PROGRAM_NAME);
  152. return 1;
  153. }
  154. npart = argc - 2;
  155. if (npart > 4) {
  156. printf("Max 4 partitions allowed.\n");
  157. return 1;
  158. }
  159. for (i = 0; i < npart; i++) {
  160. nblocks[i] = strtoul(argv[2+i], NULL, 0);
  161. if (i && !nblocks[i-1]) {
  162. printf("No sizes allowed after 0\n");
  163. return 1;
  164. }
  165. }
  166. // Open and size the device
  167. if ((fd = open(argv[1], O_RDWR)) < 0) {
  168. perror("Open flash device");
  169. return 1;
  170. }
  171. if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
  172. perror("ioctl(MEMGETINFO)");
  173. return 1;
  174. }
  175. printf("Device size is %d bytes. Erasesize is %d bytes.\n",
  176. meminfo.size, meminfo.erasesize);
  177. buf = malloc(meminfo.erasesize);
  178. oobbuf = malloc((meminfo.erasesize / meminfo.writesize) * meminfo.oobsize);
  179. if (!buf || !oobbuf) {
  180. printf("Can't malloc block buffer\n");
  181. return 1;
  182. }
  183. oob.length = meminfo.oobsize;
  184. mh = (struct INFTLMediaHeader *) buf;
  185. for (mhblock = 0; mhblock < MAXSCAN; mhblock++) {
  186. if ((ret = pread(fd, buf, meminfo.erasesize, mhblock * meminfo.erasesize)) < 0) {
  187. if (errno == EBADMSG) {
  188. printf("ECC error at eraseblock %d\n", mhblock);
  189. continue;
  190. }
  191. perror("Read eraseblock");
  192. return 1;
  193. }
  194. if (ret != meminfo.erasesize) {
  195. printf("Short read!\n");
  196. return 1;
  197. }
  198. if (!strcmp("BNAND", mh->bootRecordID)) break;
  199. }
  200. if (mhblock >= MAXSCAN) {
  201. printf("Unable to find INFTL Media Header\n");
  202. return 1;
  203. }
  204. printf("Found INFTL Media Header at block %d:\n", mhblock);
  205. mhoffs = mhblock * meminfo.erasesize;
  206. oob.ptr = oobbuf;
  207. oob.start = mhoffs;
  208. for (i = 0; i < meminfo.erasesize; i += meminfo.writesize) {
  209. if (ioctl(fd, MEMREADOOB, &oob)) {
  210. perror("ioctl(MEMREADOOB)");
  211. return 1;
  212. }
  213. oob.start += meminfo.writesize;
  214. oob.ptr += meminfo.oobsize;
  215. }
  216. show_header(mhoffs);
  217. if (!npart)
  218. return 0;
  219. printf("\n-------------------------------------------------------------------------\n");
  220. unitsize = meminfo.erasesize >> le32_to_cpu(mh->BlockMultiplierBits);
  221. totblocks = meminfo.size / unitsize;
  222. block = mhoffs / unitsize;
  223. block++;
  224. mh->NoOfBDTLPartitions = 0;
  225. mh->NoOfBinaryPartitions = npart;
  226. for (i = 0; i < npart; i++) {
  227. ip = &(mh->Partitions[i]);
  228. ip->firstUnit = cpu_to_le32(block);
  229. if (!nblocks[i])
  230. nblocks[i] = totblocks - block;
  231. ip->virtualUnits = cpu_to_le32(nblocks[i]);
  232. block += nblocks[i];
  233. ip->lastUnit = cpu_to_le32(block-1);
  234. ip->spareUnits = 0;
  235. ip->flags = cpu_to_le32(INFTL_BINARY);
  236. }
  237. if (block > totblocks) {
  238. printf("Requested partitions extend beyond end of device.\n");
  239. return 1;
  240. }
  241. ip->flags = cpu_to_le32(INFTL_BINARY | INFTL_LAST);
  242. /* update the spare as well */
  243. mh2 = (struct INFTLMediaHeader *) (buf + 4096);
  244. memcpy((void *) mh2, (void *) mh, sizeof(struct INFTLMediaHeader));
  245. printf("\nProposed new Media Header:\n");
  246. show_header(mhoffs);
  247. printf("\nReady to update device. Type 'yes' to proceed, anything else to abort: ");
  248. if (!fgets(line, sizeof(line), stdin)) {
  249. printf("Failed to retrieve input chars!\n");
  250. return 1;
  251. }
  252. if (strcmp("yes\n", line))
  253. return 0;
  254. printf("Updating MediaHeader...\n");
  255. erase.start = mhoffs;
  256. erase.length = meminfo.erasesize;
  257. if (ioctl(fd, MEMERASE, &erase)) {
  258. perror("ioctl(MEMERASE)");
  259. printf("Your MediaHeader may be hosed. UHOH!\n");
  260. return 1;
  261. }
  262. oob.ptr = oobbuf;
  263. oob.start = mhoffs;
  264. for (i = 0; i < meminfo.erasesize; i += meminfo.writesize) {
  265. memset(oob.ptr, 0xff, 6); // clear ECC.
  266. if (ioctl(fd, MEMWRITEOOB, &oob)) {
  267. perror("ioctl(MEMWRITEOOB)");
  268. printf("Your MediaHeader may be hosed. UHOH!\n");
  269. return 1;
  270. }
  271. if ((ret = pwrite(fd, buf, meminfo.writesize, oob.start)) < 0) {
  272. perror("Write page");
  273. printf("Your MediaHeader may be hosed. UHOH!\n");
  274. return 1;
  275. }
  276. if (ret != meminfo.writesize) {
  277. printf("Short write!\n");
  278. printf("Your MediaHeader may be hosed. UHOH!\n");
  279. return 1;
  280. }
  281. oob.start += meminfo.writesize;
  282. oob.ptr += meminfo.oobsize;
  283. buf += meminfo.writesize;
  284. }
  285. printf("Success. REBOOT or unload the diskonchip module to update partitions!\n");
  286. return 0;
  287. }