/* * Copyright (C) 2023 Rockchip Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include "rkimage.h" #include "log.h" #include "md5sum.h" #include "rktools.h" #include "update.h" static void display_head(PSTRUCT_RKIMAGE_HEAD pHead) { LOGD("uiTag = %x.\n", pHead->uiTag); LOGD("usSize = %x.\n", pHead->usSize); LOGD("dwVersion = %x.\n", pHead->dwVersion); UINT btMajor = ((pHead->dwVersion) & 0XFF000000) >> 24; UINT btMinor = ((pHead->dwVersion) & 0X00FF0000) >> 16; UINT usSmall = ((pHead->dwVersion) & 0x0000FFFF); LOGD("btMajor = %x, btMinor = %x, usSmall = %02x.\n", btMajor, btMinor, usSmall); LOGD("dwBootOffset = %x.\n", pHead->dwBootOffset); LOGD("dwBootSize = %x.\n", pHead->dwBootSize); LOGD("dwFWOffset = %x.\n", pHead->dwFWOffset); LOGD("dwFWSize = %x.\n", pHead->dwFWSize); } static void display_item(PRKIMAGE_ITEM pitem) { //char name[PART_NAME]; //char file[RELATIVE_PATH]; //unsigned int offset; //unsigned int flash_offset; //unsigned int usespace; //unsigned int size; LOGD("name = %s\n", pitem->name); LOGD("file = %s\n", pitem->file); LOGD("offset = %d\n", pitem->offset); LOGD("flash_offset = %d\n", pitem->flash_offset); LOGD("usespace = %d\n", pitem->usespace); LOGD("size = %d\n", pitem->size); } static void display_hdr(PRKIMAGE_HDR phdr) { //unsigned int tag; //unsigned int size; //char machine_model[MAX_MACHINE_MODEL]; //char manufacturer[MAX_MANUFACTURER]; //unsigned int version; //int item_count; //RKIMAGE_ITEM item[MAX_PACKAGE_FILES]; LOGD("tag = %d\n", phdr->tag); LOGD("size = %d\n", phdr->size); LOGD("machine_model = %s\n", phdr->machine_model); LOGD("manufacturer = %s\n", phdr->manufacturer); LOGD("version = %d\n", phdr->version); LOGD("item = %d.\n", phdr->item_count); for (int i = 0; i < phdr->item_count; i++) { LOGI("================================================\n"); display_item(&(phdr->item[i])); } } void adjustFileOffset(PRKIMAGE_HDR phdr, int offset, int loader_offset, int loader_size) { for (int i = 0; i < phdr->item_count; i++) { if ( strcmp(phdr->item[i].name, "bootloader") == 0) { phdr->item[i].offset = loader_offset; phdr->item[i].size = loader_size; continue ; } phdr->item[i].offset += offset; } } //解析固件,获得固件头部信息 int analyticImage(const char *filepath, PRKIMAGE_HDR phdr) { long long ulFwSize; STRUCT_RKIMAGE_HEAD rkimage_head; unsigned char m_md5[32]; int fd = open(filepath, O_RDONLY); if (fd < 0) { LOGE("Can't open %s\n", filepath); return -2; } //1. image 头部信息读取 if (read(fd, &rkimage_head, sizeof(STRUCT_RKIMAGE_HEAD)) != sizeof(STRUCT_RKIMAGE_HEAD)) { LOGE("Can't read %s\n(%s)\n", filepath, strerror(errno)); close(fd); return -2; } if ((rkimage_head.reserved[14] == 'H') && (rkimage_head.reserved[15] == 'I')) { ulFwSize = *((DWORD *)(&rkimage_head.reserved[16])); ulFwSize <<= 32; ulFwSize += rkimage_head.dwFWOffset; ulFwSize += rkimage_head.dwFWSize; } else { ulFwSize = rkimage_head.dwFWOffset + rkimage_head.dwFWSize; } rkimage_head.dwFWSize = ulFwSize - rkimage_head.dwFWOffset; display_head(&rkimage_head); //2. 固件md5 校验 long long fileSize; int nMd5DataSize; fileSize = lseek64(fd, 0L, SEEK_END); nMd5DataSize = fileSize - ulFwSize; if (nMd5DataSize >= 160) { LOGE("md5 : not support sign image.\n"); //sign image //m_bSignFlag = true; //m_signMd5Size = nMd5DataSize-32; //fseeko64(m_pFile,ulFwSize,SEEK_SET); //fread(m_md5,1,32,m_pFile); //fread(m_signMd5,1,nMd5DataSize-32,m_pFile); } else { lseek64(fd, -32, SEEK_END); if ( read(fd, m_md5, 32) != 32) { LOGE("lseek failed.\n"); close(fd); return -2; } } //3. image 地址信息读取 if (lseek64(fd, rkimage_head.dwFWOffset, SEEK_SET) == -1) { LOGE("lseek failed.\n"); close(fd); return -2; } if (read(fd, phdr, sizeof(RKIMAGE_HDR)) != sizeof(RKIMAGE_HDR)) { LOGE("Can't read %s\n(%s)\n", filepath, strerror(errno)); close(fd); return -2; } if (phdr->tag != RKIMAGE_TAG) { LOGE("tag: %x\n", phdr->tag); LOGE("Invalid image\n"); close(fd); return -3; } if ((phdr->manufacturer[56] == 0x55) && (phdr->manufacturer[57] == 0x66)) { USHORT *pItemRemain; pItemRemain = (USHORT *)(&phdr->manufacturer[58]); phdr->item_count += *pItemRemain; } if (rkimage_head.dwFWOffset) { adjustFileOffset(phdr, rkimage_head.dwFWOffset, rkimage_head.dwBootOffset, rkimage_head.dwBootSize); } display_hdr(phdr); close(fd); #if 1 if (!compareMd5sum((char*)filepath, m_md5, 0, fileSize - 32)) { LOGE("Md5Check update.img fwSize:%ld", fileSize - 32); return -1; } #endif LOGI("analyticImage ok.\n"); return 0; } // 获得Image 打包版本号 bool getImageVersion(const char *filepath, char *version, int maxLength) { STRUCT_RKIMAGE_HEAD rkimage_head; int fd = open(filepath, O_RDONLY); if (fd < 0) { LOGE("Can't open %s\n", filepath); return false; } //1. image 头部信息读取 if (read(fd, &rkimage_head, sizeof(STRUCT_RKIMAGE_HEAD)) != sizeof(STRUCT_RKIMAGE_HEAD)) { LOGE("Can't read %s\n(%s)\n", filepath, strerror(errno)); close(fd); return false; } close(fd); UINT btMajor = ((rkimage_head.dwVersion) & 0XFF000000) >> 24; UINT btMinor = ((rkimage_head.dwVersion) & 0x00FF0000) >> 16; UINT usSmall = ((rkimage_head.dwVersion) & 0x0000FFFF); //转换成字符串 sprintf(version, "%d.%d.%d", btMajor, btMinor, usSmall); return true; } #if 0 int main(int argc, char *argv[]) { analyticImage(argv[1]); compareVersion(); } #endif