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