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 support. Note that the mxsimage generator needs libcrypto from OpenSSL, I therefore enabled the libcrypto/libssl unconditionally. MXSSB: http://git.denx.de/?p=mxssb.git;a=summary The code is based on research presented at: http://www.rockbox.org/wiki/SbFileFormat Signed-off-by: Marek Vasut <marex@denx.de> Cc: Tom Rini <trini@ti.com> Cc: Fabio Estevam <fabio.estevam@freescale.com> Cc: Stefano Babic <sbabic@denx.de> Cc: Otavio Salvador <otavio@ossystems.com.br>master
parent
b83c709e8d
commit
bce8837071
@ -0,0 +1,6 @@ |
|||||||
|
SECTION 0x0 BOOTABLE |
||||||
|
TAG LAST |
||||||
|
LOAD 0x0 spl/u-boot-spl.bin |
||||||
|
CALL 0x14 0x0 |
||||||
|
LOAD 0x40000100 u-boot.bin |
||||||
|
CALL 0x40000100 0x0 |
@ -0,0 +1,8 @@ |
|||||||
|
SECTION 0x0 BOOTABLE |
||||||
|
TAG LAST |
||||||
|
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 |
@ -0,0 +1,165 @@ |
|||||||
|
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: |
||||||
|
|
||||||
|
TAG [LAST] |
||||||
|
- 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: |
||||||
|
|
||||||
|
NOOP |
||||||
|
- 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 |
||||||
|
pattern. |
||||||
|
|
||||||
|
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 |
||||||
|
code. |
||||||
|
|
||||||
|
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 |
||||||
|
JTAG/SPI3_EEPROM/SD_SSP0/SD_SSP1 |
||||||
|
i.MX28, string_mode = USB/I2C/SPI2_FLASH/SPI3_FLASH/NAND_BCH |
||||||
|
JTAG/SPI2_EEPROM/SD_SSP0/SD_SSP1 |
||||||
|
|
||||||
|
- 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. |
||||||
|
|
||||||
|
NOOP |
||||||
|
- 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. |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,230 @@ |
|||||||
|
/*
|
||||||
|
* Freescale i.MX28 SB image generator |
||||||
|
* |
||||||
|
* Copyright (C) 2012 Marek Vasut <marex@denx.de> |
||||||
|
* |
||||||
|
* 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 |
||||||
|
product_version; |
||||||
|
/* Component version. */ |
||||||
|
struct sb_boot_image_version |
||||||
|
component_version; |
||||||
|
/* Drive tag for the system drive. (since v1.1) */ |
||||||
|
uint16_t drive_tag; |
||||||
|
/* Padding. */ |
||||||
|
uint8_t padding1[6]; |
||||||
|
}; |
||||||
|
|
||||||
|
#define SB_VERSION_MAJOR 1 |
||||||
|
#define SB_VERSION_MINOR 1 |
||||||
|
|
||||||
|
/* 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; |
||||||
|
ret |= SB_HAB_VERSION; |
||||||
|
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; |
||||||
|
}; |
||||||
|
|
||||||
|
#define SB_SECTION_FLAG_BOOTABLE (1 << 0) |
||||||
|
|
||||||
|
struct sb_command { |
||||||
|
struct { |
||||||
|
uint8_t checksum; |
||||||
|
uint8_t tag; |
||||||
|
uint16_t flags; |
||||||
|
#define ROM_TAG_CMD_FLAG_ROM_LAST_TAG 0x1 |
||||||
|
#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, |
||||||
|
ROM_MODE_CMD = 0x06 |
||||||
|
}; |
||||||
|
|
||||||
|
struct sb_source_entry { |
||||||
|
uint8_t tag; |
||||||
|
uint32_t address; |
||||||
|
uint32_t flags; |
||||||
|
char *filename; |
||||||
|
}; |
||||||
|
|
||||||
|
#endif /* __MXSSB_H__ */ |
Loading…
Reference in new issue