1 /*
2  * Copyright (C) 2011 Vasilis Tsiligiannis <b_tsiligiannis@silverton.gr>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  */
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <libgen.h>
15 #include <getopt.h>
16 #include <errno.h>
17 #include <sys/stat.h>
18 #include <sys/endian.h>	/* for __BYTE_ORDER */
19 
20 #include "freebsd.h"
21 
22 #if (__BYTE_ORDER == __LITTLE_ENDIAN)
23 #  define HOST_TO_LE16(x)	(x)
24 #  define HOST_TO_LE32(x)	(x)
25 #else
26 #  define HOST_TO_LE16(x)	bswap_16(x)
27 #  define HOST_TO_LE32(x)	bswap_32(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 
usage(int status)53 static void usage(int status)
54 {
55     FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
56 
57     fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
58     fprintf(stream,
59 	    "\n"
60 	    "Options:\n"
61 	    "  -s <sig>        set image signature to <sig>\n"
62 	    "  -m <model>      set model to <model>\n"
63 	    "  -i <file>       read input from file <file>\n"
64 	    "  -o <file>       write output to file <file>\n"
65 	    "  -f <flash>      set flash address to <flash>\n"
66 	    "  -S <start>      set start address to <start>\n");
67 
68     exit(status);
69 }
70 
strtou32(char * arg,unsigned int * val)71 static int strtou32(char *arg, unsigned int *val)
72 {
73     char *endptr = NULL;
74 
75     errno = 0;
76     *val = strtoul(arg, &endptr, 0);
77     if (errno || (endptr == arg) || (*endptr && (endptr != NULL))) {
78 	return EXIT_SUCCESS;
79     }
80 
81     return EXIT_FAILURE;
82 }
83 
fwcsum(struct buf * buf)84 static unsigned short fwcsum (struct buf *buf) {
85     int i;
86     unsigned short ret = 0;
87 
88     for (i = 0; i < buf->size / 2; i++)
89 	ret -= ((unsigned short *) buf->start)[i];
90 
91     return ret;
92 }
93 
fwread(struct finfo * finfo,struct buf * buf)94 static int fwread(struct finfo *finfo, struct buf *buf)
95 {
96     FILE *f;
97 
98     f = fopen(finfo->name, "r");
99     if (!f) {
100 	fprintf(stderr, "could not open \"%s\" for reading\n", finfo->name);
101 	usage(EXIT_FAILURE);
102     }
103 
104     buf->size = fread(buf->start, 1, finfo->size, f);
105     if (buf->size != finfo->size) {
106 	fprintf(stderr, "unable to read from file \"%s\"\n", finfo->name);
107 	usage(EXIT_FAILURE);
108     }
109 
110     fclose(f);
111 
112     return EXIT_SUCCESS;
113 }
114 
fwwrite(struct finfo * finfo,struct buf * buf)115 static int fwwrite(struct finfo *finfo, struct buf *buf)
116 {
117     FILE *f;
118 
119     f = fopen(finfo->name, "w");
120     if (!f) {
121 	fprintf(stderr, "could not open \"%s\" for writing\n", finfo->name);
122 	usage(EXIT_FAILURE);
123     }
124 
125     buf->size = fwrite(buf->start, 1, finfo->size, f);
126     if (buf->size != finfo->size) {
127 	fprintf(stderr, "unable to write to file \"%s\"\n", finfo->name);
128 	usage(EXIT_FAILURE);
129     }
130 
131     fclose(f);
132 
133     return EXIT_SUCCESS;
134 }
135 
main(int argc,char ** argv)136 int main(int argc, char **argv)
137 {
138     struct stat st;
139     struct header header;
140     struct buf ibuf, obuf;
141     struct finfo ifinfo, ofinfo;
142     unsigned short csum;
143     int c;
144 
145     ifinfo.name = ofinfo.name = NULL;
146     header.flash = header.size = header.start = 0;
147     progname = basename(argv[0]);
148 
149     while((c = getopt(argc, argv, "i:o:m:s:f:S:h")) != -1) {
150 	switch (c) {
151 	case 'i':
152 	    ifinfo.name = optarg;
153 	    break;
154 	case 'o':
155 	    ofinfo.name = optarg;
156 	    break;
157 	case 'm':
158 	    if (strlen(optarg) != 4) {
159 		fprintf(stderr, "model must be 4 characters long\n");
160 		usage(EXIT_FAILURE);
161 	    }
162 	    memcpy(header.model, optarg, 4);
163 	    break;
164 	case 's':
165 	    if (strlen(optarg) != 4) {
166 		fprintf(stderr, "signature must be 4 characters long\n");
167 		usage(EXIT_FAILURE);
168 	    }
169 	    memcpy(header.sign, optarg, 4);
170 	    break;
171 	case 'h':
172 	    usage(EXIT_SUCCESS);
173 	    break;
174 	case 'f':
175 	    if (!strtou32(optarg, &header.flash)) {
176 		fprintf(stderr, "invalid flash address specified\n");
177 		usage(EXIT_FAILURE);
178 	    }
179 	    break;
180 	case 'S':
181 	    if (!strtou32(optarg, &header.start)) {
182 		fprintf(stderr, "invalid start address specified\n");
183 		usage(EXIT_FAILURE);
184 	    }
185 	    break;
186 	default:
187 	    usage(EXIT_FAILURE);
188 	    break;
189 	}
190     }
191 
192     if (ifinfo.name == NULL) {
193 	fprintf(stderr, "no input file specified\n");
194 	usage(EXIT_FAILURE);
195     }
196 
197     if (ofinfo.name == NULL) {
198 	fprintf(stderr, "no output file specified\n");
199 	usage(EXIT_FAILURE);
200     }
201 
202     if (stat(ifinfo.name, &st)) {
203 	fprintf(stderr, "stat failed on %s\n", ifinfo.name);
204 	usage(EXIT_FAILURE);
205     }
206 
207     if (header.sign == NULL) {
208 	fprintf(stderr, "no signature specified\n");
209 	usage(EXIT_FAILURE);
210     }
211 
212     if (header.model == NULL) {
213 	fprintf(stderr, "no model specified\n");
214 	usage(EXIT_FAILURE);
215     }
216 
217     if (!header.flash) {
218 	fprintf(stderr, "no flash address specified\n");
219 	usage(EXIT_FAILURE);
220     }
221 
222     if (!header.start) {
223 	fprintf(stderr, "no start address specified\n");
224 	usage(EXIT_FAILURE);
225     }
226 
227     ifinfo.size = st.st_size;
228 
229     obuf.size = ifinfo.size + sizeof(struct header) + sizeof(unsigned short);
230     if (obuf.size % sizeof(unsigned short))
231 	obuf.size++;
232 
233     obuf.start = malloc(obuf.size);
234     if (!obuf.start) {
235 	fprintf(stderr, "no memory for buffer\n");
236 	usage(EXIT_FAILURE);
237     }
238     memset(obuf.start, 0, obuf.size);
239 
240     ibuf.size = ifinfo.size;
241     ibuf.start = obuf.start + sizeof(struct header);
242 
243     if (fwread(&ifinfo, &ibuf))
244 	usage(EXIT_FAILURE);
245 
246     header.flash = HOST_TO_LE32(header.flash);
247     header.size = HOST_TO_LE32(obuf.size - sizeof(struct header));
248     header.start = HOST_TO_LE32(header.start);
249     memcpy (obuf.start, &header, sizeof(struct header));
250 
251     csum = HOST_TO_LE16(fwcsum(&ibuf));
252     memcpy(obuf.start + obuf.size - sizeof(unsigned short),
253 	   &csum, sizeof(unsigned short));
254 
255     ofinfo.size = obuf.size;
256 
257     if (fwwrite(&ofinfo, &obuf))
258 	usage(EXIT_FAILURE);
259 
260     return EXIT_SUCCESS;
261 }
262