1 /* 2 * Copyright (C) 2016 Michal Simek <michals@xilinx.com> 3 * Copyright (C) 2015 Nathan Rossi <nathan@nathanrossi.com> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 * 7 * The following Boot Header format/structures and values are defined in the 8 * following documents: 9 * * ug1085 ZynqMP TRM doc v1.4 (Chapter 11, Table 11-4) 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 <image.h> 61 62 #define HEADER_INTERRUPT_DEFAULT (cpu_to_le32(0xeafffffe)) 63 #define HEADER_REGINIT_NULL (cpu_to_le32(0xffffffff)) 64 #define HEADER_WIDTHDETECTION (cpu_to_le32(0xaa995566)) 65 #define HEADER_IMAGEIDENTIFIER (cpu_to_le32(0x584c4e58)) 66 67 enum { 68 ENCRYPTION_EFUSE = 0xa5c3c5a3, 69 ENCRYPTION_OEFUSE = 0xa5c3c5a7, 70 ENCRYPTION_BBRAM = 0x3a5c3c5a, 71 ENCRYPTION_OBBRAM = 0xa35c7ca5, 72 ENCRYPTION_NONE = 0x0, 73 }; 74 75 struct zynqmp_reginit { 76 uint32_t address; 77 uint32_t data; 78 }; 79 80 #define HEADER_INTERRUPT_VECTORS 8 81 #define HEADER_REGINITS 256 82 83 struct zynqmp_header { 84 uint32_t interrupt_vectors[HEADER_INTERRUPT_VECTORS]; /* 0x0 */ 85 uint32_t width_detection; /* 0x20 */ 86 uint32_t image_identifier; /* 0x24 */ 87 uint32_t encryption; /* 0x28 */ 88 uint32_t image_load; /* 0x2c */ 89 uint32_t image_offset; /* 0x30 */ 90 uint32_t pfw_image_length; /* 0x34 */ 91 uint32_t total_pfw_image_length; /* 0x38 */ 92 uint32_t image_size; /* 0x3c */ 93 uint32_t image_stored_size; /* 0x40 */ 94 uint32_t image_attributes; /* 0x44 */ 95 uint32_t checksum; /* 0x48 */ 96 uint32_t __reserved1[27]; /* 0x4c */ 97 struct zynqmp_reginit register_init[HEADER_REGINITS]; /* 0xb8 */ 98 uint32_t __reserved4[66]; /* 0x9c0 */ 99 }; 100 101 static struct zynqmp_header zynqmpimage_header; 102 static void *dynamic_header; 103 static FILE *fpmu; 104 105 static uint32_t zynqmpimage_checksum(struct zynqmp_header *ptr) 106 { 107 uint32_t checksum = 0; 108 109 if (ptr == NULL) 110 return 0; 111 112 checksum += le32_to_cpu(ptr->width_detection); 113 checksum += le32_to_cpu(ptr->image_identifier); 114 checksum += le32_to_cpu(ptr->encryption); 115 checksum += le32_to_cpu(ptr->image_load); 116 checksum += le32_to_cpu(ptr->image_offset); 117 checksum += le32_to_cpu(ptr->pfw_image_length); 118 checksum += le32_to_cpu(ptr->total_pfw_image_length); 119 checksum += le32_to_cpu(ptr->image_size); 120 checksum += le32_to_cpu(ptr->image_stored_size); 121 checksum += le32_to_cpu(ptr->image_attributes); 122 checksum = ~checksum; 123 124 return cpu_to_le32(checksum); 125 } 126 127 static void zynqmpimage_default_header(struct zynqmp_header *ptr) 128 { 129 int i; 130 131 if (ptr == NULL) 132 return; 133 134 ptr->width_detection = HEADER_WIDTHDETECTION; 135 ptr->image_attributes = 0x800; 136 ptr->image_identifier = HEADER_IMAGEIDENTIFIER; 137 ptr->encryption = cpu_to_le32(ENCRYPTION_NONE); 138 139 /* Setup not-supported/constant/reserved fields */ 140 for (i = 0; i < HEADER_INTERRUPT_VECTORS; i++) 141 ptr->interrupt_vectors[i] = HEADER_INTERRUPT_DEFAULT; 142 143 for (i = 0; i < HEADER_REGINITS; i++) { 144 ptr->register_init[i].address = HEADER_REGINIT_NULL; 145 ptr->register_init[i].data = 0; 146 } 147 148 /* 149 * Certain reserved fields are required to be set to 0, ensure they are 150 * set as such. 151 */ 152 ptr->pfw_image_length = 0x0; 153 ptr->total_pfw_image_length = 0x0; 154 } 155 156 /* mkimage glue functions */ 157 static int zynqmpimage_verify_header(unsigned char *ptr, int image_size, 158 struct image_tool_params *params) 159 { 160 struct zynqmp_header *zynqhdr = (struct zynqmp_header *)ptr; 161 162 if (image_size < sizeof(struct zynqmp_header)) 163 return -1; 164 165 if (zynqhdr->width_detection != HEADER_WIDTHDETECTION) 166 return -1; 167 if (zynqhdr->image_identifier != HEADER_IMAGEIDENTIFIER) 168 return -1; 169 170 if (zynqmpimage_checksum(zynqhdr) != zynqhdr->checksum) 171 return -1; 172 173 return 0; 174 } 175 176 static void zynqmpimage_print_header(const void *ptr) 177 { 178 struct zynqmp_header *zynqhdr = (struct zynqmp_header *)ptr; 179 int i; 180 181 printf("Image Type : Xilinx Zynq Boot Image support\n"); 182 printf("Image Offset : 0x%08x\n", le32_to_cpu(zynqhdr->image_offset)); 183 printf("Image Size : %lu bytes (%lu bytes packed)\n", 184 (unsigned long)le32_to_cpu(zynqhdr->image_size), 185 (unsigned long)le32_to_cpu(zynqhdr->image_stored_size)); 186 187 if (zynqhdr->pfw_image_length) 188 printf("PMUFW Size : %lu bytes (%lu bytes packed)\n", 189 (unsigned long)le32_to_cpu(zynqhdr->pfw_image_length), 190 (unsigned long)le32_to_cpu( 191 zynqhdr->total_pfw_image_length)); 192 193 printf("Image Load : 0x%08x\n", le32_to_cpu(zynqhdr->image_load)); 194 printf("Checksum : 0x%08x\n", le32_to_cpu(zynqhdr->checksum)); 195 196 for (i = 0; i < HEADER_INTERRUPT_VECTORS; i++) { 197 if (zynqhdr->interrupt_vectors[i] == HEADER_INTERRUPT_DEFAULT) 198 continue; 199 200 printf("Modified Interrupt Vector Address [%d]: 0x%08x\n", i, 201 le32_to_cpu(zynqhdr->interrupt_vectors[i])); 202 } 203 204 for (i = 0; i < HEADER_REGINITS; i++) { 205 if (zynqhdr->register_init[i].address == HEADER_REGINIT_NULL) 206 break; 207 208 if (i == 0) 209 printf("Custom Register Initialization:\n"); 210 211 printf(" @ 0x%08x -> 0x%08x\n", 212 le32_to_cpu(zynqhdr->register_init[i].address), 213 le32_to_cpu(zynqhdr->register_init[i].data)); 214 } 215 216 free(dynamic_header); 217 } 218 219 static int zynqmpimage_check_params(struct image_tool_params *params) 220 { 221 if (!params) 222 return 0; 223 224 if (params->addr != 0x0) { 225 fprintf(stderr, "Error: Load Address cannot be specified.\n"); 226 return -1; 227 } 228 229 /* 230 * If the entry point is specified ensure it is 64 byte aligned. 231 */ 232 if (params->eflag && (params->ep % 64 != 0)) { 233 fprintf(stderr, 234 "Error: Entry Point must be aligned to a 64-byte boundary.\n"); 235 return -1; 236 } 237 238 return !(params->lflag || params->dflag); 239 } 240 241 static int zynqmpimage_check_image_types(uint8_t type) 242 { 243 if (type == IH_TYPE_ZYNQMPIMAGE) 244 return EXIT_SUCCESS; 245 return EXIT_FAILURE; 246 } 247 248 static int fsize(FILE *fp) 249 { 250 int size; 251 int origin = ftell(fp); 252 253 fseek(fp, 0L, SEEK_END); 254 size = ftell(fp); 255 256 /* going back */ 257 fseek(fp, origin, SEEK_SET); 258 259 return size; 260 } 261 262 static void zynqmpimage_pmufw(struct zynqmp_header *zynqhdr, 263 const char *filename) 264 { 265 uint32_t size; 266 267 /* Setup PMU fw size */ 268 zynqhdr->pfw_image_length = fsize(fpmu); 269 zynqhdr->total_pfw_image_length = zynqhdr->pfw_image_length; 270 271 zynqhdr->image_size -= zynqhdr->pfw_image_length; 272 zynqhdr->image_stored_size -= zynqhdr->total_pfw_image_length; 273 274 /* Read the whole PMUFW to the header */ 275 size = fread(&zynqhdr->__reserved4[66], 1, 276 zynqhdr->pfw_image_length, fpmu); 277 if (size != zynqhdr->pfw_image_length) { 278 fprintf(stderr, "Cannot read PMUFW file: %s\n", filename); 279 fclose(fpmu); 280 exit(1); 281 } 282 283 fclose(fpmu); 284 } 285 286 static void zynqmpimage_parse_initparams(struct zynqmp_header *zynqhdr, 287 const char *filename) 288 { 289 FILE *fp; 290 struct zynqmp_reginit reginit; 291 unsigned int reg_count = 0; 292 int r, err; 293 struct stat path_stat; 294 295 /* Expect a table of register-value pairs, e.g. "0x12345678 0x4321" */ 296 fp = fopen(filename, "r"); 297 if (!fp) { 298 fprintf(stderr, "Cannot open initparams file: %s\n", filename); 299 exit(1); 300 } 301 302 err = fstat(fileno(fp), &path_stat); 303 if (err) { 304 fclose(fp); 305 return; 306 } 307 308 if (!S_ISREG(path_stat.st_mode)) { 309 fclose(fp); 310 return; 311 } 312 313 do { 314 r = fscanf(fp, "%x %x", ®init.address, ®init.data); 315 if (r == 2) { 316 zynqhdr->register_init[reg_count] = reginit; 317 ++reg_count; 318 } 319 r = fscanf(fp, "%*[^\n]\n"); /* Skip to next line */ 320 } while ((r != EOF) && (reg_count < HEADER_REGINITS)); 321 fclose(fp); 322 } 323 324 static void zynqmpimage_set_header(void *ptr, struct stat *sbuf, int ifd, 325 struct image_tool_params *params) 326 { 327 struct zynqmp_header *zynqhdr = (struct zynqmp_header *)ptr; 328 zynqmpimage_default_header(zynqhdr); 329 330 /* place image directly after header */ 331 zynqhdr->image_offset = 332 cpu_to_le32((uint32_t)sizeof(struct zynqmp_header)); 333 zynqhdr->image_size = cpu_to_le32(params->file_size - 334 sizeof(struct zynqmp_header)); 335 zynqhdr->image_stored_size = zynqhdr->image_size; 336 zynqhdr->image_load = 0xfffc0000; 337 if (params->eflag) 338 zynqhdr->image_load = cpu_to_le32((uint32_t)params->ep); 339 340 /* PMUFW */ 341 if (fpmu) 342 zynqmpimage_pmufw(zynqhdr, params->imagename); 343 344 /* User can pass in text file with init list */ 345 if (strlen(params->imagename2)) 346 zynqmpimage_parse_initparams(zynqhdr, params->imagename2); 347 348 zynqhdr->checksum = zynqmpimage_checksum(zynqhdr); 349 } 350 351 static int zynqmpimage_vrec_header(struct image_tool_params *params, 352 struct image_type_params *tparams) 353 { 354 struct stat path_stat; 355 char *filename = params->imagename; 356 int err; 357 358 /* Handle static case without PMUFW */ 359 tparams->header_size = sizeof(struct zynqmp_header); 360 tparams->hdr = (void *)&zynqmpimage_header; 361 362 /* PMUFW name is passed via params->imagename */ 363 if (strlen(filename) == 0) 364 return EXIT_SUCCESS; 365 366 fpmu = fopen(filename, "r"); 367 if (!fpmu) { 368 fprintf(stderr, "Cannot open PMUFW file: %s\n", filename); 369 return EXIT_FAILURE; 370 } 371 372 err = fstat(fileno(fpmu), &path_stat); 373 if (err) { 374 fclose(fpmu); 375 fpmu = NULL; 376 return EXIT_FAILURE; 377 } 378 379 if (!S_ISREG(path_stat.st_mode)) { 380 fclose(fpmu); 381 fpmu = NULL; 382 return EXIT_FAILURE; 383 } 384 385 /* Increase header size by PMUFW file size */ 386 tparams->header_size += fsize(fpmu); 387 388 /* Allocate buffer with space for PMUFW */ 389 dynamic_header = calloc(1, tparams->header_size); 390 tparams->hdr = dynamic_header; 391 392 return EXIT_SUCCESS; 393 } 394 395 U_BOOT_IMAGE_TYPE( 396 zynqmpimage, 397 "Xilinx ZynqMP Boot Image support", 398 sizeof(struct zynqmp_header), 399 (void *)&zynqmpimage_header, 400 zynqmpimage_check_params, 401 zynqmpimage_verify_header, 402 zynqmpimage_print_header, 403 zynqmpimage_set_header, 404 NULL, 405 zynqmpimage_check_image_types, 406 NULL, 407 zynqmpimage_vrec_header 408 ); 409