source: trunk/package/mtd/src/imagetag.c @ 28893

Last change on this file since 28893 was 28893, checked in by jogo, 5 years ago

target: linux: mtd: fix MTDREFRESH to an arbitrary high number

To make the ioctl number "stable", use an arbitrary high number to prevent
conflicts with new mtd ioctls that would push MTDREFRESH's number.

Also make mtd use the in-kernel mtd headers.

File size: 8.0 KB
Line 
1/*
2 * imagetag.c
3 *
4 * Copyright (C) 2005 Mike Baker
5 * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
6 * Copyrigth (C) 2010 Daniel Dickinson <openwrt@cshore.neomailbox.net>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21 */
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <stddef.h>
26#include <unistd.h>
27#include <fcntl.h>
28#include <sys/mman.h>
29#include <sys/stat.h>
30#include <string.h>
31#include <errno.h>
32
33#include <sys/ioctl.h>
34#include <mtd/mtd-user.h>
35#include "mtd.h"
36#include "crc32.h"
37#include "bcm_tag.h"
38
39ssize_t pread(int fd, void *buf, size_t count, off_t offset);
40ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
41
42#define CRC_START 0xFFFFFFFF
43
44static uint32_t strntoul(char *str, char **endptr, int base, size_t len) {
45  char *newstr;
46  uint32_t res = 0;
47
48  newstr = calloc(len + 1, sizeof(char));
49  if (newstr) {
50        strncpy(newstr, str, len); 
51        res = strtoul(newstr, endptr, base);
52        free(newstr);
53  }
54  return res;
55}
56
57uint32_t compute_crc32(uint32_t crc, off_t start, size_t compute_len, int fd)
58{
59        uint8_t readbuf[1024];
60        ssize_t res;
61        off_t offset = start;
62
63        /* Read a buffer's worth of bytes  */
64        while (fd && (compute_len >= sizeof(readbuf))) {
65                res = pread(fd, readbuf, sizeof(readbuf), offset);
66                crc = crc32(crc, readbuf, res);
67                compute_len = compute_len - res;
68                offset += res;
69        }
70
71        /* Less than buffer-size bytes remains, read compute_len bytes */
72        if (fd && (compute_len > 0)) {
73          res = pread(fd, readbuf, compute_len, offset);
74          crc = crc32(crc, readbuf, res);
75        }
76
77        return crc;
78}
79
80int
81trx_fixup(int fd, const char *name)
82{
83        struct mtd_info_user mtdInfo;
84        unsigned long len;
85        void *ptr, *scan;
86        int bfd;
87        struct bcm_tag *tag;
88        ssize_t res;
89        uint32_t cfelen, imagelen, imagestart, rootfslen;
90        uint32_t imagecrc, rootfscrc, headercrc;
91        uint32_t offset = 0;
92        cfelen = imagelen = imagestart = imagecrc = rootfscrc = headercrc = rootfslen = 0;
93
94
95        if (ioctl(fd, MEMGETINFO, &mtdInfo) < 0) {
96                fprintf(stderr, "Failed to get mtd info\n");
97                goto err;
98        }
99
100        len = mtdInfo.size;
101        if (mtdInfo.size <= 0) {
102                fprintf(stderr, "Invalid MTD device size\n");
103                goto err;
104        }
105
106        bfd = mtd_open(name, true);
107        ptr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, bfd, 0);
108        if (!ptr || (ptr == (void *) -1)) {
109                perror("mmap");
110                goto err1;
111        }
112
113        tag = (struct bcm_tag *) (ptr);
114
115        cfelen = strntoul(&tag->cfeLength[0], NULL, 10, IMAGE_LEN);
116        if (cfelen) {
117          fprintf(stderr, "Non-zero CFE length.  This is currently unsupported.\n");
118          exit(1);
119        }
120
121        headercrc = compute_crc32(CRC_START, offset, offsetof(struct bcm_tag, headerCRC), fd);
122        if (headercrc != *(uint32_t *)(&tag->headerCRC[0])) {
123                fprintf(stderr, "Tag verify failed.  This may not be a valid image.\n");
124                exit(1);
125        }
126
127        sprintf(&tag->flashRootLength[0], "%lu", 0);
128        strncpy(&tag->totalLength[0], &tag->kernelLength[0], IMAGE_LEN);
129
130        imagestart = sizeof(tag);
131        memcpy(&tag->imageCRC[0], &tag->kernelCRC[0], CRC_LEN);
132        memcpy(&tag->fskernelCRC[0], &tag->kernelCRC[0], CRC_LEN);
133        rootfscrc = CRC_START;
134        memcpy(&tag->rootfsCRC[0], &rootfscrc, sizeof(uint32_t));
135        headercrc = crc32(CRC_START, tag, offsetof(struct bcm_tag, headerCRC));
136        memcpy(&tag->headerCRC[0], &headercrc, sizeof(uint32_t));
137
138        msync(ptr, sizeof(struct bcm_tag), MS_SYNC|MS_INVALIDATE);
139        munmap(ptr, len);
140        close(bfd);
141        return 0;
142
143err1:
144        close(bfd);
145err:
146        fprintf(stderr, "Error fixing up imagetag header\n");
147        return -1;
148}
149
150
151int
152trx_check(int imagefd, const char *mtd, char *buf, int *len)
153{
154    struct bcm_tag *tag = (const struct bcm_tag *) buf;
155        int fd;
156        uint32_t headerCRC;
157        uint32_t imageLen;
158
159        if (strcmp(mtd, "linux") != 0)
160                return 1;
161
162        *len = read(imagefd, buf, sizeof(struct bcm_tag));
163        if (*len < sizeof(struct bcm_tag)) {
164                fprintf(stdout, "Could not get image header, file too small (%d bytes)\n", *len);
165                return 0;
166        }
167        headerCRC = crc32buf(buf, offsetof(struct bcm_tag, headerCRC));
168        if (*(uint32_t *)(&tag->headerCRC[0]) != headerCRC) {
169 
170          if (quiet < 2) {
171                fprintf(stderr, "Bad header CRC got %08lx, calculated %08lx\n",
172                                *(uint32_t *)(&tag->headerCRC[0]), headerCRC);
173                fprintf(stderr, "This is not the correct file format; refusing to flash.\n"
174                                "Please specify the correct file or use -f to force.\n");
175          }
176          return 0;
177        }
178
179        /* check if image fits to mtd device */
180        fd = mtd_check_open(mtd);
181        if(fd < 0) {
182                fprintf(stderr, "Could not open mtd device: %s\n", mtd);
183                exit(1);
184        }
185
186        imageLen = strntoul(&tag->totalLength[0], NULL, 10, IMAGE_LEN);
187       
188        if(mtdsize < imageLen) {
189                fprintf(stderr, "Image too big for partition: %s\n", mtd);
190                close(fd);
191                return 0;
192        }
193
194        close(fd);
195        return 1;
196}
197
198int
199mtd_fixtrx(const char *mtd, size_t offset)
200{
201        int fd;
202        struct bcm_tag *tag;
203        char *buf;
204        ssize_t res;
205        size_t block_offset;
206        uint32_t cfelen, imagelen, imagestart, rootfslen;
207        uint32_t imagecrc, rootfscrc, headercrc;
208        cfelen = imagelen = imagestart = imagecrc = rootfscrc = headercrc = rootfslen = 0;
209
210        if (quiet < 2)
211                fprintf(stderr, "Trying to fix trx header in %s at 0x%x...\n", mtd, offset);
212
213        block_offset = offset & ~(erasesize - 1);
214        offset -= block_offset;
215
216        fd = mtd_check_open(mtd);
217        if(fd < 0) {
218                fprintf(stderr, "Could not open mtd device: %s\n", mtd);
219                exit(1);
220        }
221
222        if (block_offset + erasesize > mtdsize) {
223                fprintf(stderr, "Offset too large, device size 0x%x\n", mtdsize);
224                exit(1);
225        }
226
227        buf = malloc(erasesize);
228        if (!buf) {
229                perror("malloc");
230                exit(1);
231        }
232
233        res = pread(fd, buf, erasesize, block_offset);
234        if (res != erasesize) {
235                perror("pread");
236                exit(1);
237        }
238
239        tag = (struct bcm_tag *) (buf + offset);
240
241        cfelen = strntoul(&tag->cfeLength[0], NULL, 10, IMAGE_LEN);
242        if (cfelen) {
243          fprintf(stderr, "Non-zero CFE length.  This is currently unsupported.\n");
244          exit(1);
245        }
246
247        if (quiet < 2) {
248          fprintf(stderr, "Verifying we actually have an imagetag.\n");
249        }
250
251        headercrc = compute_crc32(CRC_START, offset, offsetof(struct bcm_tag, headerCRC), fd);
252        if (headercrc != *(uint32_t *)(&tag->headerCRC[0])) {
253                fprintf(stderr, "Tag verify failed.  This may not be a valid image.\n");
254                exit(1);
255        }
256
257        if (quiet < 2) {
258          fprintf(stderr, "Checking current fixed status.\n");
259        }
260
261        rootfslen = strntoul(&tag->flashRootLength[0], NULL, 10, IMAGE_LEN);
262        if (rootfslen == 0) {
263          if (quiet < 2) 
264                fprintf(stderr, "Header already fixed, exiting\n");
265          close(fd);
266          return 0;
267        }
268
269        if (quiet < 2) {
270          fprintf(stderr, "Setting root length to 0.\n");
271        }
272
273        sprintf(&tag->flashRootLength[0], "%lu", 0);
274        strncpy(&tag->totalLength[0], &tag->kernelLength[0], IMAGE_LEN);
275
276        if (quiet < 2) {
277          fprintf(stderr, "Recalculating CRCs.\n");
278        }
279
280        imagestart = sizeof(tag);
281        memcpy(&tag->imageCRC[0], &tag->kernelCRC[0], CRC_LEN);
282        memcpy(&tag->fskernelCRC[0], &tag->kernelCRC[0], CRC_LEN);
283        rootfscrc = CRC_START;
284        memcpy(&tag->rootfsCRC[0], &rootfscrc, sizeof(uint32_t));
285        headercrc = crc32(CRC_START, tag, offsetof(struct bcm_tag, headerCRC));
286        memcpy(&tag->headerCRC[0], &headercrc, sizeof(uint32_t));
287
288        if (quiet < 2) {
289          fprintf(stderr, "Erasing imagetag block\n");
290        }
291
292        if (mtd_erase_block(fd, block_offset)) {
293                fprintf(stderr, "Can't erase block at 0x%x (%s)\n", block_offset, strerror(errno));
294                exit(1);
295        }
296
297        if (quiet < 2) {
298          fprintf(stderr, "New image crc32: 0x%x, rewriting block\n", 
299                          *(uint32_t *)(&tag->imageCRC[0]));
300          fprintf(stderr, "New header crc32: 0x%x, rewriting block\n", headercrc); 
301        }
302
303        if (pwrite(fd, buf, erasesize, block_offset) != erasesize) {
304                fprintf(stderr, "Error writing block (%s)\n", strerror(errno));
305                exit(1);
306        }
307
308        if (quiet < 2)
309                fprintf(stderr, "Done.\n");
310
311        close (fd);
312        sync();
313        return 0;
314
315}
Note: See TracBrowser for help on using the repository browser.