/*********************************************************************** * <:copyright-BRCM:2016:DUAL/GPL:standard * * Copyright (c) 2016 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. * * :> ************************************************************************/ /*!\file bcm_imgutil.c * \brief Broadcom firmware image utils. Most of this file is copied from * cms_util/image.c This file is the correct place for most * Broadcom image utils, since the image functions applies to * non-CMS builds as well. Going forward, make fixes and enhancements * in this file and redirect calls from image.c to this file. * */ #include #include #include #include #ifdef DESKTOP_LINUX #include #endif /* DESKTOP_LINUX */ #include "bcmTag.h" #include "board.h" #include "bcm_boarddriverctl.h" #include "genutil_crc.h" #include "bcm_flashutil.h" #include "bcm_flashutil_nand.h" #include "bcm_flashutil_emmc.h" #include "bcm_flashutil_nor.h" #include "bcm_imgutil.h" #include "libfdt.h" /* #define CC_IMGUTIL_DEBUG 1 */ #define cmsLog_error(fmt, arg...) \ printf("ERROR[%s.%u]: " fmt "\n", __FUNCTION__, __LINE__, ##arg) #if defined(CC_IMGUTIL_DEBUG) #define cmsLog_debug(fmt, arg...) \ printf("%s.%u: " fmt "\n", __FUNCTION__, __LINE__, ##arg) #else #define cmsLog_debug(fmt, arg...) #endif /* CC_IMGUTIL_DEBUG */ #if defined(CC_IMGUTIL_NOTICE) #define cmsLog_notice(fmt, arg...) \ printf("%s.%u: " fmt "\n", __FUNCTION__, __LINE__, ##arg) #else #define cmsLog_notice(fmt, arg...) #endif /* CC_IMGUTIL_NOTICE */ static UBOOL8 matchChipId(const char *strTagChipId, const char *signature2); CmsRet bcmImg_verifyBroadcomFileTag(FILE_TAG *pTag, UBOOL8 fullImageB, int imageLen); void dumpBcmFileTag(FILE_TAG *tagP); UBOOL8 bcmImg_MatchChipId( const char *strTagChipId ) { return(matchChipId(strTagChipId, NULL)); } /** * @return TRUE if the modem's chip id matches that of the image. */ static UBOOL8 matchChipId(const char *strTagChipId, const char *signature2 __attribute__((unused))) { UINT32 tagChipId = 0; UINT32 chipId; UBOOL8 match; /* this is the image's chip id */ tagChipId = (UINT32) strtol(strTagChipId, NULL, 16); /* get the system's chip id */ devCtl_getChipId(&chipId); if (tagChipId == chipId) { match = TRUE; } else if (tagChipId == CHIP_FAMILY_ID_HEX) { match = TRUE; } else { cmsLog_error("Chip Id error. Image Chip Id = %04x, Board Chip Id = %04x.", tagChipId, chipId); match = FALSE; #ifdef DESKTOP_LINUX match = TRUE; /* For debugging. */ #endif } return match; } // verify the tag of the image CmsRet bcmImg_verifyBroadcomFileTag(FILE_TAG *pTag, UBOOL8 fullImageB, int imageLen) { UINT32 crc; int totalImageSize; int tagVer, curVer; UINT32 tokenCrc, imageCrc, *pTokenCrc, *pImageCrc; cmsLog_debug("start of pTag=%p tagversion %02x %02x %02x %02x", pTag, pTag->tagVersion[0], pTag->tagVersion[1], pTag->tagVersion[2], pTag->tagVersion[3]); pTokenCrc = (UINT32 *)pTag->tagValidationToken; tokenCrc = *pTokenCrc; pImageCrc = (UINT32 *)pTag->imageValidationToken; imageCrc = *pImageCrc; #ifdef DESKTOP_LINUX /* assume desktop is running on little endien intel, but the CRC has been * written for big endien mips, so swap before compare. * FIXME! this part of code might not work with Little-endian target system. */ tokenCrc = htonl(tokenCrc); imageCrc = htonl(imageCrc); #endif // check tag validate token first crc = CRC_INITIAL_VALUE; crc = genUtl_getCrc32((UINT8 *) pTag, (UINT32)TAG_LEN-TOKEN_LEN, crc); if (crc != tokenCrc) { /* this function is called even when we are not sure the image is * a broadcom image. So if crc fails, it is not a big deal. It just * means this is not a broadcom image. */ cmsLog_debug("token crc failed, this is not a valid broadcom image"); cmsLog_debug("calculated crc=0x%x tokenCrc=0x%x", crc, tokenCrc); return CMSRET_INVALID_IMAGE; } cmsLog_debug("header CRC is OK."); tagVer = atoi((char *) pTag->tagVersion); curVer = atoi(BCM_TAG_VER); if (tagVer != curVer) { cmsLog_error("Firmware tag version [%d] is not compatible with the current Tag version [%d]", tagVer, curVer); return CMSRET_INVALID_IMAGE; } cmsLog_debug("tarVer=%d, curVar=%d", tagVer, curVer); if (!matchChipId((char *) pTag->chipId, (char *) pTag->signiture_2)) { cmsLog_error("chipid check failed"); return CMSRET_INVALID_IMAGE; } cmsLog_debug("chipid is OK"); if (fullImageB == FALSE) { cmsLog_debug("Good broadcom image header"); return CMSRET_SUCCESS; } // check imageCrc totalImageSize = atoi((char *) pTag->totalImageLen); cmsLog_debug("totalImageLen=%d, imageLen=%d, TAG_LEN=%d\n", totalImageSize, imageLen, TAG_LEN); if (totalImageSize > (imageLen -TAG_LEN)) { cmsLog_error("invalid size\n"); return CMSRET_INVALID_IMAGE; } crc = CRC_INITIAL_VALUE; crc = genUtl_getCrc32(((UINT8 *)pTag + TAG_LEN), (UINT32) totalImageSize, crc); if (crc != imageCrc) { /* * This should not happen. We already passed the crc check on the header, * so we should pass the crc check on the image. If this fails, something * is wrong. */ cmsLog_error("image crc failed after broadcom header crc succeeded"); cmsLog_error("calculated crc=0x%x imageCrc=0x%x totalImageSize=%d", crc, imageCrc, totalImageSize); return CMSRET_INVALID_IMAGE; } cmsLog_debug("image crc is OK"); cmsLog_debug("Good broadcom image"); return CMSRET_SUCCESS; } // depending on the image type, do the brcm image or whole flash image CmsRet bcmImg_flashImage(char *imagePtr, UINT32 imageLen, CmsImageFormat format, UINT32 opts, int * noReboot) { FILE_TAG *pTag = (FILE_TAG *) imagePtr; int cfeSize, rootfsSize, kernelSize; unsigned long cfeAddr, rootfsAddr, kernelAddr; UINT32 flags=0; CmsRet ret; if( opts & CMS_IMAGE_WR_OPT_PART1 ) { *noReboot = (opts & CMS_IMAGE_WR_OPT_NO_REBOOT) ? FLASH_PART1_NO_REBOOT : FLASH_PART1_REBOOT; } else if( opts & CMS_IMAGE_WR_OPT_PART2 ) { *noReboot = (opts & CMS_IMAGE_WR_OPT_NO_REBOOT) ? FLASH_PART2_NO_REBOOT : FLASH_PART2_REBOOT; } else { *noReboot = (opts & CMS_IMAGE_WR_OPT_NO_REBOOT) ? FLASH_PARTDEFAULT_NO_REBOOT : FLASH_PARTDEFAULT_REBOOT; } cmsLog_debug("format=%d noReboot=0x%x", format, *noReboot); if (format != CMS_IMAGE_FORMAT_FLASH && format != CMS_IMAGE_FORMAT_BROADCOM) { cmsLog_error("invalid image format %d", format); return CMSRET_INVALID_IMAGE; } if (format == CMS_IMAGE_FORMAT_FLASH) { cmsLog_notice("Flash whole image..."); // Pass zero for the base address of whole image flash. It will be filled by kernel code // was sysFlashImageSet if ((ret = getFlashInfo(&flags)) == CMSRET_SUCCESS) { if(flags & FLASH_INFO_FLAG_NOR) { // NOR flash device ret = devCtl_boardIoctl(BOARD_IOCTL_FLASH_WRITE, BCM_IMAGE_WHOLE, imagePtr, imageLen-TOKEN_LEN, *noReboot, 0); } else { // NAND flash device ret = writeImageToNand( (unsigned char *)imagePtr, imageLen - TOKEN_LEN ); } } if (ret != CMSRET_SUCCESS) { cmsLog_error("Failed to flash whole image"); return CMSRET_IMAGE_FLASH_FAILED; } else { return CMSRET_SUCCESS; } } /* this must be a broadcom format image */ // check imageCrc cfeSize = rootfsSize = kernelSize = 0; // check cfe's existence cfeAddr = (unsigned long) strtoul((char *) pTag->cfeAddress, NULL, 10); cfeSize = atoi((char *) pTag->cfeLen); // check kernel existence kernelAddr = (unsigned long) strtoul((char *) pTag->kernelAddress, NULL, 10); kernelSize = atoi((char *) pTag->kernelLen); // check root filesystem existence rootfsAddr = (unsigned long) strtoul((char *) pTag->rootfsAddress, NULL, 10); rootfsSize = atoi((char *) pTag->rootfsLen); cmsLog_debug("cfeSize=%d kernelSize=%d rootfsSize=%d", cfeSize, kernelSize, rootfsSize); if (cfeAddr) { printf("Flashing CFE...\n"); ret = devCtl_boardIoctl(BOARD_IOCTL_FLASH_WRITE, BCM_IMAGE_CFE, imagePtr+TAG_LEN, cfeSize, (int) cfeAddr, 0); if (ret != CMSRET_SUCCESS) { cmsLog_error("Failed to flash CFE"); return CMSRET_IMAGE_FLASH_FAILED; } } if (rootfsAddr && kernelAddr) { char *tagFs = imagePtr; // tag is alway at the sector start of fs if (cfeAddr) { tagFs = imagePtr + cfeSize; // will trash cfe memory, but cfe is already flashed memcpy(tagFs, imagePtr, TAG_LEN); } printf("Flashing root file system and kernel...\n"); /* only the buf pointer and length is needed, the offset parameter * was present in the legacy code, but is not used. */ ret = devCtl_boardIoctl(BOARD_IOCTL_FLASH_WRITE, BCM_IMAGE_FS, tagFs, TAG_LEN+rootfsSize+kernelSize, *noReboot, 0); if (ret != CMSRET_SUCCESS) { cmsLog_error("Failed to flash root file system and kernel"); return CMSRET_IMAGE_FLASH_FAILED; } } cmsLog_notice("Image flash done."); return CMSRET_SUCCESS; } CmsRet get_mtd_device_size(const char * partition, unsigned int * size) { FILE *fp; char sze[MAX_MTD_NAME_SIZE] = {0}; char line[MAX_MTD_NAME_SIZE*2] = {0}; char name[MAX_MTD_NAME_SIZE] = {0}; char compare[MAX_MTD_NAME_SIZE] = {0}; if ( (fp = fopen("/proc/mtd","r")) == 0) { printf("ERROR in %s!!! Could not open /proc/mtd\n", __FUNCTION__); return(CMSRET_OPEN_FILE_ERROR); } snprintf(compare, sizeof(compare), "%s%s%s", "\"", partition, "\""); while(fgets(line, sizeof(line), fp)) { sscanf(line, "%*s %s %*s %s", sze, name); if(!strcmp(name, compare)) { fclose(fp); *size = (unsigned int)strtol(sze, NULL, 16); return(CMSRET_SUCCESS); } } fclose(fp); printf("%s: MTD partition/device %s not found/opened\n", __FUNCTION__, partition); return(CMSRET_OBJECT_NOT_FOUND); } unsigned int bcmImg_getImageFlashSize(void) { UINT32 flashSize=0; CmsRet ret = CMSRET_OBJECT_NOT_FOUND; if(isLegacyFlashLayout()) { ret = devCtl_boardIoctl(BOARD_IOCTL_FLASH_READ, FLASH_SIZE, 0, 0, 0, &flashSize); } else { unsigned int gFlashInfo = 0; getFlashInfo(&gFlashInfo); if (gFlashInfo == FLASH_INFO_FLAG_NAND) { ret = get_mtd_device_size("image", &flashSize); } else if (gFlashInfo == FLASH_INFO_FLAG_EMMC) { #ifndef DESKTOP_LINUX flashSize = emmcGetAvailLoaderSpace() + 2 * emmcGetAvailImgSpace(1); #else flashSize = 0x1000000; #endif ret = CMSRET_SUCCESS; } else if (gFlashInfo == FLASH_INFO_FLAG_NOR) ret = get_mtd_device_size(SPI_NOR_FLASH_NAME, &flashSize); } if (ret != CMSRET_SUCCESS) { cmsLog_error("Could not get flash size, return 0"); flashSize = 0; } return flashSize; } unsigned int bcmImg_getBroadcomImageTagSize(void) { return TOKEN_LEN; } unsigned int bcmImg_getConfigFlashSize(void) { UINT32 realSize; realSize = bcmImg_getRealConfigFlashSize(); #ifdef COMPRESSED_CONFIG_FILE /* * A multiplier of 2 is now too small for some of the big voice and WLAN configs, * so allow for the possibility of 4x compression ratio. In a recent test on the * 6368 with wireless enabled, I got a compression ratio of 3.5. * The real test comes in management.c: after we do the * compression, writeValidatedConfigBuf will verify that the compressed buffer can * fit into the flash. * A 4x multiplier should be OK for small memory systems such as the 6338. * The kernel does not allocate physical pages until they are touched. * However, allocating an overly large buffer could be rejected immediately by the * kernel because it does not know we don't actually plan to use the entire buffer. * So if this is a problem on the 6338, we could improve this algorithm to * use a smaller factor on low memory systems. */ realSize = realSize * 4; #endif return realSize; } unsigned int bcmImg_getRealConfigFlashSize(void) { CmsRet ret; UINT32 size=0; UINT32 flags=0; if ((ret = getFlashInfo(&flags)) == CMSRET_SUCCESS) { if(flags & FLASH_INFO_FLAG_NOR) { #ifndef DESKTOP_LINUX if( norIsNewFlashLayout()) size=128*1024; else #endif { ret = devCtl_boardIoctl(BOARD_IOCTL_GET_PSI_SIZE, 0, NULL, 0, 0, (void *)&size); if (ret != CMSRET_SUCCESS) { cmsLog_error("boardIoctl to get config flash size failed."); size = 0; } } } else { /* * If we are using NAND, config file is stored in the /data partition, * so config file size is only limited by the size of the /data * partition. For now, implement a quick solution and hardcode the * NAND config file size to 128KB (so far, nothing has hit this limit). * In the future, could improve this solution by: * - checking against size of /data partition * - if we have 1 copy or 2 (for backup config file). * whether we are doing a distributed MDM config (done by BDK) * - reserve the space on the FS so there is no chance FS is too * full to accept the config file. */ size=128*1024; // 128KB } } else { cmsLog_error("could not determine NAND or NOR"); } cmsLog_debug("returning size=%d", size); return size; } unsigned char bcmImg_willFitInFlash(unsigned int imageSize) { UINT32 flashSize; #ifdef DESKTOP_LINUX flashSize = 2 * (imageSize + CMS_IMAGE_OVERHEAD); #else flashSize = bcmImg_getImageFlashSize(); cmsLog_debug("flash size is %u bytes, imageSize=%u bytes", flashSize, imageSize); #endif /* DESKTOP_LINUX */ return (flashSize > (imageSize + CMS_IMAGE_OVERHEAD)); } unsigned char bcmImg_isBackupConfigFlashAvailable(void) { static UBOOL8 firstTime=TRUE; static UBOOL8 avail=FALSE; CmsRet ret; if (firstTime) { UINT32 size=0; UINT32 flags=0; if ((ret = getFlashInfo(&flags)) == CMSRET_SUCCESS) { if(flags & FLASH_INFO_FLAG_NOR) { #ifndef DESKTOP_LINUX if( norIsNewFlashLayout() ) avail = TRUE; else #endif { ret = devCtl_boardIoctl(BOARD_IOCTL_GET_BACKUP_PSI_SIZE, 0, NULL, 0, 0, (void *)&size); if (ret == CMSRET_SUCCESS) { avail = TRUE; } } } else { // Backup PSI file is always available in NAND avail = TRUE; } } else { cmsLog_error("could not determine NAND or NOR"); } firstTime = FALSE; } return avail; } unsigned char bcmImg_isConfigFileLikely(const char *buf) { const char *header = " sizeof(struct fdt_header)) && (fdt_check_header(imageBuf) == 0)) { /* Found a valid Broadcom defined TAG record at the beginning of the image */ cmsLog_debug("Broadcom pktb format verified."); //FIXME: Cannot detemine total size of image at this point since we may not //have the entire dtb in memory. Will do that later result = CMS_IMAGE_FORMAT_BROADCOM; } else if ((imageLen > sizeof(FILE_TAG)) && (bcmImg_verifyBroadcomFileTag((FILE_TAG *) imageBuf, 1, imageLen) == CMSRET_SUCCESS)) { UINT32 maxLen; /* Found a valid Broadcom defined TAG record at the beginning of the image */ cmsLog_debug("Broadcom format verified."); maxLen = bcmImg_getImageFlashSize() + bcmImg_getBroadcomImageTagSize(); if (imageLen > maxLen) { cmsLog_error("broadcom image is too large for flash, got %u, max %u", imageLen, maxLen); } else { result = CMS_IMAGE_FORMAT_BROADCOM; } } else { /* if It is not a Broadcom flash format file. Now check if it is a * flash image format file. A flash image format file must have a * CRC at the end of the image. */ UINT32 crc = CRC_INITIAL_VALUE; UINT32 imageCrc; UINT8 *crcPtr; if (imageLen > TOKEN_LEN) { crcPtr = (UINT8 *) (imageBuf + (imageLen - TOKEN_LEN)); /* * CRC may not be word aligned, so extract the bytes out one-by-one. * Whole image CRC is calculated, then htonl, then written out using * fwrite (see addvtoken.c in hostTools). Because of the way we are * extracting the CRC here, we don't have to swap for endieness when * doing compares on desktop Linux and modem (?). */ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ imageCrc = crcPtr[0] | (crcPtr[1] << 8) | (crcPtr[2] << 16) | (crcPtr[3] << 24); #else imageCrc = (crcPtr[0] << 24) | (crcPtr[1] << 16) | (crcPtr[2] << 8) | crcPtr[3]; #endif crc = genUtl_getCrc32((unsigned char *) imageBuf, imageLen - TOKEN_LEN, crc); #ifndef DESKTOP_LINUX if (crc == imageCrc) #else if ((crc == imageCrc) || crc == htonl(imageCrc)) #endif { UINT32 maxLen; cmsLog_debug("Whole flash image format [%d bytes] verified.", imageLen); maxLen = bcmImg_getImageFlashSize(); if (imageLen > maxLen) { cmsLog_error("whole image is too large for flash, got %u, max %u", imageLen, maxLen); } else { result = CMS_IMAGE_FORMAT_FLASH; } } else { #if defined(EPON_SDK_BUILD) cmsLog_debug("Could not determine image format [%d bytes]", imageLen); #else cmsLog_error("Could not determine image format [%d bytes]", imageLen); #endif cmsLog_debug("calculated crc=0x%x image crc=0x%x", crc, imageCrc); } } } cmsLog_debug("returning image format %d", result); return result; } UBOOL8 bcmImg_isBcmTaggedImage(const char *imageBuf, UINT32 *imageSize) { FILE_TAG *pTag = (FILE_TAG *)imageBuf; UINT32 crc; UINT32 tokenCrc, *pTokenCrc; UBOOL8 isBcmImg = FALSE; pTokenCrc = (UINT32 *)pTag->tagValidationToken; tokenCrc = *pTokenCrc; #ifdef DESKTOP_LINUX /* assume desktop is running on little endien intel, but the CRC has been * written for big endien mips, so swap before compare. * FIXME! this part of code might not work with Little-endian target system. */ tokenCrc = htonl(tokenCrc); #endif /* check tag validate token to see if it is a valid bcmTag */ crc = CRC_INITIAL_VALUE; crc = genUtl_getCrc32((UINT8 *) pTag, (UINT32)TAG_LEN-TOKEN_LEN, crc); if (crc == tokenCrc) { isBcmImg = TRUE; *imageSize = (UINT32) atoi((char *)pTag->totalImageLen) + TAG_LEN; cmsLog_debug("It's a broadcom tagged image with length %d", *imageSize ); } else { cmsLog_debug("token crc failed, this is not a valid broadcom image"); } return isBcmImg; } CmsImageFormat bcmImg_parseImgHdr(UINT8 *bufP, UINT32 bufLen) { CmsImageFormat result = CMS_IMAGE_FORMAT_INVALID; if (bufP == NULL) { cmsLog_debug("NULL bufP pointer."); result = CMS_IMAGE_FORMAT_INVALID; } else if ((bufLen > CMS_CONFIG_FILE_DETECTION_LENGTH) && bcmImg_isConfigFileLikely((char*)bufP)) { cmsLog_debug("Detected possible CMS XML config file format"); result = CMS_IMAGE_FORMAT_XML_CFG; } #ifdef SUPPORT_MODSW_LINUXPFP else if (cmsImg_isModSwLinuxPfp((UINT8*)bufP, bufLen)) { cmsLog_debug("Detected Modular Software Linux PFP format."); result = CMS_IMAGE_FORMAT_MODSW_LINUXPFP; } #endif else if ((bufLen > sizeof(FILE_TAG)) && (bcmImg_verifyBroadcomFileTag((FILE_TAG*)bufP, 0, bufLen) == CMSRET_SUCCESS)) { cmsLog_debug("Detected Broadcom image format."); result = CMS_IMAGE_FORMAT_BROADCOM; } return result; } void dumpBcmFileTag(FILE_TAG *tagP) { printf("--------------------------------------------------------------\n"); printf("Broadcom image tag:\n"); printf("\ttagVersion: %02x %02x %02x %02x\n", tagP->tagVersion[0], tagP->tagVersion[1], tagP->tagVersion[2], tagP->tagVersion[3]); printf("\tendian: %s\n", tagP->bigEndian); printf("\ttotalImageLen: %s\n", tagP->totalImageLen); printf("\tcfeAddress: %s\n", tagP->cfeAddress); printf("\tcfeLen: %s\n", tagP->cfeLen); printf("\trootfsAddress: %s\n", tagP->rootfsAddress); printf("\trootfsLen: %s\n", tagP->rootfsLen); printf("\tkernelAddress: %s\n", tagP->kernelAddress); printf("\tkernelLen: %s\n", tagP->kernelLen); printf("\timageSequence: %s\n", tagP->imageSequence); printf("\timageVersion: %s\n", tagP->imageVersion); printf("--------------------------------------------------------------\n"); } /* * IMGUTIL_TODO: the following logic is replicated in a few places. * To consolidate. * ./private/apps/tr69c/main/informer.c: allocSize -= 64 * 1024; * ./gpl/apps/ftpd/ftpd/commands.c: totalAllocatedSize -= 64 * 1024; */ /* * If maxBufSize is initialized, try that (with allocSize = maxBufSize) * and if still failing, try reducing 64K from allocSize and try again as * long as allocSize > CMS_IMAGE_REQUIRED_LEN. */ UINT8* bcmImg_allocImgBuf(UINT32 maxBufSize, UINT32 *allocBufSizeP) { UINT32 allocSize; UINT8 *bufP = NULL; if (maxBufSize > 0) { allocSize = maxBufSize; } else { allocSize = bcmImg_getImageFlashSize() + bcmImg_getBroadcomImageTagSize(); } cmsLog_debug("bcmImg_allocImgBuf() begin, %d", allocSize); if ((bufP = (UINT8*)malloc(allocSize)) == NULL) { /* TODO: this logic in commands.c does not seem to be correct. */ /* if (maxBufSize > 0) */ { while (((bufP = (UINT8*)malloc(allocSize)) == NULL) && (allocSize > CMS_IMAGE_REQUIRED_LEN)) { allocSize -= 64 * 1024; cmsLog_debug("Try allocating %d kb", allocSize/1024); } } if (bufP == NULL) { cmsLog_error("Not enough memory to alloc %u bytes.", allocSize); *allocBufSizeP = 0; return NULL; } } cmsLog_debug("bcmImg_allocImgBuf() end, %d", allocSize); *allocBufSizeP = allocSize; return bufP; }