summaryrefslogtreecommitdiffstats
path: root/cfe/cfe/ui/ui_flash.c
diff options
context:
space:
mode:
Diffstat (limited to 'cfe/cfe/ui/ui_flash.c')
-rw-r--r--cfe/cfe/ui/ui_flash.c554
1 files changed, 554 insertions, 0 deletions
diff --git a/cfe/cfe/ui/ui_flash.c b/cfe/cfe/ui/ui_flash.c
new file mode 100644
index 0000000..d3ce7c1
--- /dev/null
+++ b/cfe/cfe/ui/ui_flash.c
@@ -0,0 +1,554 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * Flash Update commands File: ui_flash.c
+ *
+ * The routines in this file are used for updating the
+ * flash with new firmware.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+#include "lib_types.h"
+#include "lib_string.h"
+#include "lib_queue.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+
+#include "cfe_iocb.h"
+#include "cfe_devfuncs.h"
+#include "cfe_ioctl.h"
+#include "cfe_timer.h"
+#include "cfe_error.h"
+
+#include "ui_command.h"
+#include "cfe.h"
+
+#include "cfe_fileops.h"
+#include "cfe_boot.h"
+#include "bsp_config.h"
+
+#include "cfe_loader.h"
+
+#include "net_ebuf.h"
+#include "net_ether.h"
+#include "net_api.h"
+
+#include "cfe_flashimage.h"
+
+#include "addrspace.h"
+#include "url.h"
+
+
+/* *********************************************************************
+ * Constants
+ ********************************************************************* */
+
+/*
+ * Of course, these things really belong somewhere else.
+ */
+
+#define FLASH_STAGING_BUFFER CFG_FLASH_STAGING_BUFFER_ADDR
+#ifdef _FLASHPROG_
+#define FLASH_STAGING_BUFFER_SIZE (1024*1024*16)
+#else
+#define FLASH_STAGING_BUFFER_SIZE CFG_FLASH_STAGING_BUFFER_SIZE
+#endif
+
+
+/* *********************************************************************
+ * Exerns
+ ********************************************************************* */
+
+extern int cfe_iocb_dispatch(cfe_iocb_t *iocb);
+
+int ui_init_flashcmds(void);
+static int ui_cmd_flash(ui_cmdline_t *cmd,int argc,char *argv[]);
+
+
+
+/* *********************************************************************
+ * ui_init_flashcmds()
+ *
+ * Initialize the flash commands, add them to the table.
+ *
+ * Input parameters:
+ * nothing
+ *
+ * Return value:
+ * 0 if ok, else error
+ ********************************************************************* */
+
+int ui_init_flashcmds(void)
+{
+ cmd_addcmd("flash",
+ ui_cmd_flash,
+ NULL,
+ "Update a flash memory device",
+ "flash [options] filename [flashdevice]\n\n"
+ "Copies data from a source file name or device to a flash memory device.\n"
+ "The source device can be a disk file (FAT filesystem), a remote file\n"
+ "(TFTP) or a flash device. The destination device may be a flash or eeprom.\n"
+#if !CFG_EMBEDDED_PIC
+ "If the destination device is your boot flash (usually flash0), the flash\n"
+ "command will restart the firmware after the flash update is complete\n"
+#endif
+ "",
+ "-noerase;Don't erase flash before writing|"
+ "-offset=*;Begin programming at this offset in the flash device|"
+ "-size=*;Size of source device when programming from flash to flash|"
+ "-noheader;Override header verification, flash binary without checking");
+
+
+ return 0;
+}
+
+/* *********************************************************************
+ * flash_crc32(buf,len)
+ *
+ * Yes, this is an Ethernet CRC. I'm lazy.
+ *
+ * Input parameters:
+ * buf - buffer to CRC
+ * len - length of data
+ *
+ * Return value:
+ * CRC-32
+ ********************************************************************* */
+
+#define CRC32_POLY 0xEDB88320UL /* CRC-32 Poly */
+static unsigned int
+flash_crc32(const unsigned char *databuf, unsigned int datalen)
+{
+ unsigned int idx, bit, data, crc = 0xFFFFFFFFUL;
+
+ for (idx = 0; idx < datalen; idx++) {
+ for (data = *databuf++, bit = 0; bit < 8; bit++, data >>= 1) {
+ crc = (crc >> 1) ^ (((crc ^ data) & 1) ? CRC32_POLY : 0);
+ }
+ }
+
+ return crc;
+}
+
+/* *********************************************************************
+ * flash_validate(ptr)
+ *
+ * Validate the flash header to make sure we can program it.
+ *
+ * Input parameters:
+ * ptr - pointer to flash header
+ * outptr - pointer to data that we should program
+ * outsize - size of data we should program
+ *
+ * Return value:
+ * 0 if ok
+ * else error occured
+ ********************************************************************* */
+
+#define GET32(x) (((uint32_t) (x[0] << 24)) | \
+ ((uint32_t) (x[1] << 16)) | \
+ ((uint32_t) (x[2] << 8)) | \
+ ((uint32_t) (x[3] << 0)))
+
+static int flash_validate(uint8_t *ptr,int insize,uint8_t **outptr,int *outsize)
+{
+ cfe_flashimage_t *hdr = (cfe_flashimage_t *) ptr;
+ uint32_t size;
+ uint32_t flags;
+ uint32_t hdrcrc;
+ uint32_t calccrc;
+
+ if (memcmp(hdr->seal,CFE_IMAGE_SEAL,sizeof(hdr->seal)) != 0) {
+ printf("Invalid header seal. This is not a CFE flash image.\n");
+ return -1;
+ }
+
+ printf("Flash image contains CFE version %d.%d.%d for board '%s'\n",
+ hdr->majver,hdr->minver,hdr->ecover,hdr->boardname);
+
+ size = GET32(hdr->size);
+ flags = GET32(hdr->flags);
+ hdrcrc = GET32(hdr->crc);
+ printf("Flash image is %d bytes, flags %08X, CRC %08X\n",size,flags,hdrcrc);
+
+ if (strcmp(CFG_BOARDNAME,hdr->boardname) != 0) {
+ printf("This flash image is not appropriate for board type '%s'\n",CFG_BOARDNAME);
+ return -1;
+ }
+
+ if ((size == 0) || (size > FLASH_STAGING_BUFFER_SIZE) ||
+ ((size + sizeof(cfe_flashimage_t)) < insize)) {
+ printf("Flash image size is bogus!\n");
+ return -1;
+ }
+
+ calccrc = flash_crc32(ptr + sizeof(cfe_flashimage_t),size);
+
+ if (calccrc != hdrcrc) {
+ printf("CRC is incorrect. Calculated CRC is %08X\n",calccrc);
+ return -1;
+ }
+
+ *outptr = ptr + sizeof(cfe_flashimage_t);
+ *outsize = size;
+ return 0;
+}
+
+/* *********************************************************************
+ * ui_cmd_flash(cmd,argc,argv)
+ *
+ * The 'flash' command lives here. Program the boot flash,
+ * or if a device name is specified, program the alternate
+ * flash device.
+ *
+ * Input parameters:
+ * cmd - command table entry
+ * argc,argv - parameters
+ *
+ * Return value:
+ * 0 if ok
+ * else error
+ ********************************************************************* */
+
+
+static int ui_cmd_flash(ui_cmdline_t *cmd,int argc,char *argv[])
+{
+ uint8_t *ptr;
+ int fh;
+ int res;
+#if !CFG_EMBEDDED_PIC
+ int retlen;
+#endif
+ char *fname;
+ char *flashdev;
+ cfe_loadargs_t la;
+ int amtcopy;
+ int devtype;
+ int srcdevtype;
+ int chkheader;
+ int sfd;
+ int copysize;
+ flash_info_t flashinfo;
+ int offset = 0;
+ int noerase = 0;
+ char *x;
+ int size = 0;
+
+ /*
+ * Get the address of the staging buffer. We can't
+ * allocate the space from the heap to store the
+ * new flash image, because the heap may not be big
+ * enough. So, grab some unallocated memory
+ * at the 1MB line (we could also calculate
+ * something, but this will do for now).
+ * We assume the flash will be somewhere between
+ * 1KB (yeah, right) and 4MB.
+ */
+
+#if CFG_RUNFROMKSEG0
+ ptr = (uint8_t *) KERNADDR(FLASH_STAGING_BUFFER);
+#else
+ ptr = (uint8_t *) UNCADDR(FLASH_STAGING_BUFFER);
+#endif
+
+ /*
+ * Parse command line parameters
+ */
+
+ fname = cmd_getarg(cmd,0);
+
+ if (!fname) {
+ return ui_showusage(cmd);
+ }
+
+ flashdev = cmd_getarg(cmd,1);
+ if (!flashdev) flashdev = "flash0.0";
+
+ /*
+ * Make sure it's a flash device.
+ */
+
+ res = cfe_getdevinfo(flashdev);
+ if (res < 0) {
+ return ui_showerror(CFE_ERR_DEVNOTFOUND,flashdev);
+ }
+
+ devtype = res & CFE_DEV_MASK;
+
+ if ((res != CFE_DEV_FLASH) && (res != CFE_DEV_NVRAM)) {
+ xprintf("Device '%s' is not a flash or eeprom device.\n",flashdev);
+ return CFE_ERR_INV_PARAM;
+ }
+
+ /*
+ * We shouldn't really allow this, but there are some circumstances
+ * where you might want to bypass the header check and shoot
+ * yourself in the foot.
+ * Switch normally not supplied, so chkheader will be TRUE.
+ */
+
+ chkheader = !cmd_sw_isset(cmd,"-noheader");
+
+ /*
+ * Check for some obscure options here.
+ */
+
+ noerase = cmd_sw_isset(cmd,"-noerase");
+
+ if (cmd_sw_value(cmd,"-offset",&x)) {
+ offset = atoi(x);
+ }
+
+ if (cmd_sw_value(cmd,"-size",&x)) {
+ size = atoi(x);
+ }
+
+ /*
+ * Read the new flash image from the source device
+ */
+
+ srcdevtype = cfe_getdevinfo(fname) & CFE_DEV_MASK;
+
+ xprintf("Reading %s: ",fname);
+
+ switch (srcdevtype) {
+ case CFE_DEV_FLASH:
+ sfd = cfe_open(fname);
+ if (sfd < 0) {
+ return ui_showerror(sfd,"Could not open source device");
+ }
+ memset(ptr,0xFF,FLASH_STAGING_BUFFER_SIZE);
+
+ /*
+ * If the flash device can be used for NVRAM,
+ * then the max size of or flash is the
+ * offset of the flash info. Otherwise
+ * it is the full staging buffer size.
+ * XXX: if it's larger, we lose.
+ */
+
+ if (cfe_ioctl(sfd,IOCTL_FLASH_GETINFO,
+ (unsigned char *) &flashinfo,
+ sizeof(flash_info_t),
+ &res,0) != 0) {
+ flashinfo.flash_size = FLASH_STAGING_BUFFER_SIZE;
+ }
+
+ if (size > 0) {
+ xprintf("(size=0x%X) ",size);
+ }
+ else {
+ size = flashinfo.flash_size;
+ }
+
+ /* Make sure we don't overrun the staging buffer */
+
+ if (size > FLASH_STAGING_BUFFER_SIZE) {
+ size = FLASH_STAGING_BUFFER_SIZE;
+ }
+
+ /* Read the flash device here. */
+
+ res = cfe_read(sfd,ptr,size);
+
+ cfe_close(sfd);
+ if (res < 0) {
+ return ui_showerror(res,"Could not read from flash");
+ }
+ chkheader = FALSE; /* no header to check */
+ /*
+ * Search for non-0xFF byte at the end. This will work because
+ * flashes get erased to all FF's, we pre-fill our buffer to FF's,
+ */
+ while (res > 0) {
+ if (ptr[res-1] != 0xFF) break;
+ res--;
+ }
+ break;
+
+ case CFE_DEV_SERIAL:
+ la.la_filesys = "raw";
+ la.la_filename = NULL;
+ la.la_device = fname;
+ la.la_address = (intptr_t) ptr;
+ la.la_options = 0;
+ la.la_maxsize = FLASH_STAGING_BUFFER_SIZE;
+ la.la_flags = LOADFLG_SPECADDR;
+
+ res = cfe_load_program("srec",&la);
+
+ if (res < 0) {
+ ui_showerror(res,"Failed.");
+ return res;
+ }
+ break;
+
+ default:
+
+ res = ui_process_url(fname, cmd, &la);
+ if (res < 0) {
+ ui_showerror(res,"Invalid file name %s",fname);
+ return res;
+ }
+
+ la.la_address = (intptr_t) ptr;
+ la.la_options = 0;
+ la.la_maxsize = FLASH_STAGING_BUFFER_SIZE;
+ la.la_flags = LOADFLG_SPECADDR;
+
+ res = cfe_load_program("raw",&la);
+
+ if (res < 0) {
+ ui_showerror(res,"Failed.");
+ return res;
+ }
+ break;
+
+ }
+
+ xprintf("Done. %d bytes read\n",res);
+
+ copysize = res;
+
+ /*
+ * Verify the header and file's CRC.
+ */
+ if (chkheader) {
+ if (flash_validate(ptr,res,&ptr,&copysize) < 0) return -1;
+ }
+
+ if (copysize == 0) return 0; /* 0 bytes, don't flash */
+
+ /*
+ * Open the destination flash device.
+ */
+
+ fh = cfe_open(flashdev);
+ if (fh < 0) {
+ xprintf("Could not open device '%s'\n",flashdev);
+ return CFE_ERR_DEVNOTFOUND;
+ }
+
+ if (cfe_ioctl(fh,IOCTL_FLASH_GETINFO,
+ (unsigned char *) &flashinfo,
+ sizeof(flash_info_t),
+ &res,0) == 0) {
+ /* Truncate write if source size is greater than flash size */
+ if ((copysize + offset) > flashinfo.flash_size) {
+ copysize = flashinfo.flash_size;
+ }
+ }
+
+ /*
+ * If overwriting the boot flash, we need to use the special IOCTL
+ * that will force a reboot after writing the flash.
+ */
+
+ if (flashinfo.flash_base == 0x1FC00000) { /* XXX MIPS-SPECIFIC */
+#if CFG_EMBEDDED_PIC
+ xprintf("\n\n** DO NOT TURN OFF YOUR MACHINE UNTIL THE FLASH UPDATE COMPLETES!! **\n\n");
+#else
+#if CFG_NETWORK
+ if (net_getparam(NET_DEVNAME)) {
+ xprintf("Closing network.\n");
+ net_uninit();
+ }
+#endif
+ xprintf("Rewriting boot flash device '%s'\n",flashdev);
+ xprintf("\n\n**DO NOT TURN OFF YOUR MACHINE UNTIL IT REBOOTS!**\n\n");
+ cfe_ioctl(fh,IOCTL_FLASH_WRITE_ALL, ptr,copysize,&retlen,0);
+ /* should not return */
+ return CFE_ERR;
+#endif
+ }
+
+ /*
+ * Otherwise: it's not the flash we're using right
+ * now, so we can be more verbose about things, and
+ * more importantly, we can return to the command
+ * prompt without rebooting!
+ */
+
+ /*
+ * Erase the flash, if the device requires it. Our new flash
+ * driver does the copy/merge/erase for us.
+ */
+
+ if (!noerase) {
+ if ((devtype == CFE_DEV_FLASH) && !(flashinfo.flash_flags & FLASH_FLAG_NOERASE)) {
+ flash_range_t range;
+ range.range_base = offset;
+ range.range_length = copysize;
+ xprintf("Erasing flash...");
+ if (cfe_ioctl(fh,IOCTL_FLASH_ERASE_RANGE,
+ (uint8_t *) &range,sizeof(range),NULL,0) != 0) {
+ printf("Failed to erase the flash\n");
+ cfe_close(fh);
+ return CFE_ERR_IOERR;
+ }
+ }
+ }
+
+ /*
+ * Program the flash
+ */
+
+ xprintf("Programming...");
+
+ amtcopy = cfe_writeblk(fh,offset,ptr,copysize);
+
+ if (copysize == amtcopy) {
+ xprintf("done. %d bytes written\n",amtcopy);
+ res = 0;
+ }
+ else {
+ ui_showerror(amtcopy,"Failed.");
+ res = CFE_ERR_IOERR;
+ }
+
+ /*
+ * done!
+ */
+
+ cfe_close(fh);
+
+ return res;
+}
+