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