Switch from GPLv2 to GPLv2+
[fw/altos] / ao-tools / ao-makebin / ao-makebin.c
1 /*
2  * Copyright © 2016 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include <getopt.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <errno.h>
24 #include "ao-hex.h"
25 #include "ao-elf.h"
26 #include "ao-dfu.h"
27
28 static const struct option options[] = {
29         { .name = "verbose", .has_arg = 0, .val = 'v' },
30         { .name = "output", .has_arg = 1, .val = 'o' },
31         { .name = "base", .has_arg = 1, .val = 'b' },
32         { .name = "align", .has_arg = 1, .val = 'a' },
33         { .name = "dfu", .has_arg = 0, .val = 'd' },
34         { 0, 0, 0, 0},
35 };
36
37 static void usage(char *program)
38 {
39         fprintf(stderr, "usage: %s [--verbose=<level>] [--output=<output.bin>] [--base=<base-address>] [--align=<align>] [--dfu] <input.elf> ...\n", program);
40         exit(1);
41 }
42
43 static int
44 ends_with(char *whole, char *suffix)
45 {
46         int whole_len = strlen(whole);
47         int suffix_len = strlen(suffix);
48
49         if (suffix_len > whole_len)
50                 return 0;
51         return strcmp(whole + whole_len - suffix_len, suffix) == 0;
52 }
53
54 static struct ao_dfu_info dfu_info = {
55         .bcdDevice = 0x0000,
56         .idProduct = 0xdf11,
57         .idVendor = 0x0483,
58 };
59
60 int
61 main (int argc, char **argv)
62 {
63         char                    *output = NULL;
64         struct ao_hex_image     *image = NULL;
65         struct ao_sym           *file_symbols;
66         int                     num_file_symbols;
67         FILE                    *file;
68         int                     c;
69         uint32_t                base = 0xffffffff;
70         uint32_t                align = 0;
71         uint32_t                length;
72         int                     verbose = 0;
73         int                     dfu = 0;
74
75         while ((c = getopt_long(argc, argv, "dvo:b:a:", options, NULL)) != -1) {
76                 switch (c) {
77                 case 'o':
78                         output = optarg;
79                         break;
80                 case 'v':
81                         verbose++;
82                         break;
83                 case 'b':
84                         base = strtoul(optarg, NULL, 0);
85                         break;
86                 case 'a':
87                         align = strtoul(optarg, NULL, 0);
88                         break;
89                 case 'd':
90                         dfu = 1;
91                         break;
92                 default:
93                         usage(argv[0]);
94                         break;
95                 }
96         }
97
98         while (argv[optind]) {
99                 char                    *input = argv[optind];
100                 struct ao_hex_image     *tmp;
101
102                 if (ends_with (input, ".ihx"))
103                         tmp = ao_hex_load(input, &file_symbols, &num_file_symbols);
104                 else
105                         tmp = ao_load_elf(input, &file_symbols, &num_file_symbols);
106
107                 if (!tmp)
108                         usage(argv[0]);
109
110                 if (verbose)
111                         fprintf(stderr, "%s: 0x%x %d\n", input, tmp->address, tmp->length);
112
113                 if (image) {
114                         image = ao_hex_image_cat(image, tmp);
115                         if (!image)
116                                 usage(argv[0]);
117                 } else
118                         image = tmp;
119                 optind++;
120         }
121
122         if (base != 0xffffffff && base > image->address) {
123                 fprintf(stderr, "requested base 0x%x is after image address 0x%x\n",
124                         base, image->address);
125                 usage(argv[0]);
126         }
127
128         if (verbose)
129                 fprintf(stderr, "%s: base 0x%x length %d\n", output ? output : "<stdout>", image->address, image->length);
130
131         if (!output)
132                 file = stdout;
133         else {
134                 file = fopen(output, "w");
135                 if (!file) {
136                         perror(output);
137                         exit(1);
138                 }
139         }
140
141         if (dfu) {
142                 if (!ao_dfu_write(file, &dfu_info, 1, image)) {
143                         fprintf(stderr, "%s: dfu_write failed: %s\n", output, strerror(errno));
144                         if (output)
145                                 unlink(output);
146                         exit(1);
147                 }
148         } else {
149                 while (base < image->address) {
150                         fputc(0xff, file);
151                         base++;
152                 }
153
154                 if (fwrite(image->data, 1, image->length, file) != image->length) {
155                         fprintf(stderr, "%s: failed to write bin file\n", output ? output : "<stdout>");
156                         if (output)
157                                 unlink(output);
158                         exit(1);
159                 }
160
161                 if (align) {
162                         length = image->length;
163
164                         while (length % align) {
165                                 fputc(0xff, file);
166                                 length++;
167                         }
168                 }
169                 fflush(file);
170         }
171
172         exit(0);
173 }