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