1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * Flash Update commands File: ui_flash.c 5 * 6 * The routines in this file are used for updating the 7 * flash with new firmware. 8 * 9 * Author: Mitch Lichtenberg 10 * 11 ********************************************************************* 12 * 13 * Copyright 2000,2001,2002,2003,2005 14 * Broadcom Corporation. All rights reserved. 15 * 16 * This software is furnished under license and may be used and 17 * copied only in accordance with the following terms and 18 * conditions. Subject to these conditions, you may download, 19 * copy, install, use, modify and distribute modified or unmodified 20 * copies of this software in source and/or binary form. No title 21 * or ownership is transferred hereby. 22 * 23 * 1) Any source code used, modified or distributed must reproduce 24 * and retain this copyright notice and list of conditions 25 * as they appear in the source file. 26 * 27 * 2) No right is granted to use any trade name, trademark, or 28 * logo of Broadcom Corporation. The "Broadcom Corporation" 29 * name may not be used to endorse or promote products derived 30 * from this software without the prior written permission of 31 * Broadcom Corporation. 32 * 33 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR 34 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED 35 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 36 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 37 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 38 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, 39 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 40 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 41 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 42 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 43 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 44 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 45 * THE POSSIBILITY OF SUCH DAMAGE. 46 ********************************************************************* */ 47 48#include "cfe.h" 49 50#include "ui_command.h" 51 52#include "cfe_fileops.h" 53#include "cfe_boot.h" 54 55#include "cfe_loader.h" 56 57#include "net_ebuf.h" 58#include "net_ether.h" 59#include "net_api.h" 60 61#include "cfe_flashimage.h" 62 63#include "url.h" 64 65 66/* ********************************************************************* 67 * Constants 68 ********************************************************************* */ 69 70/* 71 * Of course, these things really belong somewhere else. 72 */ 73 74#define FLASH_STAGING_BUFFER CFG_FLASH_STAGING_BUFFER_ADDR 75#ifdef _FLASHPROG_ 76#define FLASH_STAGING_BUFFER_SIZE (1024*1024*16) 77#else 78#define FLASH_STAGING_BUFFER_SIZE CFG_FLASH_STAGING_BUFFER_SIZE 79#endif 80 81 82/* ********************************************************************* 83 * Exerns 84 ********************************************************************* */ 85 86extern int cfe_iocb_dispatch(cfe_iocb_t *iocb); 87 88int ui_init_flashcmds(void); 89static int ui_cmd_flash(ui_cmdline_t *cmd,int argc,char *argv[]); 90 91 92 93/* ********************************************************************* 94 * ui_init_flashcmds() 95 * 96 * Initialize the flash commands, add them to the table. 97 * 98 * Input parameters: 99 * nothing 100 * 101 * Return value: 102 * 0 if ok, else error 103 ********************************************************************* */ 104 105int ui_init_flashcmds(void) 106{ 107 cmd_addcmd("flash", 108 ui_cmd_flash, 109 NULL, 110 "Update a flash memory device", 111 "flash [options] filename [flashdevice]\n\n" 112 "Copies data from a source file name or device to a flash memory device.\n" 113 "The source device can be a disk file (FAT filesystem), a remote file\n" 114 "(TFTP) or a flash device. The destination device may be a flash or eeprom.\n" 115#if (!CFG_RELOC) 116 "If the destination device is your boot flash (usually flash0), the flash\n" 117 "command will restart the firmware after the flash update is complete\n" 118#endif 119 "", 120 "-noerase;Don't erase flash before writing|" 121 "-offset=*;Begin programming at this offset in the flash device|" 122 "-size=*;Size of source device when programming from flash to flash|" 123 "-noheader;Override header verification, flash binary without checking"); 124 125 126 return 0; 127} 128 129/* ********************************************************************* 130 * flash_crc32(buf,len) 131 * 132 * Yes, this is an Ethernet CRC. I'm lazy. 133 * 134 * Input parameters: 135 * buf - buffer to CRC 136 * len - length of data 137 * 138 * Return value: 139 * CRC-32 140 ********************************************************************* */ 141 142#define CRC32_POLY 0xEDB88320UL /* CRC-32 Poly */ 143static unsigned int 144flash_crc32(const unsigned char *databuf, unsigned int datalen) 145{ 146 unsigned int idx, bit, data, crc = 0xFFFFFFFFUL; 147 148 for (idx = 0; idx < datalen; idx++) { 149 for (data = *databuf++, bit = 0; bit < 8; bit++, data >>= 1) { 150 crc = (crc >> 1) ^ (((crc ^ data) & 1) ? CRC32_POLY : 0); 151 } 152 } 153 154 return crc; 155} 156 157/* ********************************************************************* 158 * flash_validate(ptr) 159 * 160 * Validate the flash header to make sure we can program it. 161 * 162 * Input parameters: 163 * ptr - pointer to flash header 164 * outptr - pointer to data that we should program 165 * outsize - size of data we should program 166 * 167 * Return value: 168 * 0 if ok 169 * else error occured 170 ********************************************************************* */ 171 172#define GET32(x) (((uint32_t) (x[0] << 24)) | \ 173 ((uint32_t) (x[1] << 16)) | \ 174 ((uint32_t) (x[2] << 8)) | \ 175 ((uint32_t) (x[3] << 0))) 176 177static int flash_validate(uint8_t *ptr,int insize,uint8_t **outptr,int *outsize) 178{ 179 cfe_flashimage_t *hdr = (cfe_flashimage_t *) ptr; 180 uint32_t size; 181 uint32_t flags; 182 uint32_t hdrcrc; 183 uint32_t calccrc; 184 185 if (memcmp(hdr->seal,CFE_IMAGE_SEAL,sizeof(hdr->seal)) != 0) { 186 printf("Invalid header seal. This is not a CFE flash image.\n"); 187 return -1; 188 } 189 190 printf("Flash image contains CFE version %d.%d.%d for board '%s'\n", 191 hdr->majver,hdr->minver,hdr->ecover,hdr->boardname); 192 193 size = GET32(hdr->size); 194 flags = GET32(hdr->flags); 195 hdrcrc = GET32(hdr->crc); 196 printf("Flash image is %d bytes, flags %08X, CRC %08X\n",size,flags,hdrcrc); 197 198 if (strcmp(CFG_BOARDNAME,(char *)hdr->boardname) != 0) { 199 printf("This flash image is not appropriate for board type '%s'\n",CFG_BOARDNAME); 200 return -1; 201 } 202 203 if ((size == 0) || (size > FLASH_STAGING_BUFFER_SIZE) || 204 ((size + sizeof(cfe_flashimage_t)) < insize)) { 205 printf("Flash image size is bogus!\n"); 206 return -1; 207 } 208 209 calccrc = flash_crc32(ptr + sizeof(cfe_flashimage_t),size); 210 211 if (calccrc != hdrcrc) { 212 printf("CRC is incorrect. Calculated CRC is %08X\n",calccrc); 213 return -1; 214 } 215 216 *outptr = ptr + sizeof(cfe_flashimage_t); 217 *outsize = size; 218 return 0; 219} 220 221/* ********************************************************************* 222 * ui_cmd_flash(cmd,argc,argv) 223 * 224 * The 'flash' command lives here. Program the boot flash, 225 * or if a device name is specified, program the alternate 226 * flash device. 227 * 228 * Input parameters: 229 * cmd - command table entry 230 * argc,argv - parameters 231 * 232 * Return value: 233 * 0 if ok 234 * else error 235 ********************************************************************* */ 236 237 238static int ui_cmd_flash(ui_cmdline_t *cmd,int argc,char *argv[]) 239{ 240 uint8_t *ptr; 241 int fh; 242 int res; 243#if (!CFG_RELOC) 244 int retlen; 245#endif 246 char *fname; 247 char *flashdev; 248 cfe_loadargs_t la; 249 int amtcopy; 250 int devtype; 251 int srcdevtype; 252 int chkheader; 253 int sfd; 254 int copysize; 255 flash_info_t flashinfo; 256 int offset = 0; 257 int noerase = 0; 258 char *x; 259 int size = 0; 260 261 /* 262 * Get the address of the staging buffer. We can't 263 * allocate the space from the heap to store the 264 * new flash image, because the heap may not be big 265 * enough. So, grab some unallocated memory 266 * at the 1MB line (we could also calculate 267 * something, but this will do for now). 268 * We assume the flash will be somewhere between 269 * 1KB (yeah, right) and 4MB. 270 */ 271 272#if CFG_RUNFROMKSEG0 273 ptr = (uint8_t *) KERNADDR(FLASH_STAGING_BUFFER); 274#else 275 ptr = (uint8_t *) UNCADDR(FLASH_STAGING_BUFFER); 276#endif 277 278 /* 279 * Parse command line parameters 280 */ 281 282 fname = cmd_getarg(cmd,0); 283 284 if (!fname) { 285 return ui_showusage(cmd); 286 } 287 288 flashdev = cmd_getarg(cmd,1); 289 if (!flashdev) flashdev = "flash0"; 290 291 /* 292 * Make sure it's a flash device. 293 */ 294 295 res = cfe_getdevinfo(flashdev); 296 if (res < 0) { 297 return ui_showerror(CFE_ERR_DEVNOTFOUND,flashdev); 298 } 299 300 devtype = res & CFE_DEV_MASK; 301 302 if ((res != CFE_DEV_FLASH) && (res != CFE_DEV_NVRAM)) { 303 xprintf("Device '%s' is not a flash or eeprom device.\n",flashdev); 304 return CFE_ERR_INV_PARAM; 305 } 306 307 /* 308 * We shouldn't really allow this, but there are some circumstances 309 * where you might want to bypass the header check and shoot 310 * yourself in the foot. 311 * Switch normally not supplied, so chkheader will be TRUE. 312 */ 313 314 chkheader = !cmd_sw_isset(cmd,"-noheader"); 315 316 /* 317 * Check for some obscure options here. 318 */ 319 320 noerase = cmd_sw_isset(cmd,"-noerase"); 321 322 if (cmd_sw_value(cmd,"-offset",&x)) { 323 offset = atoi(x); 324 } 325 326 if (cmd_sw_value(cmd,"-size",&x)) { 327 size = atoi(x); 328 } 329 330 /* 331 * Read the new flash image from the source device 332 */ 333 334 srcdevtype = cfe_getdevinfo(fname) & CFE_DEV_MASK; 335 336 xprintf("Reading %s: ",fname); 337 338 switch (srcdevtype) { 339 case CFE_DEV_FLASH: 340 sfd = cfe_open(fname); 341 if (sfd < 0) { 342 return ui_showerror(sfd,"Could not open source device"); 343 } 344 memset(ptr,0xFF,FLASH_STAGING_BUFFER_SIZE); 345 346 /* 347 * If the flash device can be used for NVRAM, 348 * then the max size of or flash is the 349 * offset of the flash info. Otherwise 350 * it is the full staging buffer size. 351 * XXX: if it's larger, we lose. 352 */ 353 354 if (cfe_ioctl(sfd,IOCTL_FLASH_GETINFO, 355 (unsigned char *) &flashinfo, 356 sizeof(flash_info_t), 357 &res,0) != 0) { 358 flashinfo.flash_size = FLASH_STAGING_BUFFER_SIZE; 359 } 360 361 if (size > 0) { 362 xprintf("(size=0x%X) ",size); 363 } 364 else { 365 size = flashinfo.flash_size; 366 } 367 368 /* Make sure we don't overrun the staging buffer */ 369 370 if (size > FLASH_STAGING_BUFFER_SIZE) { 371 size = FLASH_STAGING_BUFFER_SIZE; 372 } 373 374 /* Read the flash device here. */ 375 res = cfe_read(sfd,PTR2HSADDR(ptr),size); 376 377 cfe_close(sfd); 378 if (res < 0) { 379 return ui_showerror(res,"Could not read from flash"); 380 } 381 chkheader = FALSE; /* no header to check */ 382 /* 383 * Search for non-0xFF byte at the end. This will work because 384 * flashes get erased to all FF's, we pre-fill our buffer to FF's, 385 */ 386 while (res > 0) { 387 if (ptr[res-1] != 0xFF) break; 388 res--; 389 } 390 break; 391 392 case CFE_DEV_SERIAL: 393 la.la_filesys = "raw"; 394 la.la_filename = NULL; 395 la.la_device = fname; 396 la.la_address = (intptr_t) ptr; 397 la.la_options = 0; 398 la.la_maxsize = FLASH_STAGING_BUFFER_SIZE; 399 la.la_flags = LOADFLG_SPECADDR; 400 401 res = cfe_load_program("srec",&la); 402 403 if (res < 0) { 404 ui_showerror(res,"Failed."); 405 return res; 406 } 407 break; 408 409 default: 410 res = ui_process_url(fname, cmd, &la); 411 if (res < 0) { 412 ui_showerror(res,"Invalid file name %s",fname); 413 return res; 414 } 415 416 la.la_address = (intptr_t) ptr; 417 la.la_options = 0; 418 la.la_maxsize = FLASH_STAGING_BUFFER_SIZE; 419 la.la_flags = LOADFLG_SPECADDR; 420 421 res = cfe_load_program("raw",&la); 422 423 if (res < 0) { 424 ui_showerror(res,"Failed."); 425 return res; 426 } 427 break; 428 429 } 430 431 xprintf("Done. %d bytes read\n",res); 432 433 copysize = res; 434 435 /* 436 * Verify the header and file's CRC. 437 */ 438 if (chkheader) { 439 if (flash_validate(ptr,res,&ptr,©size) < 0) return -1; 440 } 441 442 if (copysize == 0) return 0; /* 0 bytes, don't flash */ 443 444 /* 445 * Open the destination flash device. 446 */ 447 448 fh = cfe_open(flashdev); 449 if (fh < 0) { 450 xprintf("Could not open device '%s'\n",flashdev); 451 return CFE_ERR_DEVNOTFOUND; 452 } 453 454 if (cfe_ioctl(fh,IOCTL_FLASH_GETINFO, 455 (unsigned char *) &flashinfo, 456 sizeof(flash_info_t), 457 &res,0) == 0) { 458 459 /* Make sure we have erase and program functions. */ 460 if (flashinfo.flash_type != FLASH_TYPE_FLASH) { 461 cfe_close(fh); 462 xprintf("Programming of device '%s' not supported\n",flashdev); 463 return CFE_ERR_UNSUPPORTED; 464 } 465 466 /* Truncate write if source size is greater than flash size */ 467 if ((copysize + offset) > flashinfo.flash_size) { 468 copysize = flashinfo.flash_size; 469 } 470 } 471 472 /* 473 * If overwriting the boot flash, we need to use the special IOCTL 474 * that will force a reboot after writing the flash. 475 */ 476 477 if (flashinfo.flash_base == 0x1FC00000 || /* XXX MIPS-SPECIFIC */ 478 flashinfo.flash_base == 0x1B000000) { /* XXX MIPS-SPECIFIC */ 479#if CFG_RELOC 480 xprintf("\n\n** DO NOT TURN OFF YOUR MACHINE UNTIL THE FLASH UPDATE COMPLETES!! **\n\n"); 481#else 482#if CFG_NETWORK 483 if (net_getparam(NET_DEVNAME)) { 484 xprintf("Closing network.\n"); 485 net_uninit(); 486 } 487#endif 488 xprintf("Rewriting boot flash device '%s'\n",flashdev); 489 xprintf("\n\n**DO NOT TURN OFF YOUR MACHINE UNTIL IT REBOOTS!**\n\n"); 490 cfe_ioctl(fh,IOCTL_FLASH_WRITE_ALL, ptr,copysize,&retlen,0); 491 /* should not return */ 492 return CFE_ERR; 493#endif 494 } 495 496 /* 497 * Otherwise: it's not the flash we're using right 498 * now, so we can be more verbose about things, and 499 * more importantly, we can return to the command 500 * prompt without rebooting! 501 */ 502 503 /* 504 * Erase the flash, if the device requires it. Our new flash 505 * driver does the copy/merge/erase for us. 506 */ 507 508 if (!noerase) { 509 if ((devtype == CFE_DEV_FLASH) && !(flashinfo.flash_flags & FLASH_FLAG_NOERASE)) { 510 flash_range_t range; 511 range.range_base = offset; 512 range.range_length = copysize; 513 xprintf("Erasing flash..."); 514 if (cfe_ioctl(fh,IOCTL_FLASH_ERASE_RANGE, 515 (uint8_t *) &range,sizeof(range),NULL,0) != 0) { 516 printf("Failed to erase the flash\n"); 517 cfe_close(fh); 518 return CFE_ERR_IOERR; 519 } 520 } 521 } 522 523 /* 524 * Program the flash 525 */ 526 527 xprintf("Programming..."); 528 529 amtcopy = cfe_writeblk(fh,offset,PTR2HSADDR(ptr),copysize); 530 531 if (copysize == amtcopy) { 532 xprintf("done. %d bytes written\n",amtcopy); 533 res = 0; 534 } 535 else { 536 ui_showerror(amtcopy,"Failed."); 537 res = CFE_ERR_IOERR; 538 } 539 540 /* 541 * done! 542 */ 543 544 cfe_close(fh); 545 546 return res; 547} 548 549