/*********************************************************************** * <:copyright-BRCM:2007:DUAL/GPL:standard * * Copyright (c) 2007 Broadcom * All Rights Reserved * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed * to you under the terms of the GNU General Public License version 2 * (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php, * with the following added to such license: * * As a special exception, the copyright holders of this software give * you permission to link this software with independent modules, and * to copy and distribute the resulting executable under terms of your * choice, provided that you also meet, for each linked independent * module, the terms and conditions of the license of that module. * An independent module is a module which is not derived from this * software. The special exception does not apply to any modifications * of the software. * * Not withstanding the above, under no circumstances may you combine * this software in any way with any other Broadcom software provided * under a license other than the GPL, without Broadcom's express prior * written consent. * * :> ************************************************************************/ #include #include #include // types #include #include #include // for open #include #include #include #include // close #include "board.h" /* in bcmdrivers/opensource/include/bcm963xx, for BCM_IMAGE_CFE */ #include "bcm_boarddriverctl.h" #include "bcm_ulog.h" #include "sysutil_fs.h" #include "bcm_flashutil.h" #include "bcm_flashutil_private.h" #include "bcm_flashutil_nand.h" #include "bcm_flashutil_emmc.h" #include "bcm_flashutil_nor.h" #include "flash_api.h" #include #include "os_defs.h" #define IS_ERR_OR_NULL(x) ((x)==0) #define IS_ERR(x) ((x)<0) #define IS_NULL(x) ((x)==0) #define ERROR -1 #define SUCCESS 0 /* #define FLASHUTIL_DEBUG 1 */ #if defined(FLASHUTIL_DEBUG) #define flashutil_debug(fmt, arg...) \ fprintf(stderr, "%s.%u: " fmt "\n", __FUNCTION__, __LINE__, ##arg) #else #define flashutil_debug(fmt, arg...) #endif #define flashutil_print(fmt, arg...) \ fprintf(stderr, "%s.%u: " fmt "\n", __FUNCTION__, __LINE__, ##arg) #define flashutil_error(fmt, arg...) \ fprintf(stderr, "ERROR[%s.%u]: " fmt "\n", __FUNCTION__, __LINE__, ##arg) /* * gFlashInfo is the cached flash info variable. 0 means no value yet. * non-zero means we already got the value and don't need to run low level * functions anymore. */ static unsigned int gFlashInfo = 0; #ifndef DESKTOP_LINUX #define UPDATE_FLASH_INFO() if(gFlashInfo == 0) {getFlashInfo(&gFlashInfo);} #ifdef DISABLE_NOR_RAW_PARTITION static int disable_nor_raw_partition = 1; #else static int disable_nor_raw_partition = 0; #endif /* Prototypes */ static unsigned int pkgtb_getCrc32(const unsigned char *pdata, unsigned int size, unsigned int crc_initial); #endif /* DESKTOP_LINUX */ /** Main entry point for board ioctl actions. See comments in * bcm_boarddriverctl.h for detailed info about this function. */ BcmRet devCtl_boardIoctl(UINT32 boardIoctl, BOARD_IOCTL_ACTION action, char *string, SINT32 strLen, SINT32 offset, void *data) { #ifndef DESKTOP_LINUX BcmRet ret=BCMRET_SUCCESS; UPDATE_FLASH_INFO(); if( (((boardIoctl == BOARD_IOCTL_FLASH_READ || boardIoctl == BOARD_IOCTL_FLASH_WRITE) && ((action == SCRATCH_PAD) || (action == PERSISTENT) || (action == BACKUP_PSI) || (action == SYSLOG))) || (boardIoctl == BOARD_IOCTL_FLASH_LIST)) && ((gFlashInfo & FLASH_INFO_FLAG_NOR) == 0 || disable_nor_raw_partition == 1) ) { ret = devCtl_flashConfigAccess(boardIoctl, action, string, strLen, offset, data); return ret; } #endif return (devCtl_boardDriverIoctl(boardIoctl, action, string, strLen, offset, data)); } #ifndef DESKTOP_LINUX void composeConfigFileName(UINT32 boardIoctl, BOARD_IOCTL_ACTION action, const char *compName, char *fname, unsigned int len); BcmRet devCtl_flashConfigAccess(UINT32 boardIoctl, BOARD_IOCTL_ACTION action, char *string, SINT32 strLen, SINT32 offset, void *data) { BcmRet ret = BCMRET_SUCCESS; if( action == SCRATCH_PAD ) { switch(boardIoctl) { case BOARD_IOCTL_FLASH_LIST: ret = devCtl_scratchPadList(SCRATCH_PAD_FILE_NAME, data, offset); break; case BOARD_IOCTL_FLASH_READ: ret = devCtl_scratchPadGet(SCRATCH_PAD_FILE_NAME, string, data, offset); break; case BOARD_IOCTL_FLASH_WRITE: if( offset == -1 ) ret = devCtl_scratchPadClearAll(SCRATCH_PAD_FILE_NAME); else ret = devCtl_scratchPadSet(SCRATCH_PAD_FILE_NAME, string, data, offset); break; default: bcmuLog_error("unhandled BOARD_IOCTL code %d for scratch pad", boardIoctl); ret = BCMRET_INVALID_ARGUMENTS; break; } } else { char fname[MAX_PSI_FILE_NAME_LEN]={0}; switch(action) { case PERSISTENT: case BACKUP_PSI: composeConfigFileName(boardIoctl, action, (char *)data, fname, sizeof(fname)); break; case SYSLOG: snprintf(fname, sizeof(fname), "%s", SYSLOG_FILE_NAME); break; default: bcmuLog_error("unhandled action %d in BOARD_IOCTL code %d", action, boardIoctl); return BCMRET_INVALID_ARGUMENTS; } if ( boardIoctl == BOARD_IOCTL_FLASH_READ ) { bcmuLog_notice("reading from fname %s", fname); ret = devCtl_flashReadFile(fname, string, strLen); } else if( boardIoctl == BOARD_IOCTL_FLASH_WRITE ) { bcmuLog_notice("writing to fname %s (len=%d)", fname, strLen); ret = devCtl_flashWriteFile(fname, string, strLen); sync(); } else { bcmuLog_error("unhandled BOARD_IOCTL code %d", boardIoctl); ret = BCMRET_INVALID_ARGUMENTS; } } return ret; } void composeConfigFileName(UINT32 boardIoctl, BOARD_IOCTL_ACTION action, const char *compName, char *fname, unsigned int len) { // Distributed MDM config files has _compName. if (compName != NULL && compName[0] != '\0') { if (action == PERSISTENT) snprintf(fname, len, "%s_%s", PSI_FILE_NAME, compName); else snprintf(fname, len, "%s_%s", PSI_BACKUP_FILE_NAME, compName); } else { if (action == PERSISTENT) snprintf(fname, len, "%s", PSI_FILE_NAME); else snprintf(fname, len, "%s", PSI_BACKUP_FILE_NAME); } if (boardIoctl == BOARD_IOCTL_FLASH_WRITE) { // There is no fallback for write operation. Write it to which ever // file was specified. return; } if (sysUtil_isFilePresent(fname)) { return; } // Distributed MDM filename does not exist, fallback to monolithic name bcmuLog_notice("%s does not exist, fallback", fname); if (action == PERSISTENT) snprintf(fname, len, "%s", PSI_FILE_NAME); else snprintf(fname, len, "%s", PSI_BACKUP_FILE_NAME); return; } #endif /* DESKTOP_LINUX */ /** read the nvramData struct from the in-memory copy of nvram. * The caller is not required to have flashImageMutex when calling this * function. However, if the caller is doing a read-modify-write of * the nvram data, then the caller must hold flashImageMutex. This function * does not know what the caller is going to do with this data, so it * cannot assert flashImageMutex held or not when this function is called. * * @return pointer to NVRAM_DATA buffer which the caller must free * or NULL if there was an error */ int readNvramData(void *nvramData) { #ifndef DESKTOP_LINUX int ret = 0; UPDATE_FLASH_INFO(); switch( gFlashInfo ) { case FLASH_INFO_FLAG_NAND: ret = nandReadNvramData(nvramData); break; case FLASH_INFO_FLAG_EMMC: ret = emmcReadNvramData(nvramData); break; default: break; } return ret; #else flashutil_print("readNvramData(%p)", nvramData); return 1; #endif } int getFlashInfo(unsigned int *flags) { if (flags == NULL) { fprintf(stderr, "flags is NULL!"); return ERROR; } if (gFlashInfo != 0) { /* use cached result */ *flags = gFlashInfo; return SUCCESS; } return (getFlashInfoUncached(flags)); } int getFlashInfoUncached(unsigned int *flags) { if (flags == NULL) { fprintf(stderr, "flags is NULL!"); return ERROR; } else { *flags = 0; } #ifndef DESKTOP_LINUX { /* First try NAND, and if not NAND, see if it is EMMC. * TOOD: There seems to be a bug in libc where if you run several * popens back to back, libc loses track of the fp and the fgets hangs. * So in the emmc case, we would first run a popen in nandIsBootDevice, * and then immediately run another popen in emmcIsBootDevice, so * there might be a hang. If so, put a sleep(1) before the call to * emmcIsBootDevice(). */ if( nandIsBootDevice() ) { *flags = FLASH_INFO_FLAG_NAND; } else if( emmcIsBootDevice() ) { *flags = FLASH_INFO_FLAG_EMMC; } else { /* If not NAND and not EMMC, default to NOR */ *flags = FLASH_INFO_FLAG_NOR; } } #else *flags = FLASH_INFO_FLAG_NAND; #endif /* cache the result */ gFlashInfo = *flags; return SUCCESS; } int getFlashTotalSize(unsigned int *size) { unsigned int value = 0; BcmRet ret = BCMRET_SUCCESS; #ifdef DESKTOP_LINUX value = 512*1024*1024; // 512MB #else UPDATE_FLASH_INFO(); switch( gFlashInfo ) { case FLASH_INFO_FLAG_NAND: ret = get_mtd_master_size(&value); break; case FLASH_INFO_FLAG_EMMC: ret = emmcGetFlashSize(&value); break; case FLASH_INFO_FLAG_NOR: default: fprintf(stderr, "Not implemented yet.\n"); break; } #endif *size = value; return ret; } unsigned int get_flash_type(void) { unsigned int value = 0; devCtl_boardIoctl(BOARD_IOCTL_GET_FLASH_TYPE, 0, NULL, 0, 0, (void *)&value); return(value); } unsigned int otp_is_btrm_boot(void) { unsigned int value = 0; #ifndef DESKTOP_LINUX devCtl_boardIoctl(BOARD_IOCTL_GET_BTRM_BOOT, 0, NULL, 0, 0, (void *)&value); #endif return(value); } unsigned int otp_is_boot_secure(void) { unsigned int value = 0; #ifndef DESKTOP_LINUX devCtl_boardIoctl(BOARD_IOCTL_GET_BOOT_SECURE, 0, NULL, 0, 0, (void *)&value); #endif return(value); } /* Only gen3 bootroms and later support a manufacturing secure stage (ie 4908, 6858, etc) */ unsigned int otp_is_boot_mfg_secure(void) { unsigned int value = 0; #ifndef DESKTOP_LINUX devCtl_boardIoctl(BOARD_IOCTL_GET_BOOT_MFG_SECURE, 0, NULL, 0, 0, (void *)&value); #endif return(value); } unsigned int get_chip_id(void) { unsigned int chip_id = 0; #ifndef DESKTOP_LINUX devCtl_boardIoctl(BOARD_IOCTL_GET_CHIP_ID, 0, NULL, 0, 0, (void *)&chip_id); #endif return(chip_id); } #ifndef DESKTOP_LINUX unsigned int getset_boot_inactive_image(int flag) { unsigned int value = 0; devCtl_boardIoctl(BOARD_IOCTL_GETSET_BOOT_INACTIVE_IMAGE, 0, NULL, 0, flag, (void *)&value); return(value); } #else unsigned int getset_boot_inactive_image(int flag __attribute__((unused))) { return(0); } #endif int devCtl_getSequenceNumber(int image) { unsigned int flag=0; getFlashInfo(&flag); if (flag & (FLASH_INFO_FLAG_NAND | FLASH_INFO_FLAG_EMMC)) // NAND flash, no need to dig into kernel space return(getSequenceNumber(image)); else return( (int) devCtl_boardIoctl(BOARD_IOCTL_GET_SEQUENCE_NUMBER, 0, NULL, 0, image, NULL) ); } int getSequenceNumber(int imageNumber) { /* NAND Flash */ #ifndef DESKTOP_LINUX int seqNumber = -1; UPDATE_FLASH_INFO(); switch( gFlashInfo ) { case FLASH_INFO_FLAG_NAND: seqNumber = nandGetSequenceNumber(imageNumber); break; case FLASH_INFO_FLAG_EMMC: seqNumber = emmcGetSequenceNumber(imageNumber); break; case FLASH_INFO_FLAG_NOR: if( !isLegacyFlashLayout() ) { //FIXME: SPINOR flash only support single image. seqNumber = imageNumber; } break; default: break; } #else int seqNumber = imageNumber; #endif /* DESKTOP_LINUX */ return(seqNumber); } int getNextSequenceNumber( int seqNumImg1, int seqNumImg2 ) { int seq_num = -1; if( (seqNumImg1 == -1) && (seqNumImg2 == -1) ) seq_num = 999; else seq_num = seqNumImg1 > seqNumImg2 ? seqNumImg1+1:seqNumImg2+1; /* Handle wrap-around case */ if( seq_num > 999 ) seq_num = 0; /* Handle zero case */ if( (seq_num == seqNumImg1) || (seq_num == seqNumImg2) ) seq_num++; return seq_num; } //#define DUMP_VER_STR 1 int devCtl_getImageVersion(int partition, char *verStr, int verStrSize) { char tag[BUFLEN_256+1]={0}; int status, i; int start = -1; int strSize = -1; int end = -1; int keyLen = strlen("$imageversion"); memset(tag, 0x0, sizeof(tag)); status = bcmFlash_getIdent(partition, &start, &end, "imageversion", tag, sizeof(tag)-1); #ifdef DUMP_VER_STR printf("%s: Image version tag[%d]:\n", __FUNCTION__, status); for(i=0; i< BUFLEN_256+1; i++) { printf("%c", tag[i]); } printf("\n"); #endif if (status > keyLen) { for (i = keyLen; i<(BUFLEN_256+1) && i= verStrSize) ? verStrSize : (status - i); #ifdef DUMP_VER_STR printf("%s: offset:%d, size:%d \n",__FUNCTION__, i, strSize); #endif memcpy(verStr, &tag[i], strSize); status = strSize; } else { status = -1; fprintf(stderr, "\nImage version not found.\n"); } return(status); } uint64_t getSysfsBytes(char * pathname) { FILE *fp; char line[256]={0}; char *temp; uint64_t bytes = 0; if( access( pathname, F_OK ) == 0 ) { fp = fopen(pathname,"r"); if (fp == NULL) { printf("%s: Error! Could not open %s!\n", __FUNCTION__, pathname); } else { if ( fgets(line, sizeof(line), fp) ) bytes = strtoull(line, &temp, 10); else printf("%s: Error reading sysfs entry %s!\n", __FUNCTION__, pathname); fclose(fp); } } return bytes; } #ifdef DESKTOP_LINUX int devCtl_getImageState(void) { return( (int) devCtl_boardIoctl(BOARD_IOCTL_BOOT_IMAGE_OPERATION, 0, NULL, 0, BOOT_GET_BOOT_IMAGE_STATE, NULL) ); } int devCtl_getBootedImagePartition(void) { return( (int) devCtl_boardDriverIoctl(BOARD_IOCTL_BOOT_IMAGE_OPERATION, 0, NULL, 1, BOOT_GET_BOOTED_IMAGE_ID, NULL) ); } int getImageVersion(uint8_t *imagePtr __attribute__((unused)), int imageSize __attribute__((unused)), char *image_name, int image_name_len) { // See also bcm_boardctl/linux/board.c BOOT_GET_IMAGE_VERSION strncpy(image_name, "DESKTOPLINUX", image_name_len); return 0; } int setBootImageState(int newState) { /* this will go to the fake boardioctl handler */ return( (int) devCtl_boardIoctl(BOARD_IOCTL_BOOT_IMAGE_OPERATION, 0, NULL, 0, newState, NULL) ); } int devCtl_setImageState(int state) { /* this will go to the fake boardioctl handler */ return( (int) devCtl_boardIoctl(BOARD_IOCTL_BOOT_IMAGE_OPERATION, 0, NULL, 0, state, NULL) ); } int getBootImageState(void) { /* this will go to the fake boardioctl handler */ return( (int) devCtl_boardIoctl(BOARD_IOCTL_BOOT_IMAGE_OPERATION, 0, NULL, 0, BOOT_GET_BOOT_IMAGE_STATE, NULL) ); } int getBootedValue(void) { /* this will go to the fake boardioctl handler */ return( (int) devCtl_boardDriverIoctl(BOARD_IOCTL_BOOT_IMAGE_OPERATION, 0, NULL, 1, BOOT_GET_BOOTED_IMAGE_ID, NULL) ); } int verifyImageDDRType(uint32_t wfiFlags __attribute__((unused)), PNVRAM_DATA pNVRAM __attribute__((unused))) { return 0; } int getBootPartition( void ) { return 1; } int getUpgradePartition( void ) { return 1; } int commit( int partition __attribute__((unused)), char *string __attribute__((unused))) { return 0; } int bcmFlash_getIdent(int part __attribute__((unused)), int *start __attribute__((unused)), int *end __attribute__((unused)), const char * key __attribute__((unused)), char * line __attribute__((unused)), int len __attribute__((unused))) { return 0; } int isLegacyFlashLayout(void) { return -1; } int setImgSeqNum( int img_idx __attribute__((unused)), int seq __attribute__((unused))) { return 0; } int getImgSeqNum( int img_idx __attribute__((unused)), int * seq __attribute__((unused))) { return 0; } #else /* end of DESKTOP_LINUX, start of real system code */ int verifyImageDDRType(uint32_t wfiFlags, PNVRAM_DATA pNVRAM) { #if defined(DDR_TYPE_CHECK) uint32_t brdtype, imgtype; int rc = -1; char* brdstr, *imgstr; if( pNVRAM ) { brdtype = pNVRAM->ulMemoryConfig&BP_DDR_TYPE_MASK; imgtype = wfiFlags&WFI_FLAG_DDR_TYPE_MASK; brdstr = (brdtype == BP_DDR_TYPE_DDR3) ? "DDR3" : "DDR4"; if( imgtype == WFI_FLAG_DDR_TYPE_NONE ) { fprintf(stderr, "\nImage ddr type not set. Probably an old image that does not support DDR type flag.\n"); fprintf(stderr, "If you are sure the image has same DDR type as the board DDR type %s, use CFE and force command to update.\n", brdstr); rc = -1; } else { imgstr = (imgtype == WFI_FLAG_DDR_TYPE_DDR3) ? "DDR3" : "DDR4"; if( imgstr[3] != brdstr[3] ) { fprintf(stderr, "\nMismatch image ddr type %s board ddr type %s, flash aborted!!!\n", imgstr, brdstr); rc = -1; } else rc = 0; } } return rc; #else return 0; #endif /* DDR_TYPE_CHECK */ } uint64_t getAvailImgSpace(int update_img_idx) { UPDATE_FLASH_INFO(); switch( gFlashInfo ) { case FLASH_INFO_FLAG_NAND: return(nandGetAvailImgSpace(update_img_idx)); break; case FLASH_INFO_FLAG_EMMC: return(emmcGetAvailImgSpace(update_img_idx)); break; case FLASH_INFO_FLAG_NOR: if( !isLegacyFlashLayout()) { //FIXME return whole flash size. return(spinorGetAvailSpace(SPI_NOR_MTD)); } break; default: break; } return 0; } uint64_t getAvailLoaderSpace(int update_img_idx) { UPDATE_FLASH_INFO(); switch( gFlashInfo ) { case FLASH_INFO_FLAG_NAND: return(nandGetAvailLoaderSpace()); break; case FLASH_INFO_FLAG_EMMC: //FIXME: Pass image index to emmc return(emmcGetAvailLoaderSpace()); break; case FLASH_INFO_FLAG_NOR: return( spinorGetAvailSpace(SPI_NOR_LOADER_MTD)); break; default: break; } return 0; } int synchLoaderEnv( char * loader_fname ) { char * in_mem_env = NULL; FILE* file_ptr; char * ptr = NULL; int tmp_buf_len = 255; char buffer[tmp_buf_len]; uint64_t env_size; char * retstr = NULL; int ret = -1; uint32_t env_magic = 0; int bytes; int written_bytes=0; UBOOT_ENV_HDR * env_hdr = NULL; char * boot_magic_ptr; int len; int i; /* Get env size */ file_ptr = fopen(PROC_BOOT_MAGIC, "r"); if( !file_ptr ) { printf("%s: Error, cannot open %s\n", __FUNCTION__, PROC_BOOT_MAGIC); ret = -1; goto exit_loader_synch; } retstr = fgets((char*)buffer, tmp_buf_len, file_ptr); if( retstr ) { env_size = strtoul(buffer,&ptr, 10); } else { printf("%s: Error, Read failed from %s\n", __FUNCTION__, PROC_BOOT_MAGIC); ret = -1; goto exit_loader_synch; } fclose(file_ptr); /* Delete env_boot_magic in flash so that it is updated by bootloader on next boot */ if(system("echo 'env_boot_magic=' > /proc/nvram/set")) { printf("%s: Error, Could not clear 'env_boot_magic' env variable\n", __FUNCTION__); ret = -1; goto exit_loader_synch; } sync(); /* Open and read the temp environment into memory */ in_mem_env = malloc( env_size + sizeof(UBOOT_ENV_HDR)); if( !in_mem_env ) { printf("%s: Error, failed to allocate memory for env!\n", __FUNCTION__); ret = -1; goto exit_loader_synch; } file_ptr = fopen(PROC_ENV_RAW, "r"); if( !file_ptr ) { printf("%s: Error, cannot open %s\n", __FUNCTION__, PROC_ENV_RAW); ret = -1; goto exit_loader_synch; } bytes = fread(in_mem_env, 1, env_size + sizeof(UBOOT_ENV_HDR), file_ptr); if( !bytes ) { printf("%s: Error, Read failed from %s\n", __FUNCTION__, PROC_ENV_RAW); ret = -1; goto exit_loader_synch; } fclose(file_ptr); /* Clear bootmagic in in_memory_copy of env if not already cleared * This captures those cases where customers disable /proc/nvram/set */ for( i=sizeof(UBOOT_ENV_HDR); imagic = UBOOT_ENV_MAGIC; env_hdr->size = (uint32_t)env_size; env_hdr->crc = pkgtb_getCrc32((unsigned char*)(in_mem_env + sizeof(UBOOT_ENV_HDR)), env_size-4, 0); /* Find environment in loader, overwrite it with current environment */ file_ptr = fopen(loader_fname, "r+"); if( !file_ptr ) { printf("%s: Error, cannot open %s\n", __FUNCTION__, loader_fname); ret = -1; goto exit_loader_synch; } while( fread((char*)&env_magic, 4, 1, file_ptr) ) { fseek( file_ptr, -4, SEEK_CUR ); if( env_magic == UBOOT_ENV_MAGIC ) { printf("Found MAGIC at 0x%08x\n", (unsigned int)ftell(file_ptr)); ret = fwrite( in_mem_env, 1, env_size, file_ptr); if( !ret ) { printf("%s: Error, Write failed to %s\n", __FUNCTION__, loader_fname); ret = -1; goto exit_loader_synch; } written_bytes+=env_size; } else { fseek( file_ptr, BOOT_MAGIC_OFFS, SEEK_CUR ); } } if( !written_bytes ) { printf("%s: Error loader environment not synched to current env!\n", __FUNCTION__); ret = -1; } else ret = 0; exit_loader_synch: if( in_mem_env ) free(in_mem_env); if( file_ptr ) fclose(file_ptr); return ret; } int getImageVersion(uint8_t *imagePtr, int imageSize, char *image_name, int image_name_len) { int ret = -1; UPDATE_FLASH_INFO(); switch( gFlashInfo ) { case FLASH_INFO_FLAG_NAND: ret = nandGetImageVersion(imagePtr, imageSize, image_name, image_name_len); break; case FLASH_INFO_FLAG_EMMC: ret = emmcGetImageVersion(imagePtr, imageSize, image_name, image_name_len); break; default: break; } return ret; } /*********************************************************************** * Function Name: bcmFlash_getIdent * Description : Get the ident value * part : Partition to search, 1 for first, 2 for second, 3 for boot, 4 for non-boot * key : ident key value, leave blank to return all ident values * buf : buffer to return ident values * len : length of passed buffer * start : starting block to search, -1 means from beginning or partition, returns block where tag was found * end : ending block to search, -1 means end of partition * Returns : return size on success (0 if nothing found), -1 on failure ***********************************************************************/ #define TRAILER 2 int bcmFlash_getIdent(int part, int *start, int *end, const char *key, char *line, int len) { int ret = 0; // total size of all entries int boot = getBootPartition(); char name[MAX_MTD_NAME_SIZE]; char *buf; FILE *fp; int point, read; int size; // size of entry int blksize; UPDATE_FLASH_INFO(); if ( (gFlashInfo == FLASH_INFO_FLAG_NAND) || ( gFlashInfo == FLASH_INFO_FLAG_NOR) ) { int mtd_fd; mtd_info_t *mtd; //FIXME should spinor flash return 0? if( gFlashInfo == FLASH_INFO_FLAG_NOR) mtd = get_mtd_device_handle(SPI_NOR_BOOTFS_MTD_NAME, &mtd_fd, 0); else mtd = get_mtd_device_handle("image", &mtd_fd, 0); if (!mtd) { fprintf(stderr, "ERROR!!! Could not get image device handle\n"); put_mtd_device(mtd, mtd_fd, -1); return(-1); } blksize = mtd->erasesize; put_mtd_device(mtd, mtd_fd, -1); if (!blksize) { fprintf(stderr, "ERROR!!! Could not find block size\n"); return(-1); } } else if (gFlashInfo == FLASH_INFO_FLAG_EMMC) { blksize = 0x20000; // match NAND minimum block size } else return(-1); if (gFlashInfo == FLASH_INFO_FLAG_NAND) { if( isLegacyFlashLayout() ) { if ( (part == boot) || (part == 3) ) ret = get_mtd_device_name("image", name); else ret = get_mtd_device_name("image_update", name); if (ret < 0) return(-1); } else { if ( (part == 1) || ((part == 3) && (boot == 1)) || ((part == 4) && (boot == 2)) ) ret = get_mtd_device_name("bootfs1", name); else ret = get_mtd_device_name("bootfs2", name); if (ret < 0) return(-1); } } else if (gFlashInfo == FLASH_INFO_FLAG_EMMC) { if ( (part == 1) || ((part == 3) && (boot == 1)) || ((part == 4) && (boot == 2)) ) strcpy(name, "/dev/bootfs1"); else strcpy(name, "/dev/bootfs2"); } else if (gFlashInfo == FLASH_INFO_FLAG_NOR) { //FIXME...NOR flash support single image if( (part == 1) || (part == 3)) ret = get_mtd_device_name(SPI_NOR_BOOTFS_MTD_NAME, name); else return(-1); if (ret < 0) return(-1); } else return(-1); fp = fopen(name,"rb"); if (fp == NULL) { fprintf(stderr, "ERROR!!! Could not open device %s\n", name); return (-1); } if ( (buf = malloc(blksize)) == 0) { fprintf(stderr, "ERROR!!! Could not allocate memory for block buffer\n"); fclose(fp); return(-1); } if (key) snprintf(name, MAX_MTD_NAME_SIZE, "$%s", key); else strcpy(name, "$"); if (*start >= 0) fseek(fp, blksize * *start, SEEK_SET); else *start = 0; ret = 0; while ( ((*end < 0) || (*start <= *end)) && ((read = fread(buf, 1, blksize, fp)) != 0) ) { for(point = 0; (point < (read - (strlen(name) + TRAILER))); point++) { // search block for version string if (!memcmp(buf + point, name, strlen(name))) { size = strlen(name); // check for valid tag while ( ((point + size) < (read - TRAILER)) && ( ( (*(buf + point + size) >= 'A') && (*(buf + point + size) <= 'Z') ) || ( (*(buf + point + size) >= 'a') && (*(buf + point + size) <= 'z') ) ) ) { size++; } if ( ( point+size < (read - TRAILER) ) && (*(buf + point + size) != ':') ) continue; while ( ((point + size) < (read - TRAILER)) && (*(buf + point + size) >= ' ') && (*(buf + point + size) <= '~') ) { // continue search for valid entry if (!memcmp(buf + point + size, " $", TRAILER)) { // found terminator and thus entry size += TRAILER; if (size <= len) { //memcpy(&line[ret], buf + point, size); snprintf(&line[ret], len, "%.*s", size, buf + point); len -= size; } ret += size; if (key) goto DONE; point += size; break; } size++; } } } (*start)++; } DONE: fclose(fp); free(buf); return( ret ); } /*********************************************************************** * Function Name: getBootPartition * Description : Returns the booted partition. * Returns : boot partition or -1 for failure ***********************************************************************/ #include #include "util.c" int getBootPartition( void ) { int ret = -1; char *blob; int len; int *value = 0; int offset; blob = utilfdt_read("/sys/firmware/fdt", NULL); if (blob) { if ( (offset = fdt_path_offset(blob, "/chosen")) >= 0 ) { if ( (value = (int *)fdt_getprop(blob, offset, "active_image", &len)) ) { if ( (ret = fdt32_to_cpu(*(fdt32_t *)value)) && (ret > 0) && (ret < 3) ) return(ret); } } } UPDATE_FLASH_INFO(); switch( gFlashInfo ) { case FLASH_INFO_FLAG_NAND: ret = nandGetBootPartition(); break; case FLASH_INFO_FLAG_EMMC: ret = emmcGetBootPartition(); break; case FLASH_INFO_FLAG_NOR: //FIXME spi nor flash only support single image. ret = 1; break; default: break; } return ret; } /*********************************************************************** * Function Name: getUpgradePartition * Description : Returns the upgrade partition. * Returns : upgrade partition ***********************************************************************/ int getUpgradePartition( void ) { int part = getBootPartition(); UPDATE_FLASH_INFO(); if( (gFlashInfo != FLASH_INFO_FLAG_NOR) && (part != -1) ) part = ((part==1)?2:1); return part; } static unsigned int pkgtb_getCrc32(const unsigned char *pdata, unsigned int size, unsigned int crc_initial) { unsigned int crc_final = genUtl_getCrc32(pdata, size, crc_initial ^ 0xffffffff) ^ 0xffffffff; return crc_final; } static int validate_metadata(MDATA *mdatap, int * committed, int *valid, int *seq) { int valid_img_idx[2] = {0}; int committed_idx = 0; int seq_img_idx[2] = {-1}; uint32_t crc; int ret = 0; int i; char * commitp = mdatap->mdata_obj.data; char * validp = commitp + strlen(commitp) + 1; char * seqp = validp + strlen(validp) + 1; crc = pkgtb_getCrc32((unsigned char*)mdatap->mdata_obj.data, (mdatap->size - 4) & 0xffff, 0); if( crc == mdatap->mdata_obj.crc ) { sscanf(commitp,"COMMITTED=%d", &committed_idx); sscanf(validp,"VALID=%d,%d", &valid_img_idx[0], &valid_img_idx[1]); //FIXME: Magic numbers for( i=0; i<2; i++ ) { if( valid_img_idx[i] ) valid[valid_img_idx[i]-1] = valid_img_idx[i]; } *committed = committed_idx; // preset the sequence numbers incase the field doesn't exist if ((*committed == 1) && valid[0]) { seq[0] = 1; if (valid[1]) seq[1] = 0; } else if ((*committed == 2) && valid[1]) { seq[1] = 1; if (valid[0]) seq[0] = 0; } sscanf(seqp,"SEQ=%d,%d", &seq_img_idx[0], &seq_img_idx[1]); for( i=0; i<2; i++ ) { if( seq_img_idx[i] != -1) seq[i] = seq_img_idx[i]; } printf("rd_metadata: committed %d valid %d,%d seq %d,%d\n", *committed, valid[0], valid[1], seq[0], seq[1]); } else { printf("ERROR: metadata crc failed! exp: 0x%08x calc: 0x%08x\n", mdatap->mdata_obj.crc, crc); *committed = 0; valid[0] = 0; valid[1] = 0; ret = -1; } return ret; } static int set_metadata_val( int * committed, int * valid, int * seq ) { MDATA * mdatap; uint32_t crc; int i, mdata_idx; int ret = -1; UPDATE_FLASH_INFO(); mdatap = (MDATA *)malloc(PKGTB_METADATA_RDWR_SIZE); mdatap->word0 = PKGTB_METADATA_SIZE; mdatap->size = PKGTB_METADATA_SIZE; i = sprintf((char*)mdatap->mdata_obj.data, "COMMITTED=%d",*committed) + 1; i = i + sprintf((char*)&mdatap->mdata_obj.data[i], "VALID=%d,%d",valid[0],valid[1]) + 1; i = i + sprintf((char*)&mdatap->mdata_obj.data[i], "SEQ=%d,%d",seq[0],seq[1]) + 1; mdatap->mdata_obj.data[i] = '\0'; crc = pkgtb_getCrc32((unsigned char*)mdatap->mdata_obj.data, (mdatap->size - 4) & 0xffff, 0); memcpy(&mdatap->mdata_obj.crc, &crc, sizeof(crc)); printf("wr_metadata: committed %d valid %d,%d seq %d,%d\n", *committed, valid[0], valid[1], seq[0], seq[1]); //FIXME: Magic numbers for( mdata_idx=1; mdata_idx<=2; mdata_idx++ ) { switch( gFlashInfo ) { case FLASH_INFO_FLAG_NAND: ret = setNandMetadata((char*)mdatap, PKGTB_METADATA_RDWR_SIZE, mdata_idx); break; case FLASH_INFO_FLAG_EMMC: ret = setEmmcMetadata((char*)mdatap, PKGTB_METADATA_RDWR_SIZE, mdata_idx); break; case FLASH_INFO_FLAG_NOR: //FIXME nor not support metadata ret = 0; break; default: break; } } free(mdatap); return ret; } static int get_metadata_val( int * committed, int * valid, int * seq) { MDATA * mdatap = (MDATA *)malloc(PKGTB_METADATA_MAX_SIZE); int ret = -1; int num_bytes_read = 0; int mdata_idx; UPDATE_FLASH_INFO(); //FIXME: Magic numbers for( mdata_idx=1; (mdata_idx<=2) && (ret < 0); mdata_idx++ ) { switch( gFlashInfo ) { case FLASH_INFO_FLAG_NAND: num_bytes_read = getNandMetadata( (char*)mdatap, PKGTB_METADATA_RDWR_SIZE, mdata_idx); break; case FLASH_INFO_FLAG_EMMC: num_bytes_read = getEmmcMetadata( (char*)mdatap, PKGTB_METADATA_RDWR_SIZE, mdata_idx); break; case FLASH_INFO_FLAG_NOR: //FIXME SPI NOR not support free(mdatap); return ret; break; default: break; } if( num_bytes_read >= PKGTB_METADATA_SIZE ) ret = validate_metadata(mdatap, committed, valid, seq); else fprintf(stderr, "ERROR!!! unable to retrieve metadata%d!", mdata_idx); } free(mdatap); if( ret ) fprintf(stderr, "ERROR!!! unable to retrieve/parse metadata!"); return ret; } static int getImgCommitStatus( int img_idx, char * commit_flag ) { int committed_img = 0; //FIXME: Magic numbers int valid_imgs[2] = {0}; int seq_imgs[2] = {-1}; int ret = get_metadata_val(&committed_img, valid_imgs, seq_imgs); if (ret) return(ret); if( committed_img == img_idx ) *commit_flag = '1'; else *commit_flag = '0'; return 0; } static int setImgCommitStatus( int img_idx , char * commit_flag) { int committed_img = 0; //FIXME: Magic numbers int valid_imgs[2] = {0}; int seq_imgs[2] = {-1}; int ret = get_metadata_val(&committed_img, valid_imgs, seq_imgs); if (ret) return(ret); if( *commit_flag == '1' ) { valid_imgs[img_idx-1] = img_idx; committed_img = img_idx; } else { if( committed_img == img_idx ) committed_img = 0; } set_metadata_val(&committed_img, valid_imgs, seq_imgs); return 0; } int setImgValidStatus( int img_idx, int * valid) { int committed_img = 0; //FIXME: Magic numbers int valid_imgs[2] = {0}; int seq_imgs[2] = {-1}; int ret = get_metadata_val(&committed_img, valid_imgs, seq_imgs); if (ret) return(ret); if( *valid ) valid_imgs[img_idx-1] = img_idx; else valid_imgs[img_idx-1] = 0; set_metadata_val(&committed_img, valid_imgs, seq_imgs); return 0; } int getImgValidStatus( int img_idx, int * valid) { int committed_img = 0; //FIXME: Magic numbers int valid_imgs[2] = {0}; int seq_imgs[2] = {-1}; int ret = get_metadata_val(&committed_img, valid_imgs, seq_imgs); if (ret) return(ret); if( valid_imgs[img_idx-1] == img_idx ) *valid = 1; else *valid = 0; return 0; } int setImgSeqNum( int img_idx, int seq) { int committed_img = 0; //FIXME: Magic numbers int valid_imgs[2] = {0}; int seq_imgs[2] = {-1}; int ret = get_metadata_val(&committed_img, valid_imgs, seq_imgs); if (ret) return(ret); if( valid_imgs[img_idx-1] ) seq_imgs[img_idx-1] = seq; set_metadata_val(&committed_img, valid_imgs, seq_imgs); return 0; } int getImgSeqNum( int img_idx, int * seq) { int committed_img = 0; //FIXME: Magic numbers int valid_imgs[2] = {0}; int seq_imgs[2] = {-1}; int ret = get_metadata_val(&committed_img, valid_imgs, seq_imgs); if (ret) return(ret); *seq = seq_imgs[img_idx-1]; return 0; } /*********************************************************************** * Function Name: commit * Description : Gets/sets the commit flag for an image. * Returns : 0 for success or -1 for failure ***********************************************************************/ int commit( int partition, char *string ) { int ret = -1; UPDATE_FLASH_INFO(); if( isLegacyFlashLayout()) { switch( gFlashInfo ) { case FLASH_INFO_FLAG_NAND: ret = nandCommit(partition, string); break; case FLASH_INFO_FLAG_EMMC: ret = emmcCommit(partition, string); break; default: break; } } else { int write = (*string != 0); /* New flash layout */ flashutil_debug("%s: Write:%d, part:%d\n", __FUNCTION__, write, partition); if( write ) ret = setImgCommitStatus(partition, string); else ret = getImgCommitStatus(partition, string); } return ret; } /*********************************************************************** * devCtl_setImageState - for all flash types (safer to call this) * setBootImageState - for NAND or EMMC flash only * Description : Persistently sets the state of an image update. * Returns : 0 - success, -1 - failure ***********************************************************************/ int devCtl_setImageState(int state) { unsigned int flag=0; getFlashInfo(&flag); if (flag & (FLASH_INFO_FLAG_NAND | FLASH_INFO_FLAG_EMMC)) // NAND flash, no need to dig into kernel space return(setBootImageState(state)); else { if( norIsNewFlashLayout()) return 0; return( (int) devCtl_boardIoctl(BOARD_IOCTL_BOOT_IMAGE_OPERATION, 0, NULL, 0, state, NULL) ); } } int getBootReason(void) { char buffer[64]; int rc; FILE *fp; if (!(fp = fopen("/proc/bootstate/reset_reason", "r"))) { printf("%s: Error, cannot open %s\n", __FUNCTION__, "/proc/bootstate/reset_reason"); return(-1); } if (!fgets((char*)buffer, 64, fp)) { fclose(fp); printf("%s: Error, Read failed from %s\n", __FUNCTION__, "/proc/bootstate/reset_reason"); return(-1); } fclose(fp); rc = strtoul(buffer, NULL, 16); return(rc); } int setBootReason( int reason ) { char command[64]; int rc; snprintf(command, sizeof command, "echo 0x%x > /proc/bootstate/reset_reason", reason); rc = system(command); return(rc); } int setBootImageState( int newState ) { int ret = -1; int currState; int seq1 = -1; int seq2 = -1; char commitflag1 = 0; char commitflag2 = 0; int pureubi1; int pureubi2; /* Get current boot state variables */ currState = getBootImageState(); seq1 = getSequenceNumber(1); seq2 = getSequenceNumber(2); pureubi1 = commit(1, &commitflag1); pureubi2 = commit(2, &commitflag2); #ifdef NO_AUTOCOMMIT_IMAGE if (newState == BOOT_SET_NEW_IMAGE) { FILE *fp; fp = fopen("/data/commit_image_after_reboot","w"); if (!IS_NULL(fp)) { fclose(fp); printf("Not committing image now but will do so after successful reboot to Linux\n"); newState = BOOT_SET_NEW_IMAGE_ONCE; } else printf("ERROR!!! Could not create data file, committing image now\n"); } #endif if ((seq1 == 0) && (seq2 == 999)) seq1 = 1000; if ((seq2 == 0) && (seq1 == 999)) seq2 = 1000; switch(newState) { // convert state to OMCI states case BOOT_SET_NEW_IMAGE: if( seq1 > seq2 ) newState = BOOT_SET_PART1_IMAGE; else newState = BOOT_SET_PART2_IMAGE; break; case BOOT_SET_OLD_IMAGE: if( seq2 > seq1 ) newState = BOOT_SET_PART1_IMAGE; else newState = BOOT_SET_PART2_IMAGE; break; case BOOT_SET_NEW_IMAGE_ONCE: if( seq1 > seq2 ) newState = BOOT_SET_PART1_IMAGE_ONCE; else newState = BOOT_SET_PART2_IMAGE_ONCE; break; case BOOT_SET_OLD_IMAGE_ONCE: if( seq2 > seq1 ) newState = BOOT_SET_PART1_IMAGE_ONCE; else newState = BOOT_SET_PART2_IMAGE_ONCE; break; default: break; } if( currState == newState ) return(0); if (isLegacyFlashLayout() && !pureubi1 && !pureubi2) { // two pureUBI images switch(newState) { case BOOT_SET_PART1_IMAGE: case BOOT_SET_PART2_IMAGE_ONCE: commit(1, "1"); if (seq2 > seq1) commit(2, "0"); break; case BOOT_SET_PART2_IMAGE: case BOOT_SET_PART1_IMAGE_ONCE: commit(2, "1"); if (seq1 > seq2) commit(1, "0"); break; default: break; } if ( (newState == BOOT_SET_PART1_IMAGE_ONCE) || (newState == BOOT_SET_PART2_IMAGE_ONCE) ) { // set bit to boot the inactive image getset_boot_inactive_image(1); } } if (!isLegacyFlashLayout()) { int valid1; int valid2; getImgValidStatus(1, &valid1); getImgValidStatus(2, &valid2); switch(newState) { // new layout works differently, there's only a single commit value so committing one image automatically uncommits the other case BOOT_SET_PART1_IMAGE: case BOOT_SET_PART2_IMAGE_ONCE: if ((commitflag1 != '1') && valid1) commit(1, "1"); break; case BOOT_SET_PART2_IMAGE: case BOOT_SET_PART1_IMAGE_ONCE: if ((commitflag2 != '1') && valid2) commit(2, "1"); break; default: break; } if (valid1 && valid2 && ((newState == BOOT_SET_PART1_IMAGE_ONCE) || (newState == BOOT_SET_PART2_IMAGE_ONCE)) ) { // set bit to boot the inactive image setBootReason(BCM_BOOT_REASON_ACTIVATE); } else setBootReason(0); } { /* NAND flash, old method of boot_state */ FILE *fp; char state_name[] = "/data/" NAND_BOOT_STATE_FILE_NAME; /* Update the image state persistently using "new image" and "old image" * states. Convert "partition" states to "new image" state for * compatibility with the non-OMCI image update. */ switch(newState) { // convert OMCI state to internal state case BOOT_SET_PART1_IMAGE: if( seq1 > seq2 ) newState = BOOT_SET_NEW_IMAGE; else newState = BOOT_SET_OLD_IMAGE; break; case BOOT_SET_PART2_IMAGE: if( seq2 > seq1 ) newState = BOOT_SET_NEW_IMAGE; else newState = BOOT_SET_OLD_IMAGE; break; case BOOT_SET_PART1_IMAGE_ONCE: if( seq1 > seq2 ) newState = BOOT_SET_NEW_IMAGE_ONCE; else newState = BOOT_SET_OLD_IMAGE_ONCE; break; case BOOT_SET_PART2_IMAGE_ONCE: if( seq2 > seq1 ) newState = BOOT_SET_NEW_IMAGE_ONCE; else newState = BOOT_SET_OLD_IMAGE_ONCE; break; default: break; } /* Remove old file: * This must happen before a new file is created so that the new file- * name will have a higher version in the FS, this is also the reason * why renaming might not work well (higher version might exist as * deleted in FS) However this discrimination should be fixed now in CFE */ { int rc; char command[64]; state_name[strlen(state_name) - 1] = '*'; snprintf(command, sizeof command, "rm %s >/dev/null 2>&1", state_name); // suppress command output in case no files were found to delete rc = system(command); if (rc < 0) { fprintf(stderr, "rm command failed.\n"); } } /* Create new state file name. */ state_name[strlen(state_name) - 1] = newState; fp = fopen(state_name,"w"); if (!IS_NULL(fp)) { fwrite(state_name, strlen(state_name), 1, fp); fclose(fp); } else printf("Unable to open '%s'.\n", state_name); ret = 0; } return( ret ); } /*********************************************************************** * devCtl_getImageState - for all flash types (safer to call this) * getBootImageState - for NAND or EMMC flash only * Description : Gets the state of an image update from flash. * Returns : state constant or -1 for failure ***********************************************************************/ int devCtl_getImageState(void) { unsigned int flag=0; getFlashInfo(&flag); if (flag & (FLASH_INFO_FLAG_NAND | FLASH_INFO_FLAG_EMMC)) return(getBootImageState()); else return( (int) devCtl_boardIoctl(BOARD_IOCTL_BOOT_IMAGE_OPERATION, 0, NULL, 0, BOOT_GET_BOOT_IMAGE_STATE, NULL) ); } int getBootImageState(void) { int seq1 = -1; int seq2 = -1; char commitflag1 = 0; char commitflag2 = 0; int ret = (getBootPartition() == 1) ? BOOT_SET_PART1_IMAGE : BOOT_SET_PART2_IMAGE; int pureubi1 = commit(1, &commitflag1); int pureubi2 = commit(2, &commitflag2); seq1 = getSequenceNumber(1); seq2 = getSequenceNumber(2); if ((seq1 == 0) && (seq2 == 999)) seq1 = 1000; if ((seq2 == 0) && (seq1 == 999)) seq2 = 1000; /* Handle new flash layout */ if( !isLegacyFlashLayout() ) { if (commitflag1 == '1') { if (getBootReason() == BCM_BOOT_REASON_ACTIVATE) ret = BOOT_SET_PART2_IMAGE_ONCE; else ret = BOOT_SET_PART1_IMAGE; } else if (commitflag2 == '1') { if (getBootReason() == BCM_BOOT_REASON_ACTIVATE) ret = BOOT_SET_PART1_IMAGE_ONCE; else ret = BOOT_SET_PART2_IMAGE; } return ret; } if (!pureubi1 && !pureubi2) { // two pureUBI images, boot state undefined if neither flag is 1 if (seq1 > seq2) { if (commitflag1 == '1') ret = BOOT_SET_PART1_IMAGE; else if (commitflag2 == '1') ret = BOOT_SET_PART2_IMAGE; } else { if (commitflag2 == '1') ret = BOOT_SET_PART2_IMAGE; else if (commitflag1 == '1') ret = BOOT_SET_PART1_IMAGE; } if (getset_boot_inactive_image(-1) == 1) { if (ret == BOOT_SET_PART1_IMAGE) ret = BOOT_SET_PART2_IMAGE_ONCE; if (ret == BOOT_SET_PART2_IMAGE) ret = BOOT_SET_PART1_IMAGE_ONCE; } } else if ((seq1 != -1) && (seq2 != -1)) { // two images and at least one JFFS2 image, boot state is in data partition /* NAND flash */ char states[] = {BOOT_SET_NEW_IMAGE, BOOT_SET_OLD_IMAGE, BOOT_SET_NEW_IMAGE_ONCE, BOOT_SET_OLD_IMAGE_ONCE}; char boot_state_name[] = "/data/" NAND_BOOT_STATE_FILE_NAME; int i; /* The boot state is stored as the last character of a file name on * the data partition, /data/boot_state_X, where X is * BOOT_SET_NEW_IMAGE, BOOT_SET_OLD_IMAGE, BOOT_SET_NEW_IMAGE_ONCE. */ for( i = 0; i < (int)sizeof(states); i++ ) { FILE *fp; boot_state_name[strlen(boot_state_name) - 1] = states[i]; fp = fopen(boot_state_name,"r"); if (fp != NULL) { fclose(fp); ret = (int) states[i]; break; } } switch(ret) { // convert state to OMCI states case BOOT_SET_NEW_IMAGE: if( seq1 > seq2 ) ret = BOOT_SET_PART1_IMAGE; else ret = BOOT_SET_PART2_IMAGE; break; case BOOT_SET_OLD_IMAGE: if( seq2 > seq1 ) ret = BOOT_SET_PART1_IMAGE; else ret = BOOT_SET_PART2_IMAGE; break; case BOOT_SET_NEW_IMAGE_ONCE: if( seq1 > seq2 ) ret = BOOT_SET_PART1_IMAGE_ONCE; else ret = BOOT_SET_PART2_IMAGE_ONCE; break; case BOOT_SET_OLD_IMAGE_ONCE: if( seq2 > seq1 ) ret = BOOT_SET_PART1_IMAGE_ONCE; else ret = BOOT_SET_PART2_IMAGE_ONCE; break; default: break; } } return( ret ); } int devCtl_getBootedImageId(void) { // this call is ok as the "0" value does not call getSequenceNumber which won't work with pureUBI images return( (int) devCtl_boardIoctl(BOARD_IOCTL_BOOT_IMAGE_OPERATION, 0, NULL, 0, BOOT_GET_BOOTED_IMAGE_ID, NULL) ); } /*********************************************************************** * devCtl_getBootedImagePartition -- for all flash types (safer to call this) * getBootedValue for NAND and EMMC types only. * Description : Gets the state of an image update from flash. * Returns : state constant or -1 for failure ***********************************************************************/ int devCtl_getBootedImagePartition(void) { unsigned int flag=0; getFlashInfo(&flag); if (flag & (FLASH_INFO_FLAG_NAND | FLASH_INFO_FLAG_EMMC)) return(getBootedValue()); else return( (int) devCtl_boardDriverIoctl(BOARD_IOCTL_BOOT_IMAGE_OPERATION, 0, NULL, 1, BOOT_GET_BOOTED_IMAGE_ID, NULL) ); } int isLegacyFlashLayout(void) { int ret = -1; UPDATE_FLASH_INFO(); switch( gFlashInfo ) { case FLASH_INFO_FLAG_NAND: ret = nandIsLegacyFlashLayout(); break; case FLASH_INFO_FLAG_EMMC: ret = emmcIsLegacyFlashLayout(); break; case FLASH_INFO_FLAG_NOR: ret = !norIsNewFlashLayout(); break; default: break; } return ret; } int getBootedValue(void) { int ret = -1; UPDATE_FLASH_INFO(); switch( gFlashInfo ) { case FLASH_INFO_FLAG_NAND: ret = nandGetBootedValue(); break; case FLASH_INFO_FLAG_EMMC: ret = emmcGetBootedValue(); break; default: break; } return ret; } #endif /* DESKTOP_LINUX */