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 MAX_CMD_BUFFER 4096 14 15static uint32_t ais_img_size; 16 17/* 18 * Supported commands for configuration file 19 */ 20static table_entry_t aisimage_cmds[] = { 21 {CMD_DATA, "DATA", "Reg Write Data"}, 22 {CMD_FILL, "FILL", "Fill range with pattern"}, 23 {CMD_CRCON, "CRCON", "CRC Enable"}, 24 {CMD_CRCOFF, "CRCOFF", "CRC Disable"}, 25 {CMD_CRCCHECK, "CRCCHECK", "CRC Validate"}, 26 {CMD_JMPCLOSE, "JMPCLOSE", "Jump & Close"}, 27 {CMD_JMP, "JMP", "Jump"}, 28 {CMD_SEQREAD, "SEQREAD", "Sequential read"}, 29 {CMD_PLL0, "PLL0", "PLL0"}, 30 {CMD_PLL1, "PLL1", "PLL1"}, 31 {CMD_CLK, "CLK", "Clock configuration"}, 32 {CMD_DDR2, "DDR2", "DDR2 Configuration"}, 33 {CMD_EMIFA, "EMIFA", "EMIFA"}, 34 {CMD_EMIFA_ASYNC, "EMIFA_ASYNC", "EMIFA Async"}, 35 {CMD_PLL, "PLL", "PLL & Clock configuration"}, 36 {CMD_PSC, "PSC", "PSC setup"}, 37 {CMD_PINMUX, "PINMUX", "Pinmux setup"}, 38 {CMD_BOOTTABLE, "BOOT_TABLE", "Boot table command"}, 39 {-1, "", ""}, 40}; 41 42static struct ais_func_exec { 43 uint32_t index; 44 uint32_t argcnt; 45} ais_func_table[] = { 46 [CMD_PLL0] = {0, 2}, 47 [CMD_PLL1] = {1, 2}, 48 [CMD_CLK] = {2, 1}, 49 [CMD_DDR2] = {3, 8}, 50 [CMD_EMIFA] = {4, 5}, 51 [CMD_EMIFA_ASYNC] = {5, 5}, 52 [CMD_PLL] = {6, 3}, 53 [CMD_PSC] = {7, 1}, 54 [CMD_PINMUX] = {8, 3} 55}; 56 57static struct cmd_table_t { 58 uint32_t nargs; 59 uint32_t AIS_cmd; 60} cmd_table[] = { 61 [CMD_FILL] = { 4, AIS_CMD_FILL}, 62 [CMD_CRCON] = { 0, AIS_CMD_ENCRC}, 63 [CMD_CRCOFF] = { 0, AIS_CMD_DISCRC}, 64 [CMD_CRCCHECK] = { 2, AIS_CMD_ENCRC}, 65 [CMD_JMPCLOSE] = { 1, AIS_CMD_JMPCLOSE}, 66 [CMD_JMP] = { 1, AIS_CMD_JMP}, 67 [CMD_SEQREAD] = { 0, AIS_CMD_SEQREAD}, 68 [CMD_PLL0] = { 2, AIS_CMD_FNLOAD}, 69 [CMD_PLL1] = { 2, AIS_CMD_FNLOAD}, 70 [CMD_CLK] = { 1, AIS_CMD_FNLOAD}, 71 [CMD_DDR2] = { 8, AIS_CMD_FNLOAD}, 72 [CMD_EMIFA] = { 5, AIS_CMD_FNLOAD}, 73 [CMD_EMIFA_ASYNC] = { 5, AIS_CMD_FNLOAD}, 74 [CMD_PLL] = { 3, AIS_CMD_FNLOAD}, 75 [CMD_PSC] = { 1, AIS_CMD_FNLOAD}, 76 [CMD_PINMUX] = { 3, AIS_CMD_FNLOAD}, 77 [CMD_BOOTTABLE] = { 4, AIS_CMD_BOOTTBL}, 78}; 79 80static uint32_t get_cfg_value(char *token, char *name, int linenr) 81{ 82 char *endptr; 83 uint32_t value; 84 85 errno = 0; 86 value = strtoul(token, &endptr, 16); 87 if (errno || (token == endptr)) { 88 fprintf(stderr, "Error: %s[%d] - Invalid hex data(%s)\n", 89 name, linenr, token); 90 exit(EXIT_FAILURE); 91 } 92 return value; 93} 94 95static int get_ais_table_id(uint32_t *ptr) 96{ 97 98 int i; 99 int func_no; 100 101 for (i = 0; i < ARRAY_SIZE(cmd_table); i++) { 102 if (*ptr == cmd_table[i].AIS_cmd) { 103 if (cmd_table[i].AIS_cmd != AIS_CMD_FNLOAD) 104 return i; 105 106 func_no = ((struct ais_cmd_func *)ptr)->func_args 107 & 0xFFFF; 108 if (func_no == ais_func_table[i].index) 109 return i; 110 } 111 } 112 113 return -1; 114} 115 116static void aisimage_print_header(const void *hdr, struct image_tool_params *params) 117{ 118 struct ais_header *ais_hdr = (struct ais_header *)hdr; 119 uint32_t *ptr; 120 struct ais_cmd_load *ais_load; 121 int id; 122 123 if (ais_hdr->magic != AIS_MAGIC_WORD) { 124 fprintf(stderr, "Error: - AIS Magic Number not found\n"); 125 return; 126 } 127 fprintf(stdout, "Image Type: TI Davinci AIS Boot Image\n"); 128 fprintf(stdout, "AIS magic : %08x\n", ais_hdr->magic); 129 ptr = (uint32_t *)&ais_hdr->magic; 130 ptr++; 131 132 while (*ptr != AIS_CMD_JMPCLOSE) { 133 /* Check if we find the image */ 134 if (*ptr == AIS_CMD_LOAD) { 135 ais_load = (struct ais_cmd_load *)ptr; 136 fprintf(stdout, "Image at : 0x%08x size 0x%08x\n", 137 ais_load->addr, 138 ais_load->size); 139 ptr = ais_load->data + ais_load->size / sizeof(*ptr); 140 continue; 141 } 142 143 id = get_ais_table_id(ptr); 144 if (id < 0) { 145 fprintf(stderr, "Error: - AIS Image corrupted\n"); 146 return; 147 } 148 fprintf(stdout, "AIS cmd : %s\n", 149 get_table_entry_name(aisimage_cmds, NULL, id)); 150 ptr += cmd_table[id].nargs + IS_FNC_EXEC(id) + 1; 151 if (((void *)ptr - hdr) > ais_img_size) { 152 fprintf(stderr, 153 "AIS Image not terminated by JMPCLOSE\n"); 154 return; 155 } 156 } 157} 158 159static uint32_t *ais_insert_cmd_header(uint32_t cmd, uint32_t nargs, 160 uint32_t *parms, struct image_type_params *tparams, 161 uint32_t *ptr) 162{ 163 int i; 164 165 *ptr++ = cmd_table[cmd].AIS_cmd; 166 if (IS_FNC_EXEC(cmd)) 167 *ptr++ = ((nargs & 0xFFFF) << 16) + ais_func_table[cmd].index; 168 169 /* Copy parameters */ 170 for (i = 0; i < nargs; i++) 171 *ptr++ = cpu_to_le32(parms[i]); 172 173 return ptr; 174 175} 176 177static uint32_t *ais_alloc_buffer(struct image_tool_params *params) 178{ 179 int dfd; 180 struct stat sbuf; 181 char *datafile = params->datafile; 182 uint32_t *ptr; 183 184 dfd = open(datafile, O_RDONLY|O_BINARY); 185 if (dfd < 0) { 186 fprintf(stderr, "%s: Can't open %s: %s\n", 187 params->cmdname, datafile, strerror(errno)); 188 exit(EXIT_FAILURE); 189 } 190 191 if (fstat(dfd, &sbuf) < 0) { 192 fprintf(stderr, "%s: Can't stat %s: %s\n", 193 params->cmdname, datafile, strerror(errno)); 194 exit(EXIT_FAILURE); 195 } 196 197 /* 198 * Place for header is allocated. The size is taken from 199 * the size of the datafile, that the ais_image_generate() 200 * will copy into the header. Copying the datafile 201 * is not left to the main program, because after the datafile 202 * the header must be terminated with the Jump & Close command. 203 */ 204 ais_img_size = ALIGN(sbuf.st_size, WORD_ALIGN0) + MAX_CMD_BUFFER; 205 ptr = (uint32_t *)malloc(ALIGN(sbuf.st_size, WORD_ALIGN0) 206 + 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 218static 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 += ALIGN(sbuf.st_size, WORD_ALIGN0) / sizeof(uint32_t); 246 247 (void) munmap((void *)ptr, sbuf.st_size); 248 (void) close(dfd); 249 250 return aisptr; 251 252} 253 254static 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 363static 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 371static 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 385static void aisimage_set_header(void *ptr, struct stat *sbuf, int ifd, 386 struct image_tool_params *params) 387{ 388} 389 390int 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 */ 415U_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