2 * docfdisk.c: Modify INFTL partition tables
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.
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.
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
19 #define PROGRAM_NAME "docfdisk"
21 #define _XOPEN_SOURCE 500 /* for pread/pwrite */
28 #include <sys/ioctl.h>
29 #include <sys/mount.h>
33 #include <asm/types.h>
34 #include <mtd/mtd-user.h>
35 #include <mtd/inftl-user.h>
43 struct INFTLMediaHeader *mh;
47 void show_header(int mhoffs) {
48 int i, unitsize, numunits, bmbits, numpart;
49 int start, end, num, nextunit;
51 struct INFTLPartition *ip;
53 bmbits = le32_to_cpu(mh->BlockMultiplierBits);
54 printf(" bootRecordID = %s\n"
55 " NoOfBootImageBlocks = %d\n"
56 " NoOfBinaryPartitions = %d\n"
57 " NoOfBDTLPartitions = %d\n"
58 " BlockMultiplierBits = %d\n"
60 " OsakVersion = %d.%d.%d.%d\n"
61 " PercentUsed = %d\n",
62 mh->bootRecordID, le32_to_cpu(mh->NoOfBootImageBlocks),
63 le32_to_cpu(mh->NoOfBinaryPartitions),
64 le32_to_cpu(mh->NoOfBDTLPartitions),
66 le32_to_cpu(mh->FormatFlags),
67 ((unsigned char *) &mh->OsakVersion)[0] & 0xf,
68 ((unsigned char *) &mh->OsakVersion)[1] & 0xf,
69 ((unsigned char *) &mh->OsakVersion)[2] & 0xf,
70 ((unsigned char *) &mh->OsakVersion)[3] & 0xf,
71 le32_to_cpu(mh->PercentUsed));
73 numpart = le32_to_cpu(mh->NoOfBinaryPartitions) +
74 le32_to_cpu(mh->NoOfBDTLPartitions);
75 unitsize = meminfo.erasesize >> bmbits;
76 numunits = meminfo.size / unitsize;
77 nextunit = mhoffs / unitsize;
79 printf("Unitsize is %d bytes. Device has %d units.\n",
81 if (numunits > 32768) {
82 printf("WARNING: More than 32768 units! Unexpectedly small BlockMultiplierBits.\n");
84 if (bmbits && (numunits <= 16384)) {
85 printf("NOTICE: Unexpectedly large BlockMultiplierBits.\n");
87 for (i = 0; i < 4; i++) {
88 ip = &(mh->Partitions[i]);
89 flags = le32_to_cpu(ip->flags);
90 start = le32_to_cpu(ip->firstUnit);
91 end = le32_to_cpu(ip->lastUnit);
92 num = le32_to_cpu(ip->virtualUnits);
93 if (start < nextunit) {
94 printf("ERROR: Overlapping or misordered partitions!\n");
96 if (start > nextunit) {
97 printf(" Unpartitioned space: %d bytes\n"
98 " virtualUnits = %d\n"
101 (start - nextunit) * unitsize, start - nextunit,
102 nextunit, start - 1);
104 if (flags & INFTL_BINARY)
105 printf(" Partition %d (BDK):", i+1);
107 printf(" Partition %d (BDTL):", i+1);
109 " virtualUnits = %d\n"
113 " spareUnits = %d\n",
114 num * unitsize, num, start, end,
115 le32_to_cpu(ip->flags), le32_to_cpu(ip->spareUnits));
116 if (num > (1 + end - start)) {
117 printf("ERROR: virtualUnits not consistent with first/lastUnit!\n");
122 if (flags & INFTL_LAST)
126 printf("Odd. Last partition was not marked with INFTL_LAST.\n");
129 if ((i+1) != numpart) {
130 printf("ERROR: Number of partitions != (NoOfBinaryPartitions + NoOfBDTLPartitions)\n");
132 if (nextunit > numunits) {
133 printf("ERROR: Partitions appear to extend beyond end of device!\n");
135 if (nextunit < numunits) {
136 printf(" Unpartitioned space: %d bytes\n"
137 " virtualUnits = %d\n"
140 (numunits - nextunit) * unitsize, numunits - nextunit,
141 nextunit, numunits - 1);
146 int main(int argc, char **argv)
148 int ret, i, mhblock, unitsize, block;
149 unsigned int nblocks[4], npart;
150 unsigned int totblocks;
151 struct INFTLPartition *ip;
152 unsigned char *oobbuf;
153 struct mtd_oob_buf oob;
156 struct INFTLMediaHeader *mh2;
160 "Usage: %s <mtddevice> [<size1> [<size2> [<size3> [<size4]]]]\n"
161 " Sizes are in device units (run with no sizes to show unitsize and current\n"
162 " partitions). Last size = 0 means go to end of device.\n",
169 printf("Max 4 partitions allowed.\n");
173 for (i = 0; i < npart; i++) {
174 nblocks[i] = strtoul(argv[2+i], NULL, 0);
175 if (i && !nblocks[i-1]) {
176 printf("No sizes allowed after 0\n");
181 // Open and size the device
182 if ((fd = open(argv[1], O_RDWR)) < 0) {
183 perror("Open flash device");
187 if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
188 perror("ioctl(MEMGETINFO)");
192 printf("Device size is %d bytes. Erasesize is %d bytes.\n",
193 meminfo.size, meminfo.erasesize);
195 buf = malloc(meminfo.erasesize);
196 oobbuf = malloc((meminfo.erasesize / meminfo.writesize) * meminfo.oobsize);
197 if (!buf || !oobbuf) {
198 printf("Can't malloc block buffer\n");
201 oob.length = meminfo.oobsize;
203 mh = (struct INFTLMediaHeader *) buf;
205 for (mhblock = 0; mhblock < MAXSCAN; mhblock++) {
206 if ((ret = pread(fd, buf, meminfo.erasesize, mhblock * meminfo.erasesize)) < 0) {
207 if (errno == EBADMSG) {
208 printf("ECC error at eraseblock %d\n", mhblock);
211 perror("Read eraseblock");
214 if (ret != meminfo.erasesize) {
215 printf("Short read!\n");
218 if (!strcmp("BNAND", mh->bootRecordID)) break;
220 if (mhblock >= MAXSCAN) {
221 printf("Unable to find INFTL Media Header\n");
224 printf("Found INFTL Media Header at block %d:\n", mhblock);
225 mhoffs = mhblock * meminfo.erasesize;
229 for (i = 0; i < meminfo.erasesize; i += meminfo.writesize) {
230 if (ioctl(fd, MEMREADOOB, &oob)) {
231 perror("ioctl(MEMREADOOB)");
234 oob.start += meminfo.writesize;
235 oob.ptr += meminfo.oobsize;
244 "-------------------------------------------------------------------------\n");
246 unitsize = meminfo.erasesize >> le32_to_cpu(mh->BlockMultiplierBits);
247 totblocks = meminfo.size / unitsize;
248 block = mhoffs / unitsize;
251 mh->NoOfBDTLPartitions = 0;
252 mh->NoOfBinaryPartitions = npart;
254 for (i = 0; i < npart; i++) {
255 ip = &(mh->Partitions[i]);
256 ip->firstUnit = cpu_to_le32(block);
258 nblocks[i] = totblocks - block;
259 ip->virtualUnits = cpu_to_le32(nblocks[i]);
261 ip->lastUnit = cpu_to_le32(block-1);
263 ip->flags = cpu_to_le32(INFTL_BINARY);
265 if (block > totblocks) {
266 printf("Requested partitions extend beyond end of device.\n");
269 ip->flags = cpu_to_le32(INFTL_BINARY | INFTL_LAST);
271 /* update the spare as well */
272 mh2 = (struct INFTLMediaHeader *) (buf + 4096);
273 memcpy((void *) mh2, (void *) mh, sizeof(struct INFTLMediaHeader));
275 printf("\nProposed new Media Header:\n");
278 printf("\nReady to update device. Type 'yes' to proceed, anything else to abort: ");
279 fgets(line, sizeof(line), stdin);
280 if (strcmp("yes\n", line))
282 printf("Updating MediaHeader...\n");
284 erase.start = mhoffs;
285 erase.length = meminfo.erasesize;
286 if (ioctl(fd, MEMERASE, &erase)) {
287 perror("ioctl(MEMERASE)");
288 printf("Your MediaHeader may be hosed. UHOH!\n");
294 for (i = 0; i < meminfo.erasesize; i += meminfo.writesize) {
295 memset(oob.ptr, 0xff, 6); // clear ECC.
296 if (ioctl(fd, MEMWRITEOOB, &oob)) {
297 perror("ioctl(MEMWRITEOOB)");
298 printf("Your MediaHeader may be hosed. UHOH!\n");
301 if ((ret = pwrite(fd, buf, meminfo.writesize, oob.start)) < 0) {
302 perror("Write page");
303 printf("Your MediaHeader may be hosed. UHOH!\n");
306 if (ret != meminfo.writesize) {
307 printf("Short write!\n");
308 printf("Your MediaHeader may be hosed. UHOH!\n");
312 oob.start += meminfo.writesize;
313 oob.ptr += meminfo.oobsize;
314 buf += meminfo.writesize;
317 printf("Success. REBOOT or unload the diskonchip module to update partitions!\n");