# [Record] An analysis of the image header in uImage
###### tags: `mkimage`, `dumpimage`, `iminfo`, `uimage`
[toc]
## Introduction
In this note, I will show how to list image header in uimage through mkimage, dumpimage and iminfo.
Before booting into linux kernel, uboot will check if an uimage is good for boot. It check the image header information in uimage including **image header/data checksum (crc32), magic number, architecture, and image format** and so on.
In fact, ++**uimage**++ = ++**zimage + image header**++.
- zimage is created when compiling kernel.
- uimage is created by a tool mkimage.
- mkimage adds the image header into zimage.
- The image header is 64 bytes including
- Image Name
- Compression Type
- Image Type
- CPU architecture
- Operating System
- Image Data CRC Checksum
- Entry Point Address
- Data Load Address
- Image Data Size
- Image Creation Timestamp
- Image Header CRC Checksum
- Image Header Magic Number
- During booting, u-boot will probably dump the header as shown below.
</br>
:::spoiler
```python=
Serial-COM5-18:13:54.930 ## Booting kernel from Legacy Image at 81000000 ...
Serial-COM5-18:13:54.931 Image Name: Linux-3.18.24
Serial-COM5-18:13:54.931 Created: 2020-07-03 10:04:30 UTC
Serial-COM5-18:13:54.943 Image Type: MIPS Linux Kernel Image (gzip compressed)
Serial-COM5-18:13:54.943 Data Size: 1985547 Bytes = 1.9 MB
Serial-COM5-18:13:54.943 Load Address: 80000000
Serial-COM5-18:13:54.953 Entry Point: 8027a050
Serial-COM5-18:13:54.997 Verifying Checksum ... OK
Serial-COM5-18:13:55.212 Uncompressing Kernel Image ... OK
```
:::
</br>
- Contents of image header can be dumpped by tools like dumpimage, mkimage or iminfo as shown below.
1. *dumpimage -l uimage*
2. *mkimage -l uimage*
3. *iminfo 0x80000000*
## Image header
Below figure shows the format of image header.
<div style="text-align: center"><img src="https://i.imgur.com/BHaEoL4.png"/></div></br>
And we can see the image header structrue and field definition in the code as below.
```C
//in include/image.h
/*
* Legacy format image header,
* all data in network byte order (aka natural aka bigendian).
*/
/*
* 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 */
/*
* 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 */
/*
* Image Types
*
* "Standalone Programs" are directly runnable in the environment
* provided by U-Boot; it is expected that (if they behave
* well) you can continue to work in U-Boot after return from
* the Standalone Program.
* "OS Kernel Images" are usually images of some Embedded OS which
* will take over control completely. Usually these programs
* will install their own set of exception handlers, device
* drivers, set up the MMU, etc. - this means, that you cannot
* expect to re-enter U-Boot except by resetting the CPU.
* "RAMDisk Images" are more or less just data blocks, and their
* parameters (address, size) are passed to an OS kernel that is
* being started.
* "Multi-File Images" contain several images, typically an OS
* (Linux) kernel image and one or more data images like
* RAMDisks. This construct is useful for instance when you want
* to boot over the network using BOOTP etc., where the boot
* server provides just a single image file, but you want to get
* for instance an OS kernel and a RAMDisk image.
*
* "Multi-File Images" start with a list of image sizes, each
* image size (in bytes) specified by an "uint32_t" in network
* byte order. This list is terminated by an "(uint32_t)0".
* Immediately after the terminating 0 follow the images, one by
* one, all aligned on "uint32_t" boundaries (size rounded up to
* a multiple of 4 bytes - except for the last file).
*
* "Firmware Images" are binary images containing firmware (like
* U-Boot or FPGA images) which usually will be programmed to
* flash memory.
*
* "Script files" are command sequences that will be executed by
* U-Boot's command interpreter; this feature is especially
* useful when you configure U-Boot to use a real shell (hush)
* as command interpreter (=> Shell Scripts).
*/
#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 */
/*
* 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_MAGIC 0x27051956 /* Image Magic Number */
#define IH_NMLEN 32 /* Image Name Length */
typedef struct image_header {
uint32_t ih_magic; /* Image Header Magic Number */
uint32_t ih_hcrc; /* Image Header CRC Checksum */
uint32_t ih_time; /* Image Creation Timestamp */
uint32_t ih_size; /* Image Data Size */
uint32_t ih_load; /* Data Load Address */
uint32_t ih_ep; /* Entry Point Address */
uint32_t 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;
typedef struct image_info {
ulong start, end; /* start/end of blob */
ulong image_start, image_len; /* start of image within blob, len of image */
ulong load; /* load addr for the image */
uint8_t comp, type, os; /* compression, type of image, os type */
} image_info_t;
```
And we can analyze **uimage** as shown below.
```
Tomas# xxd uImage | head -n 4
00000000: 2705 1956 bbd0 650c 5f00 9db6 001e 4c40 '..V..e._.....L@
|Magic Num|HeaderCRC|Timestamp|ImageSize|
00000010: 8000 0000 8027 a050 c5ca 13e5 0505 0201 .....'.P........
|DLAddress|EPAddress|Data CRC |O|C|IT|CT|
00000020: 4c69 6e75 782d 332e 3138 2e32 3400 0000 Linux-3.18.24...
| Image Name |
00000030: 0000 0000 0000 0000 0000 0000 0000 0000 ................
| Image Name |
Tomas# ./mkimage -l uImage
Image Name: Linux-3.18.24
Created: Sat Jul 4 23:18:14 2020
Image Type: MIPS Linux Kernel Image (gzip compressed)
Data Size: 1985600 Bytes = 1939.06 KiB = 1.89 MiB
Load Address: 80000000
Entry Point: 8027a050
```
## Tool usages
### mkimage
```shell
Usage: ./mkimage -l image
-l ==> list image header information
./mkimage [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image
-A ==> set architecture to 'arch'
-O ==> set operating system to 'os'
-T ==> set image type to 'type'
-C ==> set compression type 'comp'
-a ==> set load address to 'addr' (hex)
-e ==> set entry point to 'ep' (hex)
-n ==> set image name to 'name'
-d ==> use image data from 'datafile'
-x ==> set XIP (execute in place)
./mkimage [-D dtc_options] [-f fit-image.its|-f auto|-F] [-b <dtb> [-b <dtb>]] [-i <ramdisk.cpio.gz>] fit-image
<dtb> file is used with -f auto, it may occur multiple times.
-D => set all options for device tree compiler
-f => input filename for FIT source
-i => input filename for ramdisk file
Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)
./mkimage -V ==> print version information and exit
Use '-T list' to see a list of available image types
```
```shell
Tomas# ./mkimage -l uimage
Image Name: Linux-3.18.24
Created: Sat Jul 4 00:47:55 2020
Image Type: MIPS Linux Kernel Image (gzip compressed)
Data Size: 1985572 Bytes = 1939.04 KiB = 1.89 MiB
Load Address: 80000000
Entry Point: 8027a050
```
### dumpimage
- host-uboot-tools-2018.07
- uboot-tools-2018.07
```shell
Usage: ./dumpimage -l image
-l ==> list image header information
./dumpimage -i image -T type [-p position] [-o outfile] data_file
-i ==> extract from the 'image' a specific 'data_file'
-T ==> set image type to 'type'
-p ==> 'position' (starting at 0) of the 'data_file' inside the 'image'
./dumpimage -V ==> print version information and exit
```
```shell
Tomas# ./dumpimage -l uimage
Image Name: Linux-3.18.24
Created: Sat Jul 4 15:22:51 2020
Image Type: MIPS Linux Kernel Image (gzip compressed)
Data Size: 1985731 Bytes = 1939.19 KiB = 1.89 MiB
Load Address: 80000000
Entry Point: 8027a050
```
### iminfo
First, we have to know the address of kernel in uboot.
```shell
Tomas # flashshow
=============== FLASH Partition Layout ===============
Index Name Size Address
------------------------------------------------------
0 LOADER 0xe0000 0xb5000000-0xb50dffff
1 BDINFO 0x10000 0xb50e0000-0xb50effff
2 SYSINFO 0x10000 0xb50f0000-0xb50fffff
3 KERNEL1 0x200000 0xb5100000-0xb52fffff
4 ROOTFS1 0x800000 0xb5300000-0xb5afffff
5 KERNEL2 0x200000 0xb5b00000-0xb5cfffff
6 ROOTFS2 0x800000 0xb5d00000-0xb64fffff
7 JFFS2_CFG 0xb00000 0xb6500000-0xb6ffffff
8 0xa00000 0xb5100000-0xb5afffff
9 MYDRV_INIT 0xa00000 0xb5b00000-0xb64fffff
======================================================
```
And now, we can use iminfo to check out the uimage.
```shell
Tomas# help iminfo
iminfo - print header information for application image
Usage:
iminfo addr [addr ...]
- print header information for application image starting at
address 'addr' in memory; this includes verification of the
image contents (magic number, header and payload checksums)
Tomas# iminfo b51000000
## Checking Image at 51000000 ...
Legacy image found
Image Name: Linux-3.18.24
Created: 2020-07-03 16:47:55 UTC
Image Type: MIPS Linux Kernel Image (gzip compressed)
Data Size: 1985572 Bytes = 1.9 MB
Load Address: 80000000
Entry Point: 8027a050
Verifying Checksum ... OK
```
## Image creation time
It is obvious to notice the "**Created:**" row in the image header info.
This field is the date time and it cannot be designated by users. It is created during make the uimage through the mkimage tool. In fact, it is an epoch timestamp and we can convert it to readable format through
```shell
Tomas# date -d @1593847381 +'%Y/%m/%d-%H:%M:%S'
2020/07/04-15:23:01
```
### Code flow to set timestamp of image creation
- For FIT uimage
```
[tools/fit_image.c]
fit_handle_file ->
fit_add_file_data ->
[tools/image-host.c]
fit_add_verification_data ->
fit_image_add_verification_data ->
fit_image_process_sig ->
fit_image_write_sig ->
fit_set_timestamp ->
[common/image-fit.c]
fit_set_timestamp
```
```C
// in common/image-fit.c
/**
* fit_set_timestamp - set node timestamp property
* @fit: pointer to the FIT format image header
* @noffset: node offset
* @timestamp: timestamp value to be set
*
* fit_set_timestamp() attempts to set timestamp property in the requested
* node and returns operation status to the caller.
*
* returns:
* 0, on success
* -ENOSPC if no space in device tree, -1 for other error
*/
int fit_set_timestamp(void *fit, int noffset, time_t timestamp)
{
uint32_t t;
int ret;
t = cpu_to_uimage(timestamp);
ret = fdt_setprop(fit, noffset, FIT_TIMESTAMP_PROP, &t,
sizeof(uint32_t));
if (ret) {
debug("Can't set '%s' property for '%s' node (%s)\n",
FIT_TIMESTAMP_PROP, fit_get_name(fit, noffset, NULL),
fdt_strerror(ret));
return ret == -FDT_ERR_NOSPACE ? -ENOSPC : -1;
}
return 0;
}
```
## Reference
https://linux.die.net/man/1/mkimage
https://linux.incomeself.com/u-boot%e5%95%9f%e5%8b%95kernel%e4%b9%8blegacy-uimage%e8%88%87fit-uimage%e7%9a%84%e5%8d%80%e5%88%a5/#more-129
https://b8807053.pixnet.net/blog/post/3612112
https://support.huawei.com/enterprise/en/doc/EDOC1100078631/e579921/iminfo
https://www.epochconverter.com/
https://www.rapidtables.com/convert/number/hex-to-ascii.html
https://elixir.bootlin.com/u-boot/latest/source/common/image-fit.c#L1155
https://elixir.bootlin.com/u-boot/latest/source/tools/image-host.c