diff options
Diffstat (limited to 'cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_util.c')
-rwxr-xr-x | cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_util.c | 1375 |
1 files changed, 1375 insertions, 0 deletions
diff --git a/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_util.c b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_util.c new file mode 100755 index 0000000..91e1ad0 --- /dev/null +++ b/cfe/cfe/arch/mips/board/bcm63xx_ram/src/bcm63xx_util.c @@ -0,0 +1,1375 @@ +/* ********************************************************************* + * 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: <enter> 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 <enter> 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 <enter> 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; +} |