1 /* 2 * Copyright 2012-2014 Freescale Semiconductor, Inc. 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 #include "imagetool.h" 7 #include <image.h> 8 #include "pblimage.h" 9 #include "pbl_crc32.h" 10 11 #define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) 12 #define PBL_ACS_CONT_CMD 0x81000000 13 #define PBL_ADDR_24BIT_MASK 0x00ffffff 14 15 /* 16 * Initialize to an invalid value. 17 */ 18 static uint32_t next_pbl_cmd = 0x82000000; 19 /* 20 * need to store all bytes in memory for calculating crc32, then write the 21 * bytes to image file for PBL boot. 22 */ 23 static unsigned char mem_buf[1000000]; 24 static unsigned char *pmem_buf = mem_buf; 25 static int pbl_size; 26 static char *fname = "Unknown"; 27 static int lineno = -1; 28 static struct pbl_header pblimage_header; 29 static int uboot_size; 30 static int arch_flag; 31 32 static uint32_t pbl_cmd_initaddr; 33 static uint32_t pbi_crc_cmd1; 34 static uint32_t pbi_crc_cmd2; 35 static uint32_t pbl_end_cmd[4]; 36 37 static union 38 { 39 char c[4]; 40 unsigned char l; 41 } endian_test = { {'l', '?', '?', 'b'} }; 42 43 #define ENDIANNESS ((char)endian_test.l) 44 45 /* 46 * The PBL can load up to 64 bytes at a time, so we split the U-Boot 47 * image into 64 byte chunks. PBL needs a command for each piece, of 48 * the form "81xxxxxx", where "xxxxxx" is the offset. Calculate the 49 * start offset by subtracting the size of the u-boot image from the 50 * top of the allowable 24-bit range. 51 */ 52 static void generate_pbl_cmd(void) 53 { 54 uint32_t val = next_pbl_cmd; 55 next_pbl_cmd += 0x40; 56 int i; 57 58 for (i = 3; i >= 0; i--) { 59 *pmem_buf++ = (val >> (i * 8)) & 0xff; 60 pbl_size++; 61 } 62 } 63 64 static void pbl_fget(size_t size, FILE *stream) 65 { 66 unsigned char c = 0xff; 67 int c_temp; 68 69 while (size) { 70 c_temp = fgetc(stream); 71 if (c_temp != EOF) 72 c = (unsigned char)c_temp; 73 else if ((c_temp == EOF) && (arch_flag == IH_ARCH_ARM)) 74 c = 0xff; 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 next_pbl_cmd = pbl_cmd_initaddr - uboot_size; 85 while (next_pbl_cmd < pbl_cmd_initaddr) { 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 reverse_byte(uint32_t val) 143 { 144 uint32_t temp; 145 unsigned char *p1; 146 int j; 147 148 temp = val; 149 p1 = (unsigned char *)&temp; 150 for (j = 3; j >= 0; j--) 151 *p1++ = (val >> (j * 8)) & 0xff; 152 return temp; 153 } 154 155 /* write end command and crc command to memory. */ 156 static void add_end_cmd(void) 157 { 158 uint32_t crc32_pbl; 159 int i; 160 unsigned char *p = (unsigned char *)&pbl_end_cmd; 161 162 if (ENDIANNESS == 'l') { 163 for (i = 0; i < 4; i++) 164 pbl_end_cmd[i] = reverse_byte(pbl_end_cmd[i]); 165 } 166 167 for (i = 0; i < 16; i++) { 168 *pmem_buf++ = *p++; 169 pbl_size++; 170 } 171 172 /* Add PBI CRC command. */ 173 *pmem_buf++ = 0x08; 174 *pmem_buf++ = pbi_crc_cmd1; 175 *pmem_buf++ = pbi_crc_cmd2; 176 *pmem_buf++ = 0x40; 177 pbl_size += 4; 178 179 /* calculated CRC32 and write it to memory. */ 180 crc32_pbl = pbl_crc32(0, (const char *)mem_buf, pbl_size); 181 *pmem_buf++ = (crc32_pbl >> 24) & 0xff; 182 *pmem_buf++ = (crc32_pbl >> 16) & 0xff; 183 *pmem_buf++ = (crc32_pbl >> 8) & 0xff; 184 *pmem_buf++ = (crc32_pbl) & 0xff; 185 pbl_size += 4; 186 } 187 188 void pbl_load_uboot(int ifd, struct image_tool_params *params) 189 { 190 FILE *fp_uboot; 191 int size; 192 193 /* parse the rcw.cfg file. */ 194 pbl_parser(params->imagename); 195 196 /* parse the pbi.cfg file. */ 197 if (params->imagename2[0] != '\0') 198 pbl_parser(params->imagename2); 199 200 if (params->datafile) { 201 fp_uboot = fopen(params->datafile, "r"); 202 if (fp_uboot == NULL) { 203 printf("Error: %s open failed\n", params->datafile); 204 exit(EXIT_FAILURE); 205 } 206 207 load_uboot(fp_uboot); 208 fclose(fp_uboot); 209 } 210 add_end_cmd(); 211 lseek(ifd, 0, SEEK_SET); 212 213 size = pbl_size; 214 if (write(ifd, (const void *)&mem_buf, size) != size) { 215 fprintf(stderr, "Write error on %s: %s\n", 216 params->imagefile, strerror(errno)); 217 exit(EXIT_FAILURE); 218 } 219 } 220 221 static int pblimage_check_image_types(uint8_t type) 222 { 223 if (type == IH_TYPE_PBLIMAGE) 224 return EXIT_SUCCESS; 225 else 226 return EXIT_FAILURE; 227 } 228 229 static int pblimage_verify_header(unsigned char *ptr, int image_size, 230 struct image_tool_params *params) 231 { 232 struct pbl_header *pbl_hdr = (struct pbl_header *) ptr; 233 234 /* Only a few checks can be done: search for magic numbers */ 235 if (ENDIANNESS == 'l') { 236 if (pbl_hdr->preamble != reverse_byte(RCW_PREAMBLE)) 237 return -FDT_ERR_BADSTRUCTURE; 238 239 if (pbl_hdr->rcwheader != reverse_byte(RCW_HEADER)) 240 return -FDT_ERR_BADSTRUCTURE; 241 } else { 242 if (pbl_hdr->preamble != RCW_PREAMBLE) 243 return -FDT_ERR_BADSTRUCTURE; 244 245 if (pbl_hdr->rcwheader != RCW_HEADER) 246 return -FDT_ERR_BADSTRUCTURE; 247 } 248 return 0; 249 } 250 251 static void pblimage_print_header(const void *ptr) 252 { 253 printf("Image Type: Freescale PBL Boot Image\n"); 254 } 255 256 static void pblimage_set_header(void *ptr, struct stat *sbuf, int ifd, 257 struct image_tool_params *params) 258 { 259 /*nothing need to do, pbl_load_uboot takes care of whole file. */ 260 } 261 262 int pblimage_check_params(struct image_tool_params *params) 263 { 264 FILE *fp_uboot; 265 int fd; 266 struct stat st; 267 268 if (!params) 269 return EXIT_FAILURE; 270 271 if (params->datafile) { 272 fp_uboot = fopen(params->datafile, "r"); 273 if (fp_uboot == NULL) { 274 printf("Error: %s open failed\n", params->datafile); 275 exit(EXIT_FAILURE); 276 } 277 fd = fileno(fp_uboot); 278 279 if (fstat(fd, &st) == -1) { 280 printf("Error: Could not determine u-boot image size. %s\n", 281 strerror(errno)); 282 exit(EXIT_FAILURE); 283 } 284 285 /* For the variable size, pad it to 64 byte boundary */ 286 uboot_size = roundup(st.st_size, 64); 287 fclose(fp_uboot); 288 } 289 290 if (params->arch == IH_ARCH_ARM) { 291 arch_flag = IH_ARCH_ARM; 292 pbi_crc_cmd1 = 0x61; 293 pbi_crc_cmd2 = 0; 294 pbl_cmd_initaddr = params->addr & PBL_ADDR_24BIT_MASK; 295 pbl_cmd_initaddr |= PBL_ACS_CONT_CMD; 296 pbl_cmd_initaddr |= uboot_size; 297 pbl_end_cmd[0] = 0x09610000; 298 pbl_end_cmd[1] = 0x00000000; 299 pbl_end_cmd[2] = 0x096100c0; 300 pbl_end_cmd[3] = 0x00000000; 301 } else if (params->arch == IH_ARCH_PPC) { 302 arch_flag = IH_ARCH_PPC; 303 pbi_crc_cmd1 = 0x13; 304 pbi_crc_cmd2 = 0x80; 305 pbl_cmd_initaddr = 0x82000000; 306 pbl_end_cmd[0] = 0x091380c0; 307 pbl_end_cmd[1] = 0x00000000; 308 pbl_end_cmd[2] = 0x091380c0; 309 pbl_end_cmd[3] = 0x00000000; 310 } 311 312 next_pbl_cmd = pbl_cmd_initaddr; 313 return 0; 314 }; 315 316 /* pblimage parameters */ 317 U_BOOT_IMAGE_TYPE( 318 pblimage, 319 "Freescale PBL Boot Image support", 320 sizeof(struct pbl_header), 321 (void *)&pblimage_header, 322 pblimage_check_params, 323 pblimage_verify_header, 324 pblimage_print_header, 325 pblimage_set_header, 326 NULL, 327 pblimage_check_image_types, 328 NULL, 329 NULL 330 ); 331