| #include "tim.h" |
| |
| #define DTIM_MAX_SIZE (128 * 1024) |
| |
| #if 0 |
| |
| static const char *id2str(unsigned int id) |
| { |
| switch (id) { |
| case IMAGE_ID_ARBEL: |
| return "ARBEL"; |
| case IMAGE_ID_DTIM_A: |
| return "DTIM_A"; |
| case IMAGE_ID_DTIM_B: |
| return "DTIM_B"; |
| case IMAGE_ID_KERNEL: |
| return "KERNEL"; |
| case IMAGE_ID_MSA: |
| return "MSA"; |
| case IMAGE_ID_OEMD: |
| return "OEMD"; |
| case IMAGE_ID_RF: |
| return "RF"; |
| case IMAGE_ID_ROOTFS: |
| return "ROOTFS"; |
| case IMAGE_ID_UBOOT: |
| return "UBOOT"; |
| default: |
| OTA_ERR("Unkown id: 0x%x\n", id); |
| return "NULL"; |
| } |
| } |
| #endif |
| |
| static int SetTIMPointers( void *pStartAddr, TIM *pTIM_h) |
| { |
| pTIM_h->pConsTIM = (pCTIM) pStartAddr; // Overlap Contant Part of TIM with actual TIM... |
| |
| if ((pTIM_h->pConsTIM->VersionBind.Identifier != TIMIDENTIFIER) || |
| (pTIM_h->pConsTIM->VersionBind.Version < TIM_3_2_00)) { |
| /* incorrect tim */ |
| pTIM_h->pConsTIM = NULL; |
| return -1; |
| } |
| |
| // Assign a pointer to start of Images Area |
| pTIM_h->pImg = (pIMAGE_INFO_3_4_0) (pStartAddr + sizeof (CTIM)); |
| |
| // Assign a pointer to start of Key Area |
| if (pTIM_h->pConsTIM->VersionBind.Version >= TIM_3_4_00) |
| pTIM_h->pKey = (pKEY_MOD_3_4_0) ((UINT_T)pTIM_h->pImg + ((pTIM_h->pConsTIM->NumImages) * sizeof (IMAGE_INFO_3_4_0))); |
| else |
| pTIM_h->pKey = (pKEY_MOD_3_4_0) ((UINT_T)pTIM_h->pImg + ((pTIM_h->pConsTIM->NumImages) * sizeof (IMAGE_INFO_3_2_0))); |
| |
| // Assign a pointer to start of reserved area |
| if (pTIM_h->pConsTIM->VersionBind.Version >= TIM_3_4_00) |
| pTIM_h->pReserved = (PUINT) ((UINT_T)pTIM_h->pKey + ((pTIM_h->pConsTIM->NumKeys) * sizeof (KEY_MOD_3_4_0))); |
| else if (pTIM_h->pConsTIM->VersionBind.Version >= TIM_3_3_00) |
| pTIM_h->pReserved = (PUINT) ((UINT_T)pTIM_h->pKey + ((pTIM_h->pConsTIM->NumKeys) * sizeof (KEY_MOD_3_3_0))); |
| else |
| pTIM_h->pReserved = (PUINT) ((UINT_T)pTIM_h->pKey + ((pTIM_h->pConsTIM->NumKeys) * sizeof (KEY_MOD_3_2_0))); |
| |
| // Assign a pointer to start of DS |
| pTIM_h->pTBTIM_DS = (pPLAT_DS) ((UINT_T)pTIM_h->pReserved + pTIM_h->pConsTIM->SizeOfReserved); |
| return (NoError); |
| } |
| |
| #if 0 |
| static void dump_dtim(pTIM t) |
| { |
| int i; |
| pIMAGE_INFO_3_4_0 pImg; |
| OTA_DEBUG("### Image in dtim ###\n"); |
| OTA_DEBUG("Images number: %d\n", t->pConsTIM->NumImages); |
| for (i = 0; i < t->pConsTIM->NumImages; i++) { |
| pImg = (pIMAGE_INFO_3_4_0)(t->pImg + i); |
| OTA_DEBUG("[%d] ID: %s, NextID: %s, Offset: 0x%x, " |
| "LoadAddr: 0x%x, Size: %d, SizeToHash: %d, HashAlgorithmID: 0x%x\n", i, |
| id2str(pImg->ImageID), id2str(pImg->NextImageID), pImg->FlashEntryAddr, |
| pImg->LoadAddr, pImg->ImageSize, pImg->ImageSizeToHash, |
| pImg->HashAlgorithmID); |
| OTA_DEBUG("[%d] Hash: 0x%x, 0x%x, 0x%x, 0x%x, " |
| "0x%x, 0x%x, 0x%x, 0x%x, " |
| "0x%x, 0x%x, 0x%x, 0x%x, " |
| "0x%x, 0x%x, 0x%x, 0x%x\n", i, |
| pImg->Hash[0], pImg->Hash[1], pImg->Hash[2], pImg->Hash[3], |
| pImg->Hash[4], pImg->Hash[5], pImg->Hash[6], pImg->Hash[7], |
| pImg->Hash[8], pImg->Hash[9], pImg->Hash[10], pImg->Hash[11], |
| pImg->Hash[12], pImg->Hash[13], pImg->Hash[14], pImg->Hash[15]); |
| } |
| } |
| |
| static void *load_dtim(const char *dev) |
| { |
| int fd = -1; |
| |
| char _dev[32] = {0}; |
| char *buf = malloc(DTIM_MAX_SIZE); |
| if (!buf) { |
| OTA_ERR("failed to malloc 0x%x for dtim.\n", DTIM_MAX_SIZE); |
| goto out; |
| } |
| |
| sprintf(_dev, "/dev/%s", dev); |
| fd = open(_dev, O_RDWR | O_SYNC); |
| if (fd < 0) { |
| OTA_ERR("failed to open %s.\n", _dev); |
| free(buf); |
| buf = NULL; |
| goto out; |
| } |
| |
| if (complete_read(fd, buf, DTIM_MAX_SIZE) < 0) { |
| OTA_ERR("failed to load %s.\n", _dev); |
| free(buf); |
| buf = NULL; |
| goto out; |
| } |
| |
| out: |
| if (fd >= 0) |
| close(fd); |
| return buf; |
| } |
| |
| static int __save_dtim(int fd, pTIM pTIM_h) |
| { |
| int r = -1; |
| struct erase_info_user mtdEraseInfo; |
| struct mtd_info_user mtdInfo; |
| |
| if (ioctl(fd, MEMGETINFO, &mtdInfo)) { |
| OTA_ERR("could not get MTD device info.\n"); |
| goto out; |
| } |
| mtdEraseInfo.start = 0; |
| mtdEraseInfo.length = mtdInfo.erasesize; |
| |
| ioctl(fd, MEMUNLOCK, &mtdEraseInfo); |
| ioctl(fd, MEMERASE, &mtdEraseInfo); |
| |
| if (complete_write(fd, (char *)pTIM_h->pConsTIM, DTIM_MAX_SIZE) < 0) |
| goto out; |
| |
| r = 0; |
| out: |
| return r; |
| } |
| |
| static int save_dtim(const char *dev, pTIM pTIM_h) |
| { |
| int fd = -1; |
| int r = -1; |
| char _dev[32] = {0}; |
| sprintf(_dev, "/dev/%s", dev); |
| fd = open(_dev, O_RDWR | O_SYNC); |
| if (fd < 0) { |
| OTA_ERR("failed to open %s.\n", _dev); |
| goto out; |
| } |
| |
| r = __save_dtim(fd, pTIM_h); |
| if (r) |
| OTA_ERR("failed to save dtim to %s.\n", _dev); |
| out: |
| if (fd >= 0) |
| close(fd); |
| return r; |
| } |
| |
| /* sync the new to old */ |
| static int __sync_dtim(pTIM pNew, pTIM pOld) |
| { |
| int r = -1, i, j, found = 0, images; |
| int flag = 0; |
| pIMAGE_INFO_3_4_0 pImgSrc, pImgDst; |
| |
| OTA_DEBUG("%s: new dtim mode: %d, old dtim mode: %d.\n", __func__, |
| pNew->pConsTIM->VersionBind.Trusted, pOld->pConsTIM->VersionBind.Trusted); |
| if (pNew->pConsTIM->VersionBind.Trusted != pOld->pConsTIM->VersionBind.Trusted) { |
| OTA_ERR("%s: Fatal Error. Can't sync two different trust mode dtim.\n", __func__); |
| return -1; |
| } |
| |
| for (i = 0; i < pNew->pConsTIM->NumImages; i++) { |
| pImgSrc = (pIMAGE_INFO_3_4_0)(pNew->pImg + i); |
| for (j = 0; j < pOld->pConsTIM->NumImages; j++) { |
| pImgDst = (pIMAGE_INFO_3_4_0)(pOld->pImg + j); |
| if (pImgSrc->ImageID == pImgDst->ImageID && |
| pImgSrc->ImageID != IMAGE_ID_DTIM_A && |
| pImgSrc->ImageID != IMAGE_ID_DTIM_B) { |
| found++; |
| if (pImgSrc->ImageSize != pImgDst->ImageSize || |
| pImgSrc->ImageSizeToHash != pImgDst->ImageSizeToHash || |
| pImgSrc->LoadAddr != pImgDst->LoadAddr || |
| pImgSrc->HashAlgorithmID != pImgDst->HashAlgorithmID || |
| memcmp(pImgSrc->Hash, pImgDst->Hash, sizeof(pImgSrc->Hash)) != 0) |
| { |
| OTA_DEBUG("Image: %s has been changed.\n", id2str(pImgSrc->ImageID)); |
| pImgDst->ImageID = pImgSrc->ImageID; |
| pImgDst->ImageSize = pImgSrc->ImageSize; |
| pImgDst->ImageSizeToHash = pImgSrc->ImageSizeToHash; |
| pImgDst->LoadAddr = pImgSrc->LoadAddr; |
| pImgDst->HashAlgorithmID = pImgSrc->HashAlgorithmID; |
| memcpy(pImgDst->Hash, pImgSrc->Hash, sizeof(pImgSrc->Hash)); |
| flag = 1; |
| break; |
| } |
| } |
| } |
| } |
| |
| images = pNew->pConsTIM->NumImages - 1; |
| /* omit the first image(dtim it self) */ |
| if (found != images) { |
| OTA_ERR("FATAL ERROR: NumImage: %d, found: %d, not exactly match.\n" |
| , pNew->pConsTIM->NumImages, found); |
| goto out; |
| } |
| |
| r = flag; |
| out: |
| return r; |
| } |
| |
| static int update_dtim(const char *dev, void *bufNew) |
| { |
| int r = -1; |
| TIM tNew, tOld; |
| char *buf = load_dtim(dev); |
| |
| if (!buf) { |
| OTA_ERR("%s: failed to load dtim for %s.\n", __func__, dev); |
| goto out; |
| } |
| |
| SetTIMPointers(buf, &tOld); |
| SetTIMPointers(bufNew, &tNew); |
| |
| OTA_DEBUG("### Dump orignal dtim of %s. ###\n", dev); |
| dump_dtim(&tOld); |
| OTA_DEBUG("### Dump the new dtim. ###\n"); |
| dump_dtim(&tNew); |
| |
| r = __sync_dtim(&tNew, &tOld); |
| if (r < 0) |
| goto out; |
| if (r > 0) { |
| OTA_DEBUG("Images have been changed, update %s\n", dev); |
| r = save_dtim(dev, &tOld); |
| } else { |
| OTA_DEBUG("Images have NO change, DO NOT need to sync.\n"); |
| r = 0; |
| } |
| |
| OTA_DEBUG("%s: %s.\n", __func__, (r >= 0) ? "OK" : "FAILED"); |
| out: |
| if (buf) |
| free(buf); |
| return r; |
| } |
| |
| static int sync_dtim(const char *src, const char *dst) |
| { |
| int r = -1;//, i, j, found = 0; |
| // int flag = 0; |
| // pIMAGE_INFO_3_4_0 pImgSrc, pImgDst; |
| TIM tSrc; |
| TIM tDst; |
| char *bufSrc = load_dtim(src); |
| char *bufDst = load_dtim(dst); |
| |
| OTA_DEBUG("Start to sync %s to %s.\n", src, dst); |
| if (!bufSrc || !bufDst) { |
| OTA_ERR("failed to sync %s to %s.\n", src, dst); |
| goto out; |
| } |
| |
| SetTIMPointers(bufSrc, &tSrc); |
| SetTIMPointers(bufDst, &tDst); |
| |
| OTA_DEBUG("Dump dtim info of %s.\n", src); |
| dump_dtim(&tSrc); |
| OTA_DEBUG("Dump dtim info of %s.\n", dst); |
| dump_dtim(&tDst); |
| |
| if (tSrc.pConsTIM->NumImages != tDst.pConsTIM->NumImages) { |
| OTA_ERR("FATAL ERROR: NumImages(%s): %d, NumImages(%s): %d.\n", |
| src, tSrc.pConsTIM->NumImages, dst, tDst.pConsTIM->NumImages); |
| goto out; |
| } |
| |
| r = __sync_dtim(&tSrc, &tDst); |
| if (r < 0) |
| goto out; |
| if (r > 0) { |
| OTA_DEBUG("Images have been changed, need to sync %s to %s.\n", src, dst); |
| r = save_dtim(dst, &tDst); |
| } else { |
| OTA_DEBUG("Images have NO change, DO NOT need to sync.\n"); |
| r = 0; |
| } |
| out: |
| if (bufSrc) |
| free(bufSrc); |
| if (bufDst) |
| free(bufDst); |
| return r; |
| } |
| |
| /* dev is the mtd device of dtim */ |
| static int get_image_mode(const char *dev) |
| { |
| char *buf = load_dtim(dev); |
| TIM tim; |
| int mode; |
| |
| if (!buf) { |
| OTA_ERR("%s: failed to load dtim for %s.\n", __func__, dev); |
| return -1; |
| } |
| |
| SetTIMPointers(buf, &tim); |
| mode = tim.pConsTIM->VersionBind.Trusted; |
| OTA_DEBUG("%s: it is %s mode(%s).\n", __func__, (mode == 1) ? "Trusted" : "NON-Trusted", dev); |
| free(buf); |
| return mode; |
| } |
| #endif |
| |
| static UINT_T CheckReserved (pTIM pTIM_h) |
| { |
| pWTP_RESERVED_AREA pWRA = (pWTP_RESERVED_AREA) pTIM_h->pReserved; |
| |
| // Make sure that the TIM has a credible size |
| if(pTIM_h->pConsTIM->SizeOfReserved == 0) |
| return NotFoundError; |
| |
| // Older TIM's had old reserved fields definition |
| if (pTIM_h->pConsTIM->VersionBind.Version == (0x00030101)) |
| return NotFoundError; |
| |
| // Was this area in reserved field created by a WTP compliant tool so we can parse? |
| if (pWRA->WTPTP_Reserved_Area_ID != WTPRESERVEDAREAID) |
| return NotFoundError; |
| |
| return NoError; |
| } |
| |
| // Finds a Package of WTP recognized information in the reserved area based on identifier |
| static pWTP_RESERVED_AREA_HEADER FindPackageInReserved (UINT_T * Retval, pTIM pTIM_h, UINT_T Identifier) |
| { |
| UINT_T Count = 0; |
| pWTP_RESERVED_AREA_HEADER pWRAH = NULL; |
| pWTP_RESERVED_AREA pWRA = (pWTP_RESERVED_AREA) pTIM_h->pReserved; |
| |
| *Retval = CheckReserved(pTIM_h); |
| if (*Retval != NoError) |
| return NULL; |
| |
| // Start from the begining |
| pWRAH = (pWTP_RESERVED_AREA_HEADER) (pWRA + 1); |
| |
| while ((pWRAH->Identifier != Identifier) && (pWRAH->Identifier != TERMINATORID) && (Count < pWRA->NumReservedPackages)) |
| { |
| pWRAH = (pWTP_RESERVED_AREA_HEADER)((UINT_T)pWRAH + ((pWRAH->Size + 3) & ~3)); // Skip to the next one |
| Count++; |
| } |
| if (pWRAH->Identifier != Identifier) |
| { |
| *Retval = NotFoundError; |
| pWRAH = NULL; |
| } |
| |
| return pWRAH; |
| } |
| |
| // This function has been added to support to isolate backwards compatibility to tim.c |
| // It will return a point to pIMAGE_INFO based on TIM version. |
| static pIMAGE_INFO_3_4_0 ReturnPImgPtr(pTIM pTIM_h, UINT_T ImageNumber) |
| { |
| pIMAGE_INFO_3_4_0 pIMG; |
| pIMG = (pIMAGE_INFO_3_4_0) &pTIM_h->pImg[ImageNumber]; |
| return pIMG; |
| } |
| |
| // This function is used to find an image information field in the TIM |
| // of the image with the ID passed in |
| |
| static pIMAGE_INFO_3_4_0 FindImageInTIM(pTIM pTIM_h, UINT_T ImageID) |
| { |
| pIMAGE_INFO_3_4_0 pImageInfo = NULL; |
| UINT8_T i; |
| |
| if (pTIM_h) |
| { |
| for( i = 0; i < pTIM_h->pConsTIM->NumImages; i++) |
| { |
| pImageInfo = ReturnPImgPtr(pTIM_h, i); |
| if(pImageInfo->ImageID == ImageID) |
| return pImageInfo; |
| } |
| } |
| return NULL; |
| } |
| |
| static int __retrive_timh_by_ddrid(pTIM pTIM_h, unsigned int *DDR_ID, int *imagesize) |
| { |
| int i, DDRTimIndex = -1; |
| UINT_T /*LoadAddr, TimSize, */TimLoadAddr, Retval; |
| pIMAGE_INFO_3_4_0 pTimInfo = NULL; |
| pWTP_RESERVED_AREA_HEADER pWRAH = NULL; |
| pDDR_FLASH_MCP_PACKAGE pMCP = NULL; |
| #if 0 |
| if (DDR_ID == 0xFFFFFFFF || DDR_ID == 0) { |
| OTA_ERR("Warning: no valid DDR ID in ASR Flag\n"); |
| return NoError; |
| } |
| #endif |
| TimLoadAddr = (UINT_T)pTIM_h->pConsTIM; |
| |
| pWRAH = FindPackageInReserved(&Retval, pTIM_h, DDR_FLASH_MCP_PACKAGE_ID); |
| if(pWRAH == NULL) { |
| OTA_ERR("No DFMP found, single DDR TIM\n\r"); |
| return NoError; |
| } else { |
| pMCP = (DDR_FLASH_MCP_PACKAGE *) pWRAH; |
| for (i = 0; i < pMCP->NumberVendorDdrFlashSpec; i++) { |
| if(pMCP->ddrFlashSpec[i].VendorDdrPid == *DDR_ID) { |
| DDRTimIndex = i; |
| OTA_DEBUG("%s: [%d] got ddr id: 0x%x\n", __func__, i, *DDR_ID); |
| break; |
| } |
| } |
| |
| pTimInfo = FindImageInTIM(pTIM_h, IMAGE_ID_TIMH); |
| if(pTimInfo == NULL) { |
| OTA_ERR("%s %d: No TIMH found, error\n", __func__, __LINE__); |
| return TIMNotFound; |
| } |
| |
| if (DDRTimIndex < 0) { |
| OTA_ERR("NOT found ddr id: 0x%x, use the first TIM ddrid: 0x%x", |
| *DDR_ID, pMCP->ddrFlashSpec[0].VendorDdrPid); |
| *DDR_ID = pMCP->ddrFlashSpec[0].VendorDdrPid; |
| goto out; |
| } |
| |
| /* go through all the TIMs to the right one */ |
| for (i = 0; i < (DDRTimIndex + 1); i++) { |
| Retval = SetTIMPointers((void *)TimLoadAddr, pTIM_h); |
| if(Retval) { |
| OTA_ERR("%s %d: failed\n", __func__, __LINE__); |
| return TIMNotFound; |
| } |
| |
| pTimInfo = FindImageInTIM(pTIM_h, IMAGE_ID_TIMH); |
| if(pTimInfo == NULL) { |
| OTA_ERR("%s %d: No TIMH found, error\n", __func__, __LINE__); |
| return TIMNotFound; |
| } |
| TimLoadAddr += pTimInfo->ImageSize; |
| } |
| } |
| |
| out: |
| *imagesize = pTimInfo->ImageSize; |
| OTA_DEBUG("%s: index: %d, size: 0x%x\n", __func__, DDRTimIndex, pTimInfo->ImageSize); |
| return NoError; |
| } |