1bce88370SMarek Vasut /* 2bce88370SMarek Vasut * Freescale i.MX23/i.MX28 SB image generator 3bce88370SMarek Vasut * 4bce88370SMarek Vasut * Copyright (C) 2012-2013 Marek Vasut <marex@denx.de> 5bce88370SMarek Vasut * 6bce88370SMarek Vasut * SPDX-License-Identifier: GPL-2.0+ 7bce88370SMarek Vasut */ 8bce88370SMarek Vasut 9bce88370SMarek Vasut #ifdef CONFIG_MXS 10bce88370SMarek Vasut 11bce88370SMarek Vasut #include <errno.h> 12bce88370SMarek Vasut #include <fcntl.h> 13bce88370SMarek Vasut #include <stdio.h> 14bce88370SMarek Vasut #include <string.h> 15bce88370SMarek Vasut #include <unistd.h> 16bce88370SMarek Vasut #include <limits.h> 17bce88370SMarek Vasut 18bce88370SMarek Vasut #include <openssl/evp.h> 19bce88370SMarek Vasut 20f86ed6a8SGuilherme Maciel Ferreira #include "imagetool.h" 21bce88370SMarek Vasut #include "mxsimage.h" 2225308f45SCharles Manning #include "pbl_crc32.h" 23bce88370SMarek Vasut #include <image.h> 24bce88370SMarek Vasut 25*7bae13b7SMarek Vasut /* 26*7bae13b7SMarek Vasut * OpenSSL 1.1.0 and newer compatibility functions: 27*7bae13b7SMarek Vasut * https://wiki.openssl.org/index.php/1.1_API_Changes 28*7bae13b7SMarek Vasut */ 29*7bae13b7SMarek Vasut #if OPENSSL_VERSION_NUMBER < 0x10100000L 30*7bae13b7SMarek Vasut static void *OPENSSL_zalloc(size_t num) 31*7bae13b7SMarek Vasut { 32*7bae13b7SMarek Vasut void *ret = OPENSSL_malloc(num); 33*7bae13b7SMarek Vasut 34*7bae13b7SMarek Vasut if (ret != NULL) 35*7bae13b7SMarek Vasut memset(ret, 0, num); 36*7bae13b7SMarek Vasut return ret; 37*7bae13b7SMarek Vasut } 38*7bae13b7SMarek Vasut 39*7bae13b7SMarek Vasut EVP_MD_CTX *EVP_MD_CTX_new(void) 40*7bae13b7SMarek Vasut { 41*7bae13b7SMarek Vasut return OPENSSL_zalloc(sizeof(EVP_MD_CTX)); 42*7bae13b7SMarek Vasut } 43*7bae13b7SMarek Vasut 44*7bae13b7SMarek Vasut void EVP_MD_CTX_free(EVP_MD_CTX *ctx) 45*7bae13b7SMarek Vasut { 46*7bae13b7SMarek Vasut EVP_MD_CTX_cleanup(ctx); 47*7bae13b7SMarek Vasut OPENSSL_free(ctx); 48*7bae13b7SMarek Vasut } 49*7bae13b7SMarek Vasut 50*7bae13b7SMarek Vasut int EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *ctx) 51*7bae13b7SMarek Vasut { 52*7bae13b7SMarek Vasut return EVP_CIPHER_CTX_cleanup(ctx); 53*7bae13b7SMarek Vasut } 54*7bae13b7SMarek Vasut #endif 55bce88370SMarek Vasut 56bce88370SMarek Vasut /* 57bce88370SMarek Vasut * DCD block 58bce88370SMarek Vasut * |-Write to address command block 59bce88370SMarek Vasut * | 0xf00 == 0xf33d 60bce88370SMarek Vasut * | 0xba2 == 0xb33f 61bce88370SMarek Vasut * |-ORR address with mask command block 62bce88370SMarek Vasut * | 0xf00 |= 0x1337 63bce88370SMarek Vasut * |-Write to address command block 64bce88370SMarek Vasut * | 0xba2 == 0xd00d 65bce88370SMarek Vasut * : 66bce88370SMarek Vasut */ 67bce88370SMarek Vasut #define SB_HAB_DCD_WRITE 0xccUL 68bce88370SMarek Vasut #define SB_HAB_DCD_CHECK 0xcfUL 69bce88370SMarek Vasut #define SB_HAB_DCD_NOOP 0xc0UL 70bce88370SMarek Vasut #define SB_HAB_DCD_MASK_BIT (1 << 3) 71bce88370SMarek Vasut #define SB_HAB_DCD_SET_BIT (1 << 4) 72bce88370SMarek Vasut 73bce88370SMarek Vasut /* Addr.n = Value.n */ 74bce88370SMarek Vasut #define SB_DCD_WRITE \ 75bce88370SMarek Vasut (SB_HAB_DCD_WRITE << 24) 76bce88370SMarek Vasut /* Addr.n &= ~Value.n */ 77bce88370SMarek Vasut #define SB_DCD_ANDC \ 78bce88370SMarek Vasut ((SB_HAB_DCD_WRITE << 24) | SB_HAB_DCD_SET_BIT) 79bce88370SMarek Vasut /* Addr.n |= Value.n */ 80bce88370SMarek Vasut #define SB_DCD_ORR \ 81bce88370SMarek Vasut ((SB_HAB_DCD_WRITE << 24) | SB_HAB_DCD_SET_BIT | SB_HAB_DCD_MASK_BIT) 82bce88370SMarek Vasut /* (Addr.n & Value.n) == 0 */ 83bce88370SMarek Vasut #define SB_DCD_CHK_EQZ \ 84bce88370SMarek Vasut (SB_HAB_DCD_CHECK << 24) 85bce88370SMarek Vasut /* (Addr.n & Value.n) == Value.n */ 86bce88370SMarek Vasut #define SB_DCD_CHK_EQ \ 87bce88370SMarek Vasut ((SB_HAB_DCD_CHECK << 24) | SB_HAB_DCD_SET_BIT) 88bce88370SMarek Vasut /* (Addr.n & Value.n) != Value.n */ 89bce88370SMarek Vasut #define SB_DCD_CHK_NEQ \ 90bce88370SMarek Vasut ((SB_HAB_DCD_CHECK << 24) | SB_HAB_DCD_MASK_BIT) 91bce88370SMarek Vasut /* (Addr.n & Value.n) != 0 */ 92bce88370SMarek Vasut #define SB_DCD_CHK_NEZ \ 93bce88370SMarek Vasut ((SB_HAB_DCD_CHECK << 24) | SB_HAB_DCD_SET_BIT | SB_HAB_DCD_MASK_BIT) 94bce88370SMarek Vasut /* NOP */ 95bce88370SMarek Vasut #define SB_DCD_NOOP \ 96bce88370SMarek Vasut (SB_HAB_DCD_NOOP << 24) 97bce88370SMarek Vasut 98bce88370SMarek Vasut struct sb_dcd_ctx { 99bce88370SMarek Vasut struct sb_dcd_ctx *dcd; 100bce88370SMarek Vasut 101bce88370SMarek Vasut uint32_t id; 102bce88370SMarek Vasut 103bce88370SMarek Vasut /* The DCD block. */ 104bce88370SMarek Vasut uint32_t *payload; 105bce88370SMarek Vasut /* Size of the whole DCD block. */ 106bce88370SMarek Vasut uint32_t size; 107bce88370SMarek Vasut 108bce88370SMarek Vasut /* Pointer to previous DCD command block. */ 109bce88370SMarek Vasut uint32_t *prev_dcd_head; 110bce88370SMarek Vasut }; 111bce88370SMarek Vasut 112bce88370SMarek Vasut /* 113bce88370SMarek Vasut * IMAGE 114bce88370SMarek Vasut * |-SECTION 115bce88370SMarek Vasut * | |-CMD 116bce88370SMarek Vasut * | |-CMD 117bce88370SMarek Vasut * | `-CMD 118bce88370SMarek Vasut * |-SECTION 119bce88370SMarek Vasut * | |-CMD 120bce88370SMarek Vasut * : : 121bce88370SMarek Vasut */ 122bce88370SMarek Vasut struct sb_cmd_list { 123bce88370SMarek Vasut char *cmd; 124bce88370SMarek Vasut size_t len; 125bce88370SMarek Vasut unsigned int lineno; 126bce88370SMarek Vasut }; 127bce88370SMarek Vasut 128bce88370SMarek Vasut struct sb_cmd_ctx { 129bce88370SMarek Vasut uint32_t size; 130bce88370SMarek Vasut 131bce88370SMarek Vasut struct sb_cmd_ctx *cmd; 132bce88370SMarek Vasut 133bce88370SMarek Vasut uint8_t *data; 134bce88370SMarek Vasut uint32_t length; 135bce88370SMarek Vasut 136bce88370SMarek Vasut struct sb_command payload; 137bce88370SMarek Vasut struct sb_command c_payload; 138bce88370SMarek Vasut }; 139bce88370SMarek Vasut 140bce88370SMarek Vasut struct sb_section_ctx { 141bce88370SMarek Vasut uint32_t size; 142bce88370SMarek Vasut 143bce88370SMarek Vasut /* Section flags */ 144bce88370SMarek Vasut unsigned int boot:1; 145bce88370SMarek Vasut 146bce88370SMarek Vasut struct sb_section_ctx *sect; 147bce88370SMarek Vasut 148bce88370SMarek Vasut struct sb_cmd_ctx *cmd_head; 149bce88370SMarek Vasut struct sb_cmd_ctx *cmd_tail; 150bce88370SMarek Vasut 151bce88370SMarek Vasut struct sb_sections_header payload; 152bce88370SMarek Vasut }; 153bce88370SMarek Vasut 154bce88370SMarek Vasut struct sb_image_ctx { 155bce88370SMarek Vasut unsigned int in_section:1; 156bce88370SMarek Vasut unsigned int in_dcd:1; 157bce88370SMarek Vasut /* Image configuration */ 1587a139959SAlexey Ignatov unsigned int display_progress:1; 159bce88370SMarek Vasut unsigned int silent_dump:1; 160bce88370SMarek Vasut char *input_filename; 161bce88370SMarek Vasut char *output_filename; 162bce88370SMarek Vasut char *cfg_filename; 163bce88370SMarek Vasut uint8_t image_key[16]; 164bce88370SMarek Vasut 165bce88370SMarek Vasut /* Number of section in the image */ 166bce88370SMarek Vasut unsigned int sect_count; 167bce88370SMarek Vasut /* Bootable section */ 168bce88370SMarek Vasut unsigned int sect_boot; 169bce88370SMarek Vasut unsigned int sect_boot_found:1; 170bce88370SMarek Vasut 171bce88370SMarek Vasut struct sb_section_ctx *sect_head; 172bce88370SMarek Vasut struct sb_section_ctx *sect_tail; 173bce88370SMarek Vasut 174bce88370SMarek Vasut struct sb_dcd_ctx *dcd_head; 175bce88370SMarek Vasut struct sb_dcd_ctx *dcd_tail; 176bce88370SMarek Vasut 177*7bae13b7SMarek Vasut EVP_CIPHER_CTX *cipher_ctx; 178*7bae13b7SMarek Vasut EVP_MD_CTX *md_ctx; 179bce88370SMarek Vasut uint8_t digest[32]; 180bce88370SMarek Vasut struct sb_key_dictionary_key sb_dict_key; 181bce88370SMarek Vasut 182bce88370SMarek Vasut struct sb_boot_image_header payload; 183bce88370SMarek Vasut }; 184bce88370SMarek Vasut 185bce88370SMarek Vasut /* 186bce88370SMarek Vasut * Instruction semantics: 187bce88370SMarek Vasut * NOOP 188bce88370SMarek Vasut * TAG [LAST] 189bce88370SMarek Vasut * LOAD address file 190bce88370SMarek Vasut * LOAD IVT address IVT_entry_point 191bce88370SMarek Vasut * FILL address pattern length 192bce88370SMarek Vasut * JUMP [HAB] address [r0_arg] 193bce88370SMarek Vasut * CALL [HAB] address [r0_arg] 194bce88370SMarek Vasut * MODE mode 195bce88370SMarek Vasut * For i.MX23, mode = USB/I2C/SPI1_FLASH/SPI2_FLASH/NAND_BCH 196bce88370SMarek Vasut * JTAG/SPI3_EEPROM/SD_SSP0/SD_SSP1 197bce88370SMarek Vasut * For i.MX28, mode = USB/I2C/SPI2_FLASH/SPI3_FLASH/NAND_BCH 198bce88370SMarek Vasut * JTAG/SPI2_EEPROM/SD_SSP0/SD_SSP1 199bce88370SMarek Vasut */ 200bce88370SMarek Vasut 201bce88370SMarek Vasut /* 202bce88370SMarek Vasut * AES libcrypto 203bce88370SMarek Vasut */ 204bce88370SMarek Vasut static int sb_aes_init(struct sb_image_ctx *ictx, uint8_t *iv, int enc) 205bce88370SMarek Vasut { 206*7bae13b7SMarek Vasut EVP_CIPHER_CTX *ctx; 207bce88370SMarek Vasut int ret; 208bce88370SMarek Vasut 209bce88370SMarek Vasut /* If there is no init vector, init vector is all zeroes. */ 210bce88370SMarek Vasut if (!iv) 211bce88370SMarek Vasut iv = ictx->image_key; 212bce88370SMarek Vasut 213*7bae13b7SMarek Vasut ctx = EVP_CIPHER_CTX_new(); 214bce88370SMarek Vasut ret = EVP_CipherInit(ctx, EVP_aes_128_cbc(), ictx->image_key, iv, enc); 215*7bae13b7SMarek Vasut if (ret == 1) { 216bce88370SMarek Vasut EVP_CIPHER_CTX_set_padding(ctx, 0); 217*7bae13b7SMarek Vasut ictx->cipher_ctx = ctx; 218*7bae13b7SMarek Vasut } 219bce88370SMarek Vasut return ret; 220bce88370SMarek Vasut } 221bce88370SMarek Vasut 222bce88370SMarek Vasut static int sb_aes_crypt(struct sb_image_ctx *ictx, uint8_t *in_data, 223bce88370SMarek Vasut uint8_t *out_data, int in_len) 224bce88370SMarek Vasut { 225*7bae13b7SMarek Vasut EVP_CIPHER_CTX *ctx = ictx->cipher_ctx; 226bce88370SMarek Vasut int ret, outlen; 227bce88370SMarek Vasut uint8_t *outbuf; 228bce88370SMarek Vasut 229bce88370SMarek Vasut outbuf = malloc(in_len); 230bce88370SMarek Vasut if (!outbuf) 231bce88370SMarek Vasut return -ENOMEM; 232bce88370SMarek Vasut memset(outbuf, 0, sizeof(in_len)); 233bce88370SMarek Vasut 234bce88370SMarek Vasut ret = EVP_CipherUpdate(ctx, outbuf, &outlen, in_data, in_len); 235bce88370SMarek Vasut if (!ret) { 236bce88370SMarek Vasut ret = -EINVAL; 237bce88370SMarek Vasut goto err; 238bce88370SMarek Vasut } 239bce88370SMarek Vasut 240bce88370SMarek Vasut if (out_data) 241bce88370SMarek Vasut memcpy(out_data, outbuf, outlen); 242bce88370SMarek Vasut 243bce88370SMarek Vasut err: 244bce88370SMarek Vasut free(outbuf); 245bce88370SMarek Vasut return ret; 246bce88370SMarek Vasut } 247bce88370SMarek Vasut 248bce88370SMarek Vasut static int sb_aes_deinit(EVP_CIPHER_CTX *ctx) 249bce88370SMarek Vasut { 250*7bae13b7SMarek Vasut return EVP_CIPHER_CTX_reset(ctx); 251bce88370SMarek Vasut } 252bce88370SMarek Vasut 253bce88370SMarek Vasut static int sb_aes_reinit(struct sb_image_ctx *ictx, int enc) 254bce88370SMarek Vasut { 255bce88370SMarek Vasut int ret; 256*7bae13b7SMarek Vasut EVP_CIPHER_CTX *ctx = ictx->cipher_ctx; 257bce88370SMarek Vasut struct sb_boot_image_header *sb_header = &ictx->payload; 258bce88370SMarek Vasut uint8_t *iv = sb_header->iv; 259bce88370SMarek Vasut 260bce88370SMarek Vasut ret = sb_aes_deinit(ctx); 261bce88370SMarek Vasut if (!ret) 262bce88370SMarek Vasut return ret; 263bce88370SMarek Vasut return sb_aes_init(ictx, iv, enc); 264bce88370SMarek Vasut } 265bce88370SMarek Vasut 266bce88370SMarek Vasut /* 267bce88370SMarek Vasut * Debug 268bce88370SMarek Vasut */ 269bce88370SMarek Vasut static void soprintf(struct sb_image_ctx *ictx, const char *fmt, ...) 270bce88370SMarek Vasut { 271bce88370SMarek Vasut va_list ap; 272bce88370SMarek Vasut 273bce88370SMarek Vasut if (ictx->silent_dump) 274bce88370SMarek Vasut return; 275bce88370SMarek Vasut 276bce88370SMarek Vasut va_start(ap, fmt); 277bce88370SMarek Vasut vfprintf(stdout, fmt, ap); 278bce88370SMarek Vasut va_end(ap); 279bce88370SMarek Vasut } 280bce88370SMarek Vasut 281bce88370SMarek Vasut /* 282bce88370SMarek Vasut * Code 283bce88370SMarek Vasut */ 284bce88370SMarek Vasut static time_t sb_get_timestamp(void) 285bce88370SMarek Vasut { 286bce88370SMarek Vasut struct tm time_2000 = { 287bce88370SMarek Vasut .tm_yday = 1, /* Jan. 1st */ 288bce88370SMarek Vasut .tm_year = 100, /* 2000 */ 289bce88370SMarek Vasut }; 290bce88370SMarek Vasut time_t seconds_to_2000 = mktime(&time_2000); 291bce88370SMarek Vasut time_t seconds_to_now = time(NULL); 292bce88370SMarek Vasut 293bce88370SMarek Vasut return seconds_to_now - seconds_to_2000; 294bce88370SMarek Vasut } 295bce88370SMarek Vasut 296bce88370SMarek Vasut static int sb_get_time(time_t time, struct tm *tm) 297bce88370SMarek Vasut { 298bce88370SMarek Vasut struct tm time_2000 = { 299bce88370SMarek Vasut .tm_yday = 1, /* Jan. 1st */ 300bce88370SMarek Vasut .tm_year = 0, /* 1900 */ 301bce88370SMarek Vasut }; 302bce88370SMarek Vasut const time_t seconds_to_2000 = mktime(&time_2000); 303bce88370SMarek Vasut const time_t seconds_to_now = seconds_to_2000 + time; 304bce88370SMarek Vasut struct tm *ret; 305bce88370SMarek Vasut ret = gmtime_r(&seconds_to_now, tm); 306bce88370SMarek Vasut return ret ? 0 : -EINVAL; 307bce88370SMarek Vasut } 308bce88370SMarek Vasut 309bce88370SMarek Vasut static void sb_encrypt_sb_header(struct sb_image_ctx *ictx) 310bce88370SMarek Vasut { 311*7bae13b7SMarek Vasut EVP_MD_CTX *md_ctx = ictx->md_ctx; 312bce88370SMarek Vasut struct sb_boot_image_header *sb_header = &ictx->payload; 313bce88370SMarek Vasut uint8_t *sb_header_ptr = (uint8_t *)sb_header; 314bce88370SMarek Vasut 315bce88370SMarek Vasut /* Encrypt the header, compute the digest. */ 316bce88370SMarek Vasut sb_aes_crypt(ictx, sb_header_ptr, NULL, sizeof(*sb_header)); 317bce88370SMarek Vasut EVP_DigestUpdate(md_ctx, sb_header_ptr, sizeof(*sb_header)); 318bce88370SMarek Vasut } 319bce88370SMarek Vasut 320bce88370SMarek Vasut static void sb_encrypt_sb_sections_header(struct sb_image_ctx *ictx) 321bce88370SMarek Vasut { 322*7bae13b7SMarek Vasut EVP_MD_CTX *md_ctx = ictx->md_ctx; 323bce88370SMarek Vasut struct sb_section_ctx *sctx = ictx->sect_head; 324bce88370SMarek Vasut struct sb_sections_header *shdr; 325bce88370SMarek Vasut uint8_t *sb_sections_header_ptr; 326bce88370SMarek Vasut const int size = sizeof(*shdr); 327bce88370SMarek Vasut 328bce88370SMarek Vasut while (sctx) { 329bce88370SMarek Vasut shdr = &sctx->payload; 330bce88370SMarek Vasut sb_sections_header_ptr = (uint8_t *)shdr; 331bce88370SMarek Vasut 332bce88370SMarek Vasut sb_aes_crypt(ictx, sb_sections_header_ptr, 333bce88370SMarek Vasut ictx->sb_dict_key.cbc_mac, size); 334bce88370SMarek Vasut EVP_DigestUpdate(md_ctx, sb_sections_header_ptr, size); 335bce88370SMarek Vasut 336bce88370SMarek Vasut sctx = sctx->sect; 337bce88370SMarek Vasut }; 338bce88370SMarek Vasut } 339bce88370SMarek Vasut 340bce88370SMarek Vasut static void sb_encrypt_key_dictionary_key(struct sb_image_ctx *ictx) 341bce88370SMarek Vasut { 342*7bae13b7SMarek Vasut EVP_MD_CTX *md_ctx = ictx->md_ctx; 343bce88370SMarek Vasut 344bce88370SMarek Vasut sb_aes_crypt(ictx, ictx->image_key, ictx->sb_dict_key.key, 345bce88370SMarek Vasut sizeof(ictx->sb_dict_key.key)); 346bce88370SMarek Vasut EVP_DigestUpdate(md_ctx, &ictx->sb_dict_key, sizeof(ictx->sb_dict_key)); 347bce88370SMarek Vasut } 348bce88370SMarek Vasut 349bce88370SMarek Vasut static void sb_decrypt_key_dictionary_key(struct sb_image_ctx *ictx) 350bce88370SMarek Vasut { 351*7bae13b7SMarek Vasut EVP_MD_CTX *md_ctx = ictx->md_ctx; 352bce88370SMarek Vasut 353bce88370SMarek Vasut EVP_DigestUpdate(md_ctx, &ictx->sb_dict_key, sizeof(ictx->sb_dict_key)); 354bce88370SMarek Vasut sb_aes_crypt(ictx, ictx->sb_dict_key.key, ictx->image_key, 355bce88370SMarek Vasut sizeof(ictx->sb_dict_key.key)); 356bce88370SMarek Vasut } 357bce88370SMarek Vasut 358bce88370SMarek Vasut static void sb_encrypt_tag(struct sb_image_ctx *ictx, 359bce88370SMarek Vasut struct sb_cmd_ctx *cctx) 360bce88370SMarek Vasut { 361*7bae13b7SMarek Vasut EVP_MD_CTX *md_ctx = ictx->md_ctx; 362bce88370SMarek Vasut struct sb_command *cmd = &cctx->payload; 363bce88370SMarek Vasut 364bce88370SMarek Vasut sb_aes_crypt(ictx, (uint8_t *)cmd, 365bce88370SMarek Vasut (uint8_t *)&cctx->c_payload, sizeof(*cmd)); 366bce88370SMarek Vasut EVP_DigestUpdate(md_ctx, &cctx->c_payload, sizeof(*cmd)); 367bce88370SMarek Vasut } 368bce88370SMarek Vasut 369bce88370SMarek Vasut static int sb_encrypt_image(struct sb_image_ctx *ictx) 370bce88370SMarek Vasut { 371bce88370SMarek Vasut /* Start image-wide crypto. */ 372*7bae13b7SMarek Vasut ictx->md_ctx = EVP_MD_CTX_new(); 373*7bae13b7SMarek Vasut EVP_DigestInit(ictx->md_ctx, EVP_sha1()); 374bce88370SMarek Vasut 375bce88370SMarek Vasut /* 376bce88370SMarek Vasut * SB image header. 377bce88370SMarek Vasut */ 378bce88370SMarek Vasut sb_aes_init(ictx, NULL, 1); 379bce88370SMarek Vasut sb_encrypt_sb_header(ictx); 380bce88370SMarek Vasut 381bce88370SMarek Vasut /* 382bce88370SMarek Vasut * SB sections header. 383bce88370SMarek Vasut */ 384bce88370SMarek Vasut sb_encrypt_sb_sections_header(ictx); 385bce88370SMarek Vasut 386bce88370SMarek Vasut /* 387bce88370SMarek Vasut * Key dictionary. 388bce88370SMarek Vasut */ 389bce88370SMarek Vasut sb_aes_reinit(ictx, 1); 390bce88370SMarek Vasut sb_encrypt_key_dictionary_key(ictx); 391bce88370SMarek Vasut 392bce88370SMarek Vasut /* 393bce88370SMarek Vasut * Section tags. 394bce88370SMarek Vasut */ 395bce88370SMarek Vasut struct sb_cmd_ctx *cctx; 396bce88370SMarek Vasut struct sb_command *ccmd; 397bce88370SMarek Vasut struct sb_section_ctx *sctx = ictx->sect_head; 398bce88370SMarek Vasut 399bce88370SMarek Vasut while (sctx) { 400bce88370SMarek Vasut cctx = sctx->cmd_head; 401bce88370SMarek Vasut 402bce88370SMarek Vasut sb_aes_reinit(ictx, 1); 403bce88370SMarek Vasut 404bce88370SMarek Vasut while (cctx) { 405bce88370SMarek Vasut ccmd = &cctx->payload; 406bce88370SMarek Vasut 407bce88370SMarek Vasut sb_encrypt_tag(ictx, cctx); 408bce88370SMarek Vasut 409bce88370SMarek Vasut if (ccmd->header.tag == ROM_TAG_CMD) { 410bce88370SMarek Vasut sb_aes_reinit(ictx, 1); 411bce88370SMarek Vasut } else if (ccmd->header.tag == ROM_LOAD_CMD) { 412bce88370SMarek Vasut sb_aes_crypt(ictx, cctx->data, cctx->data, 413bce88370SMarek Vasut cctx->length); 414*7bae13b7SMarek Vasut EVP_DigestUpdate(ictx->md_ctx, cctx->data, 415bce88370SMarek Vasut cctx->length); 416bce88370SMarek Vasut } 417bce88370SMarek Vasut 418bce88370SMarek Vasut cctx = cctx->cmd; 419bce88370SMarek Vasut } 420bce88370SMarek Vasut 421bce88370SMarek Vasut sctx = sctx->sect; 422bce88370SMarek Vasut }; 423bce88370SMarek Vasut 424bce88370SMarek Vasut /* 425bce88370SMarek Vasut * Dump the SHA1 of the whole image. 426bce88370SMarek Vasut */ 427bce88370SMarek Vasut sb_aes_reinit(ictx, 1); 428bce88370SMarek Vasut 429*7bae13b7SMarek Vasut EVP_DigestFinal(ictx->md_ctx, ictx->digest, NULL); 430*7bae13b7SMarek Vasut EVP_MD_CTX_free(ictx->md_ctx); 431bce88370SMarek Vasut sb_aes_crypt(ictx, ictx->digest, ictx->digest, sizeof(ictx->digest)); 432bce88370SMarek Vasut 433bce88370SMarek Vasut /* Stop the encryption session. */ 434*7bae13b7SMarek Vasut sb_aes_deinit(ictx->cipher_ctx); 435bce88370SMarek Vasut 436bce88370SMarek Vasut return 0; 437bce88370SMarek Vasut } 438bce88370SMarek Vasut 439bce88370SMarek Vasut static int sb_load_file(struct sb_cmd_ctx *cctx, char *filename) 440bce88370SMarek Vasut { 441bce88370SMarek Vasut long real_size, roundup_size; 442bce88370SMarek Vasut uint8_t *data; 443bce88370SMarek Vasut long ret; 444bce88370SMarek Vasut unsigned long size; 445bce88370SMarek Vasut FILE *fp; 446bce88370SMarek Vasut 447bce88370SMarek Vasut if (!filename) { 448bce88370SMarek Vasut fprintf(stderr, "ERR: Missing filename!\n"); 449bce88370SMarek Vasut return -EINVAL; 450bce88370SMarek Vasut } 451bce88370SMarek Vasut 452bce88370SMarek Vasut fp = fopen(filename, "r"); 453bce88370SMarek Vasut if (!fp) 454bce88370SMarek Vasut goto err_open; 455bce88370SMarek Vasut 456bce88370SMarek Vasut ret = fseek(fp, 0, SEEK_END); 457bce88370SMarek Vasut if (ret < 0) 458bce88370SMarek Vasut goto err_file; 459bce88370SMarek Vasut 460bce88370SMarek Vasut real_size = ftell(fp); 461bce88370SMarek Vasut if (real_size < 0) 462bce88370SMarek Vasut goto err_file; 463bce88370SMarek Vasut 464bce88370SMarek Vasut ret = fseek(fp, 0, SEEK_SET); 465bce88370SMarek Vasut if (ret < 0) 466bce88370SMarek Vasut goto err_file; 467bce88370SMarek Vasut 468bce88370SMarek Vasut roundup_size = roundup(real_size, SB_BLOCK_SIZE); 469bce88370SMarek Vasut data = calloc(1, roundup_size); 470bce88370SMarek Vasut if (!data) 471bce88370SMarek Vasut goto err_file; 472bce88370SMarek Vasut 473bce88370SMarek Vasut size = fread(data, 1, real_size, fp); 474bce88370SMarek Vasut if (size != (unsigned long)real_size) 475bce88370SMarek Vasut goto err_alloc; 476bce88370SMarek Vasut 477bce88370SMarek Vasut cctx->data = data; 478bce88370SMarek Vasut cctx->length = roundup_size; 479bce88370SMarek Vasut 480bce88370SMarek Vasut fclose(fp); 481bce88370SMarek Vasut return 0; 482bce88370SMarek Vasut 483bce88370SMarek Vasut err_alloc: 484bce88370SMarek Vasut free(data); 485bce88370SMarek Vasut err_file: 486bce88370SMarek Vasut fclose(fp); 487bce88370SMarek Vasut err_open: 488bce88370SMarek Vasut fprintf(stderr, "ERR: Failed to load file \"%s\"\n", filename); 489bce88370SMarek Vasut return -EINVAL; 490bce88370SMarek Vasut } 491bce88370SMarek Vasut 492bce88370SMarek Vasut static uint8_t sb_command_checksum(struct sb_command *inst) 493bce88370SMarek Vasut { 494bce88370SMarek Vasut uint8_t *inst_ptr = (uint8_t *)inst; 495bce88370SMarek Vasut uint8_t csum = 0; 496bce88370SMarek Vasut unsigned int i; 497bce88370SMarek Vasut 498bce88370SMarek Vasut for (i = 0; i < sizeof(struct sb_command); i++) 499bce88370SMarek Vasut csum += inst_ptr[i]; 500bce88370SMarek Vasut 501bce88370SMarek Vasut return csum; 502bce88370SMarek Vasut } 503bce88370SMarek Vasut 504bce88370SMarek Vasut static int sb_token_to_long(char *tok, uint32_t *rid) 505bce88370SMarek Vasut { 506bce88370SMarek Vasut char *endptr; 507bce88370SMarek Vasut unsigned long id; 508bce88370SMarek Vasut 509bce88370SMarek Vasut if (tok[0] != '0' || tok[1] != 'x') { 510bce88370SMarek Vasut fprintf(stderr, "ERR: Invalid hexadecimal number!\n"); 511bce88370SMarek Vasut return -EINVAL; 512bce88370SMarek Vasut } 513bce88370SMarek Vasut 514bce88370SMarek Vasut tok += 2; 515bce88370SMarek Vasut 5165b5a82ebSMarek Vasut errno = 0; 517bce88370SMarek Vasut id = strtoul(tok, &endptr, 16); 518bce88370SMarek Vasut if ((errno == ERANGE && id == ULONG_MAX) || (errno != 0 && id == 0)) { 519bce88370SMarek Vasut fprintf(stderr, "ERR: Value can't be decoded!\n"); 520bce88370SMarek Vasut return -EINVAL; 521bce88370SMarek Vasut } 522bce88370SMarek Vasut 523bce88370SMarek Vasut /* Check for 32-bit overflow. */ 524bce88370SMarek Vasut if (id > 0xffffffff) { 525bce88370SMarek Vasut fprintf(stderr, "ERR: Value too big!\n"); 526bce88370SMarek Vasut return -EINVAL; 527bce88370SMarek Vasut } 528bce88370SMarek Vasut 529bce88370SMarek Vasut if (endptr == tok) { 530bce88370SMarek Vasut fprintf(stderr, "ERR: Deformed value!\n"); 531bce88370SMarek Vasut return -EINVAL; 532bce88370SMarek Vasut } 533bce88370SMarek Vasut 534bce88370SMarek Vasut *rid = (uint32_t)id; 535bce88370SMarek Vasut return 0; 536bce88370SMarek Vasut } 537bce88370SMarek Vasut 538bce88370SMarek Vasut static int sb_grow_dcd(struct sb_dcd_ctx *dctx, unsigned int inc_size) 539bce88370SMarek Vasut { 540bce88370SMarek Vasut uint32_t *tmp; 541bce88370SMarek Vasut 542bce88370SMarek Vasut if (!inc_size) 543bce88370SMarek Vasut return 0; 544bce88370SMarek Vasut 545bce88370SMarek Vasut dctx->size += inc_size; 546bce88370SMarek Vasut tmp = realloc(dctx->payload, dctx->size); 547bce88370SMarek Vasut if (!tmp) 548bce88370SMarek Vasut return -ENOMEM; 549bce88370SMarek Vasut 550bce88370SMarek Vasut dctx->payload = tmp; 551bce88370SMarek Vasut 552bce88370SMarek Vasut /* Assemble and update the HAB DCD header. */ 553bce88370SMarek Vasut dctx->payload[0] = htonl((SB_HAB_DCD_TAG << 24) | 554bce88370SMarek Vasut (dctx->size << 8) | 555bce88370SMarek Vasut SB_HAB_VERSION); 556bce88370SMarek Vasut 557bce88370SMarek Vasut return 0; 558bce88370SMarek Vasut } 559bce88370SMarek Vasut 560bce88370SMarek Vasut static int sb_build_dcd(struct sb_image_ctx *ictx, struct sb_cmd_list *cmd) 561bce88370SMarek Vasut { 562bce88370SMarek Vasut struct sb_dcd_ctx *dctx; 563bce88370SMarek Vasut 564bce88370SMarek Vasut char *tok; 565bce88370SMarek Vasut uint32_t id; 566bce88370SMarek Vasut int ret; 567bce88370SMarek Vasut 568bce88370SMarek Vasut dctx = calloc(1, sizeof(*dctx)); 569bce88370SMarek Vasut if (!dctx) 570bce88370SMarek Vasut return -ENOMEM; 571bce88370SMarek Vasut 572bce88370SMarek Vasut ret = sb_grow_dcd(dctx, 4); 573bce88370SMarek Vasut if (ret) 574bce88370SMarek Vasut goto err_dcd; 575bce88370SMarek Vasut 576bce88370SMarek Vasut /* Read DCD block number. */ 577bce88370SMarek Vasut tok = strtok(cmd->cmd, " "); 578bce88370SMarek Vasut if (!tok) { 579bce88370SMarek Vasut fprintf(stderr, "#%i ERR: DCD block without number!\n", 580bce88370SMarek Vasut cmd->lineno); 581bce88370SMarek Vasut ret = -EINVAL; 582bce88370SMarek Vasut goto err_dcd; 583bce88370SMarek Vasut } 584bce88370SMarek Vasut 585bce88370SMarek Vasut /* Parse the DCD block number. */ 586bce88370SMarek Vasut ret = sb_token_to_long(tok, &id); 587bce88370SMarek Vasut if (ret) { 588bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Malformed DCD block number!\n", 589bce88370SMarek Vasut cmd->lineno); 590bce88370SMarek Vasut goto err_dcd; 591bce88370SMarek Vasut } 592bce88370SMarek Vasut 593bce88370SMarek Vasut dctx->id = id; 594bce88370SMarek Vasut 595bce88370SMarek Vasut /* 596bce88370SMarek Vasut * The DCD block is now constructed. Append it to the list. 597bce88370SMarek Vasut * WARNING: The DCD size is still not computed and will be 598bce88370SMarek Vasut * updated while parsing it's commands. 599bce88370SMarek Vasut */ 600bce88370SMarek Vasut if (!ictx->dcd_head) { 601bce88370SMarek Vasut ictx->dcd_head = dctx; 602bce88370SMarek Vasut ictx->dcd_tail = dctx; 603bce88370SMarek Vasut } else { 604bce88370SMarek Vasut ictx->dcd_tail->dcd = dctx; 605bce88370SMarek Vasut ictx->dcd_tail = dctx; 606bce88370SMarek Vasut } 607bce88370SMarek Vasut 608bce88370SMarek Vasut return 0; 609bce88370SMarek Vasut 610bce88370SMarek Vasut err_dcd: 611bce88370SMarek Vasut free(dctx->payload); 612bce88370SMarek Vasut free(dctx); 613bce88370SMarek Vasut return ret; 614bce88370SMarek Vasut } 615bce88370SMarek Vasut 616bce88370SMarek Vasut static int sb_build_dcd_block(struct sb_image_ctx *ictx, 617bce88370SMarek Vasut struct sb_cmd_list *cmd, 618bce88370SMarek Vasut uint32_t type) 619bce88370SMarek Vasut { 620bce88370SMarek Vasut char *tok; 621bce88370SMarek Vasut uint32_t address, value, length; 622bce88370SMarek Vasut int ret; 623bce88370SMarek Vasut 624bce88370SMarek Vasut struct sb_dcd_ctx *dctx = ictx->dcd_tail; 625bce88370SMarek Vasut uint32_t *dcd; 626bce88370SMarek Vasut 627bce88370SMarek Vasut if (dctx->prev_dcd_head && (type != SB_DCD_NOOP) && 628bce88370SMarek Vasut ((dctx->prev_dcd_head[0] & 0xff0000ff) == type)) { 629bce88370SMarek Vasut /* Same instruction as before, just append it. */ 630bce88370SMarek Vasut ret = sb_grow_dcd(dctx, 8); 631bce88370SMarek Vasut if (ret) 632bce88370SMarek Vasut return ret; 633bce88370SMarek Vasut } else if (type == SB_DCD_NOOP) { 634bce88370SMarek Vasut ret = sb_grow_dcd(dctx, 4); 635bce88370SMarek Vasut if (ret) 636bce88370SMarek Vasut return ret; 637bce88370SMarek Vasut 638bce88370SMarek Vasut /* Update DCD command block pointer. */ 639bce88370SMarek Vasut dctx->prev_dcd_head = dctx->payload + 640bce88370SMarek Vasut dctx->size / sizeof(*dctx->payload) - 1; 641bce88370SMarek Vasut 642bce88370SMarek Vasut /* NOOP has only 4 bytes and no payload. */ 643bce88370SMarek Vasut goto noop; 644bce88370SMarek Vasut } else { 645bce88370SMarek Vasut /* 646bce88370SMarek Vasut * Either a different instruction block started now 647bce88370SMarek Vasut * or this is the first instruction block. 648bce88370SMarek Vasut */ 649bce88370SMarek Vasut ret = sb_grow_dcd(dctx, 12); 650bce88370SMarek Vasut if (ret) 651bce88370SMarek Vasut return ret; 652bce88370SMarek Vasut 653bce88370SMarek Vasut /* Update DCD command block pointer. */ 654bce88370SMarek Vasut dctx->prev_dcd_head = dctx->payload + 655bce88370SMarek Vasut dctx->size / sizeof(*dctx->payload) - 3; 656bce88370SMarek Vasut } 657bce88370SMarek Vasut 658bce88370SMarek Vasut dcd = dctx->payload + dctx->size / sizeof(*dctx->payload) - 2; 659bce88370SMarek Vasut 660bce88370SMarek Vasut /* 661bce88370SMarek Vasut * Prepare the command. 662bce88370SMarek Vasut */ 663bce88370SMarek Vasut tok = strtok(cmd->cmd, " "); 664bce88370SMarek Vasut if (!tok) { 665bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Missing DCD address!\n", 666bce88370SMarek Vasut cmd->lineno); 667bce88370SMarek Vasut ret = -EINVAL; 668bce88370SMarek Vasut goto err; 669bce88370SMarek Vasut } 670bce88370SMarek Vasut 671bce88370SMarek Vasut /* Read DCD destination address. */ 672bce88370SMarek Vasut ret = sb_token_to_long(tok, &address); 673bce88370SMarek Vasut if (ret) { 674bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Incorrect DCD address!\n", 675bce88370SMarek Vasut cmd->lineno); 676bce88370SMarek Vasut goto err; 677bce88370SMarek Vasut } 678bce88370SMarek Vasut 679bce88370SMarek Vasut tok = strtok(NULL, " "); 680bce88370SMarek Vasut if (!tok) { 681bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Missing DCD value!\n", 682bce88370SMarek Vasut cmd->lineno); 683bce88370SMarek Vasut ret = -EINVAL; 684bce88370SMarek Vasut goto err; 685bce88370SMarek Vasut } 686bce88370SMarek Vasut 687bce88370SMarek Vasut /* Read DCD operation value. */ 688bce88370SMarek Vasut ret = sb_token_to_long(tok, &value); 689bce88370SMarek Vasut if (ret) { 690bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Incorrect DCD value!\n", 691bce88370SMarek Vasut cmd->lineno); 692bce88370SMarek Vasut goto err; 693bce88370SMarek Vasut } 694bce88370SMarek Vasut 695bce88370SMarek Vasut /* Fill in the new DCD entry. */ 696bce88370SMarek Vasut dcd[0] = htonl(address); 697bce88370SMarek Vasut dcd[1] = htonl(value); 698bce88370SMarek Vasut 699bce88370SMarek Vasut noop: 700bce88370SMarek Vasut /* Update the DCD command block. */ 701bce88370SMarek Vasut length = dctx->size - 702bce88370SMarek Vasut ((dctx->prev_dcd_head - dctx->payload) * 703bce88370SMarek Vasut sizeof(*dctx->payload)); 704bce88370SMarek Vasut dctx->prev_dcd_head[0] = htonl(type | (length << 8)); 705bce88370SMarek Vasut 706bce88370SMarek Vasut err: 707bce88370SMarek Vasut return ret; 708bce88370SMarek Vasut } 709bce88370SMarek Vasut 710bce88370SMarek Vasut static int sb_build_section(struct sb_image_ctx *ictx, struct sb_cmd_list *cmd) 711bce88370SMarek Vasut { 712bce88370SMarek Vasut struct sb_section_ctx *sctx; 713bce88370SMarek Vasut struct sb_sections_header *shdr; 714bce88370SMarek Vasut char *tok; 715bce88370SMarek Vasut uint32_t bootable = 0; 716bce88370SMarek Vasut uint32_t id; 717bce88370SMarek Vasut int ret; 718bce88370SMarek Vasut 719bce88370SMarek Vasut sctx = calloc(1, sizeof(*sctx)); 720bce88370SMarek Vasut if (!sctx) 721bce88370SMarek Vasut return -ENOMEM; 722bce88370SMarek Vasut 723bce88370SMarek Vasut /* Read section number. */ 724bce88370SMarek Vasut tok = strtok(cmd->cmd, " "); 725bce88370SMarek Vasut if (!tok) { 726bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Section without number!\n", 727bce88370SMarek Vasut cmd->lineno); 728bce88370SMarek Vasut ret = -EINVAL; 729bce88370SMarek Vasut goto err_sect; 730bce88370SMarek Vasut } 731bce88370SMarek Vasut 732bce88370SMarek Vasut /* Parse the section number. */ 733bce88370SMarek Vasut ret = sb_token_to_long(tok, &id); 734bce88370SMarek Vasut if (ret) { 735bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Malformed section number!\n", 736bce88370SMarek Vasut cmd->lineno); 737bce88370SMarek Vasut goto err_sect; 738bce88370SMarek Vasut } 739bce88370SMarek Vasut 740bce88370SMarek Vasut /* Read section's BOOTABLE flag. */ 741bce88370SMarek Vasut tok = strtok(NULL, " "); 742bce88370SMarek Vasut if (tok && (strlen(tok) == 8) && !strncmp(tok, "BOOTABLE", 8)) 743bce88370SMarek Vasut bootable = SB_SECTION_FLAG_BOOTABLE; 744bce88370SMarek Vasut 745bce88370SMarek Vasut sctx->boot = bootable; 746bce88370SMarek Vasut 747bce88370SMarek Vasut shdr = &sctx->payload; 748bce88370SMarek Vasut shdr->section_number = id; 749bce88370SMarek Vasut shdr->section_flags = bootable; 750bce88370SMarek Vasut 751bce88370SMarek Vasut /* 752bce88370SMarek Vasut * The section is now constructed. Append it to the list. 753bce88370SMarek Vasut * WARNING: The section size is still not computed and will 754bce88370SMarek Vasut * be updated while parsing it's commands. 755bce88370SMarek Vasut */ 756bce88370SMarek Vasut ictx->sect_count++; 757bce88370SMarek Vasut 758bce88370SMarek Vasut /* Mark that this section is bootable one. */ 759bce88370SMarek Vasut if (bootable) { 760bce88370SMarek Vasut if (ictx->sect_boot_found) { 761bce88370SMarek Vasut fprintf(stderr, 762bce88370SMarek Vasut "#%i WARN: Multiple bootable section!\n", 763bce88370SMarek Vasut cmd->lineno); 764bce88370SMarek Vasut } else { 765bce88370SMarek Vasut ictx->sect_boot = id; 766bce88370SMarek Vasut ictx->sect_boot_found = 1; 767bce88370SMarek Vasut } 768bce88370SMarek Vasut } 769bce88370SMarek Vasut 770bce88370SMarek Vasut if (!ictx->sect_head) { 771bce88370SMarek Vasut ictx->sect_head = sctx; 772bce88370SMarek Vasut ictx->sect_tail = sctx; 773bce88370SMarek Vasut } else { 774bce88370SMarek Vasut ictx->sect_tail->sect = sctx; 775bce88370SMarek Vasut ictx->sect_tail = sctx; 776bce88370SMarek Vasut } 777bce88370SMarek Vasut 778bce88370SMarek Vasut return 0; 779bce88370SMarek Vasut 780bce88370SMarek Vasut err_sect: 781bce88370SMarek Vasut free(sctx); 782bce88370SMarek Vasut return ret; 783bce88370SMarek Vasut } 784bce88370SMarek Vasut 785bce88370SMarek Vasut static int sb_build_command_nop(struct sb_image_ctx *ictx) 786bce88370SMarek Vasut { 787bce88370SMarek Vasut struct sb_section_ctx *sctx = ictx->sect_tail; 788bce88370SMarek Vasut struct sb_cmd_ctx *cctx; 789bce88370SMarek Vasut struct sb_command *ccmd; 790bce88370SMarek Vasut 791bce88370SMarek Vasut cctx = calloc(1, sizeof(*cctx)); 792bce88370SMarek Vasut if (!cctx) 793bce88370SMarek Vasut return -ENOMEM; 794bce88370SMarek Vasut 795bce88370SMarek Vasut ccmd = &cctx->payload; 796bce88370SMarek Vasut 797bce88370SMarek Vasut /* 798bce88370SMarek Vasut * Construct the command. 799bce88370SMarek Vasut */ 800bce88370SMarek Vasut ccmd->header.checksum = 0x5a; 801bce88370SMarek Vasut ccmd->header.tag = ROM_NOP_CMD; 802bce88370SMarek Vasut 803bce88370SMarek Vasut cctx->size = sizeof(*ccmd); 804bce88370SMarek Vasut 805bce88370SMarek Vasut /* 806bce88370SMarek Vasut * Append the command to the last section. 807bce88370SMarek Vasut */ 808bce88370SMarek Vasut if (!sctx->cmd_head) { 809bce88370SMarek Vasut sctx->cmd_head = cctx; 810bce88370SMarek Vasut sctx->cmd_tail = cctx; 811bce88370SMarek Vasut } else { 812bce88370SMarek Vasut sctx->cmd_tail->cmd = cctx; 813bce88370SMarek Vasut sctx->cmd_tail = cctx; 814bce88370SMarek Vasut } 815bce88370SMarek Vasut 816bce88370SMarek Vasut return 0; 817bce88370SMarek Vasut } 818bce88370SMarek Vasut 819bce88370SMarek Vasut static int sb_build_command_tag(struct sb_image_ctx *ictx, 820bce88370SMarek Vasut struct sb_cmd_list *cmd) 821bce88370SMarek Vasut { 822bce88370SMarek Vasut struct sb_section_ctx *sctx = ictx->sect_tail; 823bce88370SMarek Vasut struct sb_cmd_ctx *cctx; 824bce88370SMarek Vasut struct sb_command *ccmd; 825bce88370SMarek Vasut char *tok; 826bce88370SMarek Vasut 827bce88370SMarek Vasut cctx = calloc(1, sizeof(*cctx)); 828bce88370SMarek Vasut if (!cctx) 829bce88370SMarek Vasut return -ENOMEM; 830bce88370SMarek Vasut 831bce88370SMarek Vasut ccmd = &cctx->payload; 832bce88370SMarek Vasut 833bce88370SMarek Vasut /* 834bce88370SMarek Vasut * Prepare the command. 835bce88370SMarek Vasut */ 836bce88370SMarek Vasut /* Check for the LAST keyword. */ 837bce88370SMarek Vasut tok = strtok(cmd->cmd, " "); 838bce88370SMarek Vasut if (tok && !strcmp(tok, "LAST")) 839bce88370SMarek Vasut ccmd->header.flags = ROM_TAG_CMD_FLAG_ROM_LAST_TAG; 840bce88370SMarek Vasut 841bce88370SMarek Vasut /* 842bce88370SMarek Vasut * Construct the command. 843bce88370SMarek Vasut */ 844bce88370SMarek Vasut ccmd->header.checksum = 0x5a; 845bce88370SMarek Vasut ccmd->header.tag = ROM_TAG_CMD; 846bce88370SMarek Vasut 847bce88370SMarek Vasut cctx->size = sizeof(*ccmd); 848bce88370SMarek Vasut 849bce88370SMarek Vasut /* 850bce88370SMarek Vasut * Append the command to the last section. 851bce88370SMarek Vasut */ 852bce88370SMarek Vasut if (!sctx->cmd_head) { 853bce88370SMarek Vasut sctx->cmd_head = cctx; 854bce88370SMarek Vasut sctx->cmd_tail = cctx; 855bce88370SMarek Vasut } else { 856bce88370SMarek Vasut sctx->cmd_tail->cmd = cctx; 857bce88370SMarek Vasut sctx->cmd_tail = cctx; 858bce88370SMarek Vasut } 859bce88370SMarek Vasut 860bce88370SMarek Vasut return 0; 861bce88370SMarek Vasut } 862bce88370SMarek Vasut 863bce88370SMarek Vasut static int sb_build_command_load(struct sb_image_ctx *ictx, 864bce88370SMarek Vasut struct sb_cmd_list *cmd) 865bce88370SMarek Vasut { 866bce88370SMarek Vasut struct sb_section_ctx *sctx = ictx->sect_tail; 867bce88370SMarek Vasut struct sb_cmd_ctx *cctx; 868bce88370SMarek Vasut struct sb_command *ccmd; 869bce88370SMarek Vasut char *tok; 870bce88370SMarek Vasut int ret, is_ivt = 0, is_dcd = 0; 871bce88370SMarek Vasut uint32_t dest, dcd = 0; 872bce88370SMarek Vasut 873bce88370SMarek Vasut cctx = calloc(1, sizeof(*cctx)); 874bce88370SMarek Vasut if (!cctx) 875bce88370SMarek Vasut return -ENOMEM; 876bce88370SMarek Vasut 877bce88370SMarek Vasut ccmd = &cctx->payload; 878bce88370SMarek Vasut 879bce88370SMarek Vasut /* 880bce88370SMarek Vasut * Prepare the command. 881bce88370SMarek Vasut */ 882bce88370SMarek Vasut tok = strtok(cmd->cmd, " "); 883bce88370SMarek Vasut if (!tok) { 884bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Missing LOAD address or 'IVT'!\n", 885bce88370SMarek Vasut cmd->lineno); 886bce88370SMarek Vasut ret = -EINVAL; 887bce88370SMarek Vasut goto err; 888bce88370SMarek Vasut } 889bce88370SMarek Vasut 890bce88370SMarek Vasut /* Check for "IVT" flag. */ 891bce88370SMarek Vasut if (!strcmp(tok, "IVT")) 892bce88370SMarek Vasut is_ivt = 1; 893bce88370SMarek Vasut if (!strcmp(tok, "DCD")) 894bce88370SMarek Vasut is_dcd = 1; 895bce88370SMarek Vasut if (is_ivt || is_dcd) { 896bce88370SMarek Vasut tok = strtok(NULL, " "); 897bce88370SMarek Vasut if (!tok) { 898bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Missing LOAD address!\n", 899bce88370SMarek Vasut cmd->lineno); 900bce88370SMarek Vasut ret = -EINVAL; 901bce88370SMarek Vasut goto err; 902bce88370SMarek Vasut } 903bce88370SMarek Vasut } 904bce88370SMarek Vasut 905bce88370SMarek Vasut /* Read load destination address. */ 906bce88370SMarek Vasut ret = sb_token_to_long(tok, &dest); 907bce88370SMarek Vasut if (ret) { 908bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Incorrect LOAD address!\n", 909bce88370SMarek Vasut cmd->lineno); 910bce88370SMarek Vasut goto err; 911bce88370SMarek Vasut } 912bce88370SMarek Vasut 913bce88370SMarek Vasut /* Read filename or IVT entrypoint or DCD block ID. */ 914bce88370SMarek Vasut tok = strtok(NULL, " "); 915bce88370SMarek Vasut if (!tok) { 916bce88370SMarek Vasut fprintf(stderr, 917bce88370SMarek Vasut "#%i ERR: Missing LOAD filename or IVT ep or DCD block ID!\n", 918bce88370SMarek Vasut cmd->lineno); 919bce88370SMarek Vasut ret = -EINVAL; 920bce88370SMarek Vasut goto err; 921bce88370SMarek Vasut } 922bce88370SMarek Vasut 923bce88370SMarek Vasut if (is_ivt) { 924bce88370SMarek Vasut /* Handle IVT. */ 925bce88370SMarek Vasut struct sb_ivt_header *ivt; 926bce88370SMarek Vasut uint32_t ivtep; 927bce88370SMarek Vasut ret = sb_token_to_long(tok, &ivtep); 928bce88370SMarek Vasut 929bce88370SMarek Vasut if (ret) { 930bce88370SMarek Vasut fprintf(stderr, 931bce88370SMarek Vasut "#%i ERR: Incorrect IVT entry point!\n", 932bce88370SMarek Vasut cmd->lineno); 933bce88370SMarek Vasut goto err; 934bce88370SMarek Vasut } 935bce88370SMarek Vasut 936bce88370SMarek Vasut ivt = calloc(1, sizeof(*ivt)); 937bce88370SMarek Vasut if (!ivt) { 938bce88370SMarek Vasut ret = -ENOMEM; 939bce88370SMarek Vasut goto err; 940bce88370SMarek Vasut } 941bce88370SMarek Vasut 942bce88370SMarek Vasut ivt->header = sb_hab_ivt_header(); 943bce88370SMarek Vasut ivt->entry = ivtep; 944bce88370SMarek Vasut ivt->self = dest; 945bce88370SMarek Vasut 946bce88370SMarek Vasut cctx->data = (uint8_t *)ivt; 947bce88370SMarek Vasut cctx->length = sizeof(*ivt); 948bce88370SMarek Vasut } else if (is_dcd) { 949bce88370SMarek Vasut struct sb_dcd_ctx *dctx = ictx->dcd_head; 950bce88370SMarek Vasut uint32_t dcdid; 951bce88370SMarek Vasut uint8_t *payload; 952bce88370SMarek Vasut uint32_t asize; 953bce88370SMarek Vasut ret = sb_token_to_long(tok, &dcdid); 954bce88370SMarek Vasut 955bce88370SMarek Vasut if (ret) { 956bce88370SMarek Vasut fprintf(stderr, 957bce88370SMarek Vasut "#%i ERR: Incorrect DCD block ID!\n", 958bce88370SMarek Vasut cmd->lineno); 959bce88370SMarek Vasut goto err; 960bce88370SMarek Vasut } 961bce88370SMarek Vasut 962bce88370SMarek Vasut while (dctx) { 963bce88370SMarek Vasut if (dctx->id == dcdid) 964bce88370SMarek Vasut break; 965bce88370SMarek Vasut dctx = dctx->dcd; 966bce88370SMarek Vasut } 967bce88370SMarek Vasut 968bce88370SMarek Vasut if (!dctx) { 969bce88370SMarek Vasut fprintf(stderr, "#%i ERR: DCD block %08x not found!\n", 970bce88370SMarek Vasut cmd->lineno, dcdid); 971bce88370SMarek Vasut goto err; 972bce88370SMarek Vasut } 973bce88370SMarek Vasut 974bce88370SMarek Vasut asize = roundup(dctx->size, SB_BLOCK_SIZE); 975bce88370SMarek Vasut payload = calloc(1, asize); 976bce88370SMarek Vasut if (!payload) { 977bce88370SMarek Vasut ret = -ENOMEM; 978bce88370SMarek Vasut goto err; 979bce88370SMarek Vasut } 980bce88370SMarek Vasut 981bce88370SMarek Vasut memcpy(payload, dctx->payload, dctx->size); 982bce88370SMarek Vasut 983bce88370SMarek Vasut cctx->data = payload; 984bce88370SMarek Vasut cctx->length = asize; 985bce88370SMarek Vasut 986bce88370SMarek Vasut /* Set the Load DCD flag. */ 987bce88370SMarek Vasut dcd = ROM_LOAD_CMD_FLAG_DCD_LOAD; 988bce88370SMarek Vasut } else { 989bce88370SMarek Vasut /* Regular LOAD of a file. */ 990bce88370SMarek Vasut ret = sb_load_file(cctx, tok); 991bce88370SMarek Vasut if (ret) { 992bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Cannot load '%s'!\n", 993bce88370SMarek Vasut cmd->lineno, tok); 994bce88370SMarek Vasut goto err; 995bce88370SMarek Vasut } 996bce88370SMarek Vasut } 997bce88370SMarek Vasut 998bce88370SMarek Vasut if (cctx->length & (SB_BLOCK_SIZE - 1)) { 999bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Unaligned payload!\n", 1000bce88370SMarek Vasut cmd->lineno); 1001bce88370SMarek Vasut } 1002bce88370SMarek Vasut 1003bce88370SMarek Vasut /* 1004bce88370SMarek Vasut * Construct the command. 1005bce88370SMarek Vasut */ 1006bce88370SMarek Vasut ccmd->header.checksum = 0x5a; 1007bce88370SMarek Vasut ccmd->header.tag = ROM_LOAD_CMD; 1008bce88370SMarek Vasut ccmd->header.flags = dcd; 1009bce88370SMarek Vasut 1010bce88370SMarek Vasut ccmd->load.address = dest; 1011bce88370SMarek Vasut ccmd->load.count = cctx->length; 101225308f45SCharles Manning ccmd->load.crc32 = pbl_crc32(0, 101325308f45SCharles Manning (const char *)cctx->data, 101425308f45SCharles Manning cctx->length); 1015bce88370SMarek Vasut 1016bce88370SMarek Vasut cctx->size = sizeof(*ccmd) + cctx->length; 1017bce88370SMarek Vasut 1018bce88370SMarek Vasut /* 1019bce88370SMarek Vasut * Append the command to the last section. 1020bce88370SMarek Vasut */ 1021bce88370SMarek Vasut if (!sctx->cmd_head) { 1022bce88370SMarek Vasut sctx->cmd_head = cctx; 1023bce88370SMarek Vasut sctx->cmd_tail = cctx; 1024bce88370SMarek Vasut } else { 1025bce88370SMarek Vasut sctx->cmd_tail->cmd = cctx; 1026bce88370SMarek Vasut sctx->cmd_tail = cctx; 1027bce88370SMarek Vasut } 1028bce88370SMarek Vasut 1029bce88370SMarek Vasut return 0; 1030bce88370SMarek Vasut 1031bce88370SMarek Vasut err: 1032bce88370SMarek Vasut free(cctx); 1033bce88370SMarek Vasut return ret; 1034bce88370SMarek Vasut } 1035bce88370SMarek Vasut 1036bce88370SMarek Vasut static int sb_build_command_fill(struct sb_image_ctx *ictx, 1037bce88370SMarek Vasut struct sb_cmd_list *cmd) 1038bce88370SMarek Vasut { 1039bce88370SMarek Vasut struct sb_section_ctx *sctx = ictx->sect_tail; 1040bce88370SMarek Vasut struct sb_cmd_ctx *cctx; 1041bce88370SMarek Vasut struct sb_command *ccmd; 1042bce88370SMarek Vasut char *tok; 1043bce88370SMarek Vasut uint32_t address, pattern, length; 1044bce88370SMarek Vasut int ret; 1045bce88370SMarek Vasut 1046bce88370SMarek Vasut cctx = calloc(1, sizeof(*cctx)); 1047bce88370SMarek Vasut if (!cctx) 1048bce88370SMarek Vasut return -ENOMEM; 1049bce88370SMarek Vasut 1050bce88370SMarek Vasut ccmd = &cctx->payload; 1051bce88370SMarek Vasut 1052bce88370SMarek Vasut /* 1053bce88370SMarek Vasut * Prepare the command. 1054bce88370SMarek Vasut */ 1055bce88370SMarek Vasut tok = strtok(cmd->cmd, " "); 1056bce88370SMarek Vasut if (!tok) { 1057bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Missing FILL address!\n", 1058bce88370SMarek Vasut cmd->lineno); 1059bce88370SMarek Vasut ret = -EINVAL; 1060bce88370SMarek Vasut goto err; 1061bce88370SMarek Vasut } 1062bce88370SMarek Vasut 1063bce88370SMarek Vasut /* Read fill destination address. */ 1064bce88370SMarek Vasut ret = sb_token_to_long(tok, &address); 1065bce88370SMarek Vasut if (ret) { 1066bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Incorrect FILL address!\n", 1067bce88370SMarek Vasut cmd->lineno); 1068bce88370SMarek Vasut goto err; 1069bce88370SMarek Vasut } 1070bce88370SMarek Vasut 1071bce88370SMarek Vasut tok = strtok(NULL, " "); 1072bce88370SMarek Vasut if (!tok) { 1073bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Missing FILL pattern!\n", 1074bce88370SMarek Vasut cmd->lineno); 1075bce88370SMarek Vasut ret = -EINVAL; 1076bce88370SMarek Vasut goto err; 1077bce88370SMarek Vasut } 1078bce88370SMarek Vasut 1079bce88370SMarek Vasut /* Read fill pattern address. */ 1080bce88370SMarek Vasut ret = sb_token_to_long(tok, &pattern); 1081bce88370SMarek Vasut if (ret) { 1082bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Incorrect FILL pattern!\n", 1083bce88370SMarek Vasut cmd->lineno); 1084bce88370SMarek Vasut goto err; 1085bce88370SMarek Vasut } 1086bce88370SMarek Vasut 1087bce88370SMarek Vasut tok = strtok(NULL, " "); 1088bce88370SMarek Vasut if (!tok) { 1089bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Missing FILL length!\n", 1090bce88370SMarek Vasut cmd->lineno); 1091bce88370SMarek Vasut ret = -EINVAL; 1092bce88370SMarek Vasut goto err; 1093bce88370SMarek Vasut } 1094bce88370SMarek Vasut 1095bce88370SMarek Vasut /* Read fill pattern address. */ 1096bce88370SMarek Vasut ret = sb_token_to_long(tok, &length); 1097bce88370SMarek Vasut if (ret) { 1098bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Incorrect FILL length!\n", 1099bce88370SMarek Vasut cmd->lineno); 1100bce88370SMarek Vasut goto err; 1101bce88370SMarek Vasut } 1102bce88370SMarek Vasut 1103bce88370SMarek Vasut /* 1104bce88370SMarek Vasut * Construct the command. 1105bce88370SMarek Vasut */ 1106bce88370SMarek Vasut ccmd->header.checksum = 0x5a; 1107bce88370SMarek Vasut ccmd->header.tag = ROM_FILL_CMD; 1108bce88370SMarek Vasut 1109bce88370SMarek Vasut ccmd->fill.address = address; 1110bce88370SMarek Vasut ccmd->fill.count = length; 1111bce88370SMarek Vasut ccmd->fill.pattern = pattern; 1112bce88370SMarek Vasut 1113bce88370SMarek Vasut cctx->size = sizeof(*ccmd); 1114bce88370SMarek Vasut 1115bce88370SMarek Vasut /* 1116bce88370SMarek Vasut * Append the command to the last section. 1117bce88370SMarek Vasut */ 1118bce88370SMarek Vasut if (!sctx->cmd_head) { 1119bce88370SMarek Vasut sctx->cmd_head = cctx; 1120bce88370SMarek Vasut sctx->cmd_tail = cctx; 1121bce88370SMarek Vasut } else { 1122bce88370SMarek Vasut sctx->cmd_tail->cmd = cctx; 1123bce88370SMarek Vasut sctx->cmd_tail = cctx; 1124bce88370SMarek Vasut } 1125bce88370SMarek Vasut 1126bce88370SMarek Vasut return 0; 1127bce88370SMarek Vasut 1128bce88370SMarek Vasut err: 1129bce88370SMarek Vasut free(cctx); 1130bce88370SMarek Vasut return ret; 1131bce88370SMarek Vasut } 1132bce88370SMarek Vasut 1133bce88370SMarek Vasut static int sb_build_command_jump_call(struct sb_image_ctx *ictx, 1134bce88370SMarek Vasut struct sb_cmd_list *cmd, 1135bce88370SMarek Vasut unsigned int is_call) 1136bce88370SMarek Vasut { 1137bce88370SMarek Vasut struct sb_section_ctx *sctx = ictx->sect_tail; 1138bce88370SMarek Vasut struct sb_cmd_ctx *cctx; 1139bce88370SMarek Vasut struct sb_command *ccmd; 1140bce88370SMarek Vasut char *tok; 1141bce88370SMarek Vasut uint32_t dest, arg = 0x0; 1142bce88370SMarek Vasut uint32_t hab = 0; 1143bce88370SMarek Vasut int ret; 1144bce88370SMarek Vasut const char *cmdname = is_call ? "CALL" : "JUMP"; 1145bce88370SMarek Vasut 1146bce88370SMarek Vasut cctx = calloc(1, sizeof(*cctx)); 1147bce88370SMarek Vasut if (!cctx) 1148bce88370SMarek Vasut return -ENOMEM; 1149bce88370SMarek Vasut 1150bce88370SMarek Vasut ccmd = &cctx->payload; 1151bce88370SMarek Vasut 1152bce88370SMarek Vasut /* 1153bce88370SMarek Vasut * Prepare the command. 1154bce88370SMarek Vasut */ 1155bce88370SMarek Vasut tok = strtok(cmd->cmd, " "); 1156bce88370SMarek Vasut if (!tok) { 1157bce88370SMarek Vasut fprintf(stderr, 1158bce88370SMarek Vasut "#%i ERR: Missing %s address or 'HAB'!\n", 1159bce88370SMarek Vasut cmd->lineno, cmdname); 1160bce88370SMarek Vasut ret = -EINVAL; 1161bce88370SMarek Vasut goto err; 1162bce88370SMarek Vasut } 1163bce88370SMarek Vasut 1164bce88370SMarek Vasut /* Check for "HAB" flag. */ 1165bce88370SMarek Vasut if (!strcmp(tok, "HAB")) { 1166bce88370SMarek Vasut hab = is_call ? ROM_CALL_CMD_FLAG_HAB : ROM_JUMP_CMD_FLAG_HAB; 1167bce88370SMarek Vasut tok = strtok(NULL, " "); 1168bce88370SMarek Vasut if (!tok) { 1169bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Missing %s address!\n", 1170bce88370SMarek Vasut cmd->lineno, cmdname); 1171bce88370SMarek Vasut ret = -EINVAL; 1172bce88370SMarek Vasut goto err; 1173bce88370SMarek Vasut } 1174bce88370SMarek Vasut } 1175bce88370SMarek Vasut /* Read load destination address. */ 1176bce88370SMarek Vasut ret = sb_token_to_long(tok, &dest); 1177bce88370SMarek Vasut if (ret) { 1178bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Incorrect %s address!\n", 1179bce88370SMarek Vasut cmd->lineno, cmdname); 1180bce88370SMarek Vasut goto err; 1181bce88370SMarek Vasut } 1182bce88370SMarek Vasut 1183bce88370SMarek Vasut tok = strtok(NULL, " "); 1184bce88370SMarek Vasut if (tok) { 1185bce88370SMarek Vasut ret = sb_token_to_long(tok, &arg); 1186bce88370SMarek Vasut if (ret) { 1187bce88370SMarek Vasut fprintf(stderr, 1188bce88370SMarek Vasut "#%i ERR: Incorrect %s argument!\n", 1189bce88370SMarek Vasut cmd->lineno, cmdname); 1190bce88370SMarek Vasut goto err; 1191bce88370SMarek Vasut } 1192bce88370SMarek Vasut } 1193bce88370SMarek Vasut 1194bce88370SMarek Vasut /* 1195bce88370SMarek Vasut * Construct the command. 1196bce88370SMarek Vasut */ 1197bce88370SMarek Vasut ccmd->header.checksum = 0x5a; 1198bce88370SMarek Vasut ccmd->header.tag = is_call ? ROM_CALL_CMD : ROM_JUMP_CMD; 1199bce88370SMarek Vasut ccmd->header.flags = hab; 1200bce88370SMarek Vasut 1201bce88370SMarek Vasut ccmd->call.address = dest; 1202bce88370SMarek Vasut ccmd->call.argument = arg; 1203bce88370SMarek Vasut 1204bce88370SMarek Vasut cctx->size = sizeof(*ccmd); 1205bce88370SMarek Vasut 1206bce88370SMarek Vasut /* 1207bce88370SMarek Vasut * Append the command to the last section. 1208bce88370SMarek Vasut */ 1209bce88370SMarek Vasut if (!sctx->cmd_head) { 1210bce88370SMarek Vasut sctx->cmd_head = cctx; 1211bce88370SMarek Vasut sctx->cmd_tail = cctx; 1212bce88370SMarek Vasut } else { 1213bce88370SMarek Vasut sctx->cmd_tail->cmd = cctx; 1214bce88370SMarek Vasut sctx->cmd_tail = cctx; 1215bce88370SMarek Vasut } 1216bce88370SMarek Vasut 1217bce88370SMarek Vasut return 0; 1218bce88370SMarek Vasut 1219bce88370SMarek Vasut err: 1220bce88370SMarek Vasut free(cctx); 1221bce88370SMarek Vasut return ret; 1222bce88370SMarek Vasut } 1223bce88370SMarek Vasut 1224bce88370SMarek Vasut static int sb_build_command_jump(struct sb_image_ctx *ictx, 1225bce88370SMarek Vasut struct sb_cmd_list *cmd) 1226bce88370SMarek Vasut { 1227bce88370SMarek Vasut return sb_build_command_jump_call(ictx, cmd, 0); 1228bce88370SMarek Vasut } 1229bce88370SMarek Vasut 1230bce88370SMarek Vasut static int sb_build_command_call(struct sb_image_ctx *ictx, 1231bce88370SMarek Vasut struct sb_cmd_list *cmd) 1232bce88370SMarek Vasut { 1233bce88370SMarek Vasut return sb_build_command_jump_call(ictx, cmd, 1); 1234bce88370SMarek Vasut } 1235bce88370SMarek Vasut 1236bce88370SMarek Vasut static int sb_build_command_mode(struct sb_image_ctx *ictx, 1237bce88370SMarek Vasut struct sb_cmd_list *cmd) 1238bce88370SMarek Vasut { 1239bce88370SMarek Vasut struct sb_section_ctx *sctx = ictx->sect_tail; 1240bce88370SMarek Vasut struct sb_cmd_ctx *cctx; 1241bce88370SMarek Vasut struct sb_command *ccmd; 1242bce88370SMarek Vasut char *tok; 1243bce88370SMarek Vasut int ret; 1244bce88370SMarek Vasut unsigned int i; 1245bce88370SMarek Vasut uint32_t mode = 0xffffffff; 1246bce88370SMarek Vasut 1247bce88370SMarek Vasut cctx = calloc(1, sizeof(*cctx)); 1248bce88370SMarek Vasut if (!cctx) 1249bce88370SMarek Vasut return -ENOMEM; 1250bce88370SMarek Vasut 1251bce88370SMarek Vasut ccmd = &cctx->payload; 1252bce88370SMarek Vasut 1253bce88370SMarek Vasut /* 1254bce88370SMarek Vasut * Prepare the command. 1255bce88370SMarek Vasut */ 1256bce88370SMarek Vasut tok = strtok(cmd->cmd, " "); 1257bce88370SMarek Vasut if (!tok) { 1258bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Missing MODE boot mode argument!\n", 1259bce88370SMarek Vasut cmd->lineno); 1260bce88370SMarek Vasut ret = -EINVAL; 1261bce88370SMarek Vasut goto err; 1262bce88370SMarek Vasut } 1263bce88370SMarek Vasut 1264bce88370SMarek Vasut for (i = 0; i < ARRAY_SIZE(modetable); i++) { 1265bce88370SMarek Vasut if (!strcmp(tok, modetable[i].name)) { 1266bce88370SMarek Vasut mode = modetable[i].mode; 1267bce88370SMarek Vasut break; 1268bce88370SMarek Vasut } 1269bce88370SMarek Vasut 1270bce88370SMarek Vasut if (!modetable[i].altname) 1271bce88370SMarek Vasut continue; 1272bce88370SMarek Vasut 1273bce88370SMarek Vasut if (!strcmp(tok, modetable[i].altname)) { 1274bce88370SMarek Vasut mode = modetable[i].mode; 1275bce88370SMarek Vasut break; 1276bce88370SMarek Vasut } 1277bce88370SMarek Vasut } 1278bce88370SMarek Vasut 1279bce88370SMarek Vasut if (mode == 0xffffffff) { 1280bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Invalid MODE boot mode argument!\n", 1281bce88370SMarek Vasut cmd->lineno); 1282bce88370SMarek Vasut ret = -EINVAL; 1283bce88370SMarek Vasut goto err; 1284bce88370SMarek Vasut } 1285bce88370SMarek Vasut 1286bce88370SMarek Vasut /* 1287bce88370SMarek Vasut * Construct the command. 1288bce88370SMarek Vasut */ 1289bce88370SMarek Vasut ccmd->header.checksum = 0x5a; 1290bce88370SMarek Vasut ccmd->header.tag = ROM_MODE_CMD; 1291bce88370SMarek Vasut 1292bce88370SMarek Vasut ccmd->mode.mode = mode; 1293bce88370SMarek Vasut 1294bce88370SMarek Vasut cctx->size = sizeof(*ccmd); 1295bce88370SMarek Vasut 1296bce88370SMarek Vasut /* 1297bce88370SMarek Vasut * Append the command to the last section. 1298bce88370SMarek Vasut */ 1299bce88370SMarek Vasut if (!sctx->cmd_head) { 1300bce88370SMarek Vasut sctx->cmd_head = cctx; 1301bce88370SMarek Vasut sctx->cmd_tail = cctx; 1302bce88370SMarek Vasut } else { 1303bce88370SMarek Vasut sctx->cmd_tail->cmd = cctx; 1304bce88370SMarek Vasut sctx->cmd_tail = cctx; 1305bce88370SMarek Vasut } 1306bce88370SMarek Vasut 1307bce88370SMarek Vasut return 0; 1308bce88370SMarek Vasut 1309bce88370SMarek Vasut err: 1310bce88370SMarek Vasut free(cctx); 1311bce88370SMarek Vasut return ret; 1312bce88370SMarek Vasut } 1313bce88370SMarek Vasut 1314bce88370SMarek Vasut static int sb_prefill_image_header(struct sb_image_ctx *ictx) 1315bce88370SMarek Vasut { 1316bce88370SMarek Vasut struct sb_boot_image_header *hdr = &ictx->payload; 1317bce88370SMarek Vasut 1318bce88370SMarek Vasut /* Fill signatures */ 1319bce88370SMarek Vasut memcpy(hdr->signature1, "STMP", 4); 1320bce88370SMarek Vasut memcpy(hdr->signature2, "sgtl", 4); 1321bce88370SMarek Vasut 1322bce88370SMarek Vasut /* SB Image version 1.1 */ 1323bce88370SMarek Vasut hdr->major_version = SB_VERSION_MAJOR; 1324bce88370SMarek Vasut hdr->minor_version = SB_VERSION_MINOR; 1325bce88370SMarek Vasut 1326bce88370SMarek Vasut /* Boot image major version */ 1327bce88370SMarek Vasut hdr->product_version.major = htons(0x999); 1328bce88370SMarek Vasut hdr->product_version.minor = htons(0x999); 1329bce88370SMarek Vasut hdr->product_version.revision = htons(0x999); 1330bce88370SMarek Vasut /* Boot image major version */ 1331bce88370SMarek Vasut hdr->component_version.major = htons(0x999); 1332bce88370SMarek Vasut hdr->component_version.minor = htons(0x999); 1333bce88370SMarek Vasut hdr->component_version.revision = htons(0x999); 1334bce88370SMarek Vasut 1335bce88370SMarek Vasut /* Drive tag must be 0x0 for i.MX23 */ 1336bce88370SMarek Vasut hdr->drive_tag = 0; 1337bce88370SMarek Vasut 1338bce88370SMarek Vasut hdr->header_blocks = 1339bce88370SMarek Vasut sizeof(struct sb_boot_image_header) / SB_BLOCK_SIZE; 1340bce88370SMarek Vasut hdr->section_header_size = 1341bce88370SMarek Vasut sizeof(struct sb_sections_header) / SB_BLOCK_SIZE; 1342bce88370SMarek Vasut hdr->timestamp_us = sb_get_timestamp() * 1000000; 1343bce88370SMarek Vasut 13447a139959SAlexey Ignatov hdr->flags = ictx->display_progress ? 13457a139959SAlexey Ignatov SB_IMAGE_FLAG_DISPLAY_PROGRESS : 0; 1346bce88370SMarek Vasut 1347bce88370SMarek Vasut /* FIXME -- We support only default key */ 1348bce88370SMarek Vasut hdr->key_count = 1; 1349bce88370SMarek Vasut 1350bce88370SMarek Vasut return 0; 1351bce88370SMarek Vasut } 1352bce88370SMarek Vasut 1353bce88370SMarek Vasut static int sb_postfill_image_header(struct sb_image_ctx *ictx) 1354bce88370SMarek Vasut { 1355bce88370SMarek Vasut struct sb_boot_image_header *hdr = &ictx->payload; 1356bce88370SMarek Vasut struct sb_section_ctx *sctx = ictx->sect_head; 1357bce88370SMarek Vasut uint32_t kd_size, sections_blocks; 1358*7bae13b7SMarek Vasut EVP_MD_CTX *md_ctx; 1359bce88370SMarek Vasut 1360bce88370SMarek Vasut /* The main SB header size in blocks. */ 1361bce88370SMarek Vasut hdr->image_blocks = hdr->header_blocks; 1362bce88370SMarek Vasut 1363bce88370SMarek Vasut /* Size of the key dictionary, which has single zero entry. */ 1364bce88370SMarek Vasut kd_size = hdr->key_count * sizeof(struct sb_key_dictionary_key); 1365bce88370SMarek Vasut hdr->image_blocks += kd_size / SB_BLOCK_SIZE; 1366bce88370SMarek Vasut 1367bce88370SMarek Vasut /* Now count the payloads. */ 1368bce88370SMarek Vasut hdr->section_count = ictx->sect_count; 1369bce88370SMarek Vasut while (sctx) { 1370bce88370SMarek Vasut hdr->image_blocks += sctx->size / SB_BLOCK_SIZE; 1371bce88370SMarek Vasut sctx = sctx->sect; 1372bce88370SMarek Vasut } 1373bce88370SMarek Vasut 1374bce88370SMarek Vasut if (!ictx->sect_boot_found) { 1375bce88370SMarek Vasut fprintf(stderr, "ERR: No bootable section selected!\n"); 1376bce88370SMarek Vasut return -EINVAL; 1377bce88370SMarek Vasut } 1378bce88370SMarek Vasut hdr->first_boot_section_id = ictx->sect_boot; 1379bce88370SMarek Vasut 1380bce88370SMarek Vasut /* The n * SB section size in blocks. */ 1381bce88370SMarek Vasut sections_blocks = hdr->section_count * hdr->section_header_size; 1382bce88370SMarek Vasut hdr->image_blocks += sections_blocks; 1383bce88370SMarek Vasut 1384bce88370SMarek Vasut /* Key dictionary offset. */ 1385bce88370SMarek Vasut hdr->key_dictionary_block = hdr->header_blocks + sections_blocks; 1386bce88370SMarek Vasut 1387bce88370SMarek Vasut /* Digest of the whole image. */ 1388bce88370SMarek Vasut hdr->image_blocks += 2; 1389bce88370SMarek Vasut 1390bce88370SMarek Vasut /* Pointer past the dictionary. */ 1391bce88370SMarek Vasut hdr->first_boot_tag_block = 1392bce88370SMarek Vasut hdr->key_dictionary_block + kd_size / SB_BLOCK_SIZE; 1393bce88370SMarek Vasut 1394bce88370SMarek Vasut /* Compute header digest. */ 1395*7bae13b7SMarek Vasut md_ctx = EVP_MD_CTX_new(); 1396bce88370SMarek Vasut 1397*7bae13b7SMarek Vasut EVP_DigestInit(md_ctx, EVP_sha1()); 1398*7bae13b7SMarek Vasut EVP_DigestUpdate(md_ctx, hdr->signature1, 1399bce88370SMarek Vasut sizeof(struct sb_boot_image_header) - 1400bce88370SMarek Vasut sizeof(hdr->digest)); 1401*7bae13b7SMarek Vasut EVP_DigestFinal(md_ctx, hdr->digest, NULL); 1402*7bae13b7SMarek Vasut EVP_MD_CTX_free(md_ctx); 1403bce88370SMarek Vasut 1404bce88370SMarek Vasut return 0; 1405bce88370SMarek Vasut } 1406bce88370SMarek Vasut 1407bce88370SMarek Vasut static int sb_fixup_sections_and_tags(struct sb_image_ctx *ictx) 1408bce88370SMarek Vasut { 1409bce88370SMarek Vasut /* Fixup the placement of sections. */ 1410bce88370SMarek Vasut struct sb_boot_image_header *ihdr = &ictx->payload; 1411bce88370SMarek Vasut struct sb_section_ctx *sctx = ictx->sect_head; 1412bce88370SMarek Vasut struct sb_sections_header *shdr; 1413bce88370SMarek Vasut struct sb_cmd_ctx *cctx; 1414bce88370SMarek Vasut struct sb_command *ccmd; 1415bce88370SMarek Vasut uint32_t offset = ihdr->first_boot_tag_block; 1416bce88370SMarek Vasut 1417bce88370SMarek Vasut while (sctx) { 1418bce88370SMarek Vasut shdr = &sctx->payload; 1419bce88370SMarek Vasut 1420bce88370SMarek Vasut /* Fill in the section TAG offset. */ 1421bce88370SMarek Vasut shdr->section_offset = offset + 1; 1422bce88370SMarek Vasut offset += shdr->section_size; 1423bce88370SMarek Vasut 1424bce88370SMarek Vasut /* Section length is measured from the TAG block. */ 1425bce88370SMarek Vasut shdr->section_size--; 1426bce88370SMarek Vasut 1427bce88370SMarek Vasut /* Fixup the TAG command. */ 1428bce88370SMarek Vasut cctx = sctx->cmd_head; 1429bce88370SMarek Vasut while (cctx) { 1430bce88370SMarek Vasut ccmd = &cctx->payload; 1431bce88370SMarek Vasut if (ccmd->header.tag == ROM_TAG_CMD) { 1432bce88370SMarek Vasut ccmd->tag.section_number = shdr->section_number; 1433bce88370SMarek Vasut ccmd->tag.section_length = shdr->section_size; 1434bce88370SMarek Vasut ccmd->tag.section_flags = shdr->section_flags; 1435bce88370SMarek Vasut } 1436bce88370SMarek Vasut 1437bce88370SMarek Vasut /* Update the command checksum. */ 1438bce88370SMarek Vasut ccmd->header.checksum = sb_command_checksum(ccmd); 1439bce88370SMarek Vasut 1440bce88370SMarek Vasut cctx = cctx->cmd; 1441bce88370SMarek Vasut } 1442bce88370SMarek Vasut 1443bce88370SMarek Vasut sctx = sctx->sect; 1444bce88370SMarek Vasut } 1445bce88370SMarek Vasut 1446bce88370SMarek Vasut return 0; 1447bce88370SMarek Vasut } 1448bce88370SMarek Vasut 1449bce88370SMarek Vasut static int sb_parse_line(struct sb_image_ctx *ictx, struct sb_cmd_list *cmd) 1450bce88370SMarek Vasut { 1451bce88370SMarek Vasut char *tok; 1452bce88370SMarek Vasut char *line = cmd->cmd; 14533cb4b713SAlbert ARIBAUD char *rptr = NULL; 1454bce88370SMarek Vasut int ret; 1455bce88370SMarek Vasut 1456bce88370SMarek Vasut /* Analyze the identifier on this line first. */ 1457bce88370SMarek Vasut tok = strtok_r(line, " ", &rptr); 1458bce88370SMarek Vasut if (!tok || (strlen(tok) == 0)) { 1459bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Invalid line!\n", cmd->lineno); 1460bce88370SMarek Vasut return -EINVAL; 1461bce88370SMarek Vasut } 1462bce88370SMarek Vasut 1463bce88370SMarek Vasut cmd->cmd = rptr; 1464bce88370SMarek Vasut 14657a139959SAlexey Ignatov /* set DISPLAY_PROGRESS flag */ 14667a139959SAlexey Ignatov if (!strcmp(tok, "DISPLAYPROGRESS")) { 14677a139959SAlexey Ignatov ictx->display_progress = 1; 14687a139959SAlexey Ignatov return 0; 14697a139959SAlexey Ignatov } 14707a139959SAlexey Ignatov 1471bce88370SMarek Vasut /* DCD */ 1472bce88370SMarek Vasut if (!strcmp(tok, "DCD")) { 1473bce88370SMarek Vasut ictx->in_section = 0; 1474bce88370SMarek Vasut ictx->in_dcd = 1; 1475bce88370SMarek Vasut sb_build_dcd(ictx, cmd); 1476bce88370SMarek Vasut return 0; 1477bce88370SMarek Vasut } 1478bce88370SMarek Vasut 1479bce88370SMarek Vasut /* Section */ 1480bce88370SMarek Vasut if (!strcmp(tok, "SECTION")) { 1481bce88370SMarek Vasut ictx->in_section = 1; 1482bce88370SMarek Vasut ictx->in_dcd = 0; 1483bce88370SMarek Vasut sb_build_section(ictx, cmd); 1484bce88370SMarek Vasut return 0; 1485bce88370SMarek Vasut } 1486bce88370SMarek Vasut 1487bce88370SMarek Vasut if (!ictx->in_section && !ictx->in_dcd) { 1488bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Data outside of a section!\n", 1489bce88370SMarek Vasut cmd->lineno); 1490bce88370SMarek Vasut return -EINVAL; 1491bce88370SMarek Vasut } 1492bce88370SMarek Vasut 1493bce88370SMarek Vasut if (ictx->in_section) { 1494bce88370SMarek Vasut /* Section commands */ 1495bce88370SMarek Vasut if (!strcmp(tok, "NOP")) { 1496bce88370SMarek Vasut ret = sb_build_command_nop(ictx); 1497bce88370SMarek Vasut } else if (!strcmp(tok, "TAG")) { 1498bce88370SMarek Vasut ret = sb_build_command_tag(ictx, cmd); 1499bce88370SMarek Vasut } else if (!strcmp(tok, "LOAD")) { 1500bce88370SMarek Vasut ret = sb_build_command_load(ictx, cmd); 1501bce88370SMarek Vasut } else if (!strcmp(tok, "FILL")) { 1502bce88370SMarek Vasut ret = sb_build_command_fill(ictx, cmd); 1503bce88370SMarek Vasut } else if (!strcmp(tok, "JUMP")) { 1504bce88370SMarek Vasut ret = sb_build_command_jump(ictx, cmd); 1505bce88370SMarek Vasut } else if (!strcmp(tok, "CALL")) { 1506bce88370SMarek Vasut ret = sb_build_command_call(ictx, cmd); 1507bce88370SMarek Vasut } else if (!strcmp(tok, "MODE")) { 1508bce88370SMarek Vasut ret = sb_build_command_mode(ictx, cmd); 1509bce88370SMarek Vasut } else { 1510bce88370SMarek Vasut fprintf(stderr, 1511bce88370SMarek Vasut "#%i ERR: Unsupported instruction '%s'!\n", 1512bce88370SMarek Vasut cmd->lineno, tok); 1513bce88370SMarek Vasut return -ENOTSUP; 1514bce88370SMarek Vasut } 1515bce88370SMarek Vasut } else if (ictx->in_dcd) { 1516bce88370SMarek Vasut char *lptr; 1517bce88370SMarek Vasut uint32_t ilen = '1'; 1518bce88370SMarek Vasut 1519bce88370SMarek Vasut tok = strtok_r(tok, ".", &lptr); 1520bce88370SMarek Vasut if (!tok || (strlen(tok) == 0) || (lptr && strlen(lptr) != 1)) { 1521bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Invalid line!\n", 1522bce88370SMarek Vasut cmd->lineno); 1523bce88370SMarek Vasut return -EINVAL; 1524bce88370SMarek Vasut } 1525bce88370SMarek Vasut 1526bce88370SMarek Vasut if (lptr && 1527bce88370SMarek Vasut (lptr[0] != '1' && lptr[0] != '2' && lptr[0] != '4')) { 1528bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Invalid instruction width!\n", 1529bce88370SMarek Vasut cmd->lineno); 1530bce88370SMarek Vasut return -EINVAL; 1531bce88370SMarek Vasut } 1532bce88370SMarek Vasut 1533bce88370SMarek Vasut if (lptr) 1534bce88370SMarek Vasut ilen = lptr[0] - '1'; 1535bce88370SMarek Vasut 1536bce88370SMarek Vasut /* DCD commands */ 1537bce88370SMarek Vasut if (!strcmp(tok, "WRITE")) { 1538bce88370SMarek Vasut ret = sb_build_dcd_block(ictx, cmd, 1539bce88370SMarek Vasut SB_DCD_WRITE | ilen); 1540bce88370SMarek Vasut } else if (!strcmp(tok, "ANDC")) { 1541bce88370SMarek Vasut ret = sb_build_dcd_block(ictx, cmd, 1542bce88370SMarek Vasut SB_DCD_ANDC | ilen); 1543bce88370SMarek Vasut } else if (!strcmp(tok, "ORR")) { 1544bce88370SMarek Vasut ret = sb_build_dcd_block(ictx, cmd, 1545bce88370SMarek Vasut SB_DCD_ORR | ilen); 1546bce88370SMarek Vasut } else if (!strcmp(tok, "EQZ")) { 1547bce88370SMarek Vasut ret = sb_build_dcd_block(ictx, cmd, 1548bce88370SMarek Vasut SB_DCD_CHK_EQZ | ilen); 1549bce88370SMarek Vasut } else if (!strcmp(tok, "EQ")) { 1550bce88370SMarek Vasut ret = sb_build_dcd_block(ictx, cmd, 1551bce88370SMarek Vasut SB_DCD_CHK_EQ | ilen); 1552bce88370SMarek Vasut } else if (!strcmp(tok, "NEQ")) { 1553bce88370SMarek Vasut ret = sb_build_dcd_block(ictx, cmd, 1554bce88370SMarek Vasut SB_DCD_CHK_NEQ | ilen); 1555bce88370SMarek Vasut } else if (!strcmp(tok, "NEZ")) { 1556bce88370SMarek Vasut ret = sb_build_dcd_block(ictx, cmd, 1557bce88370SMarek Vasut SB_DCD_CHK_NEZ | ilen); 1558bce88370SMarek Vasut } else if (!strcmp(tok, "NOOP")) { 1559bce88370SMarek Vasut ret = sb_build_dcd_block(ictx, cmd, SB_DCD_NOOP); 1560bce88370SMarek Vasut } else { 1561bce88370SMarek Vasut fprintf(stderr, 1562bce88370SMarek Vasut "#%i ERR: Unsupported instruction '%s'!\n", 1563bce88370SMarek Vasut cmd->lineno, tok); 1564bce88370SMarek Vasut return -ENOTSUP; 1565bce88370SMarek Vasut } 1566bce88370SMarek Vasut } else { 1567bce88370SMarek Vasut fprintf(stderr, "#%i ERR: Unsupported instruction '%s'!\n", 1568bce88370SMarek Vasut cmd->lineno, tok); 1569bce88370SMarek Vasut return -ENOTSUP; 1570bce88370SMarek Vasut } 1571bce88370SMarek Vasut 1572bce88370SMarek Vasut /* 1573bce88370SMarek Vasut * Here we have at least one section with one command, otherwise we 1574bce88370SMarek Vasut * would have failed already higher above. 1575bce88370SMarek Vasut * 1576bce88370SMarek Vasut * FIXME -- should the updating happen here ? 1577bce88370SMarek Vasut */ 1578bce88370SMarek Vasut if (ictx->in_section && !ret) { 1579bce88370SMarek Vasut ictx->sect_tail->size += ictx->sect_tail->cmd_tail->size; 1580bce88370SMarek Vasut ictx->sect_tail->payload.section_size = 1581bce88370SMarek Vasut ictx->sect_tail->size / SB_BLOCK_SIZE; 1582bce88370SMarek Vasut } 1583bce88370SMarek Vasut 1584bce88370SMarek Vasut return ret; 1585bce88370SMarek Vasut } 1586bce88370SMarek Vasut 1587bce88370SMarek Vasut static int sb_load_cmdfile(struct sb_image_ctx *ictx) 1588bce88370SMarek Vasut { 1589bce88370SMarek Vasut struct sb_cmd_list cmd; 1590bce88370SMarek Vasut int lineno = 1; 1591bce88370SMarek Vasut FILE *fp; 1592bce88370SMarek Vasut char *line = NULL; 1593bce88370SMarek Vasut ssize_t rlen; 1594bce88370SMarek Vasut size_t len; 1595bce88370SMarek Vasut 1596bce88370SMarek Vasut fp = fopen(ictx->cfg_filename, "r"); 1597bce88370SMarek Vasut if (!fp) 1598bce88370SMarek Vasut goto err_file; 1599bce88370SMarek Vasut 1600bce88370SMarek Vasut while ((rlen = getline(&line, &len, fp)) > 0) { 1601bce88370SMarek Vasut memset(&cmd, 0, sizeof(cmd)); 1602bce88370SMarek Vasut 1603bce88370SMarek Vasut /* Strip the trailing newline. */ 1604bce88370SMarek Vasut line[rlen - 1] = '\0'; 1605bce88370SMarek Vasut 1606bce88370SMarek Vasut cmd.cmd = line; 1607bce88370SMarek Vasut cmd.len = rlen; 1608bce88370SMarek Vasut cmd.lineno = lineno++; 1609bce88370SMarek Vasut 1610bce88370SMarek Vasut sb_parse_line(ictx, &cmd); 1611bce88370SMarek Vasut } 1612bce88370SMarek Vasut 1613bce88370SMarek Vasut free(line); 1614bce88370SMarek Vasut 1615bce88370SMarek Vasut fclose(fp); 1616bce88370SMarek Vasut 1617bce88370SMarek Vasut return 0; 1618bce88370SMarek Vasut 1619bce88370SMarek Vasut err_file: 1620bce88370SMarek Vasut fclose(fp); 1621bce88370SMarek Vasut fprintf(stderr, "ERR: Failed to load file \"%s\"\n", 1622bce88370SMarek Vasut ictx->cfg_filename); 1623bce88370SMarek Vasut return -EINVAL; 1624bce88370SMarek Vasut } 1625bce88370SMarek Vasut 1626bce88370SMarek Vasut static int sb_build_tree_from_cfg(struct sb_image_ctx *ictx) 1627bce88370SMarek Vasut { 1628bce88370SMarek Vasut int ret; 1629bce88370SMarek Vasut 1630bce88370SMarek Vasut ret = sb_load_cmdfile(ictx); 1631bce88370SMarek Vasut if (ret) 1632bce88370SMarek Vasut return ret; 1633bce88370SMarek Vasut 1634bce88370SMarek Vasut ret = sb_prefill_image_header(ictx); 1635bce88370SMarek Vasut if (ret) 1636bce88370SMarek Vasut return ret; 1637bce88370SMarek Vasut 1638bce88370SMarek Vasut ret = sb_postfill_image_header(ictx); 1639bce88370SMarek Vasut if (ret) 1640bce88370SMarek Vasut return ret; 1641bce88370SMarek Vasut 1642bce88370SMarek Vasut ret = sb_fixup_sections_and_tags(ictx); 1643bce88370SMarek Vasut if (ret) 1644bce88370SMarek Vasut return ret; 1645bce88370SMarek Vasut 1646bce88370SMarek Vasut return 0; 1647bce88370SMarek Vasut } 1648bce88370SMarek Vasut 1649bce88370SMarek Vasut static int sb_verify_image_header(struct sb_image_ctx *ictx, 1650bce88370SMarek Vasut FILE *fp, long fsize) 1651bce88370SMarek Vasut { 1652bce88370SMarek Vasut /* Verify static fields in the image header. */ 1653bce88370SMarek Vasut struct sb_boot_image_header *hdr = &ictx->payload; 1654bce88370SMarek Vasut const char *stat[2] = { "[PASS]", "[FAIL]" }; 1655bce88370SMarek Vasut struct tm tm; 1656bce88370SMarek Vasut int sz, ret = 0; 1657bce88370SMarek Vasut unsigned char digest[20]; 1658*7bae13b7SMarek Vasut EVP_MD_CTX *md_ctx; 1659bce88370SMarek Vasut unsigned long size; 1660bce88370SMarek Vasut 1661bce88370SMarek Vasut /* Start image-wide crypto. */ 1662*7bae13b7SMarek Vasut ictx->md_ctx = EVP_MD_CTX_new(); 1663*7bae13b7SMarek Vasut EVP_DigestInit(ictx->md_ctx, EVP_sha1()); 1664bce88370SMarek Vasut 1665bce88370SMarek Vasut soprintf(ictx, "---------- Verifying SB Image Header ----------\n"); 1666bce88370SMarek Vasut 1667bce88370SMarek Vasut size = fread(&ictx->payload, 1, sizeof(ictx->payload), fp); 1668bce88370SMarek Vasut if (size != sizeof(ictx->payload)) { 1669bce88370SMarek Vasut fprintf(stderr, "ERR: SB image header too short!\n"); 1670bce88370SMarek Vasut return -EINVAL; 1671bce88370SMarek Vasut } 1672bce88370SMarek Vasut 1673bce88370SMarek Vasut /* Compute header digest. */ 1674*7bae13b7SMarek Vasut md_ctx = EVP_MD_CTX_new(); 1675*7bae13b7SMarek Vasut EVP_DigestInit(md_ctx, EVP_sha1()); 1676*7bae13b7SMarek Vasut EVP_DigestUpdate(md_ctx, hdr->signature1, 1677bce88370SMarek Vasut sizeof(struct sb_boot_image_header) - 1678bce88370SMarek Vasut sizeof(hdr->digest)); 1679*7bae13b7SMarek Vasut EVP_DigestFinal(md_ctx, digest, NULL); 1680*7bae13b7SMarek Vasut EVP_MD_CTX_free(md_ctx); 1681bce88370SMarek Vasut 1682bce88370SMarek Vasut sb_aes_init(ictx, NULL, 1); 1683bce88370SMarek Vasut sb_encrypt_sb_header(ictx); 1684bce88370SMarek Vasut 1685bce88370SMarek Vasut if (memcmp(digest, hdr->digest, 20)) 1686bce88370SMarek Vasut ret = -EINVAL; 1687bce88370SMarek Vasut soprintf(ictx, "%s Image header checksum: %s\n", stat[!!ret], 1688bce88370SMarek Vasut ret ? "BAD" : "OK"); 1689bce88370SMarek Vasut if (ret) 1690bce88370SMarek Vasut return ret; 1691bce88370SMarek Vasut 1692bce88370SMarek Vasut if (memcmp(hdr->signature1, "STMP", 4) || 1693bce88370SMarek Vasut memcmp(hdr->signature2, "sgtl", 4)) 1694bce88370SMarek Vasut ret = -EINVAL; 1695bce88370SMarek Vasut soprintf(ictx, "%s Signatures: '%.4s' '%.4s'\n", 1696bce88370SMarek Vasut stat[!!ret], hdr->signature1, hdr->signature2); 1697bce88370SMarek Vasut if (ret) 1698bce88370SMarek Vasut return ret; 1699bce88370SMarek Vasut 1700bce88370SMarek Vasut if ((hdr->major_version != SB_VERSION_MAJOR) || 1701bce88370SMarek Vasut ((hdr->minor_version != 1) && (hdr->minor_version != 2))) 1702bce88370SMarek Vasut ret = -EINVAL; 1703bce88370SMarek Vasut soprintf(ictx, "%s Image version: v%i.%i\n", stat[!!ret], 1704bce88370SMarek Vasut hdr->major_version, hdr->minor_version); 1705bce88370SMarek Vasut if (ret) 1706bce88370SMarek Vasut return ret; 1707bce88370SMarek Vasut 1708bce88370SMarek Vasut ret = sb_get_time(hdr->timestamp_us / 1000000, &tm); 1709bce88370SMarek Vasut soprintf(ictx, 1710bce88370SMarek Vasut "%s Creation time: %02i:%02i:%02i %02i/%02i/%04i\n", 1711bce88370SMarek Vasut stat[!!ret], tm.tm_hour, tm.tm_min, tm.tm_sec, 1712bce88370SMarek Vasut tm.tm_mday, tm.tm_mon, tm.tm_year + 2000); 1713bce88370SMarek Vasut if (ret) 1714bce88370SMarek Vasut return ret; 1715bce88370SMarek Vasut 1716bce88370SMarek Vasut soprintf(ictx, "%s Product version: %x.%x.%x\n", stat[0], 1717bce88370SMarek Vasut ntohs(hdr->product_version.major), 1718bce88370SMarek Vasut ntohs(hdr->product_version.minor), 1719bce88370SMarek Vasut ntohs(hdr->product_version.revision)); 1720bce88370SMarek Vasut soprintf(ictx, "%s Component version: %x.%x.%x\n", stat[0], 1721bce88370SMarek Vasut ntohs(hdr->component_version.major), 1722bce88370SMarek Vasut ntohs(hdr->component_version.minor), 1723bce88370SMarek Vasut ntohs(hdr->component_version.revision)); 1724bce88370SMarek Vasut 17257a139959SAlexey Ignatov if (hdr->flags & ~SB_IMAGE_FLAGS_MASK) 1726bce88370SMarek Vasut ret = -EINVAL; 1727bce88370SMarek Vasut soprintf(ictx, "%s Image flags: %s\n", stat[!!ret], 17287a139959SAlexey Ignatov hdr->flags & SB_IMAGE_FLAG_DISPLAY_PROGRESS ? 17297a139959SAlexey Ignatov "Display_progress" : ""); 1730bce88370SMarek Vasut if (ret) 1731bce88370SMarek Vasut return ret; 1732bce88370SMarek Vasut 1733bce88370SMarek Vasut if (hdr->drive_tag != 0) 1734bce88370SMarek Vasut ret = -EINVAL; 1735bce88370SMarek Vasut soprintf(ictx, "%s Drive tag: %i\n", stat[!!ret], 1736bce88370SMarek Vasut hdr->drive_tag); 1737bce88370SMarek Vasut if (ret) 1738bce88370SMarek Vasut return ret; 1739bce88370SMarek Vasut 1740bce88370SMarek Vasut sz = sizeof(struct sb_boot_image_header) / SB_BLOCK_SIZE; 1741bce88370SMarek Vasut if (hdr->header_blocks != sz) 1742bce88370SMarek Vasut ret = -EINVAL; 1743bce88370SMarek Vasut soprintf(ictx, "%s Image header size (blocks): %i\n", stat[!!ret], 1744bce88370SMarek Vasut hdr->header_blocks); 1745bce88370SMarek Vasut if (ret) 1746bce88370SMarek Vasut return ret; 1747bce88370SMarek Vasut 1748bce88370SMarek Vasut sz = sizeof(struct sb_sections_header) / SB_BLOCK_SIZE; 1749bce88370SMarek Vasut if (hdr->section_header_size != sz) 1750bce88370SMarek Vasut ret = -EINVAL; 1751bce88370SMarek Vasut soprintf(ictx, "%s Section header size (blocks): %i\n", stat[!!ret], 1752bce88370SMarek Vasut hdr->section_header_size); 1753bce88370SMarek Vasut if (ret) 1754bce88370SMarek Vasut return ret; 1755bce88370SMarek Vasut 1756bce88370SMarek Vasut soprintf(ictx, "%s Sections count: %i\n", stat[!!ret], 1757bce88370SMarek Vasut hdr->section_count); 1758bce88370SMarek Vasut soprintf(ictx, "%s First bootable section %i\n", stat[!!ret], 1759bce88370SMarek Vasut hdr->first_boot_section_id); 1760bce88370SMarek Vasut 1761bce88370SMarek Vasut if (hdr->image_blocks != fsize / SB_BLOCK_SIZE) 1762bce88370SMarek Vasut ret = -EINVAL; 1763bce88370SMarek Vasut soprintf(ictx, "%s Image size (blocks): %i\n", stat[!!ret], 1764bce88370SMarek Vasut hdr->image_blocks); 1765bce88370SMarek Vasut if (ret) 1766bce88370SMarek Vasut return ret; 1767bce88370SMarek Vasut 1768bce88370SMarek Vasut sz = hdr->header_blocks + hdr->section_header_size * hdr->section_count; 1769bce88370SMarek Vasut if (hdr->key_dictionary_block != sz) 1770bce88370SMarek Vasut ret = -EINVAL; 1771bce88370SMarek Vasut soprintf(ictx, "%s Key dict offset (blocks): %i\n", stat[!!ret], 1772bce88370SMarek Vasut hdr->key_dictionary_block); 1773bce88370SMarek Vasut if (ret) 1774bce88370SMarek Vasut return ret; 1775bce88370SMarek Vasut 1776bce88370SMarek Vasut if (hdr->key_count != 1) 1777bce88370SMarek Vasut ret = -EINVAL; 1778bce88370SMarek Vasut soprintf(ictx, "%s Number of encryption keys: %i\n", stat[!!ret], 1779bce88370SMarek Vasut hdr->key_count); 1780bce88370SMarek Vasut if (ret) 1781bce88370SMarek Vasut return ret; 1782bce88370SMarek Vasut 1783bce88370SMarek Vasut sz = hdr->header_blocks + hdr->section_header_size * hdr->section_count; 1784bce88370SMarek Vasut sz += hdr->key_count * 1785bce88370SMarek Vasut sizeof(struct sb_key_dictionary_key) / SB_BLOCK_SIZE; 1786bce88370SMarek Vasut if (hdr->first_boot_tag_block != (unsigned)sz) 1787bce88370SMarek Vasut ret = -EINVAL; 1788bce88370SMarek Vasut soprintf(ictx, "%s First TAG block (blocks): %i\n", stat[!!ret], 1789bce88370SMarek Vasut hdr->first_boot_tag_block); 1790bce88370SMarek Vasut if (ret) 1791bce88370SMarek Vasut return ret; 1792bce88370SMarek Vasut 1793bce88370SMarek Vasut return 0; 1794bce88370SMarek Vasut } 1795bce88370SMarek Vasut 1796bce88370SMarek Vasut static void sb_decrypt_tag(struct sb_image_ctx *ictx, 1797bce88370SMarek Vasut struct sb_cmd_ctx *cctx) 1798bce88370SMarek Vasut { 1799*7bae13b7SMarek Vasut EVP_MD_CTX *md_ctx = ictx->md_ctx; 1800bce88370SMarek Vasut struct sb_command *cmd = &cctx->payload; 1801bce88370SMarek Vasut 1802bce88370SMarek Vasut sb_aes_crypt(ictx, (uint8_t *)&cctx->c_payload, 1803bce88370SMarek Vasut (uint8_t *)&cctx->payload, sizeof(*cmd)); 1804bce88370SMarek Vasut EVP_DigestUpdate(md_ctx, &cctx->c_payload, sizeof(*cmd)); 1805bce88370SMarek Vasut } 1806bce88370SMarek Vasut 1807bce88370SMarek Vasut static int sb_verify_command(struct sb_image_ctx *ictx, 1808bce88370SMarek Vasut struct sb_cmd_ctx *cctx, FILE *fp, 1809bce88370SMarek Vasut unsigned long *tsize) 1810bce88370SMarek Vasut { 1811bce88370SMarek Vasut struct sb_command *ccmd = &cctx->payload; 1812bce88370SMarek Vasut unsigned long size, asize; 1813bce88370SMarek Vasut char *csum, *flag = ""; 1814bce88370SMarek Vasut int ret; 1815bce88370SMarek Vasut unsigned int i; 1816bce88370SMarek Vasut uint8_t csn, csc = ccmd->header.checksum; 1817bce88370SMarek Vasut ccmd->header.checksum = 0x5a; 1818bce88370SMarek Vasut csn = sb_command_checksum(ccmd); 1819bce88370SMarek Vasut ccmd->header.checksum = csc; 1820bce88370SMarek Vasut 1821bce88370SMarek Vasut if (csc == csn) 1822bce88370SMarek Vasut ret = 0; 1823bce88370SMarek Vasut else 1824bce88370SMarek Vasut ret = -EINVAL; 1825bce88370SMarek Vasut csum = ret ? "checksum BAD" : "checksum OK"; 1826bce88370SMarek Vasut 1827bce88370SMarek Vasut switch (ccmd->header.tag) { 1828bce88370SMarek Vasut case ROM_NOP_CMD: 1829bce88370SMarek Vasut soprintf(ictx, " NOOP # %s\n", csum); 1830bce88370SMarek Vasut return ret; 1831bce88370SMarek Vasut case ROM_TAG_CMD: 1832bce88370SMarek Vasut if (ccmd->header.flags & ROM_TAG_CMD_FLAG_ROM_LAST_TAG) 1833bce88370SMarek Vasut flag = "LAST"; 1834bce88370SMarek Vasut soprintf(ictx, " TAG %s # %s\n", flag, csum); 1835bce88370SMarek Vasut sb_aes_reinit(ictx, 0); 1836bce88370SMarek Vasut return ret; 1837bce88370SMarek Vasut case ROM_LOAD_CMD: 1838bce88370SMarek Vasut soprintf(ictx, " LOAD addr=0x%08x length=0x%08x # %s\n", 1839bce88370SMarek Vasut ccmd->load.address, ccmd->load.count, csum); 1840bce88370SMarek Vasut 1841bce88370SMarek Vasut cctx->length = ccmd->load.count; 1842bce88370SMarek Vasut asize = roundup(cctx->length, SB_BLOCK_SIZE); 1843bce88370SMarek Vasut cctx->data = malloc(asize); 1844bce88370SMarek Vasut if (!cctx->data) 1845bce88370SMarek Vasut return -ENOMEM; 1846bce88370SMarek Vasut 1847bce88370SMarek Vasut size = fread(cctx->data, 1, asize, fp); 1848bce88370SMarek Vasut if (size != asize) { 1849bce88370SMarek Vasut fprintf(stderr, 1850bce88370SMarek Vasut "ERR: SB LOAD command payload too short!\n"); 1851bce88370SMarek Vasut return -EINVAL; 1852bce88370SMarek Vasut } 1853bce88370SMarek Vasut 1854bce88370SMarek Vasut *tsize += size; 1855bce88370SMarek Vasut 1856*7bae13b7SMarek Vasut EVP_DigestUpdate(ictx->md_ctx, cctx->data, asize); 1857bce88370SMarek Vasut sb_aes_crypt(ictx, cctx->data, cctx->data, asize); 1858bce88370SMarek Vasut 185925308f45SCharles Manning if (ccmd->load.crc32 != pbl_crc32(0, 186025308f45SCharles Manning (const char *)cctx->data, 186125308f45SCharles Manning asize)) { 1862bce88370SMarek Vasut fprintf(stderr, 1863bce88370SMarek Vasut "ERR: SB LOAD command payload CRC32 invalid!\n"); 1864bce88370SMarek Vasut return -EINVAL; 1865bce88370SMarek Vasut } 1866bce88370SMarek Vasut return 0; 1867bce88370SMarek Vasut case ROM_FILL_CMD: 1868bce88370SMarek Vasut soprintf(ictx, 1869bce88370SMarek Vasut " FILL addr=0x%08x length=0x%08x pattern=0x%08x # %s\n", 1870bce88370SMarek Vasut ccmd->fill.address, ccmd->fill.count, 1871bce88370SMarek Vasut ccmd->fill.pattern, csum); 1872bce88370SMarek Vasut return 0; 1873bce88370SMarek Vasut case ROM_JUMP_CMD: 1874bce88370SMarek Vasut if (ccmd->header.flags & ROM_JUMP_CMD_FLAG_HAB) 1875bce88370SMarek Vasut flag = " HAB"; 1876bce88370SMarek Vasut soprintf(ictx, 1877bce88370SMarek Vasut " JUMP%s addr=0x%08x r0_arg=0x%08x # %s\n", 1878bce88370SMarek Vasut flag, ccmd->fill.address, ccmd->jump.argument, csum); 1879bce88370SMarek Vasut return 0; 1880bce88370SMarek Vasut case ROM_CALL_CMD: 1881bce88370SMarek Vasut if (ccmd->header.flags & ROM_CALL_CMD_FLAG_HAB) 1882bce88370SMarek Vasut flag = " HAB"; 1883bce88370SMarek Vasut soprintf(ictx, 1884bce88370SMarek Vasut " CALL%s addr=0x%08x r0_arg=0x%08x # %s\n", 1885bce88370SMarek Vasut flag, ccmd->fill.address, ccmd->jump.argument, csum); 1886bce88370SMarek Vasut return 0; 1887bce88370SMarek Vasut case ROM_MODE_CMD: 1888bce88370SMarek Vasut for (i = 0; i < ARRAY_SIZE(modetable); i++) { 1889bce88370SMarek Vasut if (ccmd->mode.mode == modetable[i].mode) { 1890bce88370SMarek Vasut soprintf(ictx, " MODE %s # %s\n", 1891bce88370SMarek Vasut modetable[i].name, csum); 1892bce88370SMarek Vasut break; 1893bce88370SMarek Vasut } 1894bce88370SMarek Vasut } 1895bce88370SMarek Vasut fprintf(stderr, " MODE !INVALID! # %s\n", csum); 1896bce88370SMarek Vasut return 0; 1897bce88370SMarek Vasut } 1898bce88370SMarek Vasut 1899bce88370SMarek Vasut return ret; 1900bce88370SMarek Vasut } 1901bce88370SMarek Vasut 1902bce88370SMarek Vasut static int sb_verify_commands(struct sb_image_ctx *ictx, 1903bce88370SMarek Vasut struct sb_section_ctx *sctx, FILE *fp) 1904bce88370SMarek Vasut { 1905bce88370SMarek Vasut unsigned long size, tsize = 0; 1906bce88370SMarek Vasut struct sb_cmd_ctx *cctx; 1907bce88370SMarek Vasut int ret; 1908bce88370SMarek Vasut 1909bce88370SMarek Vasut sb_aes_reinit(ictx, 0); 1910bce88370SMarek Vasut 1911bce88370SMarek Vasut while (tsize < sctx->size) { 1912bce88370SMarek Vasut cctx = calloc(1, sizeof(*cctx)); 1913bce88370SMarek Vasut if (!cctx) 1914bce88370SMarek Vasut return -ENOMEM; 1915bce88370SMarek Vasut if (!sctx->cmd_head) { 1916bce88370SMarek Vasut sctx->cmd_head = cctx; 1917bce88370SMarek Vasut sctx->cmd_tail = cctx; 1918bce88370SMarek Vasut } else { 1919bce88370SMarek Vasut sctx->cmd_tail->cmd = cctx; 1920bce88370SMarek Vasut sctx->cmd_tail = cctx; 1921bce88370SMarek Vasut } 1922bce88370SMarek Vasut 1923bce88370SMarek Vasut size = fread(&cctx->c_payload, 1, sizeof(cctx->c_payload), fp); 1924bce88370SMarek Vasut if (size != sizeof(cctx->c_payload)) { 1925bce88370SMarek Vasut fprintf(stderr, "ERR: SB command header too short!\n"); 1926bce88370SMarek Vasut return -EINVAL; 1927bce88370SMarek Vasut } 1928bce88370SMarek Vasut 1929bce88370SMarek Vasut tsize += size; 1930bce88370SMarek Vasut 1931bce88370SMarek Vasut sb_decrypt_tag(ictx, cctx); 1932bce88370SMarek Vasut 1933bce88370SMarek Vasut ret = sb_verify_command(ictx, cctx, fp, &tsize); 1934bce88370SMarek Vasut if (ret) 1935bce88370SMarek Vasut return -EINVAL; 1936bce88370SMarek Vasut } 1937bce88370SMarek Vasut 1938bce88370SMarek Vasut return 0; 1939bce88370SMarek Vasut } 1940bce88370SMarek Vasut 1941bce88370SMarek Vasut static int sb_verify_sections_cmds(struct sb_image_ctx *ictx, FILE *fp) 1942bce88370SMarek Vasut { 1943bce88370SMarek Vasut struct sb_boot_image_header *hdr = &ictx->payload; 1944bce88370SMarek Vasut struct sb_sections_header *shdr; 1945bce88370SMarek Vasut unsigned int i; 1946bce88370SMarek Vasut int ret; 1947bce88370SMarek Vasut struct sb_section_ctx *sctx; 1948bce88370SMarek Vasut unsigned long size; 1949bce88370SMarek Vasut char *bootable = ""; 1950bce88370SMarek Vasut 1951bce88370SMarek Vasut soprintf(ictx, "----- Verifying SB Sections and Commands -----\n"); 1952bce88370SMarek Vasut 1953bce88370SMarek Vasut for (i = 0; i < hdr->section_count; i++) { 1954bce88370SMarek Vasut sctx = calloc(1, sizeof(*sctx)); 1955bce88370SMarek Vasut if (!sctx) 1956bce88370SMarek Vasut return -ENOMEM; 1957bce88370SMarek Vasut if (!ictx->sect_head) { 1958bce88370SMarek Vasut ictx->sect_head = sctx; 1959bce88370SMarek Vasut ictx->sect_tail = sctx; 1960bce88370SMarek Vasut } else { 1961bce88370SMarek Vasut ictx->sect_tail->sect = sctx; 1962bce88370SMarek Vasut ictx->sect_tail = sctx; 1963bce88370SMarek Vasut } 1964bce88370SMarek Vasut 1965bce88370SMarek Vasut size = fread(&sctx->payload, 1, sizeof(sctx->payload), fp); 1966bce88370SMarek Vasut if (size != sizeof(sctx->payload)) { 1967bce88370SMarek Vasut fprintf(stderr, "ERR: SB section header too short!\n"); 1968bce88370SMarek Vasut return -EINVAL; 1969bce88370SMarek Vasut } 1970bce88370SMarek Vasut } 1971bce88370SMarek Vasut 1972bce88370SMarek Vasut size = fread(&ictx->sb_dict_key, 1, sizeof(ictx->sb_dict_key), fp); 1973bce88370SMarek Vasut if (size != sizeof(ictx->sb_dict_key)) { 1974bce88370SMarek Vasut fprintf(stderr, "ERR: SB key dictionary too short!\n"); 1975bce88370SMarek Vasut return -EINVAL; 1976bce88370SMarek Vasut } 1977bce88370SMarek Vasut 1978bce88370SMarek Vasut sb_encrypt_sb_sections_header(ictx); 1979bce88370SMarek Vasut sb_aes_reinit(ictx, 0); 1980bce88370SMarek Vasut sb_decrypt_key_dictionary_key(ictx); 1981bce88370SMarek Vasut 1982bce88370SMarek Vasut sb_aes_reinit(ictx, 0); 1983bce88370SMarek Vasut 1984bce88370SMarek Vasut sctx = ictx->sect_head; 1985bce88370SMarek Vasut while (sctx) { 1986bce88370SMarek Vasut shdr = &sctx->payload; 1987bce88370SMarek Vasut 1988bce88370SMarek Vasut if (shdr->section_flags & SB_SECTION_FLAG_BOOTABLE) { 1989bce88370SMarek Vasut sctx->boot = 1; 1990bce88370SMarek Vasut bootable = " BOOTABLE"; 1991bce88370SMarek Vasut } 1992bce88370SMarek Vasut 1993bce88370SMarek Vasut sctx->size = (shdr->section_size * SB_BLOCK_SIZE) + 1994bce88370SMarek Vasut sizeof(struct sb_command); 1995bce88370SMarek Vasut soprintf(ictx, "SECTION 0x%x%s # size = %i bytes\n", 1996bce88370SMarek Vasut shdr->section_number, bootable, sctx->size); 1997bce88370SMarek Vasut 1998bce88370SMarek Vasut if (shdr->section_flags & ~SB_SECTION_FLAG_BOOTABLE) 1999bce88370SMarek Vasut fprintf(stderr, " WARN: Unknown section flag(s) %08x\n", 2000bce88370SMarek Vasut shdr->section_flags); 2001bce88370SMarek Vasut 2002bce88370SMarek Vasut if ((shdr->section_flags & SB_SECTION_FLAG_BOOTABLE) && 2003bce88370SMarek Vasut (hdr->first_boot_section_id != shdr->section_number)) { 2004bce88370SMarek Vasut fprintf(stderr, 2005bce88370SMarek Vasut " WARN: Bootable section does ID not match image header ID!\n"); 2006bce88370SMarek Vasut } 2007bce88370SMarek Vasut 2008bce88370SMarek Vasut ret = sb_verify_commands(ictx, sctx, fp); 2009bce88370SMarek Vasut if (ret) 2010bce88370SMarek Vasut return ret; 2011bce88370SMarek Vasut 2012bce88370SMarek Vasut sctx = sctx->sect; 2013bce88370SMarek Vasut } 2014bce88370SMarek Vasut 2015bce88370SMarek Vasut /* 2016bce88370SMarek Vasut * FIXME IDEA: 2017bce88370SMarek Vasut * check if the first TAG command is at sctx->section_offset 2018bce88370SMarek Vasut */ 2019bce88370SMarek Vasut return 0; 2020bce88370SMarek Vasut } 2021bce88370SMarek Vasut 2022bce88370SMarek Vasut static int sb_verify_image_end(struct sb_image_ctx *ictx, 2023bce88370SMarek Vasut FILE *fp, off_t filesz) 2024bce88370SMarek Vasut { 2025bce88370SMarek Vasut uint8_t digest[32]; 2026bce88370SMarek Vasut unsigned long size; 2027bce88370SMarek Vasut off_t pos; 2028bce88370SMarek Vasut int ret; 2029bce88370SMarek Vasut 2030bce88370SMarek Vasut soprintf(ictx, "------------- Verifying image end -------------\n"); 2031bce88370SMarek Vasut 2032bce88370SMarek Vasut size = fread(digest, 1, sizeof(digest), fp); 2033bce88370SMarek Vasut if (size != sizeof(digest)) { 2034bce88370SMarek Vasut fprintf(stderr, "ERR: SB key dictionary too short!\n"); 2035bce88370SMarek Vasut return -EINVAL; 2036bce88370SMarek Vasut } 2037bce88370SMarek Vasut 2038bce88370SMarek Vasut pos = ftell(fp); 2039bce88370SMarek Vasut if (pos != filesz) { 2040bce88370SMarek Vasut fprintf(stderr, "ERR: Trailing data past the image!\n"); 2041bce88370SMarek Vasut return -EINVAL; 2042bce88370SMarek Vasut } 2043bce88370SMarek Vasut 2044bce88370SMarek Vasut /* Check the image digest. */ 2045*7bae13b7SMarek Vasut EVP_DigestFinal(ictx->md_ctx, ictx->digest, NULL); 2046*7bae13b7SMarek Vasut EVP_MD_CTX_free(ictx->md_ctx); 2047bce88370SMarek Vasut 2048bce88370SMarek Vasut /* Decrypt the image digest from the input image. */ 2049bce88370SMarek Vasut sb_aes_reinit(ictx, 0); 2050bce88370SMarek Vasut sb_aes_crypt(ictx, digest, digest, sizeof(digest)); 2051bce88370SMarek Vasut 2052bce88370SMarek Vasut /* Check all of 20 bytes of the SHA1 hash. */ 2053bce88370SMarek Vasut ret = memcmp(digest, ictx->digest, 20) ? -EINVAL : 0; 2054bce88370SMarek Vasut 2055bce88370SMarek Vasut if (ret) 2056bce88370SMarek Vasut soprintf(ictx, "[FAIL] Full-image checksum: BAD\n"); 2057bce88370SMarek Vasut else 2058bce88370SMarek Vasut soprintf(ictx, "[PASS] Full-image checksum: OK\n"); 2059bce88370SMarek Vasut 2060bce88370SMarek Vasut return ret; 2061bce88370SMarek Vasut } 2062bce88370SMarek Vasut 2063bce88370SMarek Vasut 2064bce88370SMarek Vasut static int sb_build_tree_from_img(struct sb_image_ctx *ictx) 2065bce88370SMarek Vasut { 2066bce88370SMarek Vasut long filesize; 2067bce88370SMarek Vasut int ret; 2068bce88370SMarek Vasut FILE *fp; 2069bce88370SMarek Vasut 2070bce88370SMarek Vasut if (!ictx->input_filename) { 2071bce88370SMarek Vasut fprintf(stderr, "ERR: Missing filename!\n"); 2072bce88370SMarek Vasut return -EINVAL; 2073bce88370SMarek Vasut } 2074bce88370SMarek Vasut 2075bce88370SMarek Vasut fp = fopen(ictx->input_filename, "r"); 2076bce88370SMarek Vasut if (!fp) 2077bce88370SMarek Vasut goto err_open; 2078bce88370SMarek Vasut 2079bce88370SMarek Vasut ret = fseek(fp, 0, SEEK_END); 2080bce88370SMarek Vasut if (ret < 0) 2081bce88370SMarek Vasut goto err_file; 2082bce88370SMarek Vasut 2083bce88370SMarek Vasut filesize = ftell(fp); 2084bce88370SMarek Vasut if (filesize < 0) 2085bce88370SMarek Vasut goto err_file; 2086bce88370SMarek Vasut 2087bce88370SMarek Vasut ret = fseek(fp, 0, SEEK_SET); 2088bce88370SMarek Vasut if (ret < 0) 2089bce88370SMarek Vasut goto err_file; 2090bce88370SMarek Vasut 2091bce88370SMarek Vasut if (filesize < (signed)sizeof(ictx->payload)) { 2092bce88370SMarek Vasut fprintf(stderr, "ERR: File too short!\n"); 2093bce88370SMarek Vasut goto err_file; 2094bce88370SMarek Vasut } 2095bce88370SMarek Vasut 2096bce88370SMarek Vasut if (filesize & (SB_BLOCK_SIZE - 1)) { 2097bce88370SMarek Vasut fprintf(stderr, "ERR: The file is not aligned!\n"); 2098bce88370SMarek Vasut goto err_file; 2099bce88370SMarek Vasut } 2100bce88370SMarek Vasut 2101bce88370SMarek Vasut /* Load and verify image header */ 2102bce88370SMarek Vasut ret = sb_verify_image_header(ictx, fp, filesize); 2103bce88370SMarek Vasut if (ret) 2104bce88370SMarek Vasut goto err_verify; 2105bce88370SMarek Vasut 2106bce88370SMarek Vasut /* Load and verify sections and commands */ 2107bce88370SMarek Vasut ret = sb_verify_sections_cmds(ictx, fp); 2108bce88370SMarek Vasut if (ret) 2109bce88370SMarek Vasut goto err_verify; 2110bce88370SMarek Vasut 2111bce88370SMarek Vasut ret = sb_verify_image_end(ictx, fp, filesize); 2112bce88370SMarek Vasut if (ret) 2113bce88370SMarek Vasut goto err_verify; 2114bce88370SMarek Vasut 2115bce88370SMarek Vasut ret = 0; 2116bce88370SMarek Vasut 2117bce88370SMarek Vasut err_verify: 2118bce88370SMarek Vasut soprintf(ictx, "-------------------- Result -------------------\n"); 2119bce88370SMarek Vasut soprintf(ictx, "Verification %s\n", ret ? "FAILED" : "PASSED"); 2120bce88370SMarek Vasut 2121bce88370SMarek Vasut /* Stop the encryption session. */ 2122*7bae13b7SMarek Vasut sb_aes_deinit(ictx->cipher_ctx); 2123bce88370SMarek Vasut 2124bce88370SMarek Vasut fclose(fp); 2125bce88370SMarek Vasut return ret; 2126bce88370SMarek Vasut 2127bce88370SMarek Vasut err_file: 2128bce88370SMarek Vasut fclose(fp); 2129bce88370SMarek Vasut err_open: 2130bce88370SMarek Vasut fprintf(stderr, "ERR: Failed to load file \"%s\"\n", 2131bce88370SMarek Vasut ictx->input_filename); 2132bce88370SMarek Vasut return -EINVAL; 2133bce88370SMarek Vasut } 2134bce88370SMarek Vasut 2135bce88370SMarek Vasut static void sb_free_image(struct sb_image_ctx *ictx) 2136bce88370SMarek Vasut { 2137bce88370SMarek Vasut struct sb_section_ctx *sctx = ictx->sect_head, *s_head; 2138bce88370SMarek Vasut struct sb_dcd_ctx *dctx = ictx->dcd_head, *d_head; 2139bce88370SMarek Vasut struct sb_cmd_ctx *cctx, *c_head; 2140bce88370SMarek Vasut 2141bce88370SMarek Vasut while (sctx) { 2142bce88370SMarek Vasut s_head = sctx; 2143bce88370SMarek Vasut c_head = sctx->cmd_head; 2144bce88370SMarek Vasut 2145bce88370SMarek Vasut while (c_head) { 2146bce88370SMarek Vasut cctx = c_head; 2147bce88370SMarek Vasut c_head = c_head->cmd; 2148bce88370SMarek Vasut if (cctx->data) 2149bce88370SMarek Vasut free(cctx->data); 2150bce88370SMarek Vasut free(cctx); 2151bce88370SMarek Vasut } 2152bce88370SMarek Vasut 2153bce88370SMarek Vasut sctx = sctx->sect; 2154bce88370SMarek Vasut free(s_head); 2155bce88370SMarek Vasut } 2156bce88370SMarek Vasut 2157bce88370SMarek Vasut while (dctx) { 2158bce88370SMarek Vasut d_head = dctx; 2159bce88370SMarek Vasut dctx = dctx->dcd; 2160bce88370SMarek Vasut free(d_head->payload); 2161bce88370SMarek Vasut free(d_head); 2162bce88370SMarek Vasut } 2163bce88370SMarek Vasut } 2164bce88370SMarek Vasut 2165bce88370SMarek Vasut /* 2166bce88370SMarek Vasut * MXSSB-MKIMAGE glue code. 2167bce88370SMarek Vasut */ 2168bce88370SMarek Vasut static int mxsimage_check_image_types(uint8_t type) 2169bce88370SMarek Vasut { 2170bce88370SMarek Vasut if (type == IH_TYPE_MXSIMAGE) 2171bce88370SMarek Vasut return EXIT_SUCCESS; 2172bce88370SMarek Vasut else 2173bce88370SMarek Vasut return EXIT_FAILURE; 2174bce88370SMarek Vasut } 2175bce88370SMarek Vasut 2176bce88370SMarek Vasut static void mxsimage_set_header(void *ptr, struct stat *sbuf, int ifd, 2177f86ed6a8SGuilherme Maciel Ferreira struct image_tool_params *params) 2178bce88370SMarek Vasut { 2179bce88370SMarek Vasut } 2180bce88370SMarek Vasut 2181f86ed6a8SGuilherme Maciel Ferreira int mxsimage_check_params(struct image_tool_params *params) 2182bce88370SMarek Vasut { 2183bce88370SMarek Vasut if (!params) 2184bce88370SMarek Vasut return -1; 2185bce88370SMarek Vasut if (!strlen(params->imagename)) { 2186bce88370SMarek Vasut fprintf(stderr, 2187bce88370SMarek Vasut "Error: %s - Configuration file not specified, it is needed for mxsimage generation\n", 2188bce88370SMarek Vasut params->cmdname); 2189bce88370SMarek Vasut return -1; 2190bce88370SMarek Vasut } 2191bce88370SMarek Vasut 2192bce88370SMarek Vasut /* 2193bce88370SMarek Vasut * Check parameters: 2194bce88370SMarek Vasut * XIP is not allowed and verify that incompatible 2195bce88370SMarek Vasut * parameters are not sent at the same time 2196bce88370SMarek Vasut * For example, if list is required a data image must not be provided 2197bce88370SMarek Vasut */ 2198bce88370SMarek Vasut return (params->dflag && (params->fflag || params->lflag)) || 2199bce88370SMarek Vasut (params->fflag && (params->dflag || params->lflag)) || 2200bce88370SMarek Vasut (params->lflag && (params->dflag || params->fflag)) || 2201bce88370SMarek Vasut (params->xflag) || !(strlen(params->imagename)); 2202bce88370SMarek Vasut } 2203bce88370SMarek Vasut 2204bce88370SMarek Vasut static int mxsimage_verify_print_header(char *file, int silent) 2205bce88370SMarek Vasut { 2206bce88370SMarek Vasut int ret; 2207bce88370SMarek Vasut struct sb_image_ctx ctx; 2208bce88370SMarek Vasut 2209bce88370SMarek Vasut memset(&ctx, 0, sizeof(ctx)); 2210bce88370SMarek Vasut 2211bce88370SMarek Vasut ctx.input_filename = file; 2212bce88370SMarek Vasut ctx.silent_dump = silent; 2213bce88370SMarek Vasut 2214bce88370SMarek Vasut ret = sb_build_tree_from_img(&ctx); 2215bce88370SMarek Vasut sb_free_image(&ctx); 2216bce88370SMarek Vasut 2217bce88370SMarek Vasut return ret; 2218bce88370SMarek Vasut } 2219bce88370SMarek Vasut 2220bce88370SMarek Vasut char *imagefile; 2221bce88370SMarek Vasut static int mxsimage_verify_header(unsigned char *ptr, int image_size, 2222f86ed6a8SGuilherme Maciel Ferreira struct image_tool_params *params) 2223bce88370SMarek Vasut { 2224bce88370SMarek Vasut struct sb_boot_image_header *hdr; 2225bce88370SMarek Vasut 2226bce88370SMarek Vasut if (!ptr) 2227bce88370SMarek Vasut return -EINVAL; 2228bce88370SMarek Vasut 2229bce88370SMarek Vasut hdr = (struct sb_boot_image_header *)ptr; 2230bce88370SMarek Vasut 2231bce88370SMarek Vasut /* 2232bce88370SMarek Vasut * Check if the header contains the MXS image signatures, 2233bce88370SMarek Vasut * if so, do a full-image verification. 2234bce88370SMarek Vasut */ 2235bce88370SMarek Vasut if (memcmp(hdr->signature1, "STMP", 4) || 2236bce88370SMarek Vasut memcmp(hdr->signature2, "sgtl", 4)) 2237bce88370SMarek Vasut return -EINVAL; 2238bce88370SMarek Vasut 2239bce88370SMarek Vasut imagefile = params->imagefile; 2240bce88370SMarek Vasut 2241bce88370SMarek Vasut return mxsimage_verify_print_header(params->imagefile, 1); 2242bce88370SMarek Vasut } 2243bce88370SMarek Vasut 2244bce88370SMarek Vasut static void mxsimage_print_header(const void *hdr) 2245bce88370SMarek Vasut { 2246bce88370SMarek Vasut if (imagefile) 2247bce88370SMarek Vasut mxsimage_verify_print_header(imagefile, 0); 2248bce88370SMarek Vasut } 2249bce88370SMarek Vasut 2250bce88370SMarek Vasut static int sb_build_image(struct sb_image_ctx *ictx, 2251bce88370SMarek Vasut struct image_type_params *tparams) 2252bce88370SMarek Vasut { 2253bce88370SMarek Vasut struct sb_boot_image_header *sb_header = &ictx->payload; 2254bce88370SMarek Vasut struct sb_section_ctx *sctx; 2255bce88370SMarek Vasut struct sb_cmd_ctx *cctx; 2256bce88370SMarek Vasut struct sb_command *ccmd; 2257bce88370SMarek Vasut struct sb_key_dictionary_key *sb_dict_key = &ictx->sb_dict_key; 2258bce88370SMarek Vasut 2259bce88370SMarek Vasut uint8_t *image, *iptr; 2260bce88370SMarek Vasut 2261bce88370SMarek Vasut /* Calculate image size. */ 2262bce88370SMarek Vasut uint32_t size = sizeof(*sb_header) + 2263bce88370SMarek Vasut ictx->sect_count * sizeof(struct sb_sections_header) + 2264bce88370SMarek Vasut sizeof(*sb_dict_key) + sizeof(ictx->digest); 2265bce88370SMarek Vasut 2266bce88370SMarek Vasut sctx = ictx->sect_head; 2267bce88370SMarek Vasut while (sctx) { 2268bce88370SMarek Vasut size += sctx->size; 2269bce88370SMarek Vasut sctx = sctx->sect; 2270bce88370SMarek Vasut }; 2271bce88370SMarek Vasut 2272bce88370SMarek Vasut image = malloc(size); 2273bce88370SMarek Vasut if (!image) 2274bce88370SMarek Vasut return -ENOMEM; 2275bce88370SMarek Vasut iptr = image; 2276bce88370SMarek Vasut 2277bce88370SMarek Vasut memcpy(iptr, sb_header, sizeof(*sb_header)); 2278bce88370SMarek Vasut iptr += sizeof(*sb_header); 2279bce88370SMarek Vasut 2280bce88370SMarek Vasut sctx = ictx->sect_head; 2281bce88370SMarek Vasut while (sctx) { 2282bce88370SMarek Vasut memcpy(iptr, &sctx->payload, sizeof(struct sb_sections_header)); 2283bce88370SMarek Vasut iptr += sizeof(struct sb_sections_header); 2284bce88370SMarek Vasut sctx = sctx->sect; 2285bce88370SMarek Vasut }; 2286bce88370SMarek Vasut 2287bce88370SMarek Vasut memcpy(iptr, sb_dict_key, sizeof(*sb_dict_key)); 2288bce88370SMarek Vasut iptr += sizeof(*sb_dict_key); 2289bce88370SMarek Vasut 2290bce88370SMarek Vasut sctx = ictx->sect_head; 2291bce88370SMarek Vasut while (sctx) { 2292bce88370SMarek Vasut cctx = sctx->cmd_head; 2293bce88370SMarek Vasut while (cctx) { 2294bce88370SMarek Vasut ccmd = &cctx->payload; 2295bce88370SMarek Vasut 2296bce88370SMarek Vasut memcpy(iptr, &cctx->c_payload, sizeof(cctx->payload)); 2297bce88370SMarek Vasut iptr += sizeof(cctx->payload); 2298bce88370SMarek Vasut 2299bce88370SMarek Vasut if (ccmd->header.tag == ROM_LOAD_CMD) { 2300bce88370SMarek Vasut memcpy(iptr, cctx->data, cctx->length); 2301bce88370SMarek Vasut iptr += cctx->length; 2302bce88370SMarek Vasut } 2303bce88370SMarek Vasut 2304bce88370SMarek Vasut cctx = cctx->cmd; 2305bce88370SMarek Vasut } 2306bce88370SMarek Vasut 2307bce88370SMarek Vasut sctx = sctx->sect; 2308bce88370SMarek Vasut }; 2309bce88370SMarek Vasut 2310bce88370SMarek Vasut memcpy(iptr, ictx->digest, sizeof(ictx->digest)); 2311bce88370SMarek Vasut iptr += sizeof(ictx->digest); 2312bce88370SMarek Vasut 2313bce88370SMarek Vasut /* Configure the mkimage */ 2314bce88370SMarek Vasut tparams->hdr = image; 2315bce88370SMarek Vasut tparams->header_size = size; 2316bce88370SMarek Vasut 2317bce88370SMarek Vasut return 0; 2318bce88370SMarek Vasut } 2319bce88370SMarek Vasut 2320f86ed6a8SGuilherme Maciel Ferreira static int mxsimage_generate(struct image_tool_params *params, 2321bce88370SMarek Vasut struct image_type_params *tparams) 2322bce88370SMarek Vasut { 2323bce88370SMarek Vasut int ret; 2324bce88370SMarek Vasut struct sb_image_ctx ctx; 2325bce88370SMarek Vasut 2326bce88370SMarek Vasut /* Do not copy the U-Boot image! */ 2327bce88370SMarek Vasut params->skipcpy = 1; 2328bce88370SMarek Vasut 2329bce88370SMarek Vasut memset(&ctx, 0, sizeof(ctx)); 2330bce88370SMarek Vasut 2331bce88370SMarek Vasut ctx.cfg_filename = params->imagename; 2332bce88370SMarek Vasut ctx.output_filename = params->imagefile; 2333bce88370SMarek Vasut 2334bce88370SMarek Vasut ret = sb_build_tree_from_cfg(&ctx); 2335bce88370SMarek Vasut if (ret) 2336bce88370SMarek Vasut goto fail; 2337bce88370SMarek Vasut 2338bce88370SMarek Vasut ret = sb_encrypt_image(&ctx); 2339bce88370SMarek Vasut if (!ret) 2340bce88370SMarek Vasut ret = sb_build_image(&ctx, tparams); 2341bce88370SMarek Vasut 2342bce88370SMarek Vasut fail: 2343bce88370SMarek Vasut sb_free_image(&ctx); 2344bce88370SMarek Vasut 2345bce88370SMarek Vasut return ret; 2346bce88370SMarek Vasut } 2347bce88370SMarek Vasut 2348bce88370SMarek Vasut /* 2349bce88370SMarek Vasut * mxsimage parameters 2350bce88370SMarek Vasut */ 2351a93648d1SGuilherme Maciel Ferreira U_BOOT_IMAGE_TYPE( 2352a93648d1SGuilherme Maciel Ferreira mxsimage, 2353a93648d1SGuilherme Maciel Ferreira "Freescale MXS Boot Image support", 2354a93648d1SGuilherme Maciel Ferreira 0, 2355a93648d1SGuilherme Maciel Ferreira NULL, 2356a93648d1SGuilherme Maciel Ferreira mxsimage_check_params, 2357a93648d1SGuilherme Maciel Ferreira mxsimage_verify_header, 2358a93648d1SGuilherme Maciel Ferreira mxsimage_print_header, 2359a93648d1SGuilherme Maciel Ferreira mxsimage_set_header, 2360a93648d1SGuilherme Maciel Ferreira NULL, 2361a93648d1SGuilherme Maciel Ferreira mxsimage_check_image_types, 2362a93648d1SGuilherme Maciel Ferreira NULL, 2363a93648d1SGuilherme Maciel Ferreira mxsimage_generate 2364a93648d1SGuilherme Maciel Ferreira ); 2365bce88370SMarek Vasut #endif 2366