• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/firmware-utils/src/mkqdimg.c

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Copyright (C) 2025 Coia Prant <coiaprant@gmail.com>
  4  *
  5  * The golang version can be found at:
  6  * <https://gitlab.com/CoiaPrant/mkqdimg>
  7  */
  8 
  9 #include <stdio.h>
 10 #include <stdint.h>
 11 #include <stdlib.h>
 12 #include <stdbool.h>
 13 #include <string.h>
 14 #include <libgen.h>
 15 #include <getopt.h>
 16 #include <errno.h>
 17 #include <endian.h>
 18 
 19 #include "sha1.h"
 20 
 21 #define HDR_PADDING_BYTE        0x00
 22 #define PADDING_BYTE            0xff
 23 
 24 #define MAX_LENGTH              16647168
 25 #define BOARD_ID_LENGTH         8
 26 #define VERSION_LENGTH          8
 27 #define UBOOT_LENGTH            196608
 28 
 29 #define HDR_LENGTH              0x00000400
 30 #define HDR_OFF_BOARD_ID        0
 31 #define HDR_OFF_VERSION         8
 32 #define HDR_OFF_UBOOT           16
 33 #define HDR_OFF_FIRMWARE        32
 34 #define HDR_OFF_MAGIC           48
 35 #define HDR_OFF_CHECKSUM        52
 36 #define HDR_OFF_UBOOT_LEN       72
 37 #define HDR_OFF_FIRMWARE_LEN    76
 38 #define HDR_MAGIC               538248722
 39 
 40 /*
 41  * Globals
 42  */
 43 static char *progname;
 44 
 45 /*
 46  * Message macros
 47  */
 48 #define ERR(fmt, ...) do { \
 49         fflush(0); \
 50         fprintf(stderr, "[%s] *** error: " fmt "\n", \
 51                         progname, ## __VA_ARGS__); \
 52 } while (0)
 53 
 54 #define ERRS(fmt, ...) do { \
 55         int save = errno; \
 56         fflush(0); \
 57         fprintf(stderr, "[%s] *** error: " fmt "\n", \
 58                         progname, ## __VA_ARGS__, strerror(save)); \
 59 } while (0)
 60 
 61 static void usage(int status)
 62 {
 63         FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
 64 
 65         fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
 66         fprintf(stream,
 67 "\n"
 68 "Options:\n"
 69 "  -B <board>      create image for the board specified with <board>\n"
 70 "  -V <version>    version string\n"
 71 "  -u <file>       read uboot image from the file <file>\n"
 72 "  -f <file>       read firmware image from the file <file>\n"
 73 "  -o <file>       write output to the file <file>\n"
 74 "  -h              show this screen\n"
 75         );
 76 
 77         exit(status);
 78 }
 79 
 80 void writele(unsigned char *buf, size_t offset, uint32_t value)
 81 {
 82         value = htole32(value);
 83         memcpy(buf + offset, &value, sizeof(uint32_t));
 84 }
 85 
 86 int main(int argc, char *argv[])
 87 {
 88         int ret = EXIT_FAILURE;
 89         long ulen, flen, buflen = HDR_LENGTH, fspace;
 90         unsigned char *buf;
 91         char *board_id = NULL, *version = NULL, *ufname = NULL, *ffname = NULL, *ofname = NULL;
 92         FILE *out, *uboot = NULL, *firmware = NULL;
 93 
 94         progname = basename(argv[0]);
 95 
 96         while (1) {
 97                 int c;
 98 
 99                 c = getopt(argc, argv, "B:V:u:f:o:h");
100                 if (c == -1)
101                         break;
102 
103                 switch (c) {
104                 case 'B':
105                         board_id = optarg;
106                         break;
107                 case 'V':
108                         version = optarg;
109                         break;
110                 case 'u':
111                         ufname = optarg;
112                         break;
113                 case 'f':
114                         ffname = optarg;
115                         break;
116                 case 'o':
117                         ofname = optarg;
118                         break;
119                 case 'h':
120                         usage(EXIT_SUCCESS);
121                         break;
122                 default:
123                         usage(EXIT_FAILURE);
124                         break;
125                 }
126         }
127 
128         if (board_id == NULL) {
129                 ERR("no board specified");
130                 goto err;
131         }
132 
133         if (strlen(board_id) > BOARD_ID_LENGTH) {
134                 ERR("board_id \"%s\" is too long - max length: 8\n",
135                     board_id);
136                 goto err;
137         }
138 
139         if (version != NULL && strlen(version) > VERSION_LENGTH) {
140                 ERR("version \"%s\" is too long - max length: 8\n",
141                     version);
142                 goto err;
143         }
144 
145         if (ofname == NULL) {
146                 ERR("no output file specified");
147                 goto err;
148         }
149 
150         if (ufname != NULL) {
151                 uboot = fopen(ufname, "r");
152                 if (uboot == NULL) {
153                         ERRS("could not open \"%s\" for reading: %s", ufname);
154                         goto err;
155                 }
156 
157                 /* Get uboot length */
158                 fseek(uboot, 0, SEEK_END);
159                 ulen = ftell(uboot);
160                 rewind(uboot);
161 
162                 if (ulen > UBOOT_LENGTH) {
163                         fclose(uboot);
164                         ERR("file \"%s\" is too big - max size: 0x%08d\n",
165                           ufname, UBOOT_LENGTH);
166                         goto err;
167                 }
168 
169                 buflen += UBOOT_LENGTH;
170         }
171 
172         if (ffname != NULL) {
173                 firmware = fopen(ffname, "r");
174                 if (firmware == NULL) {
175                         ERRS("could not open \"%s\" for reading: %s", ffname);
176                         goto err;
177                 }
178 
179                 /* Get firmware length */
180                 fseek(firmware, 0, SEEK_END);
181                 flen = ftell(firmware);
182                 rewind(firmware);
183 
184                 fspace = MAX_LENGTH - buflen;
185                 if (flen > fspace) {
186                         ERR("file \"%s\" is too big - max size: 0x%08ld\n",
187                           ffname, fspace);
188                         goto err_close;
189                 }
190 
191                 buflen += flen;
192         }
193 
194         /* Allocate and initialize buffer for final image */
195         buf = malloc(buflen);
196         if (buf == NULL) {
197                 ERRS("no memory for buffer: %s\n");
198                 goto err_close;
199         }
200         memset(buf, HDR_PADDING_BYTE, HDR_LENGTH);
201         memset(buf + HDR_LENGTH, PADDING_BYTE, buflen - HDR_LENGTH);
202 
203         /* Write board id */
204         memcpy(buf + HDR_OFF_BOARD_ID, board_id, strlen(board_id));
205 
206         /* Write version */
207         if (version != NULL) {
208                 memcpy(buf + HDR_OFF_VERSION, version, strlen(version));
209         }
210 
211         if (uboot != NULL) {
212                 /* Write UBOOT ID */
213                 memcpy(buf + HDR_OFF_UBOOT, "UBOOT", 5);
214 
215                 /* Load U-Boot */
216                 fread(buf + HDR_LENGTH, ulen, 1, uboot);
217 
218                 /* Write U-Boot Length */
219                 writele(buf, HDR_OFF_UBOOT_LEN, UBOOT_LENGTH);
220         }
221 
222         if (firmware != NULL) {
223                 /* Write FIRMWARE ID */
224                 memcpy(buf + HDR_OFF_FIRMWARE, "FIRMWARE", 8);
225 
226                 /* Load Firmware */
227                 if (uboot != NULL) {
228                         fread(buf + HDR_LENGTH + UBOOT_LENGTH, flen, 1, firmware);
229                 } else {
230                         fread(buf + HDR_LENGTH, flen, 1, firmware);
231                 }
232 
233                 /* Write Firmware Length */
234                 writele(buf, HDR_OFF_FIRMWARE_LEN, flen);
235         }
236 
237         /* Write magic */
238         writele(buf, HDR_OFF_MAGIC, HDR_MAGIC);
239 
240         /* Write checksum and static hash */
241         sha1_csum(buf + HDR_LENGTH, buflen - HDR_LENGTH, buf + HDR_OFF_CHECKSUM);
242 
243         /* Save finished image */
244         out = fopen(ofname, "w");
245         if (out == NULL) {
246                 ERRS("could not open \"%s\" for writing: %s", ofname);
247                 goto err_free;
248         }
249         fwrite(buf, buflen, 1, out);
250 
251         ret = EXIT_SUCCESS;
252 
253         fclose(out);
254 
255 err_free:
256         free(buf);
257 
258 err_close:
259         if (uboot != NULL) {
260                 fclose(uboot);
261         }
262 
263         if (firmware != NULL) {
264                 fclose(firmware);
265         }
266 
267 err:
268         return ret;
269 }
270 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt