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