1 /* 2 * (C) Copyright 2008 3 * Marvell Semiconductor <www.marvell.com> 4 * Written-by: Prafulla Wadaskar <prafulla@marvell.com> 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 9 #include "imagetool.h" 10 #include <image.h> 11 #include "kwbimage.h" 12 13 /* 14 * Supported commands for configuration file 15 */ 16 static table_entry_t kwbimage_cmds[] = { 17 {CMD_BOOT_FROM, "BOOT_FROM", "boot command", }, 18 {CMD_NAND_ECC_MODE, "NAND_ECC_MODE", "NAND mode", }, 19 {CMD_NAND_PAGE_SIZE, "NAND_PAGE_SIZE", "NAND size", }, 20 {CMD_SATA_PIO_MODE, "SATA_PIO_MODE", "SATA mode", }, 21 {CMD_DDR_INIT_DELAY, "DDR_INIT_DELAY", "DDR init dly", }, 22 {CMD_DATA, "DATA", "Reg Write Data", }, 23 {CMD_INVALID, "", "", }, 24 }; 25 26 /* 27 * Supported Boot options for configuration file 28 */ 29 static table_entry_t kwbimage_bootops[] = { 30 {IBR_HDR_SPI_ID, "spi", "SPI Flash", }, 31 {IBR_HDR_NAND_ID, "nand", "NAND Flash", }, 32 {IBR_HDR_SATA_ID, "sata", "Sata port", }, 33 {IBR_HDR_PEX_ID, "pex", "PCIe port", }, 34 {IBR_HDR_UART_ID, "uart", "Serial port", }, 35 {-1, "", "Invalid", }, 36 }; 37 38 /* 39 * Supported NAND ecc options configuration file 40 */ 41 static table_entry_t kwbimage_eccmodes[] = { 42 {IBR_HDR_ECC_DEFAULT, "default", "Default mode", }, 43 {IBR_HDR_ECC_FORCED_HAMMING, "hamming", "Hamming mode", }, 44 {IBR_HDR_ECC_FORCED_RS, "rs", "RS mode", }, 45 {IBR_HDR_ECC_DISABLED, "disabled", "ECC Disabled", }, 46 {-1, "", "", }, 47 }; 48 49 static struct kwb_header kwbimage_header; 50 static int datacmd_cnt = 0; 51 static char * fname = "Unknown"; 52 static int lineno = -1; 53 54 /* 55 * Report Error if xflag is set in addition to default 56 */ 57 static int kwbimage_check_params(struct image_tool_params *params) 58 { 59 if (!strlen (params->imagename)) { 60 printf ("Error:%s - Configuration file not specified, " 61 "it is needed for kwbimage generation\n", 62 params->cmdname); 63 return CFG_INVALID; 64 } 65 return ((params->dflag && (params->fflag || params->lflag)) || 66 (params->fflag && (params->dflag || params->lflag)) || 67 (params->lflag && (params->dflag || params->fflag)) || 68 (params->xflag) || !(strlen (params->imagename))); 69 } 70 71 static uint32_t check_get_hexval (char *token) 72 { 73 uint32_t hexval; 74 75 if (!sscanf (token, "%x", &hexval)) { 76 printf ("Error:%s[%d] - Invalid hex data(%s)\n", fname, 77 lineno, token); 78 exit (EXIT_FAILURE); 79 } 80 return hexval; 81 } 82 83 /* 84 * Generates 8 bit checksum 85 */ 86 static uint8_t kwbimage_checksum8 (void *start, uint32_t len, uint8_t csum) 87 { 88 register uint8_t sum = csum; 89 volatile uint8_t *p = (volatile uint8_t *)start; 90 91 /* check len and return zero checksum if invalid */ 92 if (!len) 93 return 0; 94 95 do { 96 sum += *p; 97 p++; 98 } while (--len); 99 return (sum); 100 } 101 102 /* 103 * Generates 32 bit checksum 104 */ 105 static uint32_t kwbimage_checksum32 (uint32_t *start, uint32_t len, uint32_t csum) 106 { 107 register uint32_t sum = csum; 108 volatile uint32_t *p = start; 109 110 /* check len and return zero checksum if invalid */ 111 if (!len) 112 return 0; 113 114 if (len % sizeof(uint32_t)) { 115 printf ("Error:%s[%d] - length is not in multiple of %zu\n", 116 __FUNCTION__, len, sizeof(uint32_t)); 117 return 0; 118 } 119 120 do { 121 sum += *p; 122 p++; 123 len -= sizeof(uint32_t); 124 } while (len > 0); 125 return (sum); 126 } 127 128 static void kwbimage_check_cfgdata (char *token, enum kwbimage_cmd cmdsw, 129 struct kwb_header *kwbhdr) 130 { 131 bhr_t *mhdr = &kwbhdr->kwb_hdr; 132 extbhr_t *exthdr = &kwbhdr->kwb_exthdr; 133 int i; 134 135 switch (cmdsw) { 136 case CMD_BOOT_FROM: 137 i = get_table_entry_id (kwbimage_bootops, 138 "Kwbimage boot option", token); 139 140 if (i < 0) 141 goto INVL_DATA; 142 143 mhdr->blockid = i; 144 printf ("Preparing kirkwood boot image to boot " 145 "from %s\n", token); 146 break; 147 case CMD_NAND_ECC_MODE: 148 i = get_table_entry_id (kwbimage_eccmodes, 149 "NAND ecc mode", token); 150 151 if (i < 0) 152 goto INVL_DATA; 153 154 mhdr->nandeccmode = i; 155 printf ("Nand ECC mode = %s\n", token); 156 break; 157 case CMD_NAND_PAGE_SIZE: 158 mhdr->nandpagesize = 159 (uint16_t) check_get_hexval (token); 160 printf ("Nand page size = 0x%x\n", mhdr->nandpagesize); 161 break; 162 case CMD_SATA_PIO_MODE: 163 mhdr->satapiomode = 164 (uint8_t) check_get_hexval (token); 165 printf ("Sata PIO mode = 0x%x\n", 166 mhdr->satapiomode); 167 break; 168 case CMD_DDR_INIT_DELAY: 169 mhdr->ddrinitdelay = 170 (uint16_t) check_get_hexval (token); 171 printf ("DDR init delay = %d msec\n", mhdr->ddrinitdelay); 172 break; 173 case CMD_DATA: 174 exthdr->rcfg[datacmd_cnt].raddr = 175 check_get_hexval (token); 176 177 break; 178 case CMD_INVALID: 179 goto INVL_DATA; 180 default: 181 goto INVL_DATA; 182 } 183 return; 184 185 INVL_DATA: 186 printf ("Error:%s[%d] - Invalid data\n", fname, lineno); 187 exit (EXIT_FAILURE); 188 } 189 190 /* 191 * this function sets the kwbimage header by- 192 * 1. Abstracting input command line arguments data 193 * 2. parses the kwbimage configuration file and update extebded header data 194 * 3. calculates header, extended header and image checksums 195 */ 196 static void kwdimage_set_ext_header (struct kwb_header *kwbhdr, char* name) { 197 bhr_t *mhdr = &kwbhdr->kwb_hdr; 198 extbhr_t *exthdr = &kwbhdr->kwb_exthdr; 199 FILE *fd = NULL; 200 int j; 201 char *line = NULL; 202 char * token, *saveptr1, *saveptr2; 203 size_t len = 0; 204 enum kwbimage_cmd cmd; 205 206 fname = name; 207 /* set dram register offset */ 208 exthdr->dramregsoffs = (intptr_t)&exthdr->rcfg - (intptr_t)mhdr; 209 210 if ((fd = fopen (name, "r")) == 0) { 211 printf ("Error:%s - Can't open\n", fname); 212 exit (EXIT_FAILURE); 213 } 214 215 /* Simple kwimage.cfg file parser */ 216 lineno=0; 217 while ((getline (&line, &len, fd)) > 0) { 218 lineno++; 219 token = strtok_r (line, "\r\n", &saveptr1); 220 /* drop all lines with zero tokens (= empty lines) */ 221 if (token == NULL) 222 continue; 223 224 for (j = 0, cmd = CMD_INVALID, line = token; ; line = NULL) { 225 token = strtok_r (line, " \t", &saveptr2); 226 if (token == NULL) 227 break; 228 /* Drop all text starting with '#' as comments */ 229 if (token[0] == '#') 230 break; 231 232 /* Process rest as valid config command line */ 233 switch (j) { 234 case CFG_COMMAND: 235 cmd = get_table_entry_id (kwbimage_cmds, 236 "Kwbimage command", token); 237 238 if (cmd == CMD_INVALID) 239 goto INVL_CMD; 240 break; 241 242 case CFG_DATA0: 243 kwbimage_check_cfgdata (token, cmd, kwbhdr); 244 break; 245 246 case CFG_DATA1: 247 if (cmd != CMD_DATA) 248 goto INVL_CMD; 249 250 exthdr->rcfg[datacmd_cnt].rdata = 251 check_get_hexval (token); 252 253 if (datacmd_cnt > KWBIMAGE_MAX_CONFIG ) { 254 printf ("Error:%s[%d] - Found more " 255 "than max(%zd) allowed " 256 "data configurations\n", 257 fname, lineno, 258 KWBIMAGE_MAX_CONFIG); 259 exit (EXIT_FAILURE); 260 } else 261 datacmd_cnt++; 262 break; 263 264 default: 265 goto INVL_CMD; 266 } 267 j++; 268 } 269 } 270 if (line) 271 free (line); 272 273 fclose (fd); 274 return; 275 276 /* 277 * Invalid Command error reporring 278 * 279 * command CMD_DATA needs three strings on a line 280 * whereas other commands need only two. 281 * 282 * if more than two/three (as per command type) are observed, 283 * then error will be reported 284 */ 285 INVL_CMD: 286 printf ("Error:%s[%d] - Invalid command\n", fname, lineno); 287 exit (EXIT_FAILURE); 288 } 289 290 static void kwbimage_set_header (void *ptr, struct stat *sbuf, int ifd, 291 struct image_tool_params *params) 292 { 293 struct kwb_header *hdr = (struct kwb_header *)ptr; 294 bhr_t *mhdr = &hdr->kwb_hdr; 295 extbhr_t *exthdr = &hdr->kwb_exthdr; 296 uint32_t checksum; 297 int size; 298 299 /* Build and add image checksum header */ 300 checksum = kwbimage_checksum32 ((uint32_t *)ptr, sbuf->st_size, 0); 301 302 size = write (ifd, &checksum, sizeof(uint32_t)); 303 if (size != sizeof(uint32_t)) { 304 printf ("Error:%s - Checksum write %d bytes %s\n", 305 params->cmdname, size, params->imagefile); 306 exit (EXIT_FAILURE); 307 } 308 309 sbuf->st_size += sizeof(uint32_t); 310 311 mhdr->blocksize = sbuf->st_size - sizeof(struct kwb_header); 312 mhdr->srcaddr = sizeof(struct kwb_header); 313 mhdr->destaddr= params->addr; 314 mhdr->execaddr =params->ep; 315 mhdr->ext = 0x1; /* header extension appended */ 316 317 kwdimage_set_ext_header (hdr, params->imagename); 318 /* calculate checksums */ 319 mhdr->checkSum = kwbimage_checksum8 ((void *)mhdr, sizeof(bhr_t), 0); 320 exthdr->checkSum = kwbimage_checksum8 ((void *)exthdr, 321 sizeof(extbhr_t), 0); 322 } 323 324 static int kwbimage_verify_header (unsigned char *ptr, int image_size, 325 struct image_tool_params *params) 326 { 327 struct kwb_header *hdr = (struct kwb_header *)ptr; 328 bhr_t *mhdr = &hdr->kwb_hdr; 329 extbhr_t *exthdr = &hdr->kwb_exthdr; 330 uint8_t calc_hdrcsum; 331 uint8_t calc_exthdrcsum; 332 333 calc_hdrcsum = kwbimage_checksum8 ((void *)mhdr, 334 sizeof(bhr_t) - sizeof(uint8_t), 0); 335 if (calc_hdrcsum != mhdr->checkSum) 336 return -FDT_ERR_BADSTRUCTURE; /* mhdr csum not matched */ 337 338 calc_exthdrcsum = kwbimage_checksum8 ((void *)exthdr, 339 sizeof(extbhr_t) - sizeof(uint8_t), 0); 340 if (calc_exthdrcsum != exthdr->checkSum) 341 return -FDT_ERR_BADSTRUCTURE; /* exthdr csum not matched */ 342 343 return 0; 344 } 345 346 static void kwbimage_print_header (const void *ptr) 347 { 348 struct kwb_header *hdr = (struct kwb_header *) ptr; 349 bhr_t *mhdr = &hdr->kwb_hdr; 350 char *name = get_table_entry_name (kwbimage_bootops, 351 "Kwbimage boot option", 352 (int) mhdr->blockid); 353 354 printf ("Image Type: Kirkwood Boot from %s Image\n", name); 355 printf ("Data Size: "); 356 genimg_print_size (mhdr->blocksize - sizeof(uint32_t)); 357 printf ("Load Address: %08x\n", mhdr->destaddr); 358 printf ("Entry Point: %08x\n", mhdr->execaddr); 359 } 360 361 static int kwbimage_check_image_types (uint8_t type) 362 { 363 if (type == IH_TYPE_KWBIMAGE) 364 return EXIT_SUCCESS; 365 else 366 return EXIT_FAILURE; 367 } 368 369 /* 370 * kwbimage type parameters definition 371 */ 372 static struct image_type_params kwbimage_params = { 373 .name = "Kirkwood Boot Image support", 374 .header_size = sizeof(struct kwb_header), 375 .hdr = (void*)&kwbimage_header, 376 .check_image_type = kwbimage_check_image_types, 377 .verify_header = kwbimage_verify_header, 378 .print_header = kwbimage_print_header, 379 .set_header = kwbimage_set_header, 380 .check_params = kwbimage_check_params, 381 }; 382 383 void init_kwb_image_type (void) 384 { 385 register_image_type(&kwbimage_params); 386 } 387