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 pbl_parser(params->imagename2); 198 199 fp_uboot = fopen(params->datafile, "r"); 200 if (fp_uboot == NULL) { 201 printf("Error: %s open failed\n", params->datafile); 202 exit(EXIT_FAILURE); 203 } 204 205 load_uboot(fp_uboot); 206 add_end_cmd(); 207 fclose(fp_uboot); 208 lseek(ifd, 0, SEEK_SET); 209 210 size = pbl_size; 211 if (write(ifd, (const void *)&mem_buf, size) != size) { 212 fprintf(stderr, "Write error on %s: %s\n", 213 params->imagefile, strerror(errno)); 214 exit(EXIT_FAILURE); 215 } 216 } 217 218 static int pblimage_check_image_types(uint8_t type) 219 { 220 if (type == IH_TYPE_PBLIMAGE) 221 return EXIT_SUCCESS; 222 else 223 return EXIT_FAILURE; 224 } 225 226 static int pblimage_verify_header(unsigned char *ptr, int image_size, 227 struct image_tool_params *params) 228 { 229 struct pbl_header *pbl_hdr = (struct pbl_header *) ptr; 230 231 /* Only a few checks can be done: search for magic numbers */ 232 if (ENDIANNESS == 'l') { 233 if (pbl_hdr->preamble != reverse_byte(RCW_PREAMBLE)) 234 return -FDT_ERR_BADSTRUCTURE; 235 236 if (pbl_hdr->rcwheader != reverse_byte(RCW_HEADER)) 237 return -FDT_ERR_BADSTRUCTURE; 238 } else { 239 if (pbl_hdr->preamble != RCW_PREAMBLE) 240 return -FDT_ERR_BADSTRUCTURE; 241 242 if (pbl_hdr->rcwheader != RCW_HEADER) 243 return -FDT_ERR_BADSTRUCTURE; 244 } 245 return 0; 246 } 247 248 static void pblimage_print_header(const void *ptr) 249 { 250 printf("Image Type: Freescale PBL Boot Image\n"); 251 } 252 253 static void pblimage_set_header(void *ptr, struct stat *sbuf, int ifd, 254 struct image_tool_params *params) 255 { 256 /*nothing need to do, pbl_load_uboot takes care of whole file. */ 257 } 258 259 int pblimage_check_params(struct image_tool_params *params) 260 { 261 FILE *fp_uboot; 262 int fd; 263 struct stat st; 264 265 if (!params) 266 return EXIT_FAILURE; 267 268 fp_uboot = fopen(params->datafile, "r"); 269 if (fp_uboot == NULL) { 270 printf("Error: %s open failed\n", params->datafile); 271 exit(EXIT_FAILURE); 272 } 273 fd = fileno(fp_uboot); 274 275 if (fstat(fd, &st) == -1) { 276 printf("Error: Could not determine u-boot image size. %s\n", 277 strerror(errno)); 278 exit(EXIT_FAILURE); 279 } 280 281 /* For the variable size, we need to pad it to 64 byte boundary */ 282 uboot_size = roundup(st.st_size, 64); 283 284 if (params->arch == IH_ARCH_ARM) { 285 arch_flag = IH_ARCH_ARM; 286 pbi_crc_cmd1 = 0x61; 287 pbi_crc_cmd2 = 0; 288 pbl_cmd_initaddr = params->addr & PBL_ADDR_24BIT_MASK; 289 pbl_cmd_initaddr |= PBL_ACS_CONT_CMD; 290 pbl_cmd_initaddr |= uboot_size; 291 pbl_end_cmd[0] = 0x09610000; 292 pbl_end_cmd[1] = 0x00000000; 293 pbl_end_cmd[2] = 0x096100c0; 294 pbl_end_cmd[3] = 0x00000000; 295 } else if (params->arch == IH_ARCH_PPC) { 296 arch_flag = IH_ARCH_PPC; 297 pbi_crc_cmd1 = 0x13; 298 pbi_crc_cmd2 = 0x80; 299 pbl_cmd_initaddr = 0x82000000; 300 pbl_end_cmd[0] = 0x09138000; 301 pbl_end_cmd[1] = 0x00000000; 302 pbl_end_cmd[2] = 0x091380c0; 303 pbl_end_cmd[3] = 0x00000000; 304 } 305 306 next_pbl_cmd = pbl_cmd_initaddr; 307 return 0; 308 }; 309 310 /* pblimage parameters */ 311 static struct image_type_params pblimage_params = { 312 .name = "Freescale PBL Boot Image support", 313 .header_size = sizeof(struct pbl_header), 314 .hdr = (void *)&pblimage_header, 315 .check_image_type = pblimage_check_image_types, 316 .check_params = pblimage_check_params, 317 .verify_header = pblimage_verify_header, 318 .print_header = pblimage_print_header, 319 .set_header = pblimage_set_header, 320 }; 321 322 void init_pbl_image_type(void) 323 { 324 pbl_size = 0; 325 register_image_type(&pblimage_params); 326 } 327