1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2020 Sungbo Eo <mans0n@gorani.run> 4 * 5 * This code is based on mkdhpimg.c and mkzcfw.c 6 * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org> 7 * Copyright (c) 2016 FUKAUMI Naoki <naobsd@gmail.com> 8 * 9 * Checksum algorithm is derived from EFM's mknas utility 10 * found in GPL'ed T16000 source. 11 */ 12 13 #include <byteswap.h> 14 #include <endian.h> 15 #include <err.h> 16 #include <errno.h> 17 #include <fcntl.h> 18 #include <stdint.h> 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <string.h> 22 #include <sys/stat.h> 23 #include <time.h> 24 #include <unistd.h> 25 26 #if !defined(__BYTE_ORDER) 27 #error "Unknown byte order" 28 #endif 29 30 #if (__BYTE_ORDER == __BIG_ENDIAN) 31 #define HOST_TO_LE32(x) bswap_32(x) 32 #elif (__BYTE_ORDER == __LITTLE_ENDIAN) 33 #define HOST_TO_LE32(x) (x) 34 #else 35 #error "Unsupported endianness" 36 #endif 37 38 #define FW_HEADER_SIZE 0x400 39 #define FW_VERSION "0.0.00" 40 #define FW_MAGIC "EFM_NAS_PKG" 41 42 struct fw_header { 43 uint8_t model[32]; 44 uint8_t version[32]; 45 uint8_t ctime[32]; 46 uint32_t size; 47 uint32_t checksum; 48 uint32_t offset_header; 49 uint32_t offset_rootfs; 50 uint32_t offset_app; 51 uint32_t checksum_kr; 52 uint8_t magic[16]; 53 54 uint32_t size_kra; 55 uint32_t checksum_kra; 56 uint32_t offset_ext; 57 } __attribute__ ((packed)); 58 59 enum board_type { 60 BOARD_KIRKWOOD, 61 BOARD_ARMADA380, 62 }; 63 64 struct board_type_info { 65 int bootloader_size; 66 int block_size; 67 }; 68 69 struct board_info { 70 const char *model; 71 enum board_type type; 72 }; 73 74 struct board_type_info board_types[] = { 75 /* BOARD_KIRKWOOD */ 76 { .bootloader_size = 0x40000, .block_size = 0x0 }, 77 /* BOARD_ARMADA380 */ 78 { .bootloader_size = 0x100000, .block_size = 0x10000 }, 79 }; 80 81 struct board_info boards[] = { 82 { .model = "nas1", .type = BOARD_KIRKWOOD }, 83 { .model = "nas1dual", .type = BOARD_ARMADA380 }, 84 { /* sentinel */ } 85 }; 86 87 struct board_info *find_board(const char *model) 88 { 89 struct board_info *ret = NULL; 90 struct board_info *board; 91 92 for (board = boards; board->model != NULL; board++) { 93 if (strcmp(model, board->model) == 0) { 94 ret = board; 95 break; 96 } 97 } 98 99 return ret; 100 } 101 102 /* (FW_HEADER_SIZE + size_in + padding) % block_size == 0 */ 103 size_t calc_padding(enum board_type type, size_t size_in) 104 { 105 int block_size, remainder; 106 107 block_size = board_types[type].block_size; 108 if (block_size == 0) 109 return 0; 110 remainder = (FW_HEADER_SIZE + size_in) % block_size; 111 return remainder ? block_size - remainder : 0; 112 } 113 114 char *get_ctime(void) 115 { 116 char *env = getenv("SOURCE_DATE_EPOCH"); 117 char *endptr = env; 118 time_t timestamp = -1; 119 120 if (env && *env) { 121 errno = 0; 122 timestamp = strtoull(env, &endptr, 10); 123 124 if (errno || (endptr && *endptr != '\0')) { 125 fprintf(stderr, "Invalid SOURCE_DATE_EPOCH\n"); 126 timestamp = -1; 127 } 128 } 129 130 if (timestamp == -1) 131 time(×tamp); 132 133 return asctime(gmtime(×tamp)); 134 } 135 136 uint32_t make_checksum(const char *model_name, uint8_t *bytes, int length) 137 { 138 int i; 139 uint32_t sum = 0; 140 uint32_t magic = 0x19283745; 141 142 for (i = 0; i < length; i++) 143 sum += bytes[i]; 144 return ((uint32_t)strlen(model_name) * magic + ~sum) ^ sum; 145 } 146 147 void make_header(struct board_info *board, uint8_t *buffer, size_t img_size) 148 { 149 struct fw_header *header = (struct fw_header *)buffer; 150 char *time_created; 151 uint32_t checksum; 152 size_t bootloader_size, image_end_offset; 153 154 time_created = get_ctime(); 155 checksum = make_checksum(board->model, buffer + FW_HEADER_SIZE, img_size); 156 bootloader_size = board_types[board->type].bootloader_size; 157 image_end_offset = bootloader_size + FW_HEADER_SIZE + img_size; 158 159 strncpy((char *)header->model, board->model, sizeof(header->model)-1); 160 strncpy((char *)header->version, FW_VERSION, sizeof(header->version)-1); 161 strncpy((char *)header->ctime, time_created, sizeof(header->ctime)-1); 162 header->size = HOST_TO_LE32(img_size); 163 header->checksum = HOST_TO_LE32(checksum); 164 header->offset_header = HOST_TO_LE32(bootloader_size); 165 header->offset_rootfs = HOST_TO_LE32(image_end_offset); 166 header->offset_app = HOST_TO_LE32(image_end_offset); 167 header->checksum_kr = HOST_TO_LE32(checksum); 168 strncpy((char *)header->magic, FW_MAGIC, sizeof(header->magic)-1); 169 170 if (board->type == BOARD_ARMADA380) { 171 header->size_kra = HOST_TO_LE32(img_size); 172 header->checksum_kra = HOST_TO_LE32(checksum); 173 header->offset_ext = HOST_TO_LE32(image_end_offset); 174 } 175 } 176 177 int main(int argc, const char *argv[]) 178 { 179 const char *model_name, *img_in, *img_out; 180 struct board_info *board; 181 int file_in, file_out; 182 struct stat stat_in; 183 size_t size_in, size_in_padded, size_out; 184 uint8_t *buffer; 185 186 if (argc != 4) { 187 fprintf(stderr, "Usage: %s <model> <input> <output>\n", argv[0]); 188 return EXIT_FAILURE; 189 } 190 model_name = argv[1]; 191 img_in = argv[2]; 192 img_out = argv[3]; 193 194 board = find_board(model_name); 195 if (board == NULL) { 196 fprintf(stderr, "%s: Not supported model\n", model_name); 197 return EXIT_FAILURE; 198 } 199 200 if ((file_in = open(img_in, O_RDONLY)) == -1) 201 err(EXIT_FAILURE, "%s", img_in); 202 203 if (fstat(file_in, &stat_in) == -1) 204 err(EXIT_FAILURE, "%s", img_in); 205 206 size_in = stat_in.st_size; 207 size_in_padded = size_in + calc_padding(board->type, size_in); 208 size_out = FW_HEADER_SIZE + size_in_padded; 209 210 if ((buffer = malloc(size_out)) == NULL) 211 err(EXIT_FAILURE, "malloc"); 212 213 read(file_in, buffer + FW_HEADER_SIZE, size_in); 214 close(file_in); 215 216 memset(buffer, 0, FW_HEADER_SIZE); 217 218 make_header(board, buffer, size_in_padded); 219 220 if ((file_out = creat(img_out, 0644)) == -1) 221 err(EXIT_FAILURE, "%s", img_out); 222 write(file_out, buffer, size_out); 223 close(file_out); 224 225 free(buffer); 226 227 return EXIT_SUCCESS; 228 } 229
This page was automatically generated by LXR 0.3.1. • OpenWrt