1d09290a16b5248e20acfff023a64565b2c0ef02
[openwrt/staging/ldir.git] / tools / firmware-utils / src / mkdapimg2.c
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License,
4 * version 2 as published by the Free Software Foundation.
5 *
6 * (C) Nicolò Veronese <nicveronese@gmail.com>
7 */
8
9 #include <stdio.h>
10 #include <stdint.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <libgen.h>
14 #include <stdarg.h>
15 #include <getopt.h>
16 #include <string.h>
17 #include <errno.h>
18
19 #include <netinet/in.h> // htonl
20
21 // Usage: mkdapimg2 -s signature [-v version] [-r region]
22 // [-k uImage block size] -i <input> -o <output>
23 //
24 // NOTE: The kernel block size is used to know the offset of the rootfs
25 // in the image file.
26 //
27 // The system writes in the uImage partition until the end of uImage
28 // is reached, after that, the system jumps to the offset specified with the -k
29 // parameter and begin writing at the beginning of the rootfs MTD partition.
30 //
31 // If the -k parameter is the size of the original uImage partition, the system
32 // continue writing in the rootfs partition starting from the last block
33 // that has been wrote. (This is useful if the new kernel size is
34 // different from the original one)
35 //
36 // Example:
37 // ------------------------------------------
38 // Creating 7 MTD partitions on "ath-nor0":
39 // 0x000000000000-0x000000010000 : "u-boot"
40 // 0x000000010000-0x000000020000 : "ART"
41 // 0x000000020000-0x000000030000 : "MP"
42 // 0x000000030000-0x000000040000 : "config"
43 // 0x000000040000-0x000000120000 : "uImage"
44 // 0x000000120000-0x000000800000 : "rootfs"
45 // 0x000000040000-0x000000800000 : "firmware"
46 // ------------------------------------------
47 //
48 // 0x000000120000-0x000000040000 = 0xE0000 -> 917504
49 //
50 // e.g.: mkdapimg2 -s HONEYBEE-FIRMWARE-DAP-1330 -v 1.00.21 -r Default
51 // -k 917504 -i sysupgrade.bin -o factory.bin
52 //
53 //
54 // The img_hdr_struct was taken from the D-Link SDK:
55 // DAP-1330_OSS-firmware_1.00b21/DAP-1330_OSS-firmware_1.00b21/uboot/uboot.patch
56
57 #define MAX_SIGN_LEN 32
58 #define MAX_FW_VER_LEN 16
59 #define MAX_REG_LEN 8
60
61 struct img_hdr_struct {
62 uint32_t hdr_len;
63 uint32_t checksum;
64 uint32_t total_size;
65 uint32_t kernel_size;
66 char signature[MAX_SIGN_LEN];
67 char fw_ver[MAX_FW_VER_LEN];
68 char fw_reg[MAX_REG_LEN];
69 } imghdr ;
70
71 char *progname;
72
73 void
74 perrexit(int code, char *msg)
75 {
76 fprintf(stderr, "%s: %s: %s\n", progname, msg, strerror(errno));
77 exit(code);
78 }
79
80 void
81 usage()
82 {
83 fprintf(stderr, "usage: %s -s signature [-v version] [-r region] [-k uImage part size] -i <input> -o <output>\n", progname);
84 exit(1);
85 }
86
87 int
88 main(int ac, char *av[])
89 {
90 char signature[MAX_SIGN_LEN];
91 char version[MAX_FW_VER_LEN];
92 char region[MAX_REG_LEN];
93 int kernel = 0;
94
95 FILE *ifile = NULL;
96 FILE *ofile = NULL;
97 int c;
98
99 uint32_t cksum;
100 uint32_t bcnt;
101
102 progname = basename(av[0]);
103
104 memset(signature, 0, sizeof(signature));
105 memset(version, 0, sizeof(version));
106 memset(region, 0, sizeof(region));
107
108 while ( 1 ) {
109 char *ptr;
110 int c;
111
112 c = getopt(ac, av, "s:v:r:k:i:o:");
113 if (c == -1)
114 break;
115
116 switch (c) {
117 case 's':
118 if (strlen(optarg) > MAX_SIGN_LEN + 1) {
119 fprintf(stderr, "%s: signature exceeds %d chars\n",
120 progname, MAX_SIGN_LEN);
121 exit(1);
122 }
123 strcpy(signature, optarg);
124 break;
125 case 'v':
126 if (strlen(optarg) > MAX_FW_VER_LEN + 1) {
127 fprintf(stderr, "%s: version exceeds %d chars\n",
128 progname, MAX_FW_VER_LEN);
129 exit(1);
130 }
131 strcpy(version, optarg);
132 break;
133 case 'r':
134 if (strlen(optarg) > MAX_REG_LEN + 1) {
135 fprintf(stderr, "%s: region exceeds %d chars\n",
136 progname, MAX_REG_LEN);
137 exit(1);
138 }
139 strcpy(region, optarg);
140 break;
141 case 'k':
142 kernel = strtoul(optarg, &ptr, 0);
143 if(ptr[0] == 'k'){
144 kernel *= 1000;
145 }
146 break;
147 case 'i':
148 if ((ifile = fopen(optarg, "r")) == NULL)
149 perrexit(1, optarg);
150 break;
151 case 'o':
152 if ((ofile = fopen(optarg, "w")) == NULL)
153 perrexit(1, optarg);
154 break;
155 default:
156 usage();
157 }
158 }
159
160 if (signature[0] == 0 || ifile == NULL || ofile == NULL) {
161 usage();
162 exit(1);
163 }
164
165 for (bcnt = 0, cksum = 0 ; (c = fgetc(ifile)) != EOF ; bcnt++)
166 cksum += c & 0xff;
167
168 if (fseek(ifile, 0, SEEK_SET) < 0)
169 perrexit(2, "fseek on input");
170
171 // Fill in the header
172 memset(&imghdr, 0, sizeof(imghdr));
173 imghdr.hdr_len = sizeof(imghdr);
174 imghdr.checksum = htonl(cksum);
175 imghdr.total_size = htonl(bcnt);
176 imghdr.kernel_size = htonl(kernel);
177
178 strncpy(imghdr.signature, signature, MAX_SIGN_LEN);
179 strncpy(imghdr.fw_ver, version, MAX_FW_VER_LEN);
180 strncpy(imghdr.fw_reg, region, MAX_REG_LEN);
181
182 if (fwrite(&imghdr, sizeof(imghdr), 1, ofile) < 0)
183 perrexit(2, "fwrite header on output");
184
185 while ((c = fgetc(ifile)) != EOF) {
186 if (fputc(c, ofile) == EOF)
187 perrexit(2, "fputc on output");
188 }
189
190 if (ferror(ifile))
191 perrexit(2, "fgetc on input");
192
193 fclose(ofile);
194 fclose(ifile);
195
196 fprintf(stderr, "imgHdr.hdr_len = %lu\n", sizeof(imghdr));
197 fprintf(stderr, "imgHdr.checksum = 0x%08x\n", cksum);
198 fprintf(stderr, "imgHdr.total_size = 0x%08x\n", bcnt);
199 fprintf(stderr, "imgHdr.kernel_size = 0x%08x\n", kernel);
200 fprintf(stderr, "imgHdr.header = %s\n", signature);
201 fprintf(stderr, "imgHdr.fw_ver = %s\n", version);
202 fprintf(stderr, "imgHdr.fw_reg = %s\n", region);
203
204 return 0;
205 }