ramips: add support for TP-Link RE305 v3
[project/firmware-utils.git] / src / mkedimaximg.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2011 Vasilis Tsiligiannis <b_tsiligiannis@silverton.gr>
4 */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <byteswap.h>
10 #include <libgen.h>
11 #include <getopt.h>
12 #include <errno.h>
13 #include <sys/stat.h>
14 #include <endian.h> /* for __BYTE_ORDER */
15
16 #define FALSE 0
17 #define TRUE 1
18
19 #if (__BYTE_ORDER == __LITTLE_ENDIAN)
20 # define HOST_TO_LE16(x) (x)
21 # define HOST_TO_LE32(x) (x)
22 # define HOST_TO_BE16(x) bswap_16(x)
23 # define HOST_TO_BE32(x) bswap_32(x)
24 #else
25 # define HOST_TO_LE16(x) bswap_16(x)
26 # define HOST_TO_LE32(x) bswap_32(x)
27 # define HOST_TO_BE16(x) (x)
28 # define HOST_TO_BE32(x) (x)
29 #endif
30
31 struct header
32 {
33 unsigned char sign[4];
34 unsigned int start;
35 unsigned int flash;
36 unsigned char model[4];
37 unsigned int size;
38 } __attribute__ ((packed));
39
40 struct finfo
41 {
42 char *name;
43 off_t size;
44 };
45
46 struct buf
47 {
48 char *start;
49 size_t size;
50 };
51
52 static char *progname;
53 static int force_be = FALSE;
54
55 static void usage(int status)
56 {
57 FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
58
59 fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
60 fprintf(stream,
61 "\n"
62 "Options:\n"
63 " -s <sig> set image signature to <sig>\n"
64 " -m <model> set model to <model>\n"
65 " -i <file> read input from file <file>\n"
66 " -o <file> write output to file <file>\n"
67 " -f <flash> set flash address to <flash>\n"
68 " -S <start> set start address to <start>\n"
69 " -b big-endianness mode\n");
70
71 exit(status);
72 }
73
74 static int strtou32(char *arg, unsigned int *val)
75 {
76 char *endptr = NULL;
77
78 errno = 0;
79 *val = strtoul(arg, &endptr, 0);
80 if (errno || (endptr == arg) || (*endptr && (endptr != NULL))) {
81 return EXIT_SUCCESS;
82 }
83
84 return EXIT_FAILURE;
85 }
86
87 static unsigned short fwcsum (struct buf *buf) {
88 int i;
89 unsigned short ret = 0;
90
91 for (i = 0; i < buf->size / 2; i++) {
92 if (force_be == FALSE)
93 ret -= ((unsigned short *) buf->start)[i];
94 else
95 ret -= HOST_TO_BE16(((unsigned short *) buf->start)[i]);
96 }
97
98 return ret;
99 }
100
101 static int fwread(struct finfo *finfo, struct buf *buf)
102 {
103 FILE *f;
104
105 f = fopen(finfo->name, "r");
106 if (!f) {
107 fprintf(stderr, "could not open \"%s\" for reading\n", finfo->name);
108 usage(EXIT_FAILURE);
109 }
110
111 buf->size = fread(buf->start, 1, finfo->size, f);
112 if (buf->size != finfo->size) {
113 fprintf(stderr, "unable to read from file \"%s\"\n", finfo->name);
114 usage(EXIT_FAILURE);
115 }
116
117 fclose(f);
118
119 return EXIT_SUCCESS;
120 }
121
122 static int fwwrite(struct finfo *finfo, struct buf *buf)
123 {
124 FILE *f;
125
126 f = fopen(finfo->name, "w");
127 if (!f) {
128 fprintf(stderr, "could not open \"%s\" for writing\n", finfo->name);
129 usage(EXIT_FAILURE);
130 }
131
132 buf->size = fwrite(buf->start, 1, finfo->size, f);
133 if (buf->size != finfo->size) {
134 fprintf(stderr, "unable to write to file \"%s\"\n", finfo->name);
135 usage(EXIT_FAILURE);
136 }
137
138 fclose(f);
139
140 return EXIT_SUCCESS;
141 }
142
143 int main(int argc, char **argv)
144 {
145 struct stat st;
146 struct header header;
147 struct buf ibuf, obuf;
148 struct finfo ifinfo, ofinfo;
149 unsigned short csum;
150 int c;
151
152 ifinfo.name = ofinfo.name = NULL;
153 header.flash = header.size = header.start = 0;
154 progname = basename(argv[0]);
155
156 while((c = getopt(argc, argv, "i:o:m:s:f:S:h:b")) != -1) {
157 switch (c) {
158 case 'i':
159 ifinfo.name = optarg;
160 break;
161 case 'o':
162 ofinfo.name = optarg;
163 break;
164 case 'm':
165 if (strlen(optarg) != 4) {
166 fprintf(stderr, "model must be 4 characters long\n");
167 usage(EXIT_FAILURE);
168 }
169 memcpy(header.model, optarg, 4);
170 break;
171 case 's':
172 if (strlen(optarg) != 4) {
173 fprintf(stderr, "signature must be 4 characters long\n");
174 usage(EXIT_FAILURE);
175 }
176 memcpy(header.sign, optarg, 4);
177 break;
178 case 'h':
179 usage(EXIT_SUCCESS);
180 break;
181 case 'f':
182 if (!strtou32(optarg, &header.flash)) {
183 fprintf(stderr, "invalid flash address specified\n");
184 usage(EXIT_FAILURE);
185 }
186 break;
187 case 'S':
188 if (!strtou32(optarg, &header.start)) {
189 fprintf(stderr, "invalid start address specified\n");
190 usage(EXIT_FAILURE);
191 }
192 break;
193 case 'b':
194 force_be = TRUE;
195 break;
196 default:
197 usage(EXIT_FAILURE);
198 break;
199 }
200 }
201
202 if (ifinfo.name == NULL) {
203 fprintf(stderr, "no input file specified\n");
204 usage(EXIT_FAILURE);
205 }
206
207 if (ofinfo.name == NULL) {
208 fprintf(stderr, "no output file specified\n");
209 usage(EXIT_FAILURE);
210 }
211
212 if (stat(ifinfo.name, &st)) {
213 fprintf(stderr, "stat failed on %s\n", ifinfo.name);
214 usage(EXIT_FAILURE);
215 }
216
217 if (header.sign == NULL) {
218 fprintf(stderr, "no signature specified\n");
219 usage(EXIT_FAILURE);
220 }
221
222 if (header.model == NULL) {
223 fprintf(stderr, "no model specified\n");
224 usage(EXIT_FAILURE);
225 }
226
227 if (!header.flash) {
228 fprintf(stderr, "no flash address specified\n");
229 usage(EXIT_FAILURE);
230 }
231
232 if (!header.start) {
233 fprintf(stderr, "no start address specified\n");
234 usage(EXIT_FAILURE);
235 }
236
237 ifinfo.size = st.st_size;
238
239 obuf.size = ifinfo.size + sizeof(struct header) + sizeof(unsigned short);
240 if (obuf.size % sizeof(unsigned short))
241 obuf.size++;
242
243 obuf.start = malloc(obuf.size);
244 if (!obuf.start) {
245 fprintf(stderr, "no memory for buffer\n");
246 usage(EXIT_FAILURE);
247 }
248 memset(obuf.start, 0, obuf.size);
249
250 ibuf.size = ifinfo.size;
251 ibuf.start = obuf.start + sizeof(struct header);
252
253 if (fwread(&ifinfo, &ibuf))
254 usage(EXIT_FAILURE);
255
256 if (force_be == FALSE) {
257 header.flash = HOST_TO_LE32(header.flash);
258 header.size = HOST_TO_LE32(obuf.size - sizeof(struct header));
259 header.start = HOST_TO_LE32(header.start);
260 } else {
261 header.flash = HOST_TO_BE32(header.flash);
262 header.size = HOST_TO_BE32(obuf.size - sizeof(struct header));
263 header.start = HOST_TO_BE32(header.start);
264 }
265
266 memcpy (obuf.start, &header, sizeof(struct header));
267
268 if (force_be == FALSE)
269 csum = HOST_TO_LE16(fwcsum(&ibuf));
270 else
271 csum = HOST_TO_BE16(fwcsum(&ibuf));
272
273 memcpy(obuf.start + obuf.size - sizeof(unsigned short),
274 &csum, sizeof(unsigned short));
275
276 ofinfo.size = obuf.size;
277
278 if (fwwrite(&ofinfo, &obuf))
279 usage(EXIT_FAILURE);
280
281 return EXIT_SUCCESS;
282 }