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