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