1 /* 2 * Copyright 2012 Freescale Semiconductor, Inc. 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 #define _GNU_SOURCE 7 8 #include "mkimage.h" 9 #include <image.h> 10 #include "pblimage.h" 11 12 /* 13 * Initialize to an invalid value. 14 */ 15 static uint32_t next_pbl_cmd = 0x82000000; 16 /* 17 * need to store all bytes in memory for calculating crc32, then write the 18 * bytes to image file for PBL boot. 19 */ 20 static unsigned char mem_buf[1000000]; 21 static unsigned char *pmem_buf = mem_buf; 22 static int pbl_size; 23 static char *fname = "Unknown"; 24 static int lineno = -1; 25 static struct pbl_header pblimage_header; 26 27 static union 28 { 29 char c[4]; 30 unsigned char l; 31 } endian_test = { {'l', '?', '?', 'b'} }; 32 33 #define ENDIANNESS ((char)endian_test.l) 34 35 /* 36 * The PBL can load up to 64 bytes at a time, so we split the U-Boot 37 * image into 64 byte chunks. PBL needs a command for each piece, of 38 * the form "81xxxxxx", where "xxxxxx" is the offset. Calculate the 39 * start offset by subtracting the size of the u-boot image from the 40 * top of the allowable 24-bit range. 41 */ 42 static void init_next_pbl_cmd(FILE *fp_uboot) 43 { 44 struct stat st; 45 int fd = fileno(fp_uboot); 46 47 if (fstat(fd, &st) == -1) { 48 printf("Error: Could not determine u-boot image size. %s\n", 49 strerror(errno)); 50 exit(EXIT_FAILURE); 51 } 52 53 next_pbl_cmd = 0x82000000 - st.st_size; 54 } 55 56 static void generate_pbl_cmd(void) 57 { 58 uint32_t val = next_pbl_cmd; 59 next_pbl_cmd += 0x40; 60 int i; 61 62 for (i = 3; i >= 0; i--) { 63 *pmem_buf++ = (val >> (i * 8)) & 0xff; 64 pbl_size++; 65 } 66 } 67 68 static void pbl_fget(size_t size, FILE *stream) 69 { 70 unsigned char c; 71 int c_temp; 72 73 while (size && (c_temp = fgetc(stream)) != EOF) { 74 c = (unsigned char)c_temp; 75 *pmem_buf++ = c; 76 pbl_size++; 77 size--; 78 } 79 } 80 81 /* load split u-boot with PBI command 81xxxxxx. */ 82 static void load_uboot(FILE *fp_uboot) 83 { 84 init_next_pbl_cmd(fp_uboot); 85 while (next_pbl_cmd < 0x82000000) { 86 generate_pbl_cmd(); 87 pbl_fget(64, fp_uboot); 88 } 89 } 90 91 static void check_get_hexval(char *token) 92 { 93 uint32_t hexval; 94 int i; 95 96 if (!sscanf(token, "%x", &hexval)) { 97 printf("Error:%s[%d] - Invalid hex data(%s)\n", fname, 98 lineno, token); 99 exit(EXIT_FAILURE); 100 } 101 for (i = 3; i >= 0; i--) { 102 *pmem_buf++ = (hexval >> (i * 8)) & 0xff; 103 pbl_size++; 104 } 105 } 106 107 static void pbl_parser(char *name) 108 { 109 FILE *fd = NULL; 110 char *line = NULL; 111 char *token, *saveptr1, *saveptr2; 112 size_t len = 0; 113 114 fname = name; 115 fd = fopen(name, "r"); 116 if (fd == NULL) { 117 printf("Error:%s - Can't open\n", fname); 118 exit(EXIT_FAILURE); 119 } 120 121 while ((getline(&line, &len, fd)) > 0) { 122 lineno++; 123 token = strtok_r(line, "\r\n", &saveptr1); 124 /* drop all lines with zero tokens (= empty lines) */ 125 if (token == NULL) 126 continue; 127 for (line = token;; line = NULL) { 128 token = strtok_r(line, " \t", &saveptr2); 129 if (token == NULL) 130 break; 131 /* Drop all text starting with '#' as comments */ 132 if (token[0] == '#') 133 break; 134 check_get_hexval(token); 135 } 136 } 137 if (line) 138 free(line); 139 fclose(fd); 140 } 141 142 static uint32_t crc_table[256]; 143 144 static void make_crc_table(void) 145 { 146 uint32_t mask; 147 int i, j; 148 uint32_t poly; /* polynomial exclusive-or pattern */ 149 150 /* 151 * the polynomial used by PBL is 1 + x1 + x2 + x4 + x5 + x7 + x8 + x10 152 * + x11 + x12 + x16 + x22 + x23 + x26 + x32. 153 */ 154 poly = 0x04c11db7; 155 156 for (i = 0; i < 256; i++) { 157 mask = i << 24; 158 for (j = 0; j < 8; j++) { 159 if (mask & 0x80000000) 160 mask = (mask << 1) ^ poly; 161 else 162 mask <<= 1; 163 } 164 crc_table[i] = mask; 165 } 166 } 167 168 unsigned long pbl_crc32(unsigned long crc, const char *buf, uint32_t len) 169 { 170 uint32_t crc32_val = 0xffffffff; 171 uint32_t xor = 0x0; 172 int i; 173 174 make_crc_table(); 175 176 for (i = 0; i < len; i++) 177 crc32_val = (crc32_val << 8) ^ 178 crc_table[(crc32_val >> 24) ^ (*buf++ & 0xff)]; 179 180 crc32_val = crc32_val ^ xor; 181 if (crc32_val < 0) { 182 crc32_val += 0xffffffff; 183 crc32_val += 1; 184 } 185 return crc32_val; 186 } 187 188 static uint32_t reverse_byte(uint32_t val) 189 { 190 uint32_t temp; 191 unsigned char *p1; 192 int j; 193 194 temp = val; 195 p1 = (unsigned char *)&temp; 196 for (j = 3; j >= 0; j--) 197 *p1++ = (val >> (j * 8)) & 0xff; 198 return temp; 199 } 200 201 /* write end command and crc command to memory. */ 202 static void add_end_cmd(void) 203 { 204 uint32_t pbl_end_cmd[4] = {0x09138000, 0x00000000, 205 0x091380c0, 0x00000000}; 206 uint32_t crc32_pbl; 207 int i; 208 unsigned char *p = (unsigned char *)&pbl_end_cmd; 209 210 if (ENDIANNESS == 'l') { 211 for (i = 0; i < 4; i++) 212 pbl_end_cmd[i] = reverse_byte(pbl_end_cmd[i]); 213 } 214 215 for (i = 0; i < 16; i++) { 216 *pmem_buf++ = *p++; 217 pbl_size++; 218 } 219 220 /* Add PBI CRC command. */ 221 *pmem_buf++ = 0x08; 222 *pmem_buf++ = 0x13; 223 *pmem_buf++ = 0x80; 224 *pmem_buf++ = 0x40; 225 pbl_size += 4; 226 227 /* calculated CRC32 and write it to memory. */ 228 crc32_pbl = pbl_crc32(0, (const char *)mem_buf, pbl_size); 229 *pmem_buf++ = (crc32_pbl >> 24) & 0xff; 230 *pmem_buf++ = (crc32_pbl >> 16) & 0xff; 231 *pmem_buf++ = (crc32_pbl >> 8) & 0xff; 232 *pmem_buf++ = (crc32_pbl) & 0xff; 233 pbl_size += 4; 234 235 if ((pbl_size % 16) != 0) { 236 for (i = 0; i < 8; i++) { 237 *pmem_buf++ = 0x0; 238 pbl_size++; 239 } 240 } 241 if ((pbl_size % 16 != 0)) { 242 printf("Error: Bad size of image file\n"); 243 exit(EXIT_FAILURE); 244 } 245 } 246 247 void pbl_load_uboot(int ifd, struct mkimage_params *params) 248 { 249 FILE *fp_uboot; 250 int size; 251 252 /* parse the rcw.cfg file. */ 253 pbl_parser(params->imagename); 254 255 /* parse the pbi.cfg file. */ 256 pbl_parser(params->imagename2); 257 258 fp_uboot = fopen(params->datafile, "r"); 259 if (fp_uboot == NULL) { 260 printf("Error: %s open failed\n", params->datafile); 261 exit(EXIT_FAILURE); 262 } 263 264 load_uboot(fp_uboot); 265 add_end_cmd(); 266 fclose(fp_uboot); 267 lseek(ifd, 0, SEEK_SET); 268 269 size = pbl_size; 270 if (write(ifd, (const void *)&mem_buf, size) != size) { 271 fprintf(stderr, "Write error on %s: %s\n", 272 params->imagefile, strerror(errno)); 273 exit(EXIT_FAILURE); 274 } 275 } 276 277 static int pblimage_check_image_types(uint8_t type) 278 { 279 if (type == IH_TYPE_PBLIMAGE) 280 return EXIT_SUCCESS; 281 else 282 return EXIT_FAILURE; 283 } 284 285 static int pblimage_verify_header(unsigned char *ptr, int image_size, 286 struct mkimage_params *params) 287 { 288 struct pbl_header *pbl_hdr = (struct pbl_header *) ptr; 289 290 /* Only a few checks can be done: search for magic numbers */ 291 if (ENDIANNESS == 'l') { 292 if (pbl_hdr->preamble != reverse_byte(RCW_PREAMBLE)) 293 return -FDT_ERR_BADSTRUCTURE; 294 295 if (pbl_hdr->rcwheader != reverse_byte(RCW_HEADER)) 296 return -FDT_ERR_BADSTRUCTURE; 297 } else { 298 if (pbl_hdr->preamble != RCW_PREAMBLE) 299 return -FDT_ERR_BADSTRUCTURE; 300 301 if (pbl_hdr->rcwheader != RCW_HEADER) 302 return -FDT_ERR_BADSTRUCTURE; 303 } 304 return 0; 305 } 306 307 static void pblimage_print_header(const void *ptr) 308 { 309 printf("Image Type: Freescale PBL Boot Image\n"); 310 } 311 312 static void pblimage_set_header(void *ptr, struct stat *sbuf, int ifd, 313 struct mkimage_params *params) 314 { 315 /*nothing need to do, pbl_load_uboot takes care of whole file. */ 316 } 317 318 /* pblimage parameters */ 319 static struct image_type_params pblimage_params = { 320 .name = "Freescale PBL Boot Image support", 321 .header_size = sizeof(struct pbl_header), 322 .hdr = (void *)&pblimage_header, 323 .check_image_type = pblimage_check_image_types, 324 .verify_header = pblimage_verify_header, 325 .print_header = pblimage_print_header, 326 .set_header = pblimage_set_header, 327 }; 328 329 void init_pbl_image_type(void) 330 { 331 pbl_size = 0; 332 mkimage_register(&pblimage_params); 333 } 334