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