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