4 * Copyright (C) 2005 Mike Baker
5 * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
33 #include <sys/ioctl.h>
34 #include <mtd/mtd-user.h>
38 #define TRX_MAGIC 0x30524448 /* "HDR0" */
39 #define TRX_CRC32_DATA_OFFSET 12 /* First 12 bytes are not covered by CRC32 */
40 #define TRX_CRC32_DATA_SIZE 16
42 uint32_t magic
; /* "HDR0" */
43 uint32_t len
; /* Length of file including header */
44 uint32_t crc32
; /* 32-bit CRC from flag_version to end of file */
45 uint32_t flag_version
; /* 0:15 flags, 16:31 version */
46 uint32_t offsets
[3]; /* Offsets of partitions from start of header */
52 (void) (&_x == &_y); \
55 #if __BYTE_ORDER == __BIG_ENDIAN
56 #define STORE32_LE(X) ((((X) & 0x000000FF) << 24) | (((X) & 0x0000FF00) << 8) | (((X) & 0x00FF0000) >> 8) | (((X) & 0xFF000000) >> 24))
57 #elif __BYTE_ORDER == __LITTLE_ENDIAN
58 #define STORE32_LE(X) (X)
60 #error unknown endianness!
63 ssize_t
pread(int fd
, void *buf
, size_t count
, off_t offset
);
64 ssize_t
pwrite(int fd
, const void *buf
, size_t count
, off_t offset
);
67 trx_fixup(int fd
, const char *name
)
69 struct mtd_info_user mtdInfo
;
71 struct trx_header
*trx
;
75 if (ioctl(fd
, MEMGETINFO
, &mtdInfo
) < 0) {
76 fprintf(stderr
, "Failed to get mtd info\n");
81 if (mtdInfo
.size
<= 0) {
82 fprintf(stderr
, "Invalid MTD device size\n");
86 bfd
= mtd_open(name
, true);
87 ptr
= mmap(NULL
, len
, PROT_READ
|PROT_WRITE
, MAP_SHARED
, bfd
, 0);
88 if (!ptr
|| (ptr
== (void *) -1)) {
90 fprintf(stderr
, "Mapping the TRX header failed\n");
95 if (trx
->magic
!= TRX_MAGIC
) {
96 fprintf(stderr
, "TRX header not found\n");
100 scan
= ptr
+ offsetof(struct trx_header
, flag_version
);
101 trx
->crc32
= crc32buf(scan
, trx
->len
- (scan
- ptr
));
102 msync(ptr
, sizeof(struct trx_header
), MS_SYNC
|MS_INVALIDATE
);
113 #ifndef target_ar71xx
115 trx_check(int imagefd
, const char *mtd
, char *buf
, int *len
)
117 const struct trx_header
*trx
= (const struct trx_header
*) buf
;
120 if (strcmp(mtd
, "firmware") != 0)
124 *len
+= read(imagefd
, buf
+ *len
, 32 - *len
);
126 fprintf(stdout
, "Could not get image header, file too small (%d bytes)\n", *len
);
131 if (trx
->magic
!= TRX_MAGIC
|| trx
->len
< sizeof(struct trx_header
)) {
133 fprintf(stderr
, "Bad trx header\n");
134 fprintf(stderr
, "This is not the correct file format; refusing to flash.\n"
135 "Please specify the correct file or use -f to force.\n");
140 /* check if image fits to mtd device */
141 fd
= mtd_check_open(mtd
);
143 fprintf(stderr
, "Could not open mtd device: %s\n", mtd
);
147 if(mtdsize
< trx
->len
) {
148 fprintf(stderr
, "Image too big for partition: %s\n", mtd
);
159 mtd_fixtrx(const char *mtd
, size_t offset
, size_t data_size
)
163 struct trx_header
*trx
;
170 fprintf(stderr
, "Trying to fix trx header in %s at 0x%x...\n", mtd
, offset
);
172 fd
= mtd_check_open(mtd
);
174 fprintf(stderr
, "Could not open mtd device: %s\n", mtd
);
178 data_offset
= offset
+ TRX_CRC32_DATA_OFFSET
;
180 data_size
+= TRX_CRC32_DATA_SIZE
;
182 data_size
= erasesize
- TRX_CRC32_DATA_OFFSET
;
184 block_offset
= offset
& ~(erasesize
- 1);
185 offset
-= block_offset
;
187 if (data_offset
+ data_size
> mtdsize
) {
188 fprintf(stderr
, "Offset too large, device size 0x%x\n", mtdsize
);
192 first_block
= malloc(erasesize
);
198 res
= pread(fd
, first_block
, erasesize
, block_offset
);
199 if (res
!= erasesize
) {
204 trx
= (struct trx_header
*)(first_block
+ offset
);
205 if (trx
->magic
!= STORE32_LE(0x30524448)) {
206 fprintf(stderr
, "No trx magic found\n");
210 buf
= malloc(data_size
);
218 size_t read_block_offset
= data_offset
& ~(erasesize
- 1);
221 read_chunk
= erasesize
- (data_offset
& (erasesize
- 1));
222 read_chunk
= min(read_chunk
, data_size
);
224 /* Read from good blocks only to match CFE behavior */
225 if (!mtd_block_is_bad(fd
, read_block_offset
)) {
226 res
= pread(fd
, to
, read_chunk
, data_offset
);
227 if (res
!= read_chunk
) {
234 data_offset
+= read_chunk
;
235 data_size
-= read_chunk
;
237 data_size
= to
- buf
;
239 if (trx
->len
== STORE32_LE(data_size
+ TRX_CRC32_DATA_OFFSET
) &&
240 trx
->crc32
== STORE32_LE(crc32buf(buf
, data_size
))) {
242 fprintf(stderr
, "Header already fixed, exiting\n");
247 trx
->len
= STORE32_LE(data_size
+ offsetof(struct trx_header
, flag_version
));
249 trx
->crc32
= STORE32_LE(crc32buf(buf
, data_size
));
250 if (mtd_erase_block(fd
, block_offset
)) {
251 fprintf(stderr
, "Can't erease block at 0x%x (%s)\n", block_offset
, strerror(errno
));
256 fprintf(stderr
, "New crc32: 0x%x, rewriting block\n", trx
->crc32
);
258 if (pwrite(fd
, first_block
, erasesize
, block_offset
) != erasesize
) {
259 fprintf(stderr
, "Error writing block (%s)\n", strerror(errno
));
264 fprintf(stderr
, "Done.\n");