231 lines
6.7 KiB
C
Raw Normal View History

2025-05-10 21:49:39 +08:00
/*
* 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 <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdbool.h>
#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