1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2016 Michal Simek <michals@xilinx.com> 4 * Copyright (C) 2015 Nathan Rossi <nathan@nathanrossi.com> 5 * 6 * The following Boot Header format/structures and values are defined in the 7 * following documents: 8 * * ug1085 ZynqMP TRM doc v1.4 (Chapter 11, Table 11-4) 9 * * ug1137 ZynqMP Software Developer Guide v6.0 (Chapter 16) 10 * 11 * Expected Header Size = 0x9C0 12 * Forced as 'little' endian, 32-bit words 13 * 14 * 0x 0 - Interrupt table (8 words) 15 * ... (Default value = 0xeafffffe) 16 * 0x 1f 17 * 0x 20 - Width detection 18 * * DEFAULT_WIDTHDETECTION 0xaa995566 19 * 0x 24 - Image identifier 20 * * DEFAULT_IMAGEIDENTIFIER 0x584c4e58 21 * 0x 28 - Encryption 22 * * 0x00000000 - None 23 * * 0xa5c3c5a3 - eFuse 24 * * 0xa5c3c5a7 - obfuscated key in eFUSE 25 * * 0x3a5c3c5a - bbRam 26 * * 0xa35c7ca5 - obfuscated key in boot header 27 * 0x 2C - Image load 28 * 0x 30 - Image offset 29 * 0x 34 - PFW image length 30 * 0x 38 - Total PFW image length 31 * 0x 3C - Image length 32 * 0x 40 - Total image length 33 * 0x 44 - Image attributes 34 * 0x 48 - Header checksum 35 * 0x 4c - Obfuscated key 36 * ... 37 * 0x 68 38 * 0x 6c - Reserved 39 * 0x 70 - User defined 40 * ... 41 * 0x 9c 42 * 0x a0 - Secure header initialization vector 43 * ... 44 * 0x a8 45 * 0x ac - Obfuscated key initialization vector 46 * ... 47 * 0x b4 48 * 0x b8 - Register Initialization, 511 Address and Data word pairs 49 * * List is terminated with an address of 0xffffffff or 50 * ... * at the max number of entries 51 * 0x8b4 52 * 0x8b8 - Reserved 53 * ... 54 * 0x9bf 55 * 0x9c0 - Data/Image starts here or above 56 */ 57 58 #include "imagetool.h" 59 #include "mkimage.h" 60 #include "zynqmpimage.h" 61 #include <image.h> 62 63 static struct zynqmp_header zynqmpimage_header; 64 static void *dynamic_header; 65 static FILE *fpmu; 66 67 static uint32_t zynqmpimage_checksum(struct zynqmp_header *ptr) 68 { 69 uint32_t checksum = 0; 70 71 if (ptr == NULL) 72 return 0; 73 74 checksum += le32_to_cpu(ptr->width_detection); 75 checksum += le32_to_cpu(ptr->image_identifier); 76 checksum += le32_to_cpu(ptr->encryption); 77 checksum += le32_to_cpu(ptr->image_load); 78 checksum += le32_to_cpu(ptr->image_offset); 79 checksum += le32_to_cpu(ptr->pfw_image_length); 80 checksum += le32_to_cpu(ptr->total_pfw_image_length); 81 checksum += le32_to_cpu(ptr->image_size); 82 checksum += le32_to_cpu(ptr->image_stored_size); 83 checksum += le32_to_cpu(ptr->image_attributes); 84 checksum = ~checksum; 85 86 return cpu_to_le32(checksum); 87 } 88 89 void zynqmpimage_default_header(struct zynqmp_header *ptr) 90 { 91 int i; 92 93 if (ptr == NULL) 94 return; 95 96 ptr->width_detection = HEADER_WIDTHDETECTION; 97 ptr->image_attributes = HEADER_CPU_SELECT_A53_64BIT; 98 ptr->image_identifier = HEADER_IMAGEIDENTIFIER; 99 ptr->encryption = cpu_to_le32(ENCRYPTION_NONE); 100 101 /* Setup not-supported/constant/reserved fields */ 102 for (i = 0; i < HEADER_INTERRUPT_VECTORS; i++) 103 ptr->interrupt_vectors[i] = HEADER_INTERRUPT_DEFAULT; 104 105 for (i = 0; i < HEADER_REGINITS; i++) { 106 ptr->register_init[i].address = HEADER_REGINIT_NULL; 107 ptr->register_init[i].data = 0; 108 } 109 110 /* 111 * Certain reserved fields are required to be set to 0, ensure they are 112 * set as such. 113 */ 114 ptr->pfw_image_length = 0x0; 115 ptr->total_pfw_image_length = 0x0; 116 } 117 118 /* mkimage glue functions */ 119 static int zynqmpimage_verify_header(unsigned char *ptr, int image_size, 120 struct image_tool_params *params) 121 { 122 struct zynqmp_header *zynqhdr = (struct zynqmp_header *)ptr; 123 124 if (image_size < sizeof(struct zynqmp_header)) 125 return -1; 126 127 if (zynqhdr->width_detection != HEADER_WIDTHDETECTION) 128 return -1; 129 if (zynqhdr->image_identifier != HEADER_IMAGEIDENTIFIER) 130 return -1; 131 132 if (zynqmpimage_checksum(zynqhdr) != zynqhdr->checksum) 133 return -1; 134 135 return 0; 136 } 137 138 static void print_partition(const void *ptr, const struct partition_header *ph) 139 { 140 uint32_t attr = le32_to_cpu(ph->attributes); 141 unsigned long len = le32_to_cpu(ph->len) * 4; 142 const char *part_owner; 143 const char *dest_devs[0x8] = { 144 "none", "PS", "PL", "PMU", "unknown", "unknown", "unknown", 145 "unknown" 146 }; 147 148 switch (attr & PART_ATTR_PART_OWNER_MASK) { 149 case PART_ATTR_PART_OWNER_FSBL: 150 part_owner = "FSBL"; 151 break; 152 case PART_ATTR_PART_OWNER_UBOOT: 153 part_owner = "U-Boot"; 154 break; 155 default: 156 part_owner = "Unknown"; 157 break; 158 } 159 160 printf("%s payload on CPU %s (%s):\n", part_owner, 161 dest_cpus[(attr & PART_ATTR_DEST_CPU_MASK) >> 8], 162 dest_devs[(attr & PART_ATTR_DEST_DEVICE_MASK) >> 4]); 163 164 printf(" Offset : 0x%08x\n", le32_to_cpu(ph->offset) * 4); 165 printf(" Size : %lu (0x%lx) bytes\n", len, len); 166 printf(" Load : 0x%08llx", 167 (unsigned long long)le64_to_cpu(ph->load_address)); 168 if (ph->load_address != ph->entry_point) 169 printf(" (entry=0x%08llx)\n", 170 (unsigned long long)le64_to_cpu(ph->entry_point)); 171 else 172 printf("\n"); 173 printf(" Attributes : "); 174 175 if (attr & PART_ATTR_VEC_LOCATION) 176 printf("vec "); 177 178 if (attr & PART_ATTR_ENCRYPTED) 179 printf("encrypted "); 180 181 switch (attr & PART_ATTR_CHECKSUM_MASK) { 182 case PART_ATTR_CHECKSUM_MD5: 183 printf("md5 "); 184 break; 185 case PART_ATTR_CHECKSUM_SHA2: 186 printf("sha2 "); 187 break; 188 case PART_ATTR_CHECKSUM_SHA3: 189 printf("sha3 "); 190 break; 191 } 192 193 if (attr & PART_ATTR_BIG_ENDIAN) 194 printf("BigEndian "); 195 196 if (attr & PART_ATTR_RSA_SIG) 197 printf("RSA "); 198 199 if (attr & PART_ATTR_A53_EXEC_AARCH32) 200 printf("AArch32 "); 201 202 if (attr & PART_ATTR_TARGET_EL_MASK) 203 printf("EL%d ", (attr & PART_ATTR_TARGET_EL_MASK) >> 1); 204 205 if (attr & PART_ATTR_TZ_SECURE) 206 printf("secure "); 207 printf("\n"); 208 209 printf(" Checksum : 0x%08x\n", le32_to_cpu(ph->checksum)); 210 } 211 212 void zynqmpimage_print_header(const void *ptr) 213 { 214 struct zynqmp_header *zynqhdr = (struct zynqmp_header *)ptr; 215 int i; 216 217 printf("Image Type : Xilinx ZynqMP Boot Image support\n"); 218 printf("Image Offset : 0x%08x\n", le32_to_cpu(zynqhdr->image_offset)); 219 printf("Image Size : %lu bytes (%lu bytes packed)\n", 220 (unsigned long)le32_to_cpu(zynqhdr->image_size), 221 (unsigned long)le32_to_cpu(zynqhdr->image_stored_size)); 222 223 if (zynqhdr->pfw_image_length) 224 printf("PMUFW Size : %lu bytes (%lu bytes packed)\n", 225 (unsigned long)le32_to_cpu(zynqhdr->pfw_image_length), 226 (unsigned long)le32_to_cpu( 227 zynqhdr->total_pfw_image_length)); 228 229 printf("Image Load : 0x%08x\n", le32_to_cpu(zynqhdr->image_load)); 230 printf("Checksum : 0x%08x\n", le32_to_cpu(zynqhdr->checksum)); 231 232 for (i = 0; i < HEADER_INTERRUPT_VECTORS; i++) { 233 if (zynqhdr->interrupt_vectors[i] == HEADER_INTERRUPT_DEFAULT) 234 continue; 235 236 printf("Modified Interrupt Vector Address [%d]: 0x%08x\n", i, 237 le32_to_cpu(zynqhdr->interrupt_vectors[i])); 238 } 239 240 for (i = 0; i < HEADER_REGINITS; i++) { 241 if (zynqhdr->register_init[i].address == HEADER_REGINIT_NULL) 242 break; 243 244 if (i == 0) 245 printf("Custom Register Initialization:\n"); 246 247 printf(" @ 0x%08x -> 0x%08x\n", 248 le32_to_cpu(zynqhdr->register_init[i].address), 249 le32_to_cpu(zynqhdr->register_init[i].data)); 250 } 251 252 if (zynqhdr->image_header_table_offset) { 253 struct image_header_table *iht = (void *)ptr + 254 zynqhdr->image_header_table_offset; 255 struct partition_header *ph; 256 uint32_t ph_offset; 257 uint32_t next; 258 int i; 259 260 ph_offset = le32_to_cpu(iht->partition_header_offset) * 4; 261 ph = (void *)ptr + ph_offset; 262 for (i = 0; i < le32_to_cpu(iht->nr_parts); i++) { 263 next = le32_to_cpu(ph->next_partition_offset) * 4; 264 265 /* Partition 0 is the base image itself */ 266 if (i) 267 print_partition(ptr, ph); 268 269 ph = (void *)ptr + next; 270 } 271 } 272 273 free(dynamic_header); 274 } 275 276 static int zynqmpimage_check_params(struct image_tool_params *params) 277 { 278 if (!params) 279 return 0; 280 281 if (params->addr != 0x0) { 282 fprintf(stderr, "Error: Load Address cannot be specified.\n"); 283 return -1; 284 } 285 286 /* 287 * If the entry point is specified ensure it is 64 byte aligned. 288 */ 289 if (params->eflag && (params->ep % 64 != 0)) { 290 fprintf(stderr, 291 "Error: Entry Point must be aligned to a 64-byte boundary.\n"); 292 return -1; 293 } 294 295 return !(params->lflag || params->dflag); 296 } 297 298 static int zynqmpimage_check_image_types(uint8_t type) 299 { 300 if (type == IH_TYPE_ZYNQMPIMAGE) 301 return EXIT_SUCCESS; 302 return EXIT_FAILURE; 303 } 304 305 static uint32_t fsize(FILE *fp) 306 { 307 int size, ret, origin; 308 309 origin = ftell(fp); 310 if (origin < 0) { 311 fprintf(stderr, "Incorrect file size\n"); 312 fclose(fp); 313 exit(2); 314 } 315 316 ret = fseek(fp, 0L, SEEK_END); 317 if (ret) { 318 fprintf(stderr, "Incorrect file SEEK_END\n"); 319 fclose(fp); 320 exit(3); 321 } 322 323 size = ftell(fp); 324 if (size < 0) { 325 fprintf(stderr, "Incorrect file size\n"); 326 fclose(fp); 327 exit(4); 328 } 329 330 /* going back */ 331 ret = fseek(fp, origin, SEEK_SET); 332 if (ret) { 333 fprintf(stderr, "Incorrect file SEEK_SET to %d\n", origin); 334 fclose(fp); 335 exit(3); 336 } 337 338 return size; 339 } 340 341 static void zynqmpimage_pmufw(struct zynqmp_header *zynqhdr, 342 const char *filename) 343 { 344 uint32_t size; 345 346 /* Setup PMU fw size */ 347 zynqhdr->pfw_image_length = fsize(fpmu); 348 zynqhdr->total_pfw_image_length = zynqhdr->pfw_image_length; 349 350 zynqhdr->image_size -= zynqhdr->pfw_image_length; 351 zynqhdr->image_stored_size -= zynqhdr->total_pfw_image_length; 352 353 /* Read the whole PMUFW to the header */ 354 size = fread(&zynqhdr->__reserved4[66], 1, 355 zynqhdr->pfw_image_length, fpmu); 356 if (size != zynqhdr->pfw_image_length) { 357 fprintf(stderr, "Cannot read PMUFW file: %s\n", filename); 358 fclose(fpmu); 359 exit(1); 360 } 361 362 fclose(fpmu); 363 } 364 365 static void zynqmpimage_parse_initparams(struct zynqmp_header *zynqhdr, 366 const char *filename) 367 { 368 FILE *fp; 369 struct zynqmp_reginit reginit; 370 unsigned int reg_count = 0; 371 int r, err; 372 struct stat path_stat; 373 374 /* Expect a table of register-value pairs, e.g. "0x12345678 0x4321" */ 375 fp = fopen(filename, "r"); 376 if (!fp) { 377 fprintf(stderr, "Cannot open initparams file: %s\n", filename); 378 exit(1); 379 } 380 381 err = fstat(fileno(fp), &path_stat); 382 if (err) { 383 fclose(fp); 384 return; 385 } 386 387 if (!S_ISREG(path_stat.st_mode)) { 388 fclose(fp); 389 return; 390 } 391 392 do { 393 r = fscanf(fp, "%x %x", ®init.address, ®init.data); 394 if (r == 2) { 395 zynqhdr->register_init[reg_count] = reginit; 396 ++reg_count; 397 } 398 r = fscanf(fp, "%*[^\n]\n"); /* Skip to next line */ 399 } while ((r != EOF) && (reg_count < HEADER_REGINITS)); 400 fclose(fp); 401 } 402 403 static void zynqmpimage_set_header(void *ptr, struct stat *sbuf, int ifd, 404 struct image_tool_params *params) 405 { 406 struct zynqmp_header *zynqhdr = (struct zynqmp_header *)ptr; 407 zynqmpimage_default_header(zynqhdr); 408 409 /* place image directly after header */ 410 zynqhdr->image_offset = 411 cpu_to_le32((uint32_t)sizeof(struct zynqmp_header)); 412 zynqhdr->image_size = cpu_to_le32(params->file_size - 413 sizeof(struct zynqmp_header)); 414 zynqhdr->image_stored_size = zynqhdr->image_size; 415 zynqhdr->image_load = 0xfffc0000; 416 if (params->eflag) 417 zynqhdr->image_load = cpu_to_le32((uint32_t)params->ep); 418 419 /* PMUFW */ 420 if (fpmu) 421 zynqmpimage_pmufw(zynqhdr, params->imagename); 422 423 /* User can pass in text file with init list */ 424 if (strlen(params->imagename2)) 425 zynqmpimage_parse_initparams(zynqhdr, params->imagename2); 426 427 zynqhdr->checksum = zynqmpimage_checksum(zynqhdr); 428 } 429 430 static int zynqmpimage_vrec_header(struct image_tool_params *params, 431 struct image_type_params *tparams) 432 { 433 struct stat path_stat; 434 char *filename = params->imagename; 435 int err; 436 437 /* Handle static case without PMUFW */ 438 tparams->header_size = sizeof(struct zynqmp_header); 439 tparams->hdr = (void *)&zynqmpimage_header; 440 441 /* PMUFW name is passed via params->imagename */ 442 if (strlen(filename) == 0) 443 return EXIT_SUCCESS; 444 445 fpmu = fopen(filename, "r"); 446 if (!fpmu) { 447 fprintf(stderr, "Cannot open PMUFW file: %s\n", filename); 448 return EXIT_FAILURE; 449 } 450 451 err = fstat(fileno(fpmu), &path_stat); 452 if (err) { 453 fclose(fpmu); 454 fpmu = NULL; 455 return EXIT_FAILURE; 456 } 457 458 if (!S_ISREG(path_stat.st_mode)) { 459 fclose(fpmu); 460 fpmu = NULL; 461 return EXIT_FAILURE; 462 } 463 464 /* Increase header size by PMUFW file size */ 465 tparams->header_size += fsize(fpmu); 466 467 /* Allocate buffer with space for PMUFW */ 468 dynamic_header = calloc(1, tparams->header_size); 469 tparams->hdr = dynamic_header; 470 471 return EXIT_SUCCESS; 472 } 473 474 U_BOOT_IMAGE_TYPE( 475 zynqmpimage, 476 "Xilinx ZynqMP Boot Image support", 477 sizeof(struct zynqmp_header), 478 (void *)&zynqmpimage_header, 479 zynqmpimage_check_params, 480 zynqmpimage_verify_header, 481 zynqmpimage_print_header, 482 zynqmpimage_set_header, 483 NULL, 484 zynqmpimage_check_image_types, 485 NULL, 486 zynqmpimage_vrec_header 487 ); 488