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