Commit bce88370 authored by Marek Vasut's avatar Marek Vasut Committed by Stefano Babic

ARM: mxs: tools: Add mkimage support for MXS bootstream

Add mkimage support for generating and verifying MXS bootstream.
The implementation here is mostly a glue code between MXSSB v0.4
and mkimage, but the long-term goal is to rectify this and merge
MXSSB with mkimage more tightly. Once this code is properly in
U-Boot, MXSSB shall be deprecated in favor of mkimage-mxsimage

Note that the mxsimage generator needs libcrypto from OpenSSL, I
therefore enabled the libcrypto/libssl unconditionally.


The code is based on research presented at: default avatarMarek Vasut <>
Cc: Tom Rini <>
Cc: Fabio Estevam <>
Cc: Stefano Babic <>
Cc: Otavio Salvador <>
parent b83c709e
LOAD 0x0 spl/u-boot-spl.bin
CALL 0x14 0x0
LOAD 0x40000100 u-boot.bin
CALL 0x40000100 0x0
LOAD 0x0 spl/u-boot-spl.bin
LOAD IVT 0x8000 0x14
CALL HAB 0x8000 0x0
LOAD 0x40000100 u-boot.bin
LOAD IVT 0x8000 0x40000100
CALL HAB 0x8000 0x0
......@@ -135,6 +135,7 @@ static const table_entry_t uimage_type[] = {
{ IH_TYPE_SCRIPT, "script", "Script", },
{ IH_TYPE_STANDALONE, "standalone", "Standalone Program", },
{ IH_TYPE_UBLIMAGE, "ublimage", "Davinci UBL image",},
{ IH_TYPE_MXSIMAGE, "mxsimage", "Freescale MXS Boot Image",},
{ -1, "", "", },
......@@ -194,6 +194,15 @@ LDFLAGS_FINAL += --gc-sections
# TODO( Is this correct on Mac OS?
# MXSImage needs LibSSL
ifneq ($(CONFIG_MX23)$(CONFIG_MX28),)
HOSTLIBS += -lssl -lcrypto
# Add CONFIG_MXS into host CFLAGS, so we can check whether or not register
# the mxsimage support within tools/mxsimage.c .
HOSTLIBS += -lssl -lcrypto
Freescale i.MX233/i.MX28 SB image generator via mkimage
This tool allows user to produce SB BootStream encrypted with a zero key.
Such a BootStream is then bootable on i.MX23/i.MX28.
Usage -- producing image:
The mxsimage tool is targeted to be a simple replacement for the elftosb2 .
To generate an image, write an image configuration file and run:
mkimage -A arm -O u-boot -T mxsimage -n <path to configuration file> \
<output bootstream file>
The output bootstream file is usually using the .sb file extension. Note
that the example configuration files for producing bootable BootStream with
the U-Boot bootloader can be found under arch/arm/boot/cpu/arm926ejs/mxs/
directory. See the following files:
mxsimage.mx23.cfg -- This is an example configuration for i.MX23
mxsimage.mx28.cfg -- This is an example configuration for i.MX28
Each configuration file uses very simple instruction semantics and a few
additional rules have to be followed so that a useful image can be produced.
These semantics and rules will be outlined now.
- Each line of the configuration file contains exactly one instruction.
- Every numeric value must be encoded in hexadecimal and in format 0xabcdef12 .
- The configuration file is a concatenation of blocks called "sections" and
optionally "DCD blocks" (see below).
- Each "section" is started by the "SECTION" instruction.
- The "SECTION" instruction has the following semantics:
SECTION u32_section_number [BOOTABLE]
- u32_section_number :: User-selected ID of the section
- BOOTABLE :: Sets the section as bootable
- A bootable section is one from which the BootROM starts executing
subsequent instructions or code. Exactly one section must be selected
as bootable, usually the one containing the instructions and data to
load the bootloader.
- A "SECTION" must be immediatelly followed by a "TAG" instruction.
- The "TAG" instruction has the following semantics:
- LAST :: Flag denoting the last section in the file
- After a "TAG" unstruction, any of the following instructions may follow
in any order and any quantity:
- This instruction does nothing
LOAD u32_address string_filename
- Instructs the BootROM to load file pointed by "string_filename" onto
address "u32_address".
LOAD IVT u32_address u32_IVT_entry_point
- Crafts and loads IVT onto address "u32_address" with the entry point
of u32_IVT_entry_point.
- i.MX28-specific instruction!
LOAD DCD u32_address u32_DCD_block_ID
- Loads the DCD block with ID "u32_DCD_block_ID" onto address
"u32_address" and executes the contents of this DCD block
- i.MX28-specific instruction!
FILL u32_address u32_pattern u32_length
- Starts to write memory from addres "u32_address" with a pattern
specified by "u32_pattern". Writes exactly "u32_length" bytes of the
JUMP [HAB] u32_address [u32_r0_arg]
- Jumps onto memory address specified by "u32_address" by setting this
address in PT. The BootROM will pass the "u32_r0_arg" value in ARM
register "r0" to the executed code if this option is specified.
Otherwise, ARM register "r0" will default to value 0x00000000. The
optional "HAB" flag is i.MX28-specific flag turning on the HAB boot.
CALL [HAB] u32_address [u32_r0_arg]
- See JUMP instruction above, as the operation is exactly the same with
one difference. The CALL instruction does allow returning into the
BootROM from the executed code. U-Boot makes use of this in it's SPL
MODE string_mode
- Restart the CPU and start booting from device specified by the
"string_mode" argument. The "string_mode" differs for each CPU
and can be:
i.MX23, string_mode = USB/I2C/SPI1_FLASH/SPI2_FLASH/NAND_BCH
i.MX28, string_mode = USB/I2C/SPI2_FLASH/SPI3_FLASH/NAND_BCH
- An optional "DCD" blocks can be added at the begining of the configuration
file. Note that the DCD is only supported on i.MX28.
- The DCD blocks must be inserted before the first "section" in the
configuration file.
- The DCD block has the following semantics:
DCD u32_DCD_block_ID
- u32_DCD_block_ID :: The ID number of the DCD block, must match
the ID number used by "LOAD DCD" instruction.
- The DCD block must be followed by one of the following instructions. All
of the instructions operate either on 1, 2 or 4 bytes. This is selected by
the 'n' suffix of the instruction:
WRITE.n u32_address u32_value
- Write the "u32_value" to the "u32_address" address.
ORR.n u32_address u32_value
- Read the "u32_address", perform a bitwise-OR with the "u32_value" and
write the result back to "u32_address".
ANDC.n u32_address u32_value
- Read the "u32_address", perform a bitwise-AND with the complement of
"u32_value" and write the result back to "u32_address".
EQZ.n u32_address u32_count
- Read the "u32_address" at most "u32_count" times and test if the value
read is zero. If it is, break the loop earlier.
NEZ.n u32_address u32_count
- Read the "u32_address" at most "u32_count" times and test if the value
read is non-zero. If it is, break the loop earlier.
EQ.n u32_address u32_mask
- Read the "u32_address" in a loop and test if the result masked with
"u32_mask" equals the "u32_mask". If the values are equal, break the
reading loop.
NEQ.n u32_address u32_mask
- Read the "u32_address" in a loop and test if the result masked with
"u32_mask" does not equal the "u32_mask". If the values are not equal,
break the reading loop.
- This instruction does nothing.
- If the verbose output from the BootROM is enabled, the BootROM will produce a
letter on the Debug UART for each instruction it started processing. Here is a
mapping between the above instructions and the BootROM verbose output:
H -- SB Image header loaded
T -- TAG instruction
N -- NOOP instruction
L -- LOAD instruction
F -- FILL instruction
J -- JUMP instruction
C -- CALL instruction
M -- MODE instruction
Usage -- verifying image:
The mxsimage can also verify and dump contents of an image. Use the following
syntax to verify and dump contents of an image:
mkimage -l <input bootstream file>
This will output all the information from the SB image header and all the
instructions contained in the SB image. It will also check if the various
checksums in the SB image are correct.
......@@ -212,6 +212,7 @@ struct lmb;
#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 */
* Compression Types
......@@ -83,6 +83,7 @@ NOPED_OBJ_FILES-y += aisimage.o
NOPED_OBJ_FILES-y += kwbimage.o
NOPED_OBJ_FILES-y += pblimage.o
NOPED_OBJ_FILES-y += imximage.o
NOPED_OBJ_FILES-y += mxsimage.o
NOPED_OBJ_FILES-y += image-host.o
NOPED_OBJ_FILES-y += omapimage.o
NOPED_OBJ_FILES-y += mkenvimage.o
......@@ -209,6 +210,7 @@ $(obj)mkimage$(SFX): $(obj)aisimage.o \
$(obj)image-host.o \
$(obj)imximage.o \
$(obj)mxsimage.o \
$(obj)kwbimage.o \
$(obj)pblimage.o \
$(obj)md5.o \
......@@ -145,6 +145,8 @@ main (int argc, char **argv)
init_kwb_image_type ();
/* Init Freescale imx Boot image generation/list support */
init_imx_image_type ();
/* Init Freescale mxs Boot image generation/list support */
/* Init FIT image generation/list support */
init_fit_image_type ();
/* Init TI OMAP Boot image generation/list support */
......@@ -161,6 +161,7 @@ void init_pbl_image_type(void);
void init_ais_image_type(void);
void init_kwb_image_type (void);
void init_imx_image_type (void);
void init_mxs_image_type(void);
void init_default_image_type (void);
void init_fit_image_type (void);
void init_ubl_image_type(void);
This diff is collapsed.
* Freescale i.MX28 SB image generator
* Copyright (C) 2012 Marek Vasut <>
* SPDX-License-Identifier: GPL-2.0+
#ifndef __MXSSB_H__
#define __MXSSB_H__
#include <stdint.h>
#include <arpa/inet.h>
#define SB_BLOCK_SIZE 16
#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
struct sb_boot_image_version {
uint16_t major;
uint16_t pad0;
uint16_t minor;
uint16_t pad1;
uint16_t revision;
uint16_t pad2;
struct sb_boot_image_header {
union {
/* SHA1 of the header. */
uint8_t digest[20];
struct {
/* CBC-MAC initialization vector. */
uint8_t iv[16];
uint8_t extra[4];
/* 'STMP' */
uint8_t signature1[4];
/* Major version of the image format. */
uint8_t major_version;
/* Minor version of the image format. */
uint8_t minor_version;
/* Flags associated with the image. */
uint16_t flags;
/* Size of the image in 16b blocks. */
uint32_t image_blocks;
/* Offset of the first tag in 16b blocks. */
uint32_t first_boot_tag_block;
/* ID of the section to boot from. */
uint32_t first_boot_section_id;
/* Amount of crypto keys. */
uint16_t key_count;
/* Offset to the key dictionary in 16b blocks. */
uint16_t key_dictionary_block;
/* Size of this header in 16b blocks. */
uint16_t header_blocks;
/* Amount of section headers. */
uint16_t section_count;
/* Section header size in 16b blocks. */
uint16_t section_header_size;
/* Padding to align timestamp to uint64_t. */
uint8_t padding0[2];
/* 'sgtl' (since v1.1) */
uint8_t signature2[4];
/* Image generation date, in microseconds since 1.1.2000 . */
uint64_t timestamp_us;
/* Product version. */
struct sb_boot_image_version
/* Component version. */
struct sb_boot_image_version
/* Drive tag for the system drive. (since v1.1) */
uint16_t drive_tag;
/* Padding. */
uint8_t padding1[6];
/* Enable to HTLLC verbose boot report. */
#define SB_IMAGE_FLAG_VERBOSE (1 << 0)
struct sb_key_dictionary_key {
/* The CBC-MAC of image and sections header. */
uint8_t cbc_mac[SB_BLOCK_SIZE];
/* The AES key encrypted by image key (zero). */
uint8_t key[SB_BLOCK_SIZE];
struct sb_ivt_header {
uint32_t header;
uint32_t entry;
uint32_t reserved1;
uint32_t dcd;
uint32_t boot_data;
uint32_t self;
uint32_t csf;
uint32_t reserved2;
#define SB_HAB_IVT_TAG 0xd1UL
#define SB_HAB_DCD_TAG 0xd2UL
#define SB_HAB_VERSION 0x40UL
* The "size" field in the IVT header is not naturally aligned,
* use this macro to fill first 4 bytes of the IVT header without
* causing issues on some systems (esp. M68k, PPC, MIPS-BE, ARM-BE).
static inline uint32_t sb_hab_ivt_header(void)
uint32_t ret = 0;
ret |= SB_HAB_IVT_TAG << 24;
ret |= sizeof(struct sb_ivt_header) << 16;
return htonl(ret);
struct sb_sections_header {
/* Section number. */
uint32_t section_number;
/* Offset of this sections first instruction after "TAG". */
uint32_t section_offset;
/* Size of the section in 16b blocks. */
uint32_t section_size;
/* Section flags. */
uint32_t section_flags;
struct sb_command {
struct {
uint8_t checksum;
uint8_t tag;
uint16_t flags;
#define ROM_LOAD_CMD_FLAG_DCD_LOAD 0x1 /* MX28 only */
#define ROM_JUMP_CMD_FLAG_HAB 0x1 /* MX28 only */
#define ROM_CALL_CMD_FLAG_HAB 0x1 /* MX28 only */
} header;
union {
struct {
uint32_t reserved[3];
} nop;
struct {
uint32_t section_number;
uint32_t section_length;
uint32_t section_flags;
} tag;
struct {
uint32_t address;
uint32_t count;
uint32_t crc32;
} load;
struct {
uint32_t address;
uint32_t count;
uint32_t pattern;
} fill;
struct {
uint32_t address;
uint32_t reserved;
/* Passed in register r0 before JUMP */
uint32_t argument;
} jump;
struct {
uint32_t address;
uint32_t reserved;
/* Passed in register r0 before CALL */
uint32_t argument;
} call;
struct {
uint32_t reserved1;
uint32_t reserved2;
uint32_t mode;
} mode;
* Most of the mode names are same or at least similar
* on i.MX23 and i.MX28, but some of the mode names
* differ. The "name" field represents the mode name
* on i.MX28 as seen in Table 12-2 of the datasheet.
* The "altname" field represents the differently named
* fields on i.MX23 as seen in Table 35-3 of the
* datasheet.
static const struct {
const char *name;
const char *altname;
const uint8_t mode;
} modetable[] = {
{ "USB", NULL, 0x00 },
{ "I2C", NULL, 0x01 },
{ "SPI2_FLASH", "SPI1_FLASH", 0x02 },
{ "SPI3_FLASH", "SPI2_FLASH", 0x03 },
{ "NAND_BCH", NULL, 0x04 },
{ "JTAG", NULL, 0x06 },
{ "SPI3_EEPROM", "SPI2_EEPROM", 0x08 },
{ "SD_SSP0", NULL, 0x09 },
{ "SD_SSP1", NULL, 0x0A }
enum sb_tag {
ROM_NOP_CMD = 0x00,
ROM_TAG_CMD = 0x01,
ROM_LOAD_CMD = 0x02,
ROM_FILL_CMD = 0x03,
ROM_JUMP_CMD = 0x04,
ROM_CALL_CMD = 0x05,
struct sb_source_entry {
uint8_t tag;
uint32_t address;
uint32_t flags;
char *filename;
#endif /* __MXSSB_H__ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment