<linux> uimage头部信息详解

一、uboot中的源码展示

随便找一个主线uboot,在uboot根目录下的include/image.h文件,定义了uboot头部信息的结构体。

/*
 * Legacy format image header,
 * all data in network byte order (aka natural aka bigendian).
 */
typedef struct image_header {
        __be32          ih_magic;       /* Image Header Magic Number  0x27051956  */
        __be32          ih_hcrc;        /* Image Header CRC Checksum    */
        __be32          ih_time;        /* Image Creation Timestamp     */
        __be32          ih_size;        /* Image Data Size              */
        __be32          ih_load;        /* Data  Load  Address          */
        __be32          ih_ep;          /* Entry Point Address          */
        __be32          ih_dcrc;        /* Image Data CRC Checksum      */
        uint8_t         ih_os;          /* Operating System             */
        uint8_t         ih_arch;        /* CPU architecture             */
        uint8_t         ih_type;        /* Image Type                   */
        uint8_t         ih_comp;        /* Compression Type             */
        uint8_t         ih_name[IH_NMLEN];      /* Image Name           */
} image_header_t;

  1. ih_magic:魔术字,固定为0x27051956,占4字节,方便uboot判断要启动的镜像是否为uimage格式。
  2. ih_hcrc:整个头部的crc32校验,32位校验,所以占4字节。
  3. ih_time:时间戳,占4字节,为16进制,表示uimage生成的时间
  4. ih_size:镜像数据大小,即除去头部信息外的数据大小,占4字节。
  5. ih_load:镜像数据的解压地址,uboot启动过程中,需要将镜像数据解压到DDR的地址位置。占4字节。
  6. ih_ep:镜像解压后,启动镜像的地址位置,占4字节。
  7. ih_dcrc除去头部信息外,所有镜像数据的crc32校验数值,占4字节。
  8. ih_os:表示镜像是什么操作系统下的镜像。 占1字节
  9. ih_arch:表示镜像所属的cpu架构,如arm、mips等。
  10. ih_type镜像类型,占1字节。
  11. ih_comp:镜像的压缩类型,如gzip、lzma等,占1字节。
  12. ih_name[IHNMLEN]: 镜像的名称。占32字节。 即名称最长32个字符

整个头部信息,占用64字节,即0x40长度。

二、实例分析

以AP136固件的uboot header为例分析
在这里插入图片描述

AP136的kernel分区在后,所以镜像位置是从0x00630000开始,头部信息占用0x40长度,所以到0x00630040结束。


1、ih_magic(魔术字)

首先可以看到27 05 19 56,即0x27051956,为uboot头部信息的魔术字,可以看到该镜像是个uimage格式的镜像。这里可以看到该镜像的存储方式是大端模式,即低地址,存放高位数据


2、ih_hcrc(头部crc32校验)

接下来四字节DB 85 93 13,表示头部的crc32校验,使用win32将头部信息截取出来
在这里插入图片描述
同时将校验位设置为0,因为没有计算校验之前,是0。
在这里插入图片描述

使用linux的crc32工具,算出其校验值。

crc32 uboot_header.bin
db859313

可以看到计算出来的结果与uboot head中的DB 85 93 13一致。 这里要注意,计算crc32之前一定要将校验位设置为0.


3、ih_time(时间戳)

再往后读取4字节,60 3C E8 2A,即为时间戳。即0x603CE82A,转换为10进制为1614604330
使用时间戳转换工具,可以看到镜像生成的时间是2021-03-01 21:12:10
在这里插入图片描述


4、ih_size(镜像大小)

再读取4字节,00 14 4F E8,0x00144FE8,转换为10进制为1331176字节。将除去uboot head以外的数据截取出来。
在这里插入图片描述
可以到大小为1131176字节。
在这里插入图片描述


5、ih_load(解压地址)

往后读取4字节, 80 06 00 00,即0x8060 0000这个地址,uboot需要将镜像解压到该地址。


6、ih_ep (启动地址)

往后读取4字节,80 06 00 00,即0x8060 0000,可以看到启动镜像的地址,即解压地址。


7、ih_dcrc(镜像crc32校验)

往后读取4字节,为镜像数据的crc32校验,6B BD 55 AF, 同样我们将提取出来的kernel进行crc32计算

crc32 kernel.bin
6bbd55af

没问题,与头部信息一致。


8、ih_os (镜像操作系统类型)

读取1字节,05, os类型, 5对应位linux, 在uboot根目录下的include/image.h可以看到。

/*
 * Operating System Codes
 */
#define IH_OS_INVALID           0       /* Invalid OS   */
#define IH_OS_OPENBSD           1       /* OpenBSD      */
#define IH_OS_NETBSD            2       /* NetBSD       */
#define IH_OS_FREEBSD           3       /* FreeBSD      */
#define IH_OS_4_4BSD            4       /* 4.4BSD       */
#define IH_OS_LINUX             5       /* Linux        */
#define IH_OS_SVR4              6       /* SVR4         */
#define IH_OS_ESIX              7       /* Esix         */
#define IH_OS_SOLARIS           8       /* Solaris      */
#define IH_OS_IRIX              9       /* Irix         */
#define IH_OS_SCO               10      /* SCO          */
#define IH_OS_DELL              11      /* Dell         */
#define IH_OS_NCR               12      /* NCR          */
#define IH_OS_LYNXOS            13      /* LynxOS       */
#define IH_OS_VXWORKS           14      /* VxWorks      */
#define IH_OS_PSOS              15      /* pSOS         */
#define IH_OS_QNX               16      /* QNX          */
#define IH_OS_U_BOOT            17      /* Firmware     */
#define IH_OS_RTEMS             18      /* RTEMS        */
#define IH_OS_ARTOS             19      /* ARTOS        */
#define IH_OS_UNITY             20      /* Unity OS     */
#define IH_OS_INTEGRITY         21      /* INTEGRITY    */
#define IH_OS_OSE               22      /* OSE          */
#define IH_OS_PLAN9             23      /* Plan 9       */
#define IH_OS_OPENRTOS          24      /* OpenRTOS     */


9、ih_arch(架构类型)

再读取1字节, 05, 架构类型,对应mips架构,在uboot根目录下的include/image.h可以看到。

/*
* CPU Architecture Codes (supported by Linux)
*/
#define IH_ARCH_INVALID         0       /* Invalid CPU  */
#define IH_ARCH_ALPHA           1       /* Alpha        */
#define IH_ARCH_ARM             2       /* ARM          */
#define IH_ARCH_I386            3       /* Intel x86    */
#define IH_ARCH_IA64            4       /* IA64         */
#define IH_ARCH_MIPS            5       /* MIPS         */
#define IH_ARCH_MIPS64          6       /* MIPS  64 Bit */
#define IH_ARCH_PPC             7       /* PowerPC      */
#define IH_ARCH_S390            8       /* IBM S390     */
#define IH_ARCH_SH              9       /* SuperH       */
#define IH_ARCH_SPARC           10      /* Sparc        */
#define IH_ARCH_SPARC64         11      /* Sparc 64 Bit */
#define IH_ARCH_M68K            12      /* M68K         */
#define IH_ARCH_MICROBLAZE      14      /* MicroBlaze   */
#define IH_ARCH_NIOS2           15      /* Nios-II      */
#define IH_ARCH_BLACKFIN        16      /* Blackfin     */
#define IH_ARCH_AVR32           17      /* AVR32        */
#define IH_ARCH_ST200           18      /* STMicroelectronics ST200  */
#define IH_ARCH_SANDBOX         19      /* Sandbox architecture (test only) */
#define IH_ARCH_NDS32           20      /* ANDES Technology - NDS32  */
#define IH_ARCH_OPENRISC        21      /* OpenRISC 1000  */
#define IH_ARCH_ARM64           22      /* ARM64        */
#define IH_ARCH_ARC             23      /* Synopsys DesignWare ARC */
#define IH_ARCH_X86_64          24      /* AMD x86_64, Intel and Via */

10、ih_type(镜像类型)

再读取1字节, 02,表示镜像类型,对应为os kernel image,操作系统镜像。同样在uboot根目录下的include/image.h可以看到。

#define IH_TYPE_INVALID         0       /* Invalid Image                */
#define IH_TYPE_STANDALONE      1       /* Standalone Program           */
#define IH_TYPE_KERNEL          2       /* OS Kernel Image              */
#define IH_TYPE_RAMDISK         3       /* RAMDisk Image                */
#define IH_TYPE_MULTI           4       /* Multi-File Image             */
#define IH_TYPE_FIRMWARE        5       /* Firmware Image               */
#define IH_TYPE_SCRIPT          6       /* Script file                  */
#define IH_TYPE_FILESYSTEM      7       /* Filesystem Image (any type)  */
#define IH_TYPE_FLATDT          8       /* Binary Flat Device Tree Blob */
#define IH_TYPE_KWBIMAGE        9       /* Kirkwood Boot Image          */
#define IH_TYPE_IMXIMAGE        10      /* Freescale IMXBoot Image      */
#define IH_TYPE_UBLIMAGE        11      /* Davinci UBL Image            */
#define IH_TYPE_OMAPIMAGE       12      /* TI OMAP Config Header Image  */
#define IH_TYPE_AISIMAGE        13      /* TI Davinci AIS Image         */
#define IH_TYPE_KERNEL_NOLOAD   14      /* OS Kernel Image, can run from any load address */
#define IH_TYPE_PBLIMAGE        15      /* Freescale PBL Boot Image     */
#define IH_TYPE_MXSIMAGE        16      /* Freescale MXSBoot Image      */
#define IH_TYPE_GPIMAGE         17      /* TI Keystone GPHeader Image   */
#define IH_TYPE_ATMELIMAGE      18      /* ATMEL ROM bootable Image     */
#define IH_TYPE_SOCFPGAIMAGE    19      /* Altera SOCFPGA Preloader     */
#define IH_TYPE_X86_SETUP       20      /* x86 setup.bin Image          */
#define IH_TYPE_LPC32XXIMAGE    21      /* x86 setup.bin Image          */
#define IH_TYPE_LOADABLE        22      /* A list of typeless images    */
#define IH_TYPE_RKIMAGE         23      /* Rockchip Boot Image          */
#define IH_TYPE_RKSD            24      /* Rockchip SD card             */
#define IH_TYPE_RKSPI           25      /* Rockchip SPI image           */
#define IH_TYPE_ZYNQIMAGE       26      /* Xilinx Zynq Boot Image */

#define IH_TYPE_COUNT           27      /* Number of image types */

11、ih_comp(镜像压缩类型)

再读取1字节, 03, 镜像的压缩算法类型,对应lzma压缩类型。同样在uboot根目录下的include/image.h可以看到。

/*
 * Compression Types
 */
#define IH_COMP_NONE            0       /*  No   Compression Used       */
#define IH_COMP_GZIP            1       /* gzip  Compression Used       */
#define IH_COMP_BZIP2           2       /* bzip2 Compression Used       */
#define IH_COMP_LZMA            3       /* lzma  Compression Used       */
#define IH_COMP_LZO             4       /* lzo   Compression Used       */
#define IH_COMP_LZ4             5       /* lz4   Compression Used       */

12、ih_name(镜像名称)

读取剩余的32字节。名称为MIPS OpenWrt Linux-4.4.194
在这里插入图片描述


三、总结

  1. uboot头部占64字节。 为了方便uboot启动镜像,即bootm命令。
  2. 头部信息包括,魔术字(4)、头部crc32校验(4)、生成uimage的时间戳(4)、镜像数据大小(4)、解压地址(4)、启动地址(4)、镜像数据crc32校验(4)、镜像操作系统类型(1)、镜像架构类型(1)、镜像类型(1)、镜像压缩算法类型(1)、镜像名称(32).
  3. 计算头部crc32时,需要将校验位设置为0.
  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux 系统中,可以通过 `zlib` 库来进行 `gzip` 压缩和解压缩操作。如果要解压 `uImage.gz` 文件,可以使用 `zlib` 库提供的函数来完成。 下面是一个使用 `zlib` 库来解压 `uImage.gz` 文件的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <zlib.h> #define CHUNK_SIZE 1024 int main(int argc, char *argv[]) { gzFile infile; char *outfile_name; FILE *outfile; char buffer[CHUNK_SIZE]; int bytes_read; int ret; if (argc < 2) { fprintf(stderr, "Usage: %s uImage.gz\n", argv[0]); return -1; } /* 打开 gzip 文件 */ infile = gzopen(argv[1], "rb"); if (!infile) { fprintf(stderr, "Error: failed to open %s\n", argv[1]); return -1; } /* 构造输出文件名 */ outfile_name = (char *)malloc(strlen(argv[1]) - 2); strncpy(outfile_name, argv[1], strlen(argv[1]) - 3); strcat(outfile_name, "\0"); /* 打开输出文件 */ outfile = fopen(outfile_name, "wb"); if (!outfile) { fprintf(stderr, "Error: failed to create %s\n", outfile_name); return -1; } /* 逐块解压并写入输出文件 */ while ((bytes_read = gzread(infile, buffer, CHUNK_SIZE)) > 0) { ret = fwrite(buffer, 1, bytes_read, outfile); if (ret < bytes_read) { fprintf(stderr, "Error: failed to write to %s\n", outfile_name); return -1; } } /* 关闭文件 */ gzclose(infile); fclose(outfile); free(outfile_name); printf("Done.\n"); return 0; } ``` 上面的代码中,我们先通过 `gzopen()` 函数打开 `uImage.gz` 文件,并指定以二进制(`"rb"`)方式打开。然后,我们通过 `malloc()` 函数动态分配内存,构造输出文件名,并打开输出文件。 接着,我们使用 `gzread()` 函数逐块从 `uImage.gz` 文件中读取数据,并通过 `fwrite()` 函数将解压后的数据写入到输出文件中。最后,我们通过 `gzclose()` 和 `fclose()` 函数关闭打开的文件,并使用 `free()` 函数释放动态分配的内存。 注意,在解压 `uImage.gz` 文件时,我们只需要解压文件头之后的数据部分,因此输出文件名中去掉了 ".gz" 后缀。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值