/* ********************************************************************* * Broadcom Common Firmware Environment (CFE) * * bcm63xx utility functions * * Created on : 04/18/2002 seanl * ********************************************************************* <:copyright-broadcom Copyright (c) 2002 Broadcom Corporation All Rights Reserved No portions of this material may be reproduced in any form without the written permission of: Broadcom Corporation 16215 Alton Parkway Irvine, California 92619 All information contained in this document is Broadcom Corporation company private, proprietary, and trade secret. :> */ #define BCMTAG_EXE_USE #include "bcm63xx_util.h" #include "flash_api.h" #include "jffs2.h" #define je16_to_cpu(x) ((x).v16) #define je32_to_cpu(x) ((x).v32) static void convertBootInfo(void); static int checkChipId(int tagChipId, char *sig2); static void UpdateImageSequenceNumber( char *imageSequence ); BOOT_INFO bootInfo; static int parseFilename(char *fn) { if (strlen(fn) < BOOT_FILENAME_LEN) return 0; else return 1; } static int parseChoiceFh(char *choice) { if (*choice == 'f' || *choice == 'h') return 0; else return 1; } static int parseBootPartition(char *choice) { return( (*choice == BOOT_LATEST_IMAGE || *choice == BOOT_PREVIOUS_IMAGE) ? 0 : 1 ); } static int parseChoice09(char *choice) { int bChoice = *choice - '0'; if (bChoice >= 0 && bChoice <= 9) return 0; else return 1; } static int parseIpAddr(char *ipStr); static int parseGwIpAddr(char *ipStr); static int parseAfeId(char *afeIdStr); #define PARAM_IDX_BOARD_IPADDR 0 #define PARAM_IDX_HOST_IPADDR 1 #define PARAM_IDX_GW_IPADDR 2 #define PARAM_IDX_RUN_FROM 3 #define PARAM_IDX_RUN_FILENAME 4 #define PARAM_IDX_FLASH_FILENAME 5 #define PARAM_IDX_BOOT_DELAY 6 #define PARAM_IDX_BOOT_IMAGE 7 static PARAMETER_SETTING gBootParam[] = { // prompt name Error Prompt Boot Define Boot Param Validation function {"Board IP address :", IP_PROMPT , "e=", "", 24, parseIpAddr, TRUE}, // index 0 {"Host IP address :", IP_PROMPT , "h=", "", 15, parseIpAddr, TRUE}, // index 1 {"Gateway IP address :", IP_PROMPT , "g=", "", 15, parseGwIpAddr, TRUE}, // index 2 {"Run from flash/host (f/h) :", RUN_FROM_PROMPT , "r=", "", 1, parseChoiceFh, TRUE}, // index 3 {"Default host run file name :", HOST_FN_PROMPT , "f=", "", MAX_PROMPT_LEN - 1, parseFilename, TRUE}, // index 4 {"Default host flash file name :", FLASH_FN_PROMPT , "i=", "", MAX_PROMPT_LEN - 1, parseFilename, TRUE}, // index 5 {"Boot delay (0-9 seconds) :", BOOT_DELAY_PROMPT, "d=", "", 1, parseChoice09, TRUE}, // index 6 {"Boot image (0=latest, 1=previous) :", BOOT_PARTITION_PROMPT, "p=", "", 1, parseBootPartition, TRUE}, // index 7 {NULL}, }; static int gNumBootParams = (sizeof(gBootParam) / sizeof(PARAMETER_SETTING))-1; static PARAMETER_SETTING gAfeId[] = { // prompt name Error Prompt Boot Define Boot Param Validation function {"Primary AFE ID :", AFE_PROMPT, "", "", 12, parseAfeId, TRUE}, // index 0 {"Bonding AFE ID :", AFE_PROMPT, "", "", 12, parseAfeId, TRUE}, // index 1 {NULL}, }; static int gAfeIdParams = (sizeof(gAfeId) / sizeof(PARAMETER_SETTING))-1; // move from lib_misc.c int parseipaddr(const char *ipaddr,uint8_t *dest) { int a,b,c,d; char *x; /* make sure it's all digits and dots. */ x = (char *) ipaddr; while (*x) { if ((*x == '.') || ((*x >= '0') && (*x <= '9'))) { x++; continue; } return -1; } x = (char *) ipaddr; a = lib_atoi(ipaddr); x = lib_strchr(x,'.'); if (!x) return -1; b = lib_atoi(x+1); x = lib_strchr(x+1,'.'); if (!x) return -1; c = lib_atoi(x+1); x = lib_strchr(x+1,'.'); if (!x) return -1; d = lib_atoi(x+1); if ((a < 0) || (a > 255)) return -1; if ((b < 0) || (b > 255)) return -1; if ((c < 0) || (c > 255)) return -1; if ((d < 0) || (d > 255)) return -1; dest[0] = (uint8_t) a; dest[1] = (uint8_t) b; dest[2] = (uint8_t) c; dest[3] = (uint8_t) d; return 0; } #if 0 static const char hextable[16] = "0123456789ABCDEF"; void dumpHex(unsigned char *start, int len) { unsigned char *ptr = start, *end = start + len; while (ptr < end) { long offset = ptr - start; unsigned char text[120], *p = text; while (ptr < end && p < &text[16 * 3]) { *p++ = hextable[*ptr >> 4]; *p++ = hextable[*ptr++ & 0xF]; *p++ = ' '; } p[-1] = 0; printf("%4lX %s\n", offset, text); } } #endif int parsexdigit(char str) { int digit; if ((str >= '0') && (str <= '9')) digit = str - '0'; else if ((str >= 'a') && (str <= 'f')) digit = str - 'a' + 10; else if ((str >= 'A') && (str <= 'F')) digit = str - 'A' + 10; else return -1; return digit; } // convert in = fffffff00 to out=255.255.255.0 // return 0 = OK, 1 failed. static int convertMaskStr(char *in, char *out) { int i; char twoHex[4]; uint8_t dest[4]; char mask[BOOT_IP_LEN]; if (strlen(in) != MASK_LEN) // mask len has to 8 return 1; memset(twoHex, 0, sizeof(twoHex)); for (i = 0; i < 4; i++) { twoHex[0] = (uint8_t)*in++; twoHex[1] = (uint8_t)*in++; if (parsexdigit(*twoHex) == -1) return 1; dest[i] = (uint8_t) xtoi(twoHex); } sprintf(mask, "%d.%d.%d.%d", dest[0], dest[1], dest[2], dest[3]); strcpy(out, mask); return 0; } // return 0 - OK, !0 - Bad ip static int parseIpAddr(char *ipStr) { char *x; uint8_t dest[4]; char mask[BOOT_IP_LEN]; char ipMaskStr[2*BOOT_IP_LEN]; strcpy(ipMaskStr, ipStr); x = strchr(ipMaskStr,':'); if (!x) // no mask return parseipaddr(ipMaskStr, dest); *x = '\0'; if (parseipaddr(ipMaskStr, dest)) // ipStr is not ok return 1; x++; return convertMaskStr(x, mask); // mask is not used here } // return 0 - OK, !0 - Bad ip static int parseGwIpAddr(char *ipStr) { int ret = 0; if( *ipStr ) ret = parseIpAddr(ipStr); return(ret); } // return 0 - OK, !0 - Bad ip static int parseAfeId(char *afeIdStr) { return 0; } // port from ifconfig command in ui_netcmds.c void enet_init(void) { char devname[] = "eth0"; uint8_t addr[IP_ADDR_LEN]; int res; NVRAM_DATA nvramData; readNvramData(&nvramData); if (net_getparam(NET_DEVNAME) == NULL) { res = net_init(devname); /* turn interface on */ if (res < 0) { ui_showerror(res, "Could not activate network interface '%s'", devname); return; } } net_setparam(NET_HWADDR, nvramData.ucaBaseMacAddr); parseipaddr(bootInfo.boardIp, addr); net_setparam(NET_IPADDR, addr); if (strlen(bootInfo.boardMask) > 0) { parseipaddr(bootInfo.boardMask, addr); net_setparam(NET_NETMASK, addr); } if (strlen(bootInfo.gatewayIp) > 0) { parseipaddr(bootInfo.gatewayIp, addr); net_setparam(NET_GATEWAY, addr); } net_setnetvars(); } /*************************************************************************** // Function Name: getCrc32 // Description : caculate the CRC 32 of the given data. // Parameters : pdata - array of data. // size - number of input data bytes. // crc - either CRC32_INIT_VALUE or previous return value. // Returns : crc. ****************************************************************************/ UINT32 getCrc32(byte *pdata, UINT32 size, UINT32 crc) { while (size-- > 0) crc = (crc >> 8) ^ Crc32_table[(crc ^ *pdata++) & 0xff]; return crc; } // return 0, ok. return -1 = wrong chip static int checkChipId(int tagChipId, char *sig2) { unsigned int chipId = (PERF->RevID & 0xFFFE0000) >> 16; int result = 0; /* Force BCM681x variants to be be BCM6816) */ if( (chipId & 0xfff0) == 0x6810 ) chipId = 0x6816; if (tagChipId == chipId) result = 0; else { printf("Chip Id error. Image Chip Id = %04x, Board Chip Id = %04x.\n", tagChipId, chipId); result = -1; } return result; } // return -1: fail. // 0: OK. int verifyTag( PFILE_TAG pTag, int verbose ) { UINT32 crc; FLASH_ADDR_INFO info; int tagVer, curVer; kerSysFlashAddrInfoGet( &info ); tagVer = atoi(pTag->tagVersion); curVer = atoi(BCM_TAG_VER); if (tagVer != curVer) { if( verbose ) { printf("Firmware tag version [%d] is not compatible with the current Tag version [%d].\n", \ tagVer, curVer); } return -1; } if (checkChipId(xtoi(pTag->chipId), pTag->signiture_2) != 0) return -1; // check tag validate token first crc = CRC32_INIT_VALUE; crc = getCrc32((byte *) pTag, (UINT32)TAG_LEN-TOKEN_LEN, crc); if (crc != (UINT32)(*(UINT32*)(pTag->tagValidationToken))) { if( verbose ) printf("Illegal image ! Tag crc failed.\n"); return -1; } return 0; } #if (INC_NAND_FLASH_DRIVER==0) PFILE_TAG getTagFromPartition(int imageNumber) { static unsigned char sectAddr1[sizeof(FILE_TAG)]; static unsigned char sectAddr2[sizeof(FILE_TAG)]; int blk = 0; UINT32 crc; PFILE_TAG pTag = NULL; unsigned char *pBase = flash_get_memptr(0); unsigned char *pSectAddr = NULL; /* The image tag for the first image is always after the boot loader. * The image tag for the second image, if it exists, is at one half * of the flash size. */ if( imageNumber == 1 ) { FLASH_ADDR_INFO flash_info; kerSysFlashAddrInfoGet(&flash_info); blk = flash_get_blk((int)(pBase+flash_info.flash_rootfs_start_offset)); pSectAddr = sectAddr1; } else if( imageNumber == 2 ) { blk = flash_get_blk((int) (pBase + (flash_get_total_size() / 2))); pSectAddr = sectAddr2; } if( blk ) { memset(pSectAddr, 0x00, sizeof(FILE_TAG)); flash_read_buf((unsigned short) blk, 0, pSectAddr, sizeof(FILE_TAG)); crc = CRC32_INIT_VALUE; crc = getCrc32(pSectAddr, (UINT32)TAG_LEN-TOKEN_LEN, crc); pTag = (PFILE_TAG) pSectAddr; if (crc != (UINT32)(*(UINT32*)(pTag->tagValidationToken))) pTag = NULL; } return( pTag ); } #else #define tag_not_searched 0 #define tag_not_found 1 #define tag_found 2 PFILE_TAG getTagFromPartition(int imageNumber) { extern unsigned char *mem_topofmem; static FILE_TAG Tag1 = {{tag_not_searched}}; static FILE_TAG Tag2 = {{tag_not_searched}}; PFILE_TAG pTag = (imageNumber == 2) ? &Tag2 : &Tag1; PFILE_TAG ret = NULL; switch( pTag->tagVersion[0] ) { case tag_not_searched: { int rootfs = (imageNumber == 2) ? NP_ROOTFS_2 : NP_ROOTFS_1; char fname[] = NAND_CFE_RAM_NAME; int fname_actual_len = strlen(fname); int fname_cmp_len = strlen(fname) - 3; /* last three are digits */ unsigned char *buf = (unsigned char *) mem_topofmem + 1024; unsigned char *p; int len = flash_get_sector_size(0); int num_blks = flash_get_numsectors(); int i, done, start_blk, end_blk; struct jffs2_raw_dirent *pdir; unsigned long version = 0; NVRAM_DATA nvramData; pTag->tagVersion[0] = tag_not_found; readNvramData(&nvramData); validateNandPartTbl(&nvramData); if( nvramData.ulNandPartOfsKb[rootfs] > 0 && nvramData.ulNandPartOfsKb[rootfs] < ((num_blks * len) / 1024) && nvramData.ulNandPartSizeKb[rootfs] > 0 && nvramData.ulNandPartSizeKb[rootfs] < ((num_blks * len) / 1024) ) { const int max_not_jffs2 = 10; int not_jffs2 = 0; start_blk = nvramData.ulNandPartOfsKb[rootfs] / (len / 1024); end_blk = start_blk + (nvramData.ulNandPartSizeKb[rootfs] / (len / 1024)); /* 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_actual_len == pdir->nsize && !memcmp(fname, pdir->name, fname_cmp_len) ) { if( je32_to_cpu(pdir->version) > version ) { if( je32_to_cpu(pdir->ino) != 0 ) { unsigned char *seq = pdir->name + fname_cmp_len; pTag->imageSequence[0] = seq[0]; pTag->imageSequence[1] = seq[1]; pTag->imageSequence[2] = seq[2]; pTag->imageSequence[3] = '\0'; pTag->tagVersion[0] = tag_found; version = je32_to_cpu(pdir->version); /* Setting 'done = 1' assumes there is * only one version of the directory * entry. */ done = 1; ret = pTag; break; } } } p += (je32_to_cpu(pdir->totlen) + 0x03) & ~0x03; not_jffs2 = 0; } else { if( not_jffs2++ > max_not_jffs2 ) done = 1; break; } } } } } } break; case tag_found: ret = pTag; break; case tag_not_found: ret = NULL; break; } return(ret); } #endif int getPartitionFromTag( PFILE_TAG pTag ) { int ret = 0; if( pTag ) { PFILE_TAG pTag1 = getTagFromPartition(1); PFILE_TAG pTag2 = getTagFromPartition(2); int sequence = atoi(pTag->imageSequence); int sequence1 = (pTag1) ? atoi(pTag1->imageSequence) : -1; int sequence2 = (pTag2) ? atoi(pTag2->imageSequence) : -1; if( pTag1 && sequence == sequence1 ) ret = 1; else if( pTag2 && sequence == sequence2 ) ret = 2; } return( ret ); } PFILE_TAG getBootImageTag(void) { PFILE_TAG pTag = NULL; if( flash_get_flash_type() != FLASH_IFC_NAND ) { PFILE_TAG pTag1 = getTagFromPartition(1); /* Foxconn modified end pling 10/13/2008 */ PFILE_TAG pTag2 = NULL; // PFILE_TAG pTag2 = getTagFromPartition(2); //* Foxconn modified end pling 10/13/2008 */ if( pTag1 && pTag2 ) { /* Two images are flashed. */ int sequence1 = atoi(pTag1->imageSequence); int sequence2 = atoi(pTag2->imageSequence); if( bootInfo.bootPartition == BOOT_LATEST_IMAGE ) pTag = (sequence2 > sequence1) ? pTag2 : pTag1; else /* Boot from the previous image. */ pTag = (sequence2 < sequence1) ? pTag2 : pTag1; } else /* One image is flashed. */ pTag = (pTag2) ? pTag2 : pTag1; } else { /* TBD. Verify that linux is on the file system. */ /* pTag pointer is only compared to NULL for NAND flash boot. */ pTag = (PFILE_TAG) 1; } return( pTag ); } static void UpdateImageSequenceNumber( char *imageSequence ) { int newImageSequence = 0; PFILE_TAG pTag = getTagFromPartition(1); if( pTag ) newImageSequence = atoi(pTag->imageSequence); pTag = getTagFromPartition(2); if( pTag && atoi(pTag->imageSequence) > newImageSequence ) newImageSequence = atoi(pTag->imageSequence); newImageSequence++; sprintf(imageSequence, "%d", newImageSequence); } // return -1: fail. // 0: OK. int flashImage(uint8_t *imagePtr) { UINT32 crc; FLASH_ADDR_INFO info; int totalImageSize = 0; int cfeSize; int cfeAddr, rootfsAddr, kernelAddr; int status = 0; PFILE_TAG pTag = (PFILE_TAG) imagePtr; NVRAM_DATA nvramData, tmpNvramData; if( flash_get_flash_type() == FLASH_IFC_NAND ) { printf("ERROR: Image is not a valid NAND flash image.\n"); return -1; } // save existing NVRAM data into a local structure readNvramData(&nvramData); if( verifyTag( pTag, 1 ) == -1 ) return -1; kerSysFlashAddrInfoGet( &info ); // check imageCrc totalImageSize = atoi(pTag->totalImageLen); crc = CRC32_INIT_VALUE; crc = getCrc32((imagePtr+TAG_LEN), (UINT32) totalImageSize, crc); if (crc != (UINT32) (*(UINT32*)(pTag->imageValidationToken))) { printf(" Illegal image ! Image crc failed.\n"); return -1; } cfeSize = cfeAddr = rootfsAddr = kernelAddr = 0; // check cfe's existence cfeAddr = atoi(pTag->cfeAddress); if (cfeAddr) { cfeSize = atoi(pTag->cfeLen); if( (cfeSize <= 0) ) { printf("Illegal cfe size [%d].\n", cfeSize ); return -1; } printf("\nFlashing CFE: "); if ((status = kerSysBcmImageSet(cfeAddr+BOOT_OFFSET, imagePtr+TAG_LEN, cfeSize, 0)) != 0) { printf("Failed to flash CFE. Error: %d\n", status); return status; } // Check if the new image has valid NVRAM if ((readNvramData(&tmpNvramData) != 0) || (BpSetBoardId(tmpNvramData.szBoardId) != BP_SUCCESS) || (BpSetVoiceBoardId(tmpNvramData.szBoardId) != BP_SUCCESS)) writeNvramData(&nvramData); } // check root filesystem and kernel existence rootfsAddr = atoi(pTag->rootfsAddress); kernelAddr = atoi(pTag->kernelAddress); if( rootfsAddr && kernelAddr ) { char *p; unsigned char *tagFs = imagePtr; unsigned int baseAddr = (unsigned int) flash_get_memptr(0); unsigned int totalSize = (unsigned int) flash_get_total_size(); unsigned int reservedBytesAtEnd; unsigned int availableSizeOneImg; unsigned int reserveForTwoImages; unsigned int availableSizeTwoImgs; unsigned int newImgSize = atoi(pTag->rootfsLen)+atoi(pTag->kernelLen); PFILE_TAG pCurTag = getBootImageTag(); UINT32 crc; unsigned int curImgSize = 0; unsigned int rootfsOffset = (unsigned int)rootfsAddr-IMAGE_BASE-TAG_LEN; FLASH_ADDR_INFO flash_info; kerSysFlashAddrInfoGet(&flash_info); if( rootfsOffset < flash_info.flash_rootfs_start_offset ) { // Increase rootfs and kernel addresses by the difference between // rootfs offset and what it needs to be. rootfsAddr += flash_info.flash_rootfs_start_offset - rootfsOffset; kernelAddr += flash_info.flash_rootfs_start_offset - rootfsOffset; sprintf(pTag->rootfsAddress,"%lu", (unsigned long) rootfsAddr); sprintf(pTag->kernelAddress,"%lu", (unsigned long) kernelAddr); crc = CRC32_INIT_VALUE; crc = getCrc32((unsigned char *)pTag,(UINT32)TAG_LEN-TOKEN_LEN,crc); *(unsigned long *) &pTag->tagValidationToken[0] = crc; } rootfsAddr += BOOT_OFFSET; kernelAddr += BOOT_OFFSET; reservedBytesAtEnd = flash_get_reserved_bytes_at_end(&flash_info); availableSizeOneImg = totalSize - ((unsigned int)rootfsAddr-baseAddr) - reservedBytesAtEnd; reserveForTwoImages = (flash_info.flash_rootfs_start_offset > reservedBytesAtEnd) ? flash_info.flash_rootfs_start_offset : reservedBytesAtEnd; availableSizeTwoImgs = (totalSize / 2) - reserveForTwoImages; // printf("availableSizeOneImage=%dKB availableSizeTwoImgs=%dKB reserve=%dKB\n", // availableSizeOneImg/1024, availableSizeTwoImgs/1024, reserveForTwoImages/1024); if( pCurTag ) curImgSize = atoi(pCurTag->rootfsLen) + atoi(pCurTag->kernelLen); if( newImgSize > availableSizeOneImg) { printf("Illegal image size %d. Image size must not be greater " "than %d.\n", newImgSize, availableSizeOneImg); return -1; } // tag is alway at the sector start of fs if (cfeAddr) { // will trash cfe memory, but cfe is already flashed tagFs = imagePtr + cfeSize; memcpy(tagFs, imagePtr, TAG_LEN); } // If the current image fits in half the flash space and the new // image to flash also fits in half the flash space, then flash it // in the partition that is not currently being used to boot from. if( curImgSize <= availableSizeTwoImgs && newImgSize <= availableSizeTwoImgs && getPartitionFromTag( pCurTag ) == 1 ) { // Update rootfsAddr to point to the second boot partition. int offset = (totalSize / 2) + TAG_LEN; sprintf(((PFILE_TAG) tagFs)->kernelAddress, "%lu", (unsigned long) IMAGE_BASE + offset + (kernelAddr-rootfsAddr)); kernelAddr = baseAddr + offset + (kernelAddr - rootfsAddr); sprintf(((PFILE_TAG) tagFs)->rootfsAddress, "%lu", (unsigned long) IMAGE_BASE + offset); rootfsAddr = baseAddr + offset; } UpdateImageSequenceNumber( ((PFILE_TAG) tagFs)->imageSequence ); crc = CRC32_INIT_VALUE; crc = getCrc32((unsigned char *)tagFs, (UINT32)TAG_LEN-TOKEN_LEN, crc); *(unsigned long *) &((PFILE_TAG) tagFs)->tagValidationToken[0] = crc; printf("\nFlashing root file system and kernel at 0x%8.8lx: ", rootfsAddr - TAG_LEN); if( (status = kerSysBcmImageSet((rootfsAddr-TAG_LEN), tagFs, TAG_LEN + newImgSize, 0)) != 0 ) { printf("Failed to flash root file system. Error: %d\n", status); return status; } for( p = nvramData.szBootline; p[2] != '\0'; p++ ) { if( p[0] == 'p' && p[1] == '=' && p[2] != BOOT_LATEST_IMAGE ) { // Change boot partition to boot from new image. p[2] = BOOT_LATEST_IMAGE; writeNvramData(&nvramData); break; } } } printf(".\n*** Image flash done *** !\n"); return status; } static int nandUpdateImageSequenceNumber( uint8_t *imagePtr, int imageSize ) { unsigned char *buf, *p; char fname[] = NAND_CFE_RAM_NAME; int fname_actual_len = strlen(fname); int fname_cmp_len = strlen(fname) - 3; /* last three are digits */ int len = flash_get_sector_size(0); struct jffs2_raw_dirent *pdir; unsigned long version = 0; PFILE_TAG pTag1 = getTagFromPartition(1); PFILE_TAG pTag2 = getTagFromPartition(2); int seq = (pTag1) ? atoi(pTag1->imageSequence) : -1; int seq2 = (pTag2) ? atoi(pTag2->imageSequence) : -1; int ret = 0; if( seq2 > seq ) seq = seq2; if( seq != -1 ) { int done = 0; /* Increment the new highest sequence number. Add it to the CFE RAM * file name. */ seq++; for(buf = imagePtr; buf < imagePtr+imageSize && done == 0; buf += len) { 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_actual_len == pdir->nsize && !memcmp(fname, pdir->name, fname_cmp_len) && je32_to_cpu(pdir->version) > version && je32_to_cpu(pdir->ino) != 0 ) { p = pdir->name + fname_cmp_len; p[0] = (seq / 100) + '0'; p[1] = ((seq % 100) / 10) + '0'; p[2] = ((seq % 100) % 10) + '0'; p[3] = '\0'; je32_to_cpu(pdir->name_crc) = getCrc32(pdir->name, (unsigned long) fname_actual_len, 0); version = je32_to_cpu(pdir->version); /* Setting 'done = 1' assumes there is only one version * of the directory entry. */ done = 1; ret = (buf - imagePtr) / len; /* block number */ break; } p += (je32_to_cpu(pdir->totlen) + 0x03) & ~0x03; } else break; } } } return(ret); } // return -1: fail. // 0: OK. int writeWholeImage(uint8_t *imagePtr, int wholeImageSize) { UINT32 crc; int status = 0; int offset = 0; int imageSize = wholeImageSize - TOKEN_LEN; unsigned char crcBuf[CRC_LEN]; NVRAM_DATA nvramData, tmpNvramData; WFI_TAG wfiTag; #if (INC_SPI_PROG_NAND==1) if( flash_get_flash_type() != FLASH_IFC_NAND && wholeImageSize > FLASH_LENGTH_BOOT_ROM) flash_change_flash_type(FLASH_IFC_NAND); #endif // if whole image size (plus TOKEN_LEN of crc) is greater than total flash size, return error if (wholeImageSize > (flash_get_total_size() + TOKEN_LEN)) { printf("Image size too big\n"); return -1; } memcpy(&wfiTag, imagePtr + imageSize, sizeof(wfiTag)); if( (wfiTag.wfiVersion & WFI_ANY_VERS_MASK) == WFI_ANY_VERS && checkChipId(wfiTag.wfiChipId, NULL) != 0 ) return -1; // check tag validate token first crc = CRC32_INIT_VALUE; crc = getCrc32(imagePtr, (UINT32)imageSize, crc); memcpy(crcBuf, imagePtr+imageSize, CRC_LEN); if (memcmp(&crc, crcBuf, CRC_LEN) != 0) { printf("Illegal whole flash image\n"); return -1; } // save existing NVRAM data into a local structure readNvramData(&nvramData); if( flash_get_flash_type() == FLASH_IFC_NAND ) { /* The CFE ROM boot loader saved the rootfs partition index at the * memory location before CFE RAM load address. */ extern unsigned char _ftext; /* Allow addition blocks to flash cfram block that has sequence number * and is flashed last. */ const int overhead_blocks = 8; int rootfs = (int) *(&_ftext - 1); int blksize = flash_get_sector_size(0) / 1024; int sectsize = flash_get_sector_size(0); int i, cferam_blk, after_cferam, cferam_overhead; if( (wfiTag.wfiVersion & WFI_ANY_VERS_MASK) == WFI_ANY_VERS && ((blksize == 16 && wfiTag.wfiFlashType != WFI_NAND16_FLASH) || (blksize == 128 && wfiTag.wfiFlashType != WFI_NAND128_FLASH)) ) { printf("\nERROR: NAND flash block size does not match image " "block size\n\n"); return -1; } if( *(unsigned short *) imagePtr != JFFS2_MAGIC_BITMASK ) { /* Flash block 0 (cferom). */ PNVRAM_DATA pnd = (PNVRAM_DATA) (imagePtr + NVRAM_DATA_OFFSET); char *p; /* Copy NVRAM data to block to be flashed so it is preserved. */ memcpy((unsigned char *) pnd, (unsigned char *) &nvramData, sizeof(NVRAM_DATA)); for( p = pnd->szBootline; p[2] != '\0'; p++ ) { if( p[0] == 'p' && p[1] == '=' && p[2] != BOOT_LATEST_IMAGE ) { // Change boot partition to boot from new image. p[2] = BOOT_LATEST_IMAGE; break; } } /* Recalculate the nvramData CRC. */ pnd->ulCheckSum = 0; pnd->ulCheckSum = getCrc32((unsigned char *) pnd, sizeof(NVRAM_DATA), CRC32_INIT_VALUE); if((status = kerSysBcmImageSet(FLASH_BASE,imagePtr,sectsize,0)) != 0) printf("Failed to flash block 0. Error: %d\n", status); imagePtr += sectsize; imageSize -= sectsize; } validateNandPartTbl(&nvramData); cferam_blk = nandUpdateImageSequenceNumber(imagePtr, imageSize); /* rootfs is the partition that the CFE RAM booted from. Write the * image to the other rootfs partition. */ if(rootfs == NP_ROOTFS_1 && nvramData.ulNandPartSizeKb[NP_ROOTFS_2]>0) offset = nvramData.ulNandPartOfsKb[NP_ROOTFS_2] * 1024; else offset = nvramData.ulNandPartOfsKb[NP_ROOTFS_1] * 1024; after_cferam = (cferam_blk + 1) * sectsize; cferam_overhead = overhead_blocks * sectsize; /* Erase block with cferam JFFS2 directory entry so if flashing this * image does not finish, the partition will not be valid. */ for( i = 0; i < (cferam_blk + 1 + overhead_blocks); i++ ) flash_sector_erase_int((offset / sectsize) + i); /* Flash image after cferam directory entry. */ printf("\nFlashing root file system at 0x%8.8lx: ", FLASH_BASE+offset); if((status = kerSysBcmImageSet(FLASH_BASE + offset + after_cferam + cferam_overhead, imagePtr + after_cferam, imageSize - after_cferam, 1)) != 0) { printf("Failed to flash whole image. Error: %d\n", status); return status; } /* Flash block(s) up to and including the block with cferam JFFS2 * directory entry. */ if((status = kerSysBcmImageSet(FLASH_BASE + offset, imagePtr, after_cferam, 0)) != 0) { printf("Failed to flash whole image. Error: %d\n", status); return status; } } else /* NOR FLASH */ { printf("\nFlashing root file system and kernel at 0x%8.8lx\n", FLASH_BASE+offset); if( (wfiTag.wfiVersion & WFI_ANY_VERS_MASK) == WFI_ANY_VERS && wfiTag.wfiFlashType != WFI_NOR_FLASH ) { printf("\nERROR: Image does not support a NOR flash device.\n\n"); return -1; } if((status = kerSysBcmImageSet(FLASH_BASE+offset, imagePtr, imageSize, 1)) != 0) { printf("Failed to flash whole image. Error: %d\n", status); return status; } } // Check if the new image has valid NVRAM // Also check if the new image still supports currently configured board ID if( (readNvramData(&tmpNvramData) != 0) || (BpSetBoardId(tmpNvramData.szBoardId) != BP_SUCCESS) || (BpSetVoiceBoardId(tmpNvramData.szVoiceBoardId) != BP_SUCCESS) ) { // Don't write NVRAM area if we are flashing tiny bridge image. // unlike cfe.w, the tiny bridge .w image will not have NVRAM_DATA_ID set if (*(unsigned long *) &tmpNvramData == NVRAM_DATA_ID) writeNvramData(&nvramData); } return status; } int processPrompt(PPARAMETER_SETTING promptPtr, int promptCt) { char tmpBuf[MAX_PROMPT_LEN]; int i = 0; int bChange = FALSE; printf("Press: to use current value\r\n"); printf(" '-' to go previous parameter\r\n"); printf(" '.' to clear the current value\r\n"); printf(" 'x' to exit this command\r\n"); memset(tmpBuf, 0, MAX_PROMPT_LEN); while (i < promptCt) { if( (promptPtr+i)->enabled == FALSE ) { if( tmpBuf[0] == '-' ) { if( i > 0 ) { i--; continue; } } else { i++; continue; } } if (strlen((promptPtr+i)->parameter) > 0) printf("%s %s ", (promptPtr+i)->promptName, (promptPtr+i)->parameter); else printf("%s %s", (promptPtr+i)->promptName, (promptPtr+i)->parameter); memset(tmpBuf, 0, MAX_PROMPT_LEN); console_readline ("", tmpBuf, (promptPtr+i)->maxValueLength + 1); switch (tmpBuf[0]) { case '-': // go back one parameter if (i > 0) i--; break; case 'x': // get out the b command if ((promptPtr+i)->func != 0) // validate function is supplied, do a check { if ((promptPtr+i)->func((promptPtr+i)->parameter)) { printf("\n%s; Try again!\n", (promptPtr+i)->errorPrompt); break; } } i = promptCt; break; case '.': // clear the current parameter and advance if ((promptPtr+i)->func != 0) // validate function is supplied, do a check { if ((promptPtr+i)->func("")) { printf("\n%s; Try again!\n", (promptPtr+i)->errorPrompt); break; } } memset((promptPtr+i)->parameter, 0, MAX_PROMPT_LEN); i++; bChange = TRUE; break; case 0: // no input; use default if it is OK if ((promptPtr+i)->func != 0) // validate function is supplied, do a check { if ((promptPtr+i)->func((promptPtr+i)->parameter)) { printf("\n%s; Try again!\n", (promptPtr+i)->errorPrompt); break; } } i++; break; default: // new parameter if ((promptPtr+i)->func != 0) // validate function is supplied, do a check { if ((promptPtr+i)->func(tmpBuf)) { printf("\n%s; Try again!\n", (promptPtr+i)->errorPrompt); break; } } memset((promptPtr+i)->parameter, 0, MAX_PROMPT_LEN); memcpy((promptPtr+i)->parameter, tmpBuf, strlen(tmpBuf)); i++; bChange = TRUE; } } return bChange; } // processPrompt // write the nvramData struct to nvram after CRC is calculated void writeNvramData(PNVRAM_DATA pNvramData) { UINT32 crc = CRC32_INIT_VALUE; pNvramData->ulCheckSum = 0; crc = getCrc32((unsigned char *)pNvramData, sizeof(NVRAM_DATA), crc); pNvramData->ulCheckSum = crc; kerSysNvRamSet((unsigned char *)pNvramData, sizeof(NVRAM_DATA), 0); } // read the nvramData struct from nvram // return -1: crc fail, 0 ok int readNvramData(PNVRAM_DATA pNvramData) { UINT32 crc = CRC32_INIT_VALUE, savedCrc; kerSysNvRamGet((unsigned char *)pNvramData, sizeof(NVRAM_DATA), 0); savedCrc = pNvramData->ulCheckSum; pNvramData->ulCheckSum = 0; crc = getCrc32((unsigned char *)pNvramData, sizeof(NVRAM_DATA), crc); if (savedCrc != crc) return -1; return 0; } static void convertBootInfo(void) { char *x; memset(&bootInfo, 0, sizeof(BOOT_INFO)); strcpy(bootInfo.boardIp, gBootParam[PARAM_IDX_BOARD_IPADDR].parameter); if ((x = strchr(bootInfo.boardIp, ':'))) // has mask { *x = '\0'; convertMaskStr((x+1), bootInfo.boardMask); } strcpy(bootInfo.hostIp, gBootParam[PARAM_IDX_HOST_IPADDR].parameter); if ((x = strchr(bootInfo.hostIp, ':'))) // ignore host mask *x = '\0'; strcpy(bootInfo.gatewayIp, gBootParam[PARAM_IDX_GW_IPADDR].parameter); if ((x = strchr(bootInfo.gatewayIp, ':'))) // ignore gw mask *x = '\0'; bootInfo.runFrom = gBootParam[PARAM_IDX_RUN_FROM].parameter[0]; strcpy(bootInfo.hostFileName, gBootParam[PARAM_IDX_RUN_FILENAME].parameter); strcpy(bootInfo.flashFileName, gBootParam[PARAM_IDX_FLASH_FILENAME].parameter); bootInfo.bootDelay = (int)(gBootParam[PARAM_IDX_BOOT_DELAY].parameter[0] - '0'); bootInfo.bootPartition = gBootParam[PARAM_IDX_BOOT_IMAGE].parameter[0]; } void getBootLine(void) { int i; char *curPtr; char *dPtr; NVRAM_DATA nvramData; readNvramData(&nvramData); if ((nvramData.szBootline[0] == (char)0xff) || (nvramData.szBootline[0] == (char)0)) { setDefaultBootline(); return; } curPtr = nvramData.szBootline; for (i = 0; (i < gNumBootParams) && (curPtr != 0); i++) { curPtr = strchr(curPtr, '='); if (curPtr) // found '=' and get the param. { dPtr = strchr(curPtr, ' '); // find param. deliminator ' ' memset(gBootParam[i].parameter, 0, MAX_PROMPT_LEN); memcpy(gBootParam[i].parameter, curPtr+1, dPtr-curPtr-1); // move to next param. curPtr = dPtr; } } // for loop if (i < gNumBootParams) { setDefaultBootline(); return; } convertBootInfo(); } // print the bootline and board parameter info and fill in the struct for later use // int printSysInfo(void) { int i; ETHERNET_MAC_INFO EnetInfos[BP_MAX_ENET_MACS]; // display the bootline info if( getTagFromPartition(1) == NULL || getTagFromPartition(2) == NULL ) gBootParam[PARAM_IDX_BOOT_IMAGE].enabled = FALSE; for (i = 0; i < gNumBootParams; i++) if( gBootParam[i].enabled ) printf("%s %s \n", gBootParam[i].promptName, gBootParam[i].parameter); // display the board param displayBoardParam(); if( BpGetEthernetMacInfo( EnetInfos, BP_MAX_ENET_MACS ) == BP_SUCCESS ) { // Here we should print whether EMAC1 or EMAC2 is selected } printf("\n"); return 0; } //************************************************************************** // Function Name: changeBootLine // Description : Use vxWorks bootrom style parameter input method: // Press to use default, '-' to go to previous parameter // Note: Parameter is set to current value in the menu. // Returns : None. //************************************************************************** int changeBootLine(void) { int i; char boardIpSaved[BOOT_IP_LEN]; NVRAM_DATA nvramData; readNvramData(&nvramData); strcpy(boardIpSaved, bootInfo.boardIp); if (processPrompt(gBootParam, gNumBootParams)) { char *blPtr = nvramData.szBootline; int paramLen; memset(blPtr, 0, NVRAM_BOOTLINE_LEN); for (i = 0; i < gNumBootParams; i++) { memcpy(blPtr, gBootParam[i].promptDefine, PROMPT_DEFINE_LEN); blPtr += PROMPT_DEFINE_LEN; paramLen = strlen(gBootParam[i].parameter); memcpy(blPtr, gBootParam[i].parameter, paramLen); blPtr += paramLen; if (!(gBootParam[i].parameter[0] == ' ')) { memcpy(blPtr, " ", 1); blPtr += 1; } } writeNvramData(&nvramData); } getBootLine(); // if board ip differs, do enet init if (strcmp(boardIpSaved, bootInfo.boardIp) != 0) enet_init(); return 0; } void setDefaultBootline(void) { char boardIpSaved[BOOT_IP_LEN]; NVRAM_DATA nvramData; readNvramData(&nvramData); strcpy(boardIpSaved, bootInfo.boardIp); memset(nvramData.szBootline, 0, NVRAM_BOOTLINE_LEN); strncpy(nvramData.szBootline, DEFAULT_BOOTLINE, strlen(DEFAULT_BOOTLINE)); printf("Use default boot line parameters: %s\n", DEFAULT_BOOTLINE); writeNvramData(&nvramData); getBootLine(); // if board ip differs, do enet init if (strcmp(boardIpSaved, bootInfo.boardIp) != 0) enet_init(); } //************************************************************************** // Function Name: changeAfeId // Description : Use vxWorks bootrom style parameter input method: // Press to use default, '-' to go to previous parameter // Note: Parameter is set to current value in the menu. // Returns : None. //************************************************************************** static void hex2Str(unsigned long num, char *str) { static const char hextable[16] = "0123456789ABCDEF"; unsigned long i, n; str[0] = '0'; str[1] = 'x'; if (0 == num) { str[2] = '0'; str[3] = 0; return; } str +=2; n = num >> 28; i = 0; while (0 == n) { num <<= 4; n = num >> 28; i++; } for (; i < 8; i++) { *str++ = hextable[num >> 28]; num <<= 4; } *str = 0; } int changeAfeId(void) { NVRAM_DATA nvramData; readNvramData(&nvramData); hex2Str(nvramData.afeId[0], gAfeId[0].parameter); hex2Str(nvramData.afeId[1], gAfeId[1].parameter); if (processPrompt(gAfeId, gAfeIdParams)) { nvramData.afeId[0] = lib_atoi(gAfeId[0].parameter); nvramData.afeId[1] = lib_atoi(gAfeId[1].parameter); writeNvramData(&nvramData); } return 0; }