/* ********************************************************************* * Broadcom Common Firmware Environment (CFE) * * * bcm63xx board specific routines and commands. * * by: seanl * * April 1, 2002 * ********************************************************************* * * 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 "bcm63xx_util.h" #include "flash_api.h" #include "jffs2.h" /* Foxconn add start by Cliff Wang, 03/23/2010 */ #include "tftpd.h" #include "net_nmrp.h" extern int nmrp_server_detected; extern unsigned long cfe_sdramsize; extern int ui_init_tftpdcmds(void); int verify_checksum(char *buf, unsigned long buf_len, unsigned long chksum); /* Foxconn add end by Cliff Wang, 03/23/2010 */ #define je16_to_cpu(x) ((x).v16) #define je32_to_cpu(x) ((x).v32) #define FLASH_STAGING_BUFFER BOARD_IMAGE_DOWNLOAD_ADDRESS #define FLASH_STAGING_BUFFER_SIZE BOARD_IMAGE_DOWNLOAD_SIZE extern int decompressLZMA(unsigned char *in, unsigned insize, unsigned char *out, unsigned outsize); // global int g_processing_cmd = 0; char fakeConsole[2] = " "; /* Foxconn add start by Jenny Zhao, 07/02/2008*/ struct image_header { unsigned long magic; /* magic */ unsigned long header_len; /* Length of header */ unsigned char reserved[8]; unsigned long kernel_chksum; /* Kernel image chksum */ unsigned long rootfs_chksum; /* rootfs image chksum */ unsigned long kernel_len; /* Length of kernel */ unsigned long rootfs_len; /* Length of rootfs */ unsigned long image_chksum; /* checksum across length of image */ unsigned long header_chksum; /* checksum across length of header */ }; #define swap32(val) \ ((unsigned int)( \ (((unsigned int)(val) & (unsigned int)0x000000ffUL)) | \ (((unsigned int)(val) & (unsigned int)0x0000ff00UL)) | \ (((unsigned int)(val) & (unsigned int)0x00ff0000UL)) | \ (((unsigned int)(val) & (unsigned int)0xff000000UL)) )) /* pling added 12/04/2008, define the Foxconn board ID length */ #define FOXCONN_BOARD_ID_LEN 64 /* Foxconn add end by Jenny Zhao, 07/02/2008*/ static int ui_cmd_set_board_param(ui_cmdline_t *cmd,int argc,char *argv[]) { int ret = 0; int i = 0; int reset = 0; if(!argc) { reset += setBoardParam(); } while(argc && !ret) { if(!strcmp(argv[i], "g")) { reset += setGponBoardParam(); } else { /*Setup WPS Device Pin*/ if(!strcmp(argv[i], "w")) { reset += setWpsDevicePinBoardParam(); } else { ret = -1; } } argc--; i++; } if(reset) softReset(); return ret; } static int ui_cmd_reset(ui_cmdline_t *cmd,int argc,char *argv[]) { softReset(); return 0; } // return 0 if 'y' int yesno(void) { char ans[5]; printf(" (y/n):"); console_readline ("", ans, sizeof (ans)); if (ans[0] != 'y') return -1; return 0; } // erase Persistent sector static int ui_cmd_erase_psi(ui_cmdline_t *cmd,int argc,char *argv[]) { printf("Erase persisten storage data?"); if (yesno()) return -1; kerSysErasePsi(); return 0; } static int ui_cmd_erase_nand(ui_cmdline_t *cmd,int argc,char *argv[]) { #if (INC_NAND_FLASH_DRIVER==1) char *flag; int i, blk_end; flag = cmd_getarg(cmd,0); if (!flag) { printf("'e b' to reinitialize NAND flash or 'e a' to erase kernel\n"); return 0; } switch (*flag) { case 'b': printf("Reinitialize NAND flash?"); if (yesno()) return 0; printf("\nNow think carefully. Do you really,\n" "really want to reinitialize the NAND flag?"); if (yesno()) return 0; flash_sector_erase_int(NAND_REINIT_FLASH); break; case 'a': printf("Erase NAND flash? The modem will not be able to boot from " "flash"); if (yesno()) return 0; blk_end = flash_get_numsectors(); for (i = 1; i < blk_end; i++) { printf("."); flash_sector_erase_int(i); } printf("\n"); break; case 's': { extern void dump_spare(void); dump_spare(); } break; case 'r': { extern unsigned char *mem_topofmem; unsigned char *buf = (unsigned char *) mem_topofmem + 1024; char *pszLen = cmd_getarg(cmd, 2); int len = (pszLen) ? atoi(pszLen) : 64; char *pszBlk = cmd_getarg(cmd, 1); if( flash_read_buf(atoi(pszBlk), 0, buf, 16 * 1024) > 0 ) { void ui_dumpaddr( unsigned char *pAddr, int nLen ); printf("block read into buffer at 0x%8.8lx\n", (unsigned long)buf); ui_dumpaddr(buf, len); /* dump first few bytes */ } else printf("block NOT read into buffer at 0x%8.8lx\n",(unsigned long)buf); /* Can break into JTAG now to view entire block contents. */ } break; default: printf("Erase [n]vram, [p]ersistent storage or [a]ll flash except bootrom\nusage: e [n/p/a]\n"); return 0; } #elif (INC_SPI_PROG_NAND==1) char *flag; int i, blk_end; flash_change_flash_type(FLASH_IFC_NAND); flag = cmd_getarg(cmd,0); if (!flag) { printf("'n b' to reinitialize NAND flash or 'n a' to erase kernel on NAND\n"); goto finish; } switch (*flag) { case 'b': printf("Reinitialize NAND flash?"); if (yesno()) goto finish; printf("\nNow think carefully. Do you really,\n" "really want to reinitialize the NAND flag?"); if (yesno()) goto finish; flash_sector_erase_int(NAND_REINIT_FLASH); break; case 'a': printf("Erase NAND flash? The modem will not be able to boot from " "flash"); if (yesno()) goto finish; blk_end = flash_get_numsectors(); for (i = 1; i < blk_end; i++) { printf("."); flash_sector_erase_int(i); } printf("\n"); break; case 's': { extern void dump_spare(void); dump_spare(); } break; case 'r': { extern unsigned char *mem_topofmem; unsigned char *buf = (unsigned char *) mem_topofmem + 1024; char *pszBlk = cmd_getarg(cmd, 1); if( flash_read_buf(atoi(pszBlk), 0, buf, 16 * 1024) > 0 ) { void ui_dumpaddr( unsigned char *pAddr, int nLen ); printf("block read into buffer at 0x%8.8lx\n", (unsigned long)buf); ui_dumpaddr(buf, 64); /* dump first few bytes */ } else printf("block NOT read into buffer at 0x%8.8lx\n",(unsigned long)buf); /* Can break into JTAG now to view entire block contents. */ } break; default: printf("Erase [n]vram, [p]ersistent storage or [a]ll flash except bootrom on NAND\nusage: n [n/p/a]\n"); } finish: flash_change_flash_type(FLASH_IFC_SPI); #endif return 0; } // erase some sectors static int ui_cmd_erase(ui_cmdline_t *cmd,int argc,char *argv[]) { //FILE_TAG cfeTag; PFILE_TAG pTag; char *flag; int i, blk_start, blk_end; flag = cmd_getarg(cmd,0); if (!flag) { printf("Erase [n]vram, [p]ersistent storage or [a]ll flash except bootrom\nusage: e [n/p/a]\n"); return 0; } switch (*flag) { case 'b': printf("Erase boot loader?"); if (yesno()) return 0; printf("\nNow think carefully. Do you really,\n" "really want to erase the boot loader?"); if (yesno()) return 0; flash_sector_erase_int(0); break; case 'n': printf("Erase nvram?"); if (yesno()) return 0; kerSysEraseNvRam(); softReset(); break; case 'a': printf("Erase all flash (except bootrom)?"); if (yesno()) return 0; blk_end = flash_get_numsectors(); if ((pTag = getTagFromPartition(1)) != NULL) blk_start = flash_get_blk(atoi(pTag->rootfsAddress) + BOOT_OFFSET); else // just erase all after cfe { FLASH_ADDR_INFO flash_info; kerSysFlashAddrInfoGet(&flash_info); for( blk_start = 0, i = 0; i 0 ) { for (i = blk_start; i < blk_end; i++) { printf("."); flash_sector_erase_int(i); } printf("\n"); } /* Preserve the NVRAM fields that are used in the 'b' command. */ softReset(); break; case 'p': ui_cmd_erase_psi(cmd,argc,argv); break; default: printf("Erase [n]vram, [p]ersistent storage or [a]ll flash except bootrom\nusage: e [n/p/a]\n"); return 0; } return 0; } static int loadRaw(char *hostImageName, uint8_t *ptr) { cfe_loadargs_t la; int res; printf("Loading %s ...\n", hostImageName); // tftp only la.la_filesys = "tftp"; la.la_filename = hostImageName; la.la_device = NULL; la.la_address = (long)ptr; la.la_options = NULL; la.la_maxsize = FLASH_STAGING_BUFFER_SIZE; la.la_flags = LOADFLG_SPECADDR; res = bcm63xx_cfe_rawload(&la); if (res < 0) { ui_showerror(res, "Loading failed."); return res; } printf("Finished loading %d bytes\n", res); return res; } // flash the image static int ui_cmd_flash_image(ui_cmdline_t *cmd,int argc,char *argv[]) { char hostImageName[BOOT_FILENAME_LEN + BOOT_IP_LEN]; char *imageName; int res; uint8_t *ptr = (uint8_t *) KERNADDR(FLASH_STAGING_BUFFER); g_processing_cmd = 1; imageName = cmd_getarg(cmd, 0); if (imageName) { if (strchr(imageName, ':')) strcpy(hostImageName, imageName); else { strcpy(hostImageName, bootInfo.hostIp); strcat(hostImageName, ":"); strcat(hostImageName, imageName); } } else // use default flash file name { strcpy(hostImageName, bootInfo.hostIp); strcat(hostImageName, ":"); strcat(hostImageName, bootInfo.flashFileName); } if ((res = loadRaw(hostImageName, ptr)) < 0) { g_processing_cmd = 0; return res; } // check and flash image res = flashImage(ptr); if( res == 0 ) { char *p; NVRAM_DATA nvramData; readNvramData(&nvramData); for( p = nvramData.szBootline; p[2] != '\0'; p++ ) { if( p[0] == 'r' && p[1] == '=' && p[2] == 'h' ) { /* Change boot source to "boot from flash". */ p[2] = 'f'; writeNvramData(&nvramData); break; } } softReset(); } g_processing_cmd = 0; return( res ); } static int ui_cmd_write_chk_image(ui_cmdline_t *cmd,int argc,char *argv[]) { char hostImageName[BOOT_FILENAME_LEN + BOOT_IP_LEN]; char *imageName; uint8_t *ptr = (uint8_t *) KERNADDR(FLASH_STAGING_BUFFER); int res; struct image_header *header; unsigned long image_len, image_chksum; unsigned long header_len = 0; unsigned long board_id_len = 0; char board_id[FOX_BOARD_ID_MAX_LEN]; uint8_t *tmp; g_processing_cmd = 1; imageName = cmd_getarg(cmd, 0); if (!imageName) return ui_showusage(cmd); if (strchr(imageName, ':')) strcpy(hostImageName, imageName); else { strcpy(hostImageName, bootInfo.hostIp); strcat(hostImageName, ":"); strcat(hostImageName, imageName); } if ((res = loadRaw(hostImageName, ptr)) < 0) { g_processing_cmd = 0; return res; } /* check chk file */ header = (struct image_header *)ptr; header_len = swap32(header->header_len); image_len = swap32(header->kernel_len); image_chksum = swap32(header->kernel_chksum); board_id_len = header_len - sizeof(struct image_header); memset(board_id, 0, sizeof(board_id)); memcpy(board_id, header+1, board_id_len); printf("total:%d header:%d kernel:%d \n", res, header_len, image_len); tmp = ptr; ptr += header_len; res -= header_len; if (verify_checksum((char*)ptr, image_len, image_chksum)) { printf("fail to comapre checksum ... \n "); return CFE_ERR_BADIMAGE; } memcpy(tmp, ptr, res); // check and flash image res = writeWholeImage(tmp, res); printf("Finished flashing image.\n"); /* if (res == 0) { softReset(); } */ g_processing_cmd = 0; return( res ); } // write the whole image static int ui_cmd_write_whole_image(ui_cmdline_t *cmd,int argc,char *argv[]) { char hostImageName[BOOT_FILENAME_LEN + BOOT_IP_LEN]; char *imageName; uint8_t *ptr = (uint8_t *) KERNADDR(FLASH_STAGING_BUFFER); int res; g_processing_cmd = 1; imageName = cmd_getarg(cmd, 0); if (!imageName) return ui_showusage(cmd); if (strchr(imageName, ':')) strcpy(hostImageName, imageName); else { strcpy(hostImageName, bootInfo.hostIp); strcat(hostImageName, ":"); strcat(hostImageName, imageName); } if ((res = loadRaw(hostImageName, ptr)) < 0) { g_processing_cmd = 0; return res; } // check and flash image res = writeWholeImage(ptr, res); printf("Finished flashing image.\n"); if (res == 0) { softReset(); } g_processing_cmd = 0; return( res ); } static int ui_cmd_flash_router_image(ui_cmdline_t *cmd,int argc,char *argv[]) { char hostImageName[BOOT_FILENAME_LEN + BOOT_IP_LEN]; char *imageName; uint8_t *ptr = (uint8_t *) KERNADDR(FLASH_STAGING_BUFFER); #if (INC_NAND_FLASH_DRIVER==1) uint8_t *tmp; #endif int res; char board_id[FOX_BOARD_ID_MAX_LEN]; //Silver int update=0; char board_id_test[PROJECT_ID_LEN]; #if (INC_NAND_FLASH_DRIVER==1) NVRAM_DATA nvramData; #endif imageName = cmd_getarg(cmd, 0); if (!imageName) return ui_showusage(cmd); if (strchr(imageName, ':')) strcpy(hostImageName, imageName); else { strcpy(hostImageName, ""); strcat(hostImageName, ":"); strcat(hostImageName, ""); } set_tftpd_state(TFTPD_STATE_WAIT_IMAGE); if ((res = loadRaw(hostImageName, ptr)) < 0) { printf("fail to load raw file ... \n"); return res; } if ( nmrp_server_detected == 0) { set_tftpd_state(TFTPD_STATE_OFF); // Foxconn added to turn on RED. setPowerOnLedOn(); // Foxconn added to turn on RED. } /* Foxconn add start by Jenny Zhao, 07/02/2008*/ if (1) { struct image_header *header; unsigned long image_len, image_chksum; unsigned long header_len = 0; unsigned long board_id_len = 0; header = (struct image_header *)ptr; header_len = swap32(header->header_len); image_len = swap32(header->kernel_len); image_chksum = swap32(header->kernel_chksum); /* Check Board ID first */ board_id_len = header_len - sizeof(struct image_header); memset(board_id, 0, sizeof(board_id)); //for(i=0;i>> kerSysBcmImageSet= 0x%x\n", FLASH_IMAGE_START_ADDR); #if (INC_NAND_FLASH_DRIVER==1) memcpy(tmp, ptr, res); if ((res = writeWholeImage(tmp, res) )!= 0) #else if ((res = kerSysBcmImageSet(FLASH_IMAGE_START_ADDR, ptr, res, 0)) != 0) #endif printf("Failed to flash image. Error: %d\n", res); else { /* Foxconn added start, Silver Shih for burn board Id */ if( strlen(board_id) < FOX_BOARD_ID_MAX_LEN) { if(strcmp(board_id_test, board_id) != 0) //if (strcmp((char *)BOARD_DATA_ADDR, board_id) != 0) { //printf("board id not match, addr:0x%x\n", BOARD_DATA_ADDR); //5 is indicated to burn board id #if (INC_NAND_FLASH_DRIVER==0) kerSysBcmImageSet(BOARD_DATA_ADDR, (unsigned char *)board_id, strlen(board_id)+1 , 5); #endif } } /* Foxconn added end, Silver Shih for burn board Id */ update=1; printf("Finished flashing image in NMRP mode.\n"); } } /* Foxconn added start pling 12/04/2008, for 'tftpd' */ #if (INC_NAND_FLASH_DRIVER==0) else if ((res = kerSysBcmImageSet(FLASH_IMAGE_START_ADDR, ptr, res, 0)) != 0) printf("Failed to flash image. Error: %d\n", res); #endif else printf("finishing flash image for flashimage command ... \n"); /* Foxconn added end pling 12/04/2008 */ if (res == 0) { char *p; NVRAM_DATA nvramData; readNvramData(&nvramData); memcpy(nvramData.szFirmwareUpgradeBoardId, board_id, strlen(board_id)); for( p = nvramData.szBootline; p[2] != '\0'; p++ ) { if( p[0] == 'r' && p[1] == '=' && p[2] == 'h' ) { /* Change boot source to "boot from flash". */ p[2] = 'f'; //writeNvramData(&nvramData); break; } } writeNvramData(&nvramData); // softReset(); //remove by EricHuang } if (nmrp_server_detected==1 && update==1) //NMRP mode { // Restore to factory default. printf("try to restore to default, addr=0x%x\n", BOARD_FOXNVRAM_ADDR); #if (INC_NAND_FLASH_DRIVER==0) kerSysBcmImageSet(BOARD_FOXNVRAM_ADDR, (unsigned char *)"", 0x10000 , 5); #endif } return( res ); } /************************************************************************ * cfe_go(la) * * Starts a previously loaded program. cfe_loadargs.la_entrypt * must be set to the entry point of the program to be started * * Input parameters: * la - loader args * * Return value: * does not return ********************************************************************* */ void cfe_go(cfe_loadargs_t *la) { if (la->la_entrypt == 0) { xprintf("No program has been loaded.\n"); return; } if (net_getparam(NET_DEVNAME)) { xprintf("Closing network.\n"); net_uninit(); } xprintf("Starting program at 0x%p\n",la->la_entrypt); setPowerOnLedOn(); cfe_start(la->la_entrypt); } static int bootImage(char *fileSys, char *device, int zflag, char *imageName) { cfe_loadargs_t la; int res; // elf only la.la_filesys = fileSys; la.la_filename = imageName; la.la_device = device; la.la_options = 0; la.la_maxsize = 0; la.la_address = 0; la.la_flags = zflag; res = bcm63xx_cfe_elfload(&la); if (res != 0) return res; if (la.la_flags & LOADFLG_NOISY) xprintf("Entry at 0x%p\n",la.la_entrypt); if ((la.la_flags & LOADFLG_EXECUTE) && (la.la_entrypt != 0)) { cfe_go(&la); } return res; } // Compressed image head format in Big Endia: // 1) Text Start address: 4 bytes // 2) Program Entry point: 4 bytes // 3) Compress image Length: 4 bytes // 4) Compress data starts: compressed data static int bootCompressedImage(unsigned int *puiCmpImage, int retry) { unsigned char *pucSrc; unsigned char *pucDst; unsigned char *pucEntry; unsigned int dataLen; int ret = 0; cfe_loadargs_t la; if( (unsigned long) puiCmpImage > FLASH_BASE ) { /* Boot compressed image from flash. */ unsigned int *puiOrigCmpImage = puiCmpImage; unsigned int *puiNewCmpImage = NULL; unsigned int *puiOldCmpImage = NULL; unsigned int *puiFs = NULL; PFILE_TAG pTag1 = getTagFromPartition(1); PFILE_TAG pTag2 = getTagFromPartition(2); PFILE_TAG pCurTag = NULL; unsigned int *puiImg= NULL; int nImgLen = 0; unsigned long ulCrc, ulImgCrc; if( pTag1 && pTag2 ) { /* Two images are on flash. Determine which one is being booted. */ PFILE_TAG pNewTag = NULL; PFILE_TAG pOldTag = NULL; int seq1 = atoi(pTag1->imageSequence); int seq2 = atoi(pTag2->imageSequence); if( seq1 > seq2 ) { pNewTag = pTag1; pOldTag = pTag2; } else { pNewTag = pTag2; pOldTag = pTag1; } puiNewCmpImage = (unsigned int *) (atoi(pNewTag->kernelAddress) + BOOT_OFFSET); puiOldCmpImage = (unsigned int *) (atoi(pOldTag->kernelAddress) + BOOT_OFFSET); if( puiOrigCmpImage == puiOldCmpImage ) { printf("Booting from previous image (0x%8.8lx) ...\n", (unsigned long) atoi(pOldTag->rootfsAddress) + BOOT_OFFSET - TAG_LEN); pCurTag = pOldTag; } else { printf("Booting from latest image (0x%8.8lx) ...\n", (unsigned long) atoi(pNewTag->rootfsAddress) + BOOT_OFFSET - TAG_LEN); pCurTag = pNewTag; } } else if( pTag1 || pTag2 ) { /* Only one image on flash. */ pCurTag = (pTag1) ? pTag1 : pTag2; printf("Booting from only image (0x%8.8lx) ...\n", (unsigned long) atoi(pCurTag->rootfsAddress) + BOOT_OFFSET - TAG_LEN); } else { /* No image on flash. */ printf("No valid boot image\n"); ret = -1; } if( ret == 0 ) { /* Copy compressed image to SDRAM. */ extern unsigned char *mem_topofmem; FLASH_ADDR_INFO info; unsigned char *pDest = (unsigned char *) mem_topofmem + 1024; unsigned char *pImgEnd; kerSysFlashAddrInfoGet( &info ); pImgEnd = flash_get_memptr( info.flash_meta_start_blk ); kerSysReadFromFlash( pDest, (unsigned long) puiCmpImage, (unsigned long) pImgEnd - (unsigned long) puiCmpImage ); puiCmpImage = (unsigned int *) pDest; /* Copy file system to SDRAM. */ pDest += (unsigned long) pImgEnd - (unsigned long) puiOrigCmpImage + 1024; kerSysReadFromFlash( pDest, (unsigned long) atoi(pCurTag->rootfsAddress) + BOOT_OFFSET, atoi(pCurTag->rootfsLen)); puiFs = (unsigned int *) pDest; pucDst = (unsigned char *) *puiCmpImage; pucEntry = (unsigned char *) *(puiCmpImage + 1); dataLen = (unsigned int) *(puiCmpImage + 2); pucSrc = (unsigned char*) (puiCmpImage + 3); printf("Code Address: 0x%08X, Entry Address: 0x%08x\n", (unsigned int) pucDst, (unsigned int) pucEntry); /* Check Linux file system CRC */ ulImgCrc = *(unsigned long *) (pCurTag->imageValidationToken + CRC_LEN); if( ulImgCrc ) { if( puiFs ) puiImg = puiFs; else { puiImg = (unsigned int *) (atoi(pCurTag->rootfsAddress) + BOOT_OFFSET); } nImgLen = atoi(pCurTag->rootfsLen); ulCrc = CRC32_INIT_VALUE; ulCrc = getCrc32((unsigned char *) puiImg, (UINT32) nImgLen, ulCrc); if( ulCrc != ulImgCrc) { printf("Linux file system CRC error. Corrupted image?\n"); ret = -1; } } /* Check Linux kernel CRC */ ulImgCrc = *(unsigned long *) (pCurTag->imageValidationToken + (CRC_LEN * 2)); if( ulImgCrc ) { puiImg = (unsigned int *) puiCmpImage; nImgLen = atoi(pCurTag->kernelLen); ulCrc = CRC32_INIT_VALUE; ulCrc = getCrc32((unsigned char *) puiImg, (UINT32) nImgLen, ulCrc); if( ulCrc != ulImgCrc) { printf("Linux kernel CRC error. Corrupted image?\n"); ret = -1; } } if( ret == 0 ) { ret = decompressLZMA(pucSrc, dataLen, pucDst, 23*1024*1024); if (ret != 0) printf("Failed to decompress image. Corrupted image?\n"); } if (ret != 0) { /* Try to boot from the other flash image, if one exists. */ if( retry == TRUE && pTag1 && pTag2 ) { int blk = 0; unsigned char *pBase = flash_get_memptr(0); unsigned int *flash_addr_kernel; FLASH_ADDR_INFO flash_info; /* The boot image is bad. Erase the sector with the tag so * the image is not tried in subsequent boots. */ kerSysFlashAddrInfoGet(&flash_info); if( pCurTag == pTag1 ) { blk = flash_get_blk((int)(pBase + flash_info.flash_rootfs_start_offset)); } else if( pCurTag == pTag2 ) { blk = flash_get_blk((int) (pBase + (flash_get_total_size()/2))); } if( blk ) flash_sector_erase_int(blk); /* Boot from the other flash image. */ if( puiOrigCmpImage == puiOldCmpImage ) flash_addr_kernel = puiNewCmpImage; else flash_addr_kernel = puiOldCmpImage; ret = bootCompressedImage( flash_addr_kernel, FALSE ); } } else { printf("Decompression OK!\n"); la.la_entrypt = (long) pucEntry; printf("Entry at 0x%p\n",la.la_entrypt); cfe_go(&la); // never return... } } } else { /* Boot compressed image that was downloaded to RAM. */ pucDst = (unsigned char *) *puiCmpImage; pucEntry = (unsigned char *) *(puiCmpImage + 1); dataLen = (unsigned int) *(puiCmpImage + 2); pucSrc = (unsigned char*) (puiCmpImage + 3); printf("Code Address: 0x%08X, Entry Address: 0x%08x\n", (unsigned int) pucDst, (unsigned int) pucEntry); ret = decompressLZMA(pucSrc, dataLen, pucDst, 23*1024*1024); if (ret == 0) { printf("Decompression OK!\n"); la.la_entrypt = (long) pucEntry; printf("Entry at 0x%p\n",la.la_entrypt); cfe_go(&la); // never return... } else printf("Failed on decompression. Corrupted image?\n"); } return ret; } static int bootNandImageFromRootfs(int start_blk, int end_blk) { extern unsigned char *mem_topofmem; char fname[] = NAND_FLASH_BOOT_IMAGE_NAME; int fname_len = strlen(fname); int len = flash_get_sector_size(0); unsigned char *buf = (unsigned char *) mem_topofmem + 1024; unsigned char *pDest = (unsigned char *) buf + len; unsigned long *pulDest = (unsigned long *) pDest; unsigned char *p; unsigned long version = 0; unsigned long ino = 0; int i, done; struct jffs2_raw_dirent *pdir; struct jffs2_raw_inode *pino; int ret = 0; /* Find the directory entry. */ for( i = start_blk, done = 0; i < end_blk && done == 0; i++ ) { if( flash_read_buf(i, 0, buf, len) > 0 ) { p = buf; while( p < buf + len ) { pdir = (struct jffs2_raw_dirent *) p; if( je16_to_cpu(pdir->magic) == JFFS2_MAGIC_BITMASK ) { if( je16_to_cpu(pdir->nodetype) == JFFS2_NODETYPE_DIRENT && fname_len == pdir->nsize && !memcmp(fname, pdir->name, fname_len) ) { if( je32_to_cpu(pdir->version) > version ) { if( (ino = je32_to_cpu(pdir->ino)) != 0 ) { version = je32_to_cpu(pdir->version); /* Setting 'done = 1' assumes there is only one * version of the directory entry. This may not * be correct if the file is updated after it * was initially flashed. * * TBD. Look for a higher version of the * directory entry without searching the entire * flash part. */ done = 1; break; } } } p += (je32_to_cpu(pdir->totlen) + 0x03) & ~0x03; } else break; } } } if( version ) { unsigned char *pucSrc; unsigned char *pucDst; unsigned char *pucEntry; unsigned int dataLen; unsigned long cur_isize = 0; /* Get the file contents. */ for( i = start_blk, done = 0; i < end_blk && done == 0; i++ ) { if( flash_read_buf(i, 0, buf, len) > 0 ) { p = buf; while( p < buf + len ) { pino = (struct jffs2_raw_inode *) p; if( je16_to_cpu(pino->magic) == JFFS2_MAGIC_BITMASK ) { if(je16_to_cpu(pino->nodetype)==JFFS2_NODETYPE_INODE && je32_to_cpu(pino->ino) == ino) { unsigned long size = je32_to_cpu(pino->dsize); unsigned long ofs = je32_to_cpu(pino->offset); unsigned long isize = je32_to_cpu(pino->isize); if( size ) { memcpy(pDest + ofs, pino->data, size); if( (cur_isize += size) >= isize ) { done = 1; break; } } } p += (je32_to_cpu(pino->totlen) + 0x03) & ~0x03; } else break; } } } pucDst = (unsigned char *) *pulDest; pucEntry = (unsigned char *) *(pulDest + 1); dataLen = (unsigned int) *(pulDest + 2); pucSrc = (unsigned char *) (pulDest + 3); ret = decompressLZMA(pucSrc, dataLen, pucDst, 23*1024*1024); if (ret != 0) printf("Failed to decompress image. Corrupted image?\n"); else { cfe_loadargs_t la; /* Save the rootfs offset of the rootfs that the Linux image * is loaded from at the memory location before the Linux load * address. The Linux image uses this value to determine the * the rootfs to use. */ *(unsigned long *) (pucDst - 4) = (start_blk * len) / 1024; printf("Decompression OK!\n"); la.la_entrypt = (long) pucEntry; printf("Entry at 0x%p\n",la.la_entrypt); cfe_go(&la); // never return... } } else printf("ERROR: A JFFS2 directory entry for %s was not found.\n",fname); return( ret ); } static int bootNandImage(void) { int ret = -1; char *msgA, *msgB; PFILE_TAG pTag1 = getTagFromPartition(1); PFILE_TAG pTag2 = getTagFromPartition(2); int seq1 = (pTag1) ? atoi(pTag1->imageSequence) : -1; int seq2 = (pTag2) ? atoi(pTag2->imageSequence) : -1; int start_blk, end_blk, rootfsA, rootfsB; int len = flash_get_sector_size(0) / 1024; NVRAM_DATA nvramData; readNvramData(&nvramData); validateNandPartTbl(&nvramData); if( pTag1 && pTag2 ) { if( bootInfo.bootPartition == BOOT_LATEST_IMAGE ) { msgA = "Booting from latest image (0x%8.8lx) ...\n"; msgB = "Booting from previous image (0x%8.8lx) ...\n"; rootfsA = (seq2 > seq1) ? NP_ROOTFS_2 : NP_ROOTFS_1; } else /* Boot from the previous image. */ { msgA = "Booting from previous image (0x%8.8lx) ...\n"; msgB = "Booting from latest image (0x%8.8lx) ...\n"; rootfsA = (seq2 <= seq1) ? NP_ROOTFS_2 : NP_ROOTFS_1; } rootfsB = (rootfsA == NP_ROOTFS_2) ? NP_ROOTFS_1 : NP_ROOTFS_2; start_blk = nvramData.ulNandPartOfsKb[rootfsA] / len; end_blk = start_blk + (nvramData.ulNandPartSizeKb[rootfsA] / len); printf(msgA, FLASH_BASE + (nvramData.ulNandPartOfsKb[rootfsA] * 1024)); if( (ret = bootNandImageFromRootfs(start_blk, end_blk)) != 0 ) { start_blk = nvramData.ulNandPartOfsKb[rootfsB] / len; end_blk = start_blk + (nvramData.ulNandPartSizeKb[rootfsB] / len); printf(msgB, FLASH_BASE+(nvramData.ulNandPartOfsKb[rootfsB]*1024)); if( (ret = bootNandImageFromRootfs(start_blk, end_blk)) != 0 ) printf("Unable to boot image.\n"); } } else { if( pTag1 ) rootfsA = NP_ROOTFS_1; else if( pTag2 ) rootfsA = NP_ROOTFS_2; if( pTag1 || pTag2 ) { start_blk = nvramData.ulNandPartOfsKb[rootfsA] / len; end_blk = start_blk + (nvramData.ulNandPartSizeKb[rootfsA] / len); printf("Booting from only image (0x%8.8lx) ...\n", FLASH_BASE + (nvramData.ulNandPartOfsKb[rootfsA] * 1024)); if( (ret = bootNandImageFromRootfs(start_blk, end_blk)) != 0 ) printf("Unable to boot image.\n"); } else printf("No image found.\n"); } return( ret ); } static int autoRun(char *imageName) { char ipImageName[BOOT_FILENAME_LEN + BOOT_IP_LEN]; int ret; if (bootInfo.runFrom == 'f' && !imageName) { if (!imageName) { if( flash_get_flash_type() != FLASH_IFC_NAND ) { PFILE_TAG pTag = getBootImageTag(); int flash_addr_kernel = atoi(pTag->kernelAddress) + BOOT_OFFSET; ret = bootCompressedImage((unsigned int *)flash_addr_kernel, TRUE); } else ret = bootNandImage(); } else printf("Image name not allowed for boot from flash.\n"); } else // loading from host { if (imageName) { if (strchr(imageName, ':')) strcpy(ipImageName, imageName); else { strcpy(ipImageName, bootInfo.hostIp); strcat(ipImageName, ":"); strcat(ipImageName, imageName); } } else // use default host file name { strcpy(ipImageName, bootInfo.hostIp); strcat(ipImageName, ":"); strcat(ipImageName, bootInfo.hostFileName); } // try uncompressed image first ret = bootImage("tftp", "eth0", LOADFLG_EXECUTE | LOADFLG_NOISY, ipImageName); if( ret == CFE_ERR_NOTELF ) { uint8_t *ptr = (uint8_t *) KERNADDR(FLASH_STAGING_BUFFER); // next try as a compressed image printf("Retry loading it as a compressed image.\n"); if ((ret = loadRaw(ipImageName, ptr)) > 0) bootCompressedImage((unsigned int *) ptr, TRUE); } } return ret; } // run program from compressed image in flash or from tftped program from host static int ui_cmd_run_program(ui_cmdline_t *cmd,int argc,char *argv[]) { int ret; if( getBootImageTag() || bootInfo.runFrom == 'r' ) { char *imageName; imageName = cmd_getarg(cmd, 0); g_processing_cmd = 1; ret = autoRun(imageName); } else { printf("ERROR: There is not a valid image to boot from.\n"); ret = CFE_ERR_FILENOTFOUND; } return( ret ); } static int ui_cmd_print_system_info(ui_cmdline_t *cmd,int argc,char *argv[]) { return printSysInfo(); } static int ui_cmd_change_bootline(ui_cmdline_t *cmd,int argc,char *argv[]) { return changeBootLine(); } static int ui_cmd_set_afe_id(ui_cmdline_t *cmd,int argc,char *argv[]) { return changeAfeId(); } void ui_dumpaddr( unsigned char *pAddr, int nLen ); void ui_dumpaddr( unsigned char *pAddr, int nLen ) { static char szHexChars[] = "0123456789abcdef"; char szLine[80]; char *p = szLine; unsigned char ch, *q; int i = 0, j, size = 0; unsigned long ul; unsigned short us; if( ((unsigned long) pAddr & 0xff000000) == 0xff000000 || ((unsigned long) pAddr & 0xff000000) == 0xb0000000 ) { if (nLen == 2) { pAddr = (unsigned char *) ((unsigned long) pAddr & ~0x01); } else if (nLen != 1) { /* keeping the old logic as is. */ if( ((unsigned long) pAddr & 0x03) != 0 ) nLen += 4; pAddr = (unsigned char *) ((unsigned long) pAddr & ~0x03); } } while( nLen > 0 ) { sprintf( szLine, "%8.8lx: ", (unsigned long) pAddr ); p = szLine + strlen(szLine); if( ((unsigned long) pAddr & 0xff000000) == 0xff000000 || ((unsigned long) pAddr & 0xff000000) == 0xb0000000 ) { for(i = 0; i < 6 && nLen > 0; i += sizeof(long), nLen -= sizeof(long)) { if (nLen == 1) { q = pAddr; size = 1; } else if (nLen == 2) { us = *(unsigned short *)pAddr; q = (unsigned char *) &us; size = 2; } else { ul = *(unsigned long *) &pAddr[i]; q = (unsigned char *) &ul; size = sizeof(long); } for( j = 0; j < size; j++ ) { *p++ = szHexChars[q[j] >> 4]; *p++ = szHexChars[q[j] & 0x0f]; } *p++ = ' '; } } else { for(i = 0; i < 16 && nLen > 0; i++, nLen-- ) { ch = pAddr[i]; *p++ = szHexChars[ch >> 4]; *p++ = szHexChars[ch & 0x0f]; *p++ = ' '; } } for( j = 0; j < 16 - i; j++ ) *p++ = ' ', *p++ = ' ', *p++ = ' '; *p++ = ' ', *p++ = ' ', *p++ = ' '; for( j = 0; j < i; j++ ) { ch = pAddr[j]; *p++ = (ch >= ' ' && ch <= '~') ? ch : '.'; } *p++ = '\0'; printf( "%s\r\n", szLine ); pAddr += i; } printf( "\r\n" ); } /* ui_dumpaddr */ static int ui_cmd_dump_mem(ui_cmdline_t *cmd,int argc,char *argv[]) { char *pszAddr = cmd_getarg(cmd, 0); char *pszLen = cmd_getarg(cmd, 1); if( pszAddr && pszLen ) ui_dumpaddr((unsigned char *) xtoi(pszAddr), atoi(pszLen)); else printf("dm address_in_hex length_in_decimal\n"); return( 0 ); } static int ui_cmd_set_mem(ui_cmdline_t *cmd,int argc,char *argv[]) { char *pszAddr = cmd_getarg(cmd, 0); char *pszValue = cmd_getarg(cmd, 1); char *pszSize = cmd_getarg(cmd, 2); if( pszAddr && pszValue && pszSize ) { unsigned long ulAddr = (unsigned long) xtoi(pszAddr); unsigned long ulValue = (unsigned long) atoi(pszValue); int nSize = atoi(pszSize); unsigned long *pul = (unsigned long *) ulAddr; unsigned short *pus = (unsigned short *) ulAddr; unsigned char *puc = (unsigned char *) ulAddr; switch( nSize ) { case 4: *pul = (unsigned long) ulValue; break; case 2: *pus = (unsigned short) ulValue; break; case 1: *puc = (unsigned char) ulValue; break; default: printf("sm address_in_hex value_in_hex size_4_2_or_1"); break; } ui_dumpaddr((unsigned char *) ulAddr, 4); } else printf("sm address_in_hex value_in_hex size_4_2_or_1"); return( 0 ); } static int ui_cmd_check_mem(ui_cmdline_t *cmd,int argc,char *argv[]) { #define RAM_BASE_ADDRESS 0xa0000000 #define BOOT_CODE_SIZE 256 * 1024 // 256KB #define CFE_MEM_SPACE 0xa0400000 #define CFE_MEM_SIZE 4*1024*1024 // 4MB #define MEMORY_SIZE 32*1024*1024 // 32MB #define MAGIC_NUMBER 0xacacacac #define NAND_SECTOR_SIZE (16*1024) // 16KB #define NAND_TEST_SIZE (30*1024*1024) // 30MB unsigned char *addr = NULL; int pass=1; #if 0 unsigned int buf1[NAND_SECTOR_SIZE/4]; unsigned int buf2[NAND_SECTOR_SIZE/4]; int i, j; #endif printf("Verifying DRAM access...\n"); for(addr=(unsigned char *)(RAM_BASE_ADDRESS+BOOT_CODE_SIZE); addr< (unsigned char *)(RAM_BASE_ADDRESS+MEMORY_SIZE); addr+=4) { if( addr< (unsigned char *)CFE_MEM_SPACE || addr > (unsigned char *)CFE_MEM_SPACE+CFE_MEM_SIZE ) { *(unsigned long *)addr = MAGIC_NUMBER; } } for(addr=(unsigned char *)(RAM_BASE_ADDRESS+BOOT_CODE_SIZE); addr< (unsigned char *)(RAM_BASE_ADDRESS+MEMORY_SIZE); addr+=4) { if( addr< (unsigned char *)CFE_MEM_SPACE || addr > (unsigned char *)CFE_MEM_SPACE+CFE_MEM_SIZE ) { if( *(unsigned long *)addr != MAGIC_NUMBER ) pass=0; } } if(pass) printf("DRAM check OK!!!!\n"); else printf("DRAM check NG!!!!\n"); #if 0 //printf("Verifying NAND flash access...\n"); pass=1; for(i=0; i0) offset = nvramData.ulNandPartOfsKb[NP_ROOTFS_2] * 1024; else offset = nvramData.ulNandPartOfsKb[NP_ROOTFS_1] * 1024; printf("Verifying NAND flash access from 0x%08x...\n", FLASH_BASE+offset); for(i=0; i -- if no filename, tftped from host with file name in 'Default host flash file name'", ""); cmd_addcmd("c", ui_cmd_change_bootline, NULL, "Change booline parameters", "", ""); cmd_addcmd("p", ui_cmd_print_system_info, NULL, "Print boot line and board parameter info", "", ""); cmd_addcmd("r", ui_cmd_run_program, NULL, "Run program from flash image or from host depend on [f/h] flag", "eg. r [[hostip:]filenaem] if no filename, use the file name in 'Default host run file name'", ""); #if (INC_SPI_PROG_NAND==1) cmd_addcmd("n", ui_cmd_erase_nand, NULL, "Erase NAND flash", "e [a]", ""); #else if( flash_get_flash_type() == FLASH_IFC_NAND ) cmd_addcmd("e", ui_cmd_erase_nand, NULL, "Erase NAND flash", "e [a]", ""); else #endif cmd_addcmd("e", ui_cmd_erase, NULL, "Erase [n]vram or [a]ll flash except bootrom", "e [n/a]", ""); cmd_addcmd("w", ui_cmd_write_whole_image, NULL, "Write the whole image start from beginning of the flash", "eg. w [hostip:]whole_image_file_name", ""); cmd_addcmd("chw", ui_cmd_write_chk_image, NULL, "Write chkw image start from beginning of the flash", "eg. chkw [hostip:]whole_image_file_name", ""); cmd_addcmd("dm", ui_cmd_dump_mem, NULL, "Dump memory or registers.", "eg. dm address_in_hex length_in_decimal", ""); cmd_addcmd("sm", ui_cmd_set_mem, NULL, "Set memory or registers.", "eg. sm address_in_hex value_in_hex size_4_2_or_1", ""); cmd_addcmd("nmrp", ui_cmd_nmrp, NULL, "start memory or registers.", "eg. nmrp ", ""); cmd_addcmd("fr", ui_cmd_flash_read, NULL, "read data from flash.", "eg. fr addr ", ""); /* Foxconn add start by Cliff Wang, 03/23/2010 */ cmd_addcmd("checkmem", ui_cmd_check_mem, NULL, "Check memory.", "Check memory.", ""); ui_init_tftpdcmds(); /* Foxconn add end by Cliff Wang, 03/23/2010 */ return 0; } static int runDelay(int delayCount) { int goAuto = 0; if (delayCount == 0) return goAuto; printf("*** Press any key to stop auto run (%d seconds) ***\n", delayCount); printf("Auto run second count down: %d", delayCount); cfe_sleep(CFE_HZ/8); // about 1/4 second while (1) { printf("\b%d", delayCount); cfe_sleep(CFE_HZ); // about 1 second if (console_status()) break; if (--delayCount == 0) { goAuto = 1; break; } } printf("\b%d\n", delayCount); return goAuto; } int bcm63xx_run(int breakIntoCfe) { int goAuto; ui_init_bcm63xx_cmds(); printSysInfo(); enet_init(); goAuto = runDelay(bootInfo.bootDelay); if (!breakIntoCfe && runDelay(bootInfo.bootDelay)) { /* Foxconn add start by Cliff Wang, 03/23/2010 */ if(_start_nmrp() != 0) autoRun(NULL); // never returns /* Foxconn add end by Cliff Wang, 03/23/2010 */ } return goAuto; }