sizeif(i++).sizeof(++i) 的问题

考虑以下代码:

int i = 3;
int j = sizeof(++i);
int k = sizeof(i++);
cout << i << endl;

对上述代码,输出的结果为 : 3


原因:根据C99规范, sizeof是一个编译时刻就起效果的运算符,在其内的任何运算都没有意义, k= sizeof(i++); 在编译的时候被翻译成 j=sizeof((i++的数据类型)) 也就是 j = sizeof(int); 也就是 j= 4; (32bit系统,如果是16位系统,则j=2) 然后才会继续编译成最终的程序,当然在最终程序执行的时候,自然不会执行任何++i 或 i++ 了。

static int buildFw(const char* outputPath, const char *devName) //构建完整的固件镜像(如 up_boot.bin 和 flash.bin),将多个组件(如 bootloader、kernel、rootfs、tpheader、模块规格、扩展固件等)按照特定布局打包进一个缓冲区,并最终写入输出文件。 { int i = 0; char *buf = NULL; char *p = NULL; char *fwBase = NULL; int fwLen = 0; int ret = EXIT_FAILURE; int bufLen = layout->flashSize + sizeof(BLOCK_HEADER) + gExtModuleSpecBlockLen; int ext_fw_file_len = 0; char *p_tmp = NULL; int default_flag = 0; char tpheaderName[FIRMWARE_NAME_MAXLEN] = {0}; char factoryInfoName[FIRMWARE_NAME_MAXLEN] = {0}; char ispConfigName[FIRMWARE_NAME_MAXLEN]= {0}; char ispDefaultName[FIRMWARE_NAME_MAXLEN]= {0}; char cp_cmd[FIRMWARE_NAME_MAXLEN]= {0}; int facinfo_len = 0; int is_larger_jffs2 = 0; int user_record_alarm_offset = 0; if (gExtFwUpgrade) { bufLen = layout->flashSize + sizeof(BLOCK_HEADER) + gExtModuleSpecBlockLen + gExtFwBlockLen; } buf = (char *)malloc(bufLen); if (!buf) { ERR("no memory for buffer"); goto out_free_buf; } memset(buf, 0xff, bufLen); /* deal with up_boot.bin first */ if (1 == gNoPackUboot) { /* up_boot.bin 布局(从低地址到高地址): up header + factory_boot + tphead + kernel + romfs + jffs2_len */ fwBase = buf + mi.tpHeaderOffset - mi.fdtLen - mi.bootloaderLen - uhTagLength; fwLen = bufLen - mi.tpHeaderOffset + mi.bootloaderLen + mi.fdtLen + uhTagLength; DBG("2680:mi.fdtLen is %d", mi.fdtLen); } else { fwBase = buf + mi.bootloaderOffset - mi.fdtLen - uhTagLength; /* have a up header before bootloader */ fwLen = bufLen - mi.bootloaderOffset + mi.fdtLen + uhTagLength; DBG("2686:mi.fdtLen is %d", mi.fdtLen); } #ifdef FDT_UPGRADE_SUPPORT //fdt p = buf + mi.bootloaderOffset - mi.fdtLen; DBG("read dts to 0x%x",p - buf); ret = readToBuf(&fdtInfo, p); if (ret) { goto out_free_buf; } #endif if (use_nand_flash) { if (1 == gNoPackUboot) { p = buf + mi.tpHeaderOffset + mi.tpHeaderLen; } else { p = buf + mi.bootloaderOffset + mi.bootloaderLen + mi.tpHeaderLen; } } else { p = buf + mi.kernelOffset; } DBG("read kernel to 0x%x",p - buf); ret = readToBuf(&kernelInfo, p); if (ret) { goto out_free_buf; } p += mi.kernelLen; DBG("read rootfs to 0x%x",p - buf); ret = readToBuf(&rootfsInfo, p); if (ret) { goto out_free_buf; } if(encrypt_rootfs_header) { i = _AES_cfb1_encrypt_rijndael(AES_CFB1_key, AES_KEY_LEN, AES_CFB1_iv, p, ENCRYPT_ROOTFS_HEADER_SIZE, encrypt_rootfs_header_buffer); if(i != ENCRYPT_ROOTFS_HEADER_SIZE){ ERR("ENCRYPT_ROOTFS_HEADER Fail! (ret:%d != %d)\n", i , ENCRYPT_ROOTFS_HEADER_SIZE); goto out_free_buf; } memcpy(p,encrypt_rootfs_header_buffer,ENCRYPT_ROOTFS_HEADER_SIZE); if (use_nand_flash) { DBG("nand flash, write back to rootfs : 0x%x", rootfsInfo.fileSize); writeToBinFile(p, rootfsInfo.fileSize, rootfsInfo.fileName); } } if (mi.jffs2fsOffset != 0) { if (SUPPORT_SPMINIOS) { if (mi.rootfsOffset + mi.rootfsLen > layout->flashSize) { ERR("space left is not enough for jffs2"); exit(1); } if (use_nand_flash) { mi.rootfsLen = ALIGN(rootfsInfo.fileSize, rootfsAlign); } else { mi.rootfsLen = mi.jffs2fsOffset - mi.rootfsOffset; } DBG("rootfsLen: 0x%x", mi.rootfsLen); mi.jffs2fsLen = layout->flashSize - USER_RECORD_PARTITION_SIZE - VERIFY_SIZE - mi.jffs2fsOffset; #ifndef SLP_CAMERA_SUPPORT /* SLP升级机型只指定jffs2 offset,不按照larger jffs2的方式进行固件打包 */ is_larger_jffs2 = 1; #endif if (mi.rootfsLen < rootfsInfo.fileSize) { ERR("space left is not enough for rootfs"); exit(1); } } else { if (mi.jffs2fsLen == 0) { if (mi.statisticsOffset) { mi.jffs2fsLen = mi.statisticsOffset - mi.jffs2fsOffset; } else if (mi.exfsOffset) { mi.jffs2fsLen = mi.exfsOffset - mi.jffs2fsOffset; } else if (mi.upbootOffset) { mi.jffs2fsLen = mi.upbootOffset - mi.jffs2fsOffset; } else { mi.jffs2fsLen = layout->flashSize - mi.jffs2fsOffset; } } if (0 != (mi.jffs2fsLen % FLASH_SECTOR_SIZE) || 0 != (mi.jffs2fsOffset % FLASH_SECTOR_SIZE)) { ERR("fixed jffs2 offset or length is not on flash sector boundary"); ret = EXIT_FAILURE; goto out_free_buf; } if (use_nand_flash) { mi.rootfsLen = ALIGN(rootfsInfo.fileSize, rootfsAlign); DBG("rootfsLen: 0x%x", mi.rootfsLen); } else { if (mi.rootfsOffset + rootfsInfo.fileSize > mi.jffs2fsOffset || mi.jffs2fsOffset + mi.jffs2fsLen > layout->flashSize) { ERR("space left is not enough for fixed jffs2 length"); ret = EXIT_FAILURE; goto out_free_buf; } mi.rootfsLen = mi.jffs2fsOffset - mi.rootfsOffset; //ALIGN to flash sector_size,for factory_boot uip recovery mi.rootfsLen = ALIGN(mi.rootfsOffset + rootfsInfo.fileSize, FLASH_SECTOR_SIZE) - mi.rootfsOffset; DBG("rootfsLen:0x%x",mi.rootfsLen); } } DBG("Jffs2Len:0x%x",mi.jffs2fsLen); } else { #if 0 if (use_nand_flash) { ERR("not adapt"); exit(1); } #endif if (mi.rootfsOffset + mi.rootfsLen > layout->flashSize) { ERR("space left is not enough for jffs2"); exit(1); } if (SUPPORT_SPMINIOS) { mi.jffs2fsOffset = (layout->flashSize - USER_RECORD_PARTITION_SIZE - VERIFY_SIZE + mi.tpHeaderOffset) / 2; mi.rootfsLen = mi.jffs2fsOffset - mi.rootfsOffset; mi.jffs2fsLen = layout->flashSize - USER_RECORD_PARTITION_SIZE - VERIFY_SIZE - mi.jffs2fsOffset; } else { if (use_nand_flash) { mi.rootfsLen = ALIGN(rootfsInfo.fileSize, rootfsAlign); DBG("rootfsLen: 0x%x", mi.rootfsLen); } else { /* jffs2offset 按64K对齐,如果不使用jffs2(IMG_JFFS2_OFFSET==0), 把jffs2fsLen设置为0 未指定IMG_JFFS2_OFFSET则认为按默认打包jffs2分区,指定jffs2区间为从rootfs结束到固件最后*/ mi.jffs2fsOffset = ALIGN(mi.rootfsOffset + rootfsInfo.fileSize, FLASH_SECTOR_SIZE); mi.rootfsLen = mi.jffs2fsOffset - mi.rootfsOffset; mi.jffs2fsLen = gUseJffs2 ? layout->flashSize - mi.jffs2fsOffset : 0; } } } if (SUPPORT_SPMINIOS) { p += mi.rootfsLen; DBG("read servicefs to 0x%x", p - buf); ret = readToBuf(&serviceFileInfo, p); if (ret) { goto out_free_buf; } if (is_larger_jffs2) { mi.jffs2RealFsLen = serviceFileInfo.fileSize; } if (mi.jffs2fsLen < serviceFileInfo.fileSize) { ERR("space left is not enough for service"); exit(1); } #if 0 if(encrypt_rootfs_header) { i = _AES_cfb1_encrypt_rijndael(AES_CFB1_key, AES_KEY_LEN, AES_CFB1_iv, p, ENCRYPT_ROOTFS_HEADER_SIZE, encrypt_rootfs_header_buffer); if(i != ENCRYPT_ROOTFS_HEADER_SIZE){ ERR("ENCRYPT_ROOTFS_HEADER Fail! (ret:%d != %d)\n", i , ENCRYPT_ROOTFS_HEADER_SIZE); goto out_free_buf; } memcpy(p,encrypt_rootfs_header_buffer,ENCRYPT_ROOTFS_HEADER_SIZE); if (use_nand_flash) { DBG("nand flash, write back to service : 0x%x", serviceFileInfo.fileSize); writeToBinFile(p, serviceFileInfo.fileSize, serviceFileInfo.fileName); } } #endif } /* 如果只使用factory_boot,那么将factory_boot.bin打包进upboot.bin的位置 */ if (1 == gNoPackUboot) { p = buf + mi.tpHeaderOffset - mi.bootloaderLen; DBG("read bootloader to 0x%x",p - buf); ret = readToBuf(&factorybootInfo, p); if (ret) { goto out_free_buf; } } else { p = buf + mi.bootloaderOffset; DBG("read bootloader to 0x%x",p - buf); ret = readToBuf(&bootloaderInfo, p); if (ret) { goto out_free_buf; } } if (gExtFwUpgrade) { if (use_nand_flash) { if (gNoPackUboot == 1) { p = buf + mi.tpHeaderOffset + mi.tpHeaderLen + mi.kernelLen + mi.rootfsLen; } else { p = buf + mi.bootloaderOffset + mi.bootloaderLen + mi.tpHeaderLen + mi.kernelLen + mi.rootfsLen; } /* 再加上service分区的大小 */ if (SUPPORT_SPMINIOS) { p += serviceFileInfo.fileSize; } } else { /* 计算升级固件block偏移位置 */ if (SUPPORT_SPMINIOS) { if (is_larger_jffs2) { p = buf + mi.jffs2fsOffset + serviceFileInfo.fileSize; } else { #ifdef SLP_CAMERA_SUPPORT /* SLP升级机型在固件的jffs2结束和block之间预留verify分区 */ p = buf + layout->flashSize - USER_RECORD_PARTITION_SIZE; #else p = buf + layout->flashSize - VERIFY_SIZE - USER_RECORD_PARTITION_SIZE; #endif } } else { p = buf + mi.rootfsOffset + mi.rootfsLen; } } DBG("read BlockHeader to 0x%x sizeof(BLOCK_HEADER):0x%x",p - buf, sizeof(BLOCK_HEADER)); memcpy(p, &gBlockHeader, sizeof(BLOCK_HEADER)); p += sizeof(BLOCK_HEADER); /* 往up_boot.bin固件的jffs2fsOffset中写module_spec */ if (0 != gExtModuleSpecBlockNum) { ret = packExtModuleSpec(&gExtModuleSpecBlock, p); if (ret) { goto out_free_buf; } p += ALIGN(gExtModuleSpecBlock.fileInfo.fileSize + sizeof(EXT_MODULE_SPEC_HEADER), 4); } /* 往up_boot.bin固件的jffs2fsOffset中写isp_config */ for (i = 0; i < gExtFwBlockNum; i++) { if (gExtFwBlock[i].add) { /* 将所有add配置项为true的 isp_config往up_boot.bin的jffs2fs分区写 */ ret = packExtFw(&gExtFwBlock[i], p, outputPath); if (ret) { goto out_free_buf; } /* upboot 的 extFw 头部和文件长度累加,需要使用文件对齐后的长度 */ ext_fw_file_len += ALIGN(gExtFwBlock[i].fileInfo.fileSize + sizeof(EXT_FW_HEADER), 4); p += ALIGN(gExtFwBlock[i].fileInfo.fileSize + sizeof(EXT_FW_HEADER), 4); } } if (use_nand_flash) { /* FwID md5 content: bootloader + tpHeader + kernel + rootfs + (servicefs ? )+ extBlock */ fillTpHeader(fwBase + uhTagLength + mi.fdtLen, mi.bootloaderLen + mi.tpHeaderLen + mi.kernelLen + mi.rootfsLen + (SUPPORT_SPMINIOS ? serviceFileInfo.fileSize : 0) + \ sizeof(BLOCK_HEADER) + gExtModuleSpecBlockLen + gExtFwBlockLen); DBG("fill tpheader done %s()-%d", __FUNCTION__, __LINE__); fwLen = uhTagLength + mi.fdtLen + mi.bootloaderLen; fwLen += mi.tpHeaderLen + mi.kernelLen + mi.rootfsLen; fwLen += (SUPPORT_SPMINIOS ? serviceFileInfo.fileSize : 0); fwLen += sizeof(BLOCK_HEADER) + gExtModuleSpecBlockLen + gExtFwBlockLen; DBG("3004:mi.fdtLen is %d", mi.fdtLen); DBG("up_boot fwLen:0x%x", fwLen); DBG("up_boot (p - fwBase):0x%x", (p - fwBase)); if (fwLen != (p - fwBase)) { ERR("fwLen is wrong!!! pls fix!!!"); exit(1); } } /* FwID md5 content: bootloader + tpHeader + kernel + romfs + extFwBlock */ else { if (SUPPORT_SPMINIOS) { fillTpHeader(fwBase + uhTagLength + mi.fdtLen, fwLen - uhTagLength - mi.fdtLen - VERIFY_SIZE - USER_RECORD_PARTITION_SIZE); } else { fillTpHeader(fwBase + uhTagLength + mi.fdtLen, fwLen - uhTagLength - mi.fdtLen - mi.jffs2fsLen - (mi.jffs2fsOffset - mi.rootfsOffset - mi.rootfsLen)); } DBG("fill tpheader done %s()-%d", __FUNCTION__, __LINE__); } } else { if(use_nand_flash) { ERR("not adapt,if adapt pls attention fwLen"); exit(1); } else { p = buf + mi.jffs2fsOffset; DBG("read BlockHeader to 0x%x sizeof(BLOCK_HEADER):0x%x",p - buf, sizeof(BLOCK_HEADER)); memcpy(p, &gBlockHeader, sizeof(BLOCK_HEADER)); p += sizeof(BLOCK_HEADER); /* 往up_boot.bin固件的jffs2fsOffset中写module_spec */ if (0 != gExtModuleSpecBlockNum) { ret = packExtModuleSpec(&gExtModuleSpecBlock, p); if (ret) { goto out_free_buf; } p += ALIGN(gExtModuleSpecBlock.fileInfo.fileSize + sizeof(EXT_MODULE_SPEC_HEADER), 4); } /* FwID md5 content: bootloader + tpHeader + kernel + romfs */ if (SUPPORT_SPMINIOS) { fillTpHeader(fwBase + uhTagLength + mi.fdtLen, fwLen - uhTagLength - mi.fdtLen); } else { fillTpHeader(fwBase + uhTagLength + mi.fdtLen, fwLen - uhTagLength - mi.fdtLen - mi.jffs2fsLen); } DBG("fill tpheader done %s()-%d", __FUNCTION__, __LINE__); } } if(use_nand_flash) { snprintf(tpheaderName, FIRMWARE_NAME_MAXLEN, "%s/%s", outputPath, "tpheader.bin"); DBG("write tpheader.bin"); writeToBinFile(fwBase + uhTagLength + mi.fdtLen + mi.bootloaderLen, mi.tpHeaderLen, tpheaderName); } if (gUpbootBuildTimes != 1) { if (!use_nand_flash) { fwLen = uhTagLength + mi.fdtLen + mi.bootloaderLen; fwLen += mi.jffs2fsOffset - mi.tpHeaderOffset + sizeof(BLOCK_HEADER) + gExtModuleSpecBlockLen + ext_fw_file_len; fwLen -= (mi.jffs2fsOffset - mi.rootfsOffset - mi.rootfsLen); if (SUPPORT_SPMINIOS) { if (is_larger_jffs2) { fwLen += serviceFileInfo.fileSize; DBG("block offset:0x%x\n", fwLen-(sizeof(BLOCK_HEADER) + gExtModuleSpecBlockLen + ext_fw_file_len)); } else { fwLen += mi.jffs2fsLen; #ifdef SLP_CAMERA_SUPPORT /* SLP机型在jffs2结束和block之间多预留了verify分区的大小,计算固件长度时需要加上这部分 */ fwLen += VERIFY_SIZE; #endif } } } ret = writeFw(fwBase, fwLen, outputPath, "up_boot.bin", TRUE); if (ret != EXIT_SUCCESS) { goto out_free_buf; } if(gUpbootBuildTimes == 0) { gUpbootBuildTimes = 1; } } /* then deal with flash.bin */ if (1 == gNoPackUboot) { /* clear up header and factory_boot filled in up_boot.bin */ memset(fwBase, 0xff, uhTagLength + mi.fdtLen + mi.bootloaderLen); } else { /* clear up header filled in up_boot.bin */ memset(fwBase, 0xff, uhTagLength + mi.fdtLen); } fwBase = buf; fwLen =layout->flashSize; DBG("reset to 0xff from:0x%x len:0x%x", mi.rootfsOffset + mi.rootfsLen, mi.jffs2fsOffset - mi.rootfsOffset - mi.rootfsLen); if(mi.jffs2fsOffset - mi.rootfsOffset - mi.rootfsLen > 0) { ERR("rootfs is not aligned"); memset(buf + mi.rootfsOffset + mi.rootfsLen, 0xff , mi.jffs2fsOffset - mi.rootfsOffset - mi.rootfsLen); } /* 往flash.bin中写入default isp_config */ if (gExtFwUpgrade) { p = NULL; for (i = 0; i < gExtFwBlockNum; i++) { /* 将 default extFw 写入 radio 分区,即往 flash.bin 写入 default isp_config */ if (0 == strcasecmp(gExtFwBlock[i].deviceName, DEFAULT_EXT_FW_NAME)) { p = buf + mi.radioOffset; if (useLittleFs) { if (gExtFwBlock[i].lfsFileInfo.fileSize > mi.radioLen) { DBG("radio sector[size 0x%08x] is not enough to write isp file [size 0x%08x]", mi.radioLen, gExtFwBlock[i].fileInfo.fileSize); ret = EXIT_FAILURE; goto out_free_buf; } ret = packExtLfsFw(&gExtFwBlock[i], p, outputPath); if (ret) { goto out_free_buf; } } else { if (sizeof(EXT_FW_HEADER) + gExtFwBlock[i].fileInfo.fileSize > mi.radioLen) { DBG("radio sector[size 0x%08x] is not enough to write isp file [size 0x%08x]", mi.radioLen, sizeof(EXT_FW_HEADER) + gExtFwBlock[i].fileInfo.fileSize); ret = EXIT_FAILURE; goto out_free_buf; } ret = packExtFw(&gExtFwBlock[i], p, outputPath); if (ret) { goto out_free_buf; } } } } /* 如果 ext_fw.config中 没有找到 default,那么往flash.bin的radio写入ext_Fw.config 中的第一个 block */ if (NULL == p) { if (useLittleFs) { if (gExtFwBlock[0].lfsFileInfo.fileSize > mi.radioLen) { DBG("radio sector[size 0x%08x] is not enough to write isp file [size 0x%08x]", mi.radioLen, gExtFwBlock[0].fileInfo.fileSize); ret = EXIT_FAILURE; goto out_free_buf; } ret = packExtLfsFw(&gExtFwBlock[0], buf + mi.radioOffset, outputPath); if (ret) { goto out_free_buf; } } else { if (sizeof(EXT_FW_HEADER) + gExtFwBlock[0].fileInfo.fileSize > mi.radioLen) { DBG("radio sector[size 0x%08x] is not enough to write isp file [size 0x%08x]", mi.radioLen, sizeof(EXT_FW_HEADER) + gExtFwBlock[0].fileInfo.fileSize); ret = EXIT_FAILURE; goto out_free_buf; } ret = packExtFw(&gExtFwBlock[0], buf + mi.radioOffset, outputPath); if (ret) { goto out_free_buf; } } /* nand flash生成一份默认isp参数,便于estar命令直接写入flash */ if (use_nand_flash) { snprintf(ispConfigName, FIRMWARE_NAME_MAXLEN, "%s/isp_config/%s.isp_config", outputPath, gExtFwBlock[0].deviceName); snprintf(ispDefaultName, FIRMWARE_NAME_MAXLEN, "%s/isp_config/%s.isp_config", outputPath, DEFAULT_EXT_FW_NAME); snprintf(cp_cmd, 1024, "cp \"%s\" \"%s\"", ispConfigName, ispDefaultName); system(cp_cmd); } } } /* 由于打包 up_boot 时填入 ispconfig,需要将 jffs2 写入deadcode */ if (USER_RECORD_PARTITION_SIZE > 0) { if (0 == use_nand_flash) { if (gUseJffs2) { ERR("\n=============================Now not support to enable both CONFIG_USES_JFFS2 and CONFIG_TAPO_USR_DEF_AUDIO_ALARM!!! Please check.============\n"); abort(); } user_record_alarm_offset = layout->flashSize - VERIFY_SIZE - USER_RECORD_PARTITION_SIZE; if (NULL == jffs2FileInfo.fileName || 0 == jffs2FileInfo.fileSize) { memcpy(buf + user_record_alarm_offset, jffs2EofMark, sizeof(jffs2EofMark)); } else { if (readToBuf(&jffs2FileInfo, buf + user_record_alarm_offset)) { goto out_free_buf; } } } else { DBG("\n==========use nand flash?!!!!!!!============\n"); } } else { if (gUseJffs2 && use_nand_flash == 0) { if (jffs2FileInfo.fileName == NULL || jffs2FileInfo.fileSize == 0) { if (SUPPORT_SPMINIOS) { } else { memcpy(buf + mi.jffs2fsOffset, jffs2EofMark, sizeof(jffs2EofMark)); } } else { if (jffs2FileInfo.fileSize > mi.jffs2fsLen) { ERR("not enough space for jffs2."); goto out_free_buf; } if (readToBuf(&jffs2FileInfo, buf + mi.jffs2fsOffset)) { goto out_free_buf; } } } } /* fill factory boot */ p = buf; ret = readToBuf(&factorybootInfo, p); if (ret) { goto out_free_buf; } /* prefill factory info area */ p = buf + mi.factoryInfoOffset; facinfo_len = fillFactoryInfo(p, devName); if (facinfo_len == -1) { goto out_free_buf; } if(use_nand_flash) { snprintf(factoryInfoName, FIRMWARE_NAME_MAXLEN, "%s/%s", outputPath, "factory_info.bin"); DBG("write factory_info.bin"); writeToBinFile(p, facinfo_len, factoryInfoName); } /* fill uc partition with uc file */ p = buf + mi.ucOffset; ret = readToBuf(&ucFileInfo, p); if (ret) { goto out_free_buf; } if(use_nand_flash) { ;//dont pack flash.bin image } else { ret = writeFw(fwBase, fwLen, outputPath, "flash.bin", FALSE); if (ret != EXIT_SUCCESS) { goto out_free_buf; } } DBG("make firmware done"); ret = EXIT_SUCCESS; out_free_buf: if (buf) { free(buf); } out: return ret; }详细解析一下
最新发布
09-10
以下是对 `buildFw()` 函数的**逐行详细解析**,包括其作用、逻辑流程、关键结构体、调用函数、内存布局以及固件打包的全过程。 --- ## 🧱 函数定义 ```c static int buildFw(const char* outputPath, const char *devName) ``` ### ✅ 作用: 构建完整的固件镜像(如 `up_boot.bin` 和 `flash.bin`),将多个组件(如 bootloader、kernel、rootfs、tpheader、模块规格、扩展固件等)按照特定布局打包进一个缓冲区,并最终写入输出文件。 --- ## 📦 主要变量说明 | 变量 | 类型 | 含义 | |------|------|------| | `buf` | `char*` | 固件缓冲区,用于构建固件镜像 | | `p` | `char*` | 当前写入指针,用于在 `buf` 中移动 | | `fwBase` | `char*` | 固件起始地址 | | `fwLen` | `int` | 固件总长度 | | `layout` | `FLASH_LAYOUT*` | Flash 布局信息(大小、加载地址等) | | `gBlockHeader` | `BLOCK_HEADER` | 扩展块头部信息(模块规格、扩展固件) | | `mi` | `FIRMWARE_LAYOUT` | 固件布局结构,包含各个分区的偏移和长度 | | `use_nand_flash` | `int` | 是否使用 NAND Flash | | `gExtFwUpgrade` | `int` | 是否启用扩展固件升级功能 | --- ## 🧩 主要流程详解 ### 1. **计算缓冲区大小** ```c int bufLen = layout->flashSize + sizeof(BLOCK_HEADER) + gExtModuleSpecBlockLen; ``` - `layout->flashSize`:Flash 总容量(如 4MB) - `sizeof(BLOCK_HEADER)`:扩展块头部大小 - `gExtModuleSpecBlockLen`:模块规格文件长度 如果启用了扩展固件升级(`gExtFwUpgrade`): ```c bufLen += gExtFwBlockLen; ``` --- ### 2. **分配内存** ```c buf = (char *)malloc(bufLen); if (!buf) { ERR("no memory for buffer"); goto out_free_buf; } ``` - 分配固件缓冲区,失败则跳转到 `out_free_buf` 释放内存。 --- ### 3. **初始化缓冲区** ```c memset(buf, 0xff, bufLen); ``` - 将缓冲区初始化为全 `0xff`(Flash 默认值)。 --- ### 4. **确定固件起始地址 `fwBase`** 根据是否跳过 U-Boot 打包(`gNoPackUboot`)来决定起始地址: ```c if (1 == gNoPackUboot) { fwBase = buf + mi.tpHeaderOffset - mi.fdtLen - mi.bootloaderLen - uhTagLength; } else { fwBase = buf + mi.bootloaderOffset - mi.fdtLen - uhTagLength; } ``` --- ### 5. **读取设备树(FDT)** ```c p = buf + mi.bootloaderOffset - mi.fdtLen; ret = readToBuf(&fdtInfo, p); ``` - 读取设备树文件(`.dts` 或 `.dtb`)到指定位置。 --- ### 6. **读取内核(kernel)** ```c p = buf + mi.kernelOffset; ret = readToBuf(&kernelInfo, p); ``` - 将内核文件读入缓冲区。 --- ### 7. **读取根文件系统(rootfs)** ```c p += mi.kernelLen; ret = readToBuf(&rootfsInfo, p); ``` - 读取 rootfs 文件到缓冲区。 --- ### 8. **加密 rootfs 头部(可选)** ```c if(encrypt_rootfs_header) { _AES_cfb1_encrypt_rijndael(...); memcpy(p, encrypt_rootfs_header_buffer, ENCRYPT_ROOTFS_HEADER_SIZE); } ``` - 如果启用 rootfs 加密,加密前几个字节并覆盖。 --- ### 9. **处理 jffs2 文件系统(可选)** ```c if (mi.jffs2fsOffset != 0) { p += mi.rootfsLen; ret = readToBuf(&serviceFileInfo, p); } ``` - 如果启用 `SUPPORT_SPMINIOS`,读取 service 文件系统。 --- ### 10. **读取 bootloader** ```c p = buf + mi.bootloaderOffset; ret = readToBuf(&bootloaderInfo, p); ``` - 读取 U-Boot 到指定位置。 --- ### 11. **处理扩展固件(ext_fw)** ```c if (gExtFwUpgrade) { p = buf + mi.jffs2fsOffset + serviceFileInfo.fileSize; memcpy(p, &gBlockHeader, sizeof(BLOCK_HEADER)); p += sizeof(BLOCK_HEADER); } ``` - 拷贝扩展块头到缓冲区。 --- ### 12. **打包模块规格文件(module_spec.config)** ```c if (0 != gExtModuleSpecBlockNum) { ret = packExtModuleSpec(&gExtModuleSpecBlock, p); p += ALIGN(...); } ``` - 将模块规格文件打包进固件。 --- ### 13. **打包扩展固件(如 isp_config)** ```c for (i = 0; i < gExtFwBlockNum; i++) { if (gExtFwBlock[i].add) { ret = packExtFw(&gExtFwBlock[i], p, outputPath); p += ALIGN(...); } } ``` - 遍历所有扩展固件块,按需打包。 --- ### 14. **填充 TP_HEADER** ```c fillTpHeader(fwBase + uhTagLength + mi.fdtLen, ...); ``` - 填充固件头部,包含各分区偏移、长度、MD5 校验等信息。 --- ### 15. **写入 up_boot.bin** ```c ret = writeFw(fwBase, fwLen, outputPath, "up_boot.bin", TRUE); ``` - 将打包好的固件写入 `up_boot.bin` 文件。 --- ### 16. **清空 up_boot.bin 的 U-Boot 区域** ```c memset(fwBase, 0xff, uhTagLength + mi.fdtLen); ``` - 清空已写入的区域,为 `flash.bin` 做准备。 --- ### 17. **构建 flash.bin** ```c fwBase = buf; fwLen = layout->flashSize; ``` - 重新设置起始地址和长度。 --- ### 18. **写入默认扩展固件(如 isp_config)** ```c for (i = 0; i < gExtFwBlockNum; i++) { if (0 == strcasecmp(gExtFwBlock[i].deviceName, DEFAULT_EXT_FW_NAME)) { ret = packExtFw(&gExtFwBlock[i], buf + mi.radioOffset, outputPath); } } ``` - 将默认扩展固件写入 radio 分区。 --- ### 19. **写入用户自定义数据(如 alarm)** ```c memcpy(buf + user_record_alarm_offset, jffs2EofMark, sizeof(jffs2EofMark)); ``` - 如果启用了用户自定义音频告警功能,写入 EOF 标志。 --- ### 20. **写入 factory boot 和 factory info** ```c ret = readToBuf(&factorybootInfo, buf); facinfo_len = fillFactoryInfo(buf + mi.factoryInfoOffset, devName); ``` - 写入 factory boot 和 factory info 分区内容。 --- ### 21. **写入 uc 分区** ```c p = buf + mi.ucOffset; ret = readToBuf(&ucFileInfo, p); ``` - 写入 uc 分区文件。 --- ### 22. **写入 flash.bin** ```c ret = writeFw(fwBase, fwLen, outputPath, "flash.bin", FALSE); ``` - 将打包好的固件写入 `flash.bin` 文件。 --- ## 🧱 关键结构体说明 ### 1. `FIRMWARE_LAYOUT mi` 记录固件各分区偏移和长度: ```c { .bootloaderOffset = 0x0000, .kernelOffset = 0x20000, .rootfsOffset = 0x200000, ... } ``` ### 2. `FLASH_LAYOUT *layout` 记录 Flash 容量和加载地址: ```c { .id = "4M", .flashSize = 0x400000, .kernelLoadAddress = 0x80060000, } ``` ### 3. `BLOCK_HEADER gBlockHeader` 记录扩展块信息: ```c { .num = 2, .info[0] = { .type = CONTENT_TYPE_MODULE_SPEC, .length = 0x1000 }, .info[1] = { .type = CONTENT_TYPE_ISP_CONFIG, .length = 0x2000 }, } ``` --- ## 📦 调用函数说明 | 函数名 | 作用 | |--------|------| | `readToBuf()` | 读取文件内容到内存缓冲区 | | `packExtModuleSpec()` | 打包模块规格文件 | | `packExtFw()` | 打包扩展固件(如 isp_config) | | `fillTpHeader()` | 填充 TP_HEADER | | `writeFw()` | 写入二进制固件文件 | | `fillFactoryInfo()` | 填充 factory info 分区 | --- ## 🧠 总结一句话: > `buildFw()` 函数通过分配缓冲区、依次读取并打包 bootloader、kernel、rootfs、模块规格、扩展固件等组件,并填充头部信息,最终生成 `up_boot.bin` 和 `flash.bin` 固件镜像。 --- ##
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值