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