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