1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2011 4 * Stefano Babic, DENX Software Engineering, sbabic@denx.de. 5 */ 6 7 #include "imagetool.h" 8 #include "aisimage.h" 9 #include <image.h> 10 11 #define IS_FNC_EXEC(c) (cmd_table[c].AIS_cmd == AIS_CMD_FNLOAD) 12 #define WORD_ALIGN0 4 13 #define WORD_ALIGN(len) (((len)+WORD_ALIGN0-1) & ~(WORD_ALIGN0-1)) 14 #define MAX_CMD_BUFFER 4096 15 16 static uint32_t ais_img_size; 17 18 /* 19 * Supported commands for configuration file 20 */ 21 static table_entry_t aisimage_cmds[] = { 22 {CMD_DATA, "DATA", "Reg Write Data"}, 23 {CMD_FILL, "FILL", "Fill range with pattern"}, 24 {CMD_CRCON, "CRCON", "CRC Enable"}, 25 {CMD_CRCOFF, "CRCOFF", "CRC Disable"}, 26 {CMD_CRCCHECK, "CRCCHECK", "CRC Validate"}, 27 {CMD_JMPCLOSE, "JMPCLOSE", "Jump & Close"}, 28 {CMD_JMP, "JMP", "Jump"}, 29 {CMD_SEQREAD, "SEQREAD", "Sequential read"}, 30 {CMD_PLL0, "PLL0", "PLL0"}, 31 {CMD_PLL1, "PLL1", "PLL1"}, 32 {CMD_CLK, "CLK", "Clock configuration"}, 33 {CMD_DDR2, "DDR2", "DDR2 Configuration"}, 34 {CMD_EMIFA, "EMIFA", "EMIFA"}, 35 {CMD_EMIFA_ASYNC, "EMIFA_ASYNC", "EMIFA Async"}, 36 {CMD_PLL, "PLL", "PLL & Clock configuration"}, 37 {CMD_PSC, "PSC", "PSC setup"}, 38 {CMD_PINMUX, "PINMUX", "Pinmux setup"}, 39 {CMD_BOOTTABLE, "BOOT_TABLE", "Boot table command"}, 40 {-1, "", ""}, 41 }; 42 43 static struct ais_func_exec { 44 uint32_t index; 45 uint32_t argcnt; 46 } ais_func_table[] = { 47 [CMD_PLL0] = {0, 2}, 48 [CMD_PLL1] = {1, 2}, 49 [CMD_CLK] = {2, 1}, 50 [CMD_DDR2] = {3, 8}, 51 [CMD_EMIFA] = {4, 5}, 52 [CMD_EMIFA_ASYNC] = {5, 5}, 53 [CMD_PLL] = {6, 3}, 54 [CMD_PSC] = {7, 1}, 55 [CMD_PINMUX] = {8, 3} 56 }; 57 58 static struct cmd_table_t { 59 uint32_t nargs; 60 uint32_t AIS_cmd; 61 } cmd_table[] = { 62 [CMD_FILL] = { 4, AIS_CMD_FILL}, 63 [CMD_CRCON] = { 0, AIS_CMD_ENCRC}, 64 [CMD_CRCOFF] = { 0, AIS_CMD_DISCRC}, 65 [CMD_CRCCHECK] = { 2, AIS_CMD_ENCRC}, 66 [CMD_JMPCLOSE] = { 1, AIS_CMD_JMPCLOSE}, 67 [CMD_JMP] = { 1, AIS_CMD_JMP}, 68 [CMD_SEQREAD] = { 0, AIS_CMD_SEQREAD}, 69 [CMD_PLL0] = { 2, AIS_CMD_FNLOAD}, 70 [CMD_PLL1] = { 2, AIS_CMD_FNLOAD}, 71 [CMD_CLK] = { 1, AIS_CMD_FNLOAD}, 72 [CMD_DDR2] = { 8, AIS_CMD_FNLOAD}, 73 [CMD_EMIFA] = { 5, AIS_CMD_FNLOAD}, 74 [CMD_EMIFA_ASYNC] = { 5, AIS_CMD_FNLOAD}, 75 [CMD_PLL] = { 3, AIS_CMD_FNLOAD}, 76 [CMD_PSC] = { 1, AIS_CMD_FNLOAD}, 77 [CMD_PINMUX] = { 3, AIS_CMD_FNLOAD}, 78 [CMD_BOOTTABLE] = { 4, AIS_CMD_BOOTTBL}, 79 }; 80 81 static uint32_t get_cfg_value(char *token, char *name, int linenr) 82 { 83 char *endptr; 84 uint32_t value; 85 86 errno = 0; 87 value = strtoul(token, &endptr, 16); 88 if (errno || (token == endptr)) { 89 fprintf(stderr, "Error: %s[%d] - Invalid hex data(%s)\n", 90 name, linenr, token); 91 exit(EXIT_FAILURE); 92 } 93 return value; 94 } 95 96 static int get_ais_table_id(uint32_t *ptr) 97 { 98 99 int i; 100 int func_no; 101 102 for (i = 0; i < ARRAY_SIZE(cmd_table); i++) { 103 if (*ptr == cmd_table[i].AIS_cmd) { 104 if (cmd_table[i].AIS_cmd != AIS_CMD_FNLOAD) 105 return i; 106 107 func_no = ((struct ais_cmd_func *)ptr)->func_args 108 & 0xFFFF; 109 if (func_no == ais_func_table[i].index) 110 return i; 111 } 112 } 113 114 return -1; 115 } 116 117 static void aisimage_print_header(const void *hdr) 118 { 119 struct ais_header *ais_hdr = (struct ais_header *)hdr; 120 uint32_t *ptr; 121 struct ais_cmd_load *ais_load; 122 int id; 123 124 if (ais_hdr->magic != AIS_MAGIC_WORD) { 125 fprintf(stderr, "Error: - AIS Magic Number not found\n"); 126 return; 127 } 128 fprintf(stdout, "Image Type: TI Davinci AIS Boot Image\n"); 129 fprintf(stdout, "AIS magic : %08x\n", ais_hdr->magic); 130 ptr = (uint32_t *)&ais_hdr->magic; 131 ptr++; 132 133 while (*ptr != AIS_CMD_JMPCLOSE) { 134 /* Check if we find the image */ 135 if (*ptr == AIS_CMD_LOAD) { 136 ais_load = (struct ais_cmd_load *)ptr; 137 fprintf(stdout, "Image at : 0x%08x size 0x%08x\n", 138 ais_load->addr, 139 ais_load->size); 140 ptr = ais_load->data + ais_load->size / sizeof(*ptr); 141 continue; 142 } 143 144 id = get_ais_table_id(ptr); 145 if (id < 0) { 146 fprintf(stderr, "Error: - AIS Image corrupted\n"); 147 return; 148 } 149 fprintf(stdout, "AIS cmd : %s\n", 150 get_table_entry_name(aisimage_cmds, NULL, id)); 151 ptr += cmd_table[id].nargs + IS_FNC_EXEC(id) + 1; 152 if (((void *)ptr - hdr) > ais_img_size) { 153 fprintf(stderr, 154 "AIS Image not terminated by JMPCLOSE\n"); 155 return; 156 } 157 } 158 } 159 160 static uint32_t *ais_insert_cmd_header(uint32_t cmd, uint32_t nargs, 161 uint32_t *parms, struct image_type_params *tparams, 162 uint32_t *ptr) 163 { 164 int i; 165 166 *ptr++ = cmd_table[cmd].AIS_cmd; 167 if (IS_FNC_EXEC(cmd)) 168 *ptr++ = ((nargs & 0xFFFF) << 16) + ais_func_table[cmd].index; 169 170 /* Copy parameters */ 171 for (i = 0; i < nargs; i++) 172 *ptr++ = cpu_to_le32(parms[i]); 173 174 return ptr; 175 176 } 177 178 static uint32_t *ais_alloc_buffer(struct image_tool_params *params) 179 { 180 int dfd; 181 struct stat sbuf; 182 char *datafile = params->datafile; 183 uint32_t *ptr; 184 185 dfd = open(datafile, O_RDONLY|O_BINARY); 186 if (dfd < 0) { 187 fprintf(stderr, "%s: Can't open %s: %s\n", 188 params->cmdname, datafile, strerror(errno)); 189 exit(EXIT_FAILURE); 190 } 191 192 if (fstat(dfd, &sbuf) < 0) { 193 fprintf(stderr, "%s: Can't stat %s: %s\n", 194 params->cmdname, datafile, strerror(errno)); 195 exit(EXIT_FAILURE); 196 } 197 198 /* 199 * Place for header is allocated. The size is taken from 200 * the size of the datafile, that the ais_image_generate() 201 * will copy into the header. Copying the datafile 202 * is not left to the main program, because after the datafile 203 * the header must be terminated with the Jump & Close command. 204 */ 205 ais_img_size = WORD_ALIGN(sbuf.st_size) + MAX_CMD_BUFFER; 206 ptr = (uint32_t *)malloc(WORD_ALIGN(sbuf.st_size) + MAX_CMD_BUFFER); 207 if (!ptr) { 208 fprintf(stderr, "%s: malloc return failure: %s\n", 209 params->cmdname, strerror(errno)); 210 exit(EXIT_FAILURE); 211 } 212 213 close(dfd); 214 215 return ptr; 216 } 217 218 static uint32_t *ais_copy_image(struct image_tool_params *params, 219 uint32_t *aisptr) 220 221 { 222 int dfd; 223 struct stat sbuf; 224 char *datafile = params->datafile; 225 void *ptr; 226 227 dfd = open(datafile, O_RDONLY|O_BINARY); 228 if (dfd < 0) { 229 fprintf(stderr, "%s: Can't open %s: %s\n", 230 params->cmdname, datafile, strerror(errno)); 231 exit(EXIT_FAILURE); 232 } 233 234 if (fstat(dfd, &sbuf) < 0) { 235 fprintf(stderr, "%s: Can't stat %s: %s\n", 236 params->cmdname, datafile, strerror(errno)); 237 exit(EXIT_FAILURE); 238 } 239 240 ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0); 241 *aisptr++ = AIS_CMD_LOAD; 242 *aisptr++ = params->ep; 243 *aisptr++ = sbuf.st_size; 244 memcpy((void *)aisptr, ptr, sbuf.st_size); 245 aisptr += WORD_ALIGN(sbuf.st_size) / sizeof(uint32_t); 246 247 (void) munmap((void *)ptr, sbuf.st_size); 248 (void) close(dfd); 249 250 return aisptr; 251 252 } 253 254 static int aisimage_generate(struct image_tool_params *params, 255 struct image_type_params *tparams) 256 { 257 FILE *fd = NULL; 258 char *line = NULL; 259 char *token, *saveptr1, *saveptr2; 260 int lineno = 0; 261 int fld; 262 size_t len; 263 int32_t cmd; 264 uint32_t nargs, cmd_parms[10]; 265 uint32_t value, size; 266 char *name = params->imagename; 267 uint32_t *aishdr; 268 269 fd = fopen(name, "r"); 270 if (fd == 0) { 271 fprintf(stderr, 272 "Error: %s - Can't open AIS configuration\n", name); 273 exit(EXIT_FAILURE); 274 } 275 276 /* 277 * the size of the header is variable and is computed 278 * scanning the configuration file. 279 */ 280 tparams->header_size = 0; 281 282 /* 283 * Start allocating a buffer suitable for most command 284 * The buffer is then reallocated if it is too small 285 */ 286 aishdr = ais_alloc_buffer(params); 287 tparams->hdr = aishdr; 288 *aishdr++ = AIS_MAGIC_WORD; 289 290 /* Very simple parsing, line starting with # are comments 291 * and are dropped 292 */ 293 while ((getline(&line, &len, fd)) > 0) { 294 lineno++; 295 296 token = strtok_r(line, "\r\n", &saveptr1); 297 if (token == NULL) 298 continue; 299 300 /* Check inside the single line */ 301 line = token; 302 fld = CFG_COMMAND; 303 cmd = CMD_INVALID; 304 nargs = 0; 305 while (token != NULL) { 306 token = strtok_r(line, " \t", &saveptr2); 307 if (token == NULL) 308 break; 309 310 /* Drop all text starting with '#' as comments */ 311 if (token[0] == '#') 312 break; 313 314 switch (fld) { 315 case CFG_COMMAND: 316 cmd = get_table_entry_id(aisimage_cmds, 317 "aisimage commands", token); 318 if (cmd < 0) { 319 fprintf(stderr, 320 "Error: %s[%d] - Invalid command" 321 "(%s)\n", name, lineno, token); 322 323 exit(EXIT_FAILURE); 324 } 325 break; 326 case CFG_VALUE: 327 value = get_cfg_value(token, name, lineno); 328 cmd_parms[nargs++] = value; 329 if (nargs > cmd_table[cmd].nargs) { 330 fprintf(stderr, 331 "Error: %s[%d] - too much arguments:" 332 "(%s) for command %s\n", name, 333 lineno, token, 334 aisimage_cmds[cmd].sname); 335 exit(EXIT_FAILURE); 336 } 337 break; 338 } 339 line = NULL; 340 fld = CFG_VALUE; 341 } 342 if (cmd != CMD_INVALID) { 343 /* Now insert the command into the header */ 344 aishdr = ais_insert_cmd_header(cmd, nargs, cmd_parms, 345 tparams, aishdr); 346 } 347 348 } 349 fclose(fd); 350 351 aishdr = ais_copy_image(params, aishdr); 352 353 /* Add Jmp & Close */ 354 *aishdr++ = AIS_CMD_JMPCLOSE; 355 *aishdr++ = params->ep; 356 357 size = (aishdr - (uint32_t *)tparams->hdr) * sizeof(uint32_t); 358 tparams->header_size = size; 359 360 return 0; 361 } 362 363 static int aisimage_check_image_types(uint8_t type) 364 { 365 if (type == IH_TYPE_AISIMAGE) 366 return EXIT_SUCCESS; 367 else 368 return EXIT_FAILURE; 369 } 370 371 static int aisimage_verify_header(unsigned char *ptr, int image_size, 372 struct image_tool_params *params) 373 { 374 struct ais_header *ais_hdr = (struct ais_header *)ptr; 375 376 if (ais_hdr->magic != AIS_MAGIC_WORD) 377 return -FDT_ERR_BADSTRUCTURE; 378 379 /* Store the total size to remember in print_hdr */ 380 ais_img_size = image_size; 381 382 return 0; 383 } 384 385 static void aisimage_set_header(void *ptr, struct stat *sbuf, int ifd, 386 struct image_tool_params *params) 387 { 388 } 389 390 int aisimage_check_params(struct image_tool_params *params) 391 { 392 if (!params) 393 return CFG_INVALID; 394 if (!strlen(params->imagename)) { 395 fprintf(stderr, "Error: %s - Configuration file not specified, " 396 "it is needed for aisimage generation\n", 397 params->cmdname); 398 return CFG_INVALID; 399 } 400 /* 401 * Check parameters: 402 * XIP is not allowed and verify that incompatible 403 * parameters are not sent at the same time 404 * For example, if list is required a data image must not be provided 405 */ 406 return (params->dflag && (params->fflag || params->lflag)) || 407 (params->fflag && (params->dflag || params->lflag)) || 408 (params->lflag && (params->dflag || params->fflag)) || 409 (params->xflag) || !(strlen(params->imagename)); 410 } 411 412 /* 413 * aisimage parameters 414 */ 415 U_BOOT_IMAGE_TYPE( 416 aisimage, 417 "TI Davinci AIS Boot Image support", 418 0, 419 NULL, 420 aisimage_check_params, 421 aisimage_verify_header, 422 aisimage_print_header, 423 aisimage_set_header, 424 NULL, 425 aisimage_check_image_types, 426 NULL, 427 aisimage_generate 428 ); 429