blob: f8e5a6eaaedbb8888adb801e5adc5a917ba1bd48 [file] [log] [blame]
/*******************************************************************************
Copyright (C) Marvell International Ltd. and its affiliates
This software file (the "File") is owned and distributed by Marvell
International Ltd. and/or its affiliates ("Marvell") under the following
alternative licensing terms. Once you have made an election to distribute the
File under one of the following license alternatives, please (i) delete this
introductory statement regarding license alternatives, (ii) delete the two
license alternatives that you have not elected to use and (iii) preserve the
Marvell copyright notice above.
********************************************************************************
Marvell Commercial License Option
If you received this File from Marvell and you have entered into a commercial
license agreement (a "Commercial License") with Marvell, the File is licensed
to you under the terms of the applicable Commercial License.
********************************************************************************
Marvell GPL License Option
If you received this File from Marvell, you may opt to use, redistribute and/or
modify this File in accordance with the terms and conditions of the General
Public License Version 2, June 1991 (the "GPL License"), a copy of which is
available along with the File in the license.txt file or by writing to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
DISCLAIMED. The GPL License provides additional details about this warranty
disclaimer.
********************************************************************************
Marvell BSD License Option
If you received this File from Marvell, you may opt to use, redistribute and/or
modify this File under the following licensing terms.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Marvell nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/mman.h>
#include <time.h>
#define _HOST_COMPILER
#include "bootstrap_def.h"
//#include "soc_spec.h"
#include "polarssl/sha2.h"
#include "polarssl/rsa.h"
#include "polarssl/aes.h"
#include "doimage.h"
#undef MV_SEC_HDR_DBG /* print SHA-256 digest of RSA public key */
#include "polarssl/mvMemPool.h"
/* Global variables */
int f_in = -1;
int f_out = -1;
int f_header = -1;
struct stat fs_stat;
rsa_context rsa;
aes_context aes;
unsigned char IV[16] = {0};
/*******************************************************************************
* create_rsa_signature (memory buffer content)
*******************************************************************************/
int create_rsa_signature (
unsigned char *input,
int ilen,
unsigned char *signature,
char *print_val)
{
unsigned char sha_256[32];
int i;
memset(sha_256, 0, 32 * sizeof(unsigned char));
/* compute SHA-256 digest */
sha2(input, ilen, sha_256, 0);
if (print_val != NULL)
{
printf("\n%s ", print_val);
for (i = 0; i < 32; i++)
printf("%02X", sha_256[i]);
printf("\n");
}
return rsa_pkcs1_sign(&rsa, RSA_PRIVATE, RSA_SHA256, 32, sha_256, signature);
} /* end of create_rsa_signature() */
/*******************************************************************************
* verify_rsa_signature (memory buffer content)
*******************************************************************************/
int verify_rsa_signature (
unsigned char *input,
int ilen,
unsigned char *signature)
{
unsigned char sha_256[32];
memset(sha_256, 0, 32 * sizeof(unsigned char));
/* compute SHA-256 digest */
sha2(input, ilen, sha_256, 0);
return rsa_pkcs1_verify(&rsa, RSA_PUBLIC, RSA_SHA256, 32, sha_256, signature);
} /* end of create_rsa_signature() */
/*******************************************************************************
* build_headers
*******************************************************************************/
int pre_load_image (USER_OPTIONS *opt, char *buf_in)
{
int offset = 0;
opt->image_buf = malloc(opt->image_sz);
if (opt->image_buf == NULL)
return -1;
memset(opt->image_buf, 0, opt->image_sz);
if ((opt->pre_padding) && (opt->prepadding_size))
{
memset(opt->image_buf, 0x5, opt->prepadding_size);
offset = opt->prepadding_size;
}
if ((opt->post_padding) && (opt->postpadding_size))
{
memset(opt->image_buf + opt->image_sz - 4 - opt->postpadding_size,
0xA, opt->postpadding_size);
}
memcpy(opt->image_buf + offset, buf_in, fs_stat.st_size);
/* IV must be the last before checksum */
if (opt->flags & A_OPTION_MASK)
{
memcpy(opt->image_buf + opt->image_sz - 20, IV, 16);
}
return 0;
}
/*******************************************************************************
* build_headers
*******************************************************************************/
int build_headers (USER_OPTIONS *opt, char *buf_in)
{
BHR_t *hdr = NULL;
secExtBHR_t *secExtHdr = NULL;
headExtBHR_t *headExtHdr = NULL;
tailExtBHR_t *tailExtHdr = NULL;
MV_U8 *tmpHeader = NULL;
int i;
MV_U32 header_size = 0;
MV_U32 twsi_size = 0;
int size_written = 0;
MV_U16 max_bytes_to_write;
int error = 1;
tmpHeader = malloc(MAX_HDR_SZ(opt->flags & U_OPTION_MASK));
if (tmpHeader == NULL)
{
fprintf(stderr,"Header space allocation error!\n");
goto header_error;
}
memset(tmpHeader, 0 , MAX_HDR_SZ(opt->flags & U_OPTION_MASK));
hdr = (BHR_t *)tmpHeader;
switch (opt->image_type)
{
case IMG_SATA:
hdr->blockID = IBR_HDR_SATA_ID;
break;
case IMG_UART:
hdr->blockID = IBR_HDR_UART_ID;
break;
case IMG_FLASH:
hdr->blockID = IBR_HDR_SPI_ID;
break;
case IMG_NAND:
hdr->blockID = IBR_HDR_NAND_ID;
/*hdr->nandEccMode = (MV_U8)opt->nandEccMode;*/
hdr->nandPageSize = (MV_U16)opt->nandPageSize;
hdr->nandBlockSize = (MV_U8)opt->nandBlkSize;
if ((opt->nandCellTech == 'S') || (opt->nandCellTech == 's'))
hdr->nandTechnology = MAIN_HDR_NAND_SLC;
else
hdr->nandTechnology = MAIN_HDR_NAND_MLC;
break;
case IMG_PEX:
hdr->blockID = IBR_HDR_PEX_ID;
break;
case IMG_I2C:
hdr->blockID = IBR_HDR_I2C_ID;
break;
default:
fprintf(stderr,"Illegal image type %d for header construction!\n",
opt->image_type);
return 1;
}
hdr->destinationAddr = opt->image_dest;
hdr->executionAddr = (MV_U32)opt->image_exec;
hdr->version = MAIN_HDR_VERSION;
hdr->blockSize = fs_stat.st_size;
header_size = sizeof(BHR_t);
/* Update Block size address */
if ((opt->flags & X_OPTION_MASK) || (opt->flags & Y_OPTION_MASK))
{
/* Align padding to 32 bit */
if (opt->prepadding_size & 0x3)
{
opt->prepadding_size += (4 - (opt->prepadding_size & 0x3));
}
if (opt->postpadding_size & 0x3)
{
opt->postpadding_size += (4 - (opt->postpadding_size & 0x3));
}
hdr->blockSize += opt->prepadding_size + opt->postpadding_size;
}
/* Align the image size to 4 byte boundary */
if (hdr->blockSize & 0x3)
{
opt->bytesToAlign = (4 - (hdr->blockSize & 0x3));
hdr->blockSize += opt->bytesToAlign;
}
/* Create extension header(s) */
/* Security Header */
if (opt->flags & Z_OPTION_MASK)
{
if (opt->flags & A_OPTION_MASK)
{
int align16 = 0;
if (hdr->blockSize & 0xF)
align16 = 16 - hdr->blockSize & 0xF;
/* At this stage everything is 4-bytes aligned */
/* For AES-128 the image should be aligned to 16 bytes */
/* Additional 16 bytes are also required for IV storage */
hdr->blockSize += align16 + 16;
opt->postpadding_size += align16;
opt->post_padding = 1;
}
/* Allocate space for security header, but do not fill in it now */
secExtHdr = (secExtBHR_t *)(tmpHeader + header_size);
secExtHdr->head.type = EXT_HDR_TYP_SECURITY;
header_size += sizeof(secExtBHR_t);
/* Indicate extention header existance in main header */
hdr->ext = 1;
/* Prepare header extension tail for next extension (if any) */
tailExtHdr = &secExtHdr->tail;
}
/***************************** TWSI Header ********************************/
/* TWSI header has a special purpose and placed ahead of the main header */
if (opt->flags & M_OPTION_MASK)
{
if (opt->fname_twsi)
{
FILE *f_twsi;
MV_U8 *tmpTwsi = NULL;
MV_U32 *twsi_reg;
tmpTwsi = malloc(MAX_TWSI_HDR_SIZE);
if (tmpTwsi == NULL)
{
fprintf(stderr,"TWSI space allocation error!\n");
goto header_error;
}
memset(tmpTwsi, 0xFF, MAX_TWSI_HDR_SIZE);
twsi_reg = (MV_U32 *)tmpTwsi;
f_twsi = fopen(opt->fname_twsi, "r");
if (f_twsi == NULL)
{
fprintf(stderr,"File '%s' not found \n",opt->fname_twsi);
goto header_error;
}
for (i = 0; i < (MAX_TWSI_HDR_SIZE / 4); i++)
{
if (EOF == fscanf(f_twsi,"%x\n",twsi_reg))
break;
/* Swap Enianess */
*twsi_reg = ( ((*twsi_reg >> 24) & 0xFF) |
((*twsi_reg >> 8) & 0xFF00) |
((*twsi_reg << 8) & 0xFF0000) |
((*twsi_reg << 24) & 0xFF000000) );
twsi_reg++;
}
fclose(f_twsi);
/* Align to size = 512,1024,.. with at least 8 0xFF bytes @ the end */
twsi_size = ((((i + 2) * 4) & ~0x1FF) + 0x200);
if ((write(f_out, tmpTwsi, twsi_size)) != twsi_size)
{
fprintf(stderr,"Error writing %s file \n",opt->fname.out);
goto header_error;
}
} /* opt->fname_twsi */
} /* (opt->flags & M_OPTION_MASK) */
/************************** End of TWSI Header ****************************/
/************************** Registers Header ******************************/
/* Registers Configuration Header */
if (opt->flags & R_OPTION_MASK)
{
/* First we will take of DRAM */
if (opt->fname_dram)
{
FILE *f_dram;
MV_U32 *dram_reg = (MV_U32 *)(tmpHeader + header_size + sizeof(headExtBHR_t));
MV_U32 reg_size;
MV_U32 tmp_len;
/* Count extension headers */
if (hdr->ext != 255)
hdr->ext++;
headExtHdr = (headExtBHR_t *)(tmpHeader + header_size);
headExtHdr->type = EXT_HDR_TYP_REGISTER;
/* Indicate next header in previous extension */
if (tailExtHdr != NULL)
{
tailExtHdr->nextHdr = 1;
}
max_bytes_to_write = MAX_HDR_SZ(opt->flags & U_OPTION_MASK) - header_size -
EXT_HDR_BASE_SIZE;
if ((f_dram = fopen(opt->fname_dram, "r")) == NULL)
{
fprintf(stderr,"File '%s' not found \n",opt->fname_dram);
goto header_error;
}
for (i = 0; i < (max_bytes_to_write / 8); i += 2)
{
if (fscanf(f_dram,"%x %x\n",&dram_reg[i], &dram_reg[i+1]) == EOF)
{
break;
}
else if ((dram_reg[i] == 0x0) && (dram_reg[i+1] == 0x0))
{
break;
}
}
fclose(f_dram);
if (i >= (max_bytes_to_write / 8))
{
fprintf(stderr,"Registers configuration exceeds the maximum"
"size of %d bytes\n", max_bytes_to_write);
goto header_error;
}
reg_size = i * 4;
tmp_len = EXT_HDR_BASE_SIZE + reg_size;
EXT_HDR_SET_LEN(headExtHdr, tmp_len);
header_size += tmp_len;
tailExtHdr = (tailExtBHR_t *)(tmpHeader + header_size - sizeof(tailExtBHR_t));
} /* if (fname_dram) */
} /* if (opts & R_OPTION_MASK) */
/********************** End of Registers Header ***************************/
/**************************** Binary Header *******************************/
if (opt->flags & G_OPTION_MASK)
{
if (opt->fname_bin)
{
FILE *f_bin;
MV_U32 *bin_reg;
MV_U32 bin_size;
MV_U32 tmp_len;
/* Count extension headers */
if (hdr->ext != 255)
hdr->ext++;
/* one word contains number of arguments, LSB-aligned */
bin_reg = (MV_U32 *)(tmpHeader + header_size + sizeof(headExtBHR_t));
/*
*((MV_U8 *)bin_reg) = opt->argsNum & 0xFF;
bin_reg++;
*/
headExtHdr = (headExtBHR_t *)(tmpHeader + header_size);
headExtHdr->type = EXT_HDR_TYP_BINARY;
/* Indicate next header in previous extension */
if (tailExtHdr != NULL)
{
tailExtHdr->nextHdr = 1;
}
/* 4 bytes for argumets length field */
max_bytes_to_write = MAX_HDR_SZ(opt->flags & U_OPTION_MASK) - header_size -
EXT_HDR_BASE_SIZE /*- 4*/;
f_bin = fopen(opt->fname_bin, "r");
if (f_bin == NULL)
{
fprintf(stderr,"File '%s' not found \n", opt->fname_bin);
goto header_error;
}
for (i = 0; i < (max_bytes_to_write / 4); i++)
{
if (fread (bin_reg, 1, 4, f_bin) != 4)
break;
bin_reg++;
}
fclose(f_bin);
if (i >= (max_bytes_to_write / 4))
{
fprintf(stderr,"Binary extention exeeds the maximum size "
"of %d bytes\n", max_bytes_to_write);
goto header_error;
}
//tmp_len = EXT_HDR_BASE_SIZE + (i + 1) * 4; /* 1 word for num of arguments */
tmp_len = EXT_HDR_BASE_SIZE + i * 4;
if ((opt->flags & U_OPTION_MASK) && (tmp_len > PNC_SRAM_SIZE))
{
fprintf(stderr,"Binary extention exeeds %d bytes "
"allowed in restricted mode\n", PNC_SRAM_SIZE);
goto header_error;
}
EXT_HDR_SET_LEN(headExtHdr, tmp_len);
header_size += tmp_len;
tailExtHdr = (tailExtBHR_t *)(tmpHeader + header_size - sizeof(tailExtBHR_t));
}
} /* (opt->flags & G_OPTION_MASK) */
/********************** End of Binary Header ******************************/
/* Align the headers block to... */
if (opt->image_type == IMG_NAND)
{
/* ... NAND page size */
header_size += opt->nandPageSize - (header_size & (opt->nandPageSize - 1));
}
else if (opt->image_type == IMG_SATA)
{
/* ... disk logical block size */
header_size += 512 - (header_size & 0x1FF);
}
else if (opt->image_type == IMG_UART)
{
/* ... Xmodem packet size */
header_size += 128 - (header_size & 0x7F);
}
/* For SATA the maximum header size is based on disk DOS compatibility
area width (32KB) minus size of MBR (512B) */
if ((header_size > MAX_HDR_SZ(opt->flags & U_OPTION_MASK)) ||
((opt->image_type == IMG_SATA) && (header_size > 32256)))
{
fprintf(stderr, "The header is too big - %d bytes!\n", header_size);
goto header_error;
}
/* Setup the image source address */
if (opt->image_type == IMG_SATA)
{
hdr->sourceAddr = opt->image_source;
}
else
{
if ((opt->image_source) && (opt->image_source > header_size))
{
hdr->sourceAddr = opt->image_source;
}
else
{
/* The source imgage address should be aligned
to 32 byte boundary (cache line size).
For NAND it should be aligned to 512 bytes boundary (for ECC)
The image immediately follows the header block,
so if the source addess is undefined, it should be
derived from the header size.
The headers size is always alighed to 4 byte boundary */
int boundary = 32;
if (opt->image_type == IMG_NAND)
boundary = 512;
if (header_size & (boundary - 1))
opt->img_gap = boundary - (header_size & (boundary - 1));
hdr->sourceAddr = header_size + opt->img_gap;
}
}
/* source address and extension headers number can be written now */
fprintf(stdout, "Ext. headers = %d, Header size = %d bytes Hdr-to-Img gap = %d bytes\n",
hdr->ext, header_size, opt->img_gap);
/* If not UART/TWSI image, an extra word for boot image checksum is needed */
if ((opt->image_type == IMG_FLASH) ||
(opt->image_type == IMG_NAND) ||
(opt->image_type == IMG_SATA) ||
(opt->image_type == IMG_PEX) ||
(opt->image_type == IMG_I2C))
{
hdr->blockSize += 4;
}
fprintf(stdout, "New image size = %#x[%d] Source image size = %#x[%d]\n",
hdr->blockSize, hdr->blockSize, (unsigned int)fs_stat.st_size, (int)fs_stat.st_size);
hdr->hdrSizeMsb = (header_size & 0x00FF0000) >> 16;
hdr->hdrSizeLsb = header_size & 0x0000FFFF;
opt->image_sz = hdr->blockSize;
/* Load image into memory buffer */
if (REGULAR_IMAGE(opt))
{
if (0 != pre_load_image(opt, buf_in))
{
fprintf(stderr, "Failed image pre-load!\n");
goto header_error;
}
}
/* Security Header should be filled after all the rest of headers */
/* Since it includes the headers block RSA signature */
if (opt->flags & Z_OPTION_MASK)
{
MV_U16 rsa_exp_len;
MV_U16 rsa_key_len;
unsigned char rsa_signature[RSA_MAX_KEY_LEN_BYTES];
#ifdef MV_SEC_HDR_DBG
FILE *f_sha;
unsigned char rsa_digest[32];
int k;
#endif
if(opt->flags & B_OPTION_MASK)
{
secExtHdr->boxId = opt->boxId;
}
if(opt->flags & F_OPTION_MASK)
{
secExtHdr->flashId = opt->flashId;
}
if(opt->flags & J_OPTION_MASK)
{
secExtHdr->jtagEn = 1;
}
/* Security header has a constant length */
secExtHdr->head.lenLsb = sizeof(secExtBHR_t);
rsa_exp_len = (mpi_msb(&rsa.E) + 7) >> 3; /* exponent length in bytes */
/* Full RSA public key lengh in DER encoding includes:
- modulus (N) length
- exponent (E) length
- 4 bytes for each of the above components (type and length fields)
Four bytes for the data block header are not included in this calculation
*/
rsa_key_len = rsa.len + rsa_exp_len + 8;
/* First the RSA public key should be inserted into security header */
/* Use DER encoding and long length field form (3 bytes) */
secExtHdr->pubKey[0] = 0x30; /* Type field for entire block */
secExtHdr->pubKey[1] = 0x82; /* long form, 2 bytes length field */
secExtHdr->pubKey[2] = (rsa_key_len & 0xFF00) >> 8;
secExtHdr->pubKey[3] = rsa_key_len & 0x00FF;
secExtHdr->pubKey[4] = 0x02; /* modulus type (integer) */
secExtHdr->pubKey[5] = 0x82; /* long form, 2 bytes length field */
secExtHdr->pubKey[6] = (rsa.len & 0x0000FF00) >> 8;
secExtHdr->pubKey[7] = rsa.len; /*we support up to 256 bytes key length */
secExtHdr->pubKey[8 + rsa.len] = 0x02; /* exponent type (integer) */
secExtHdr->pubKey[9 + rsa.len] = 0x82; /* long form, 2 bytes length field */
secExtHdr->pubKey[10 + rsa.len] = (rsa_exp_len & 0x0000FF00) >> 8;
secExtHdr->pubKey[11 + rsa.len] = rsa_exp_len;
if ((0 != mpi_write_binary(&rsa.N, &secExtHdr->pubKey[8], rsa.len)) ||
(0 != mpi_write_binary(&rsa.E, &secExtHdr->pubKey[12 + rsa.len], rsa_exp_len)))
{
fprintf(stderr, "Failed to write RSA key to security header\n");
goto header_error;
}
#ifdef MV_SEC_HDR_DBG
sha2((unsigned char *)secExtHdr->pubKey, rsa_key_len + 4, rsa_digest, 0);
if ((f_sha = fopen("./sha256.txt", "w")) == NULL)
{
fprintf(stderr, "Error opening SHA-256 digest file ./sha256.txt\n");
}
fprintf(stdout, "SHA-256 digest of the RSA public key is:\n");
fprintf(f_sha, "SHA256: ");
for (k = 0; k < 32; k++)
{
if (0 == (k % 8))
fprintf(stdout, "\n");
fprintf(stdout, "0x%02X, ", rsa_digest[k]);
fprintf(f_sha, "%02X", rsa_digest[k]);
}
fprintf(stdout, "\n\n");
fprintf(f_sha, "\n");
fclose(f_sha);
fprintf(stdout, "Box ID = 0x%08X, Flash ID = 0x%04X, JTAG %s\n",
opt->boxId, opt->flashId, opt->jtagDelay == 0 ? "DISABLED" : "ENABLED");
#endif /* MV_SEC_HDR_DBG */
/* Encrypt boot image using AES-128-CBC if required */
if (opt->flags & A_OPTION_MASK)
{
MV_U32 chsum32 = 0;
secExtHdr->encrypt = 1;
if ((opt->image_dest == 0xFFFFFFFF) &&
(opt->image_type == IMG_FLASH))
{
fprintf(stderr, "Wrong setup - Encrypted image with direct SPI boot!\n");
fprintf(stderr, "The image should be downloaded into RAM for decryption.\n");
fprintf(stderr, "Please define a valid destination address!\n");
goto header_error;
}
/* 16 bytes at head - IV, 4 bytes at tail - CHKSUM */
chsum32 = checksum32((void *)(opt->image_buf), opt->image_sz - 20, 0);
fprintf(stdout, "The image (plain img. CHKSUM = %08X) is encrypted using AES-128.\n", chsum32);
if ((opt->image_sz - 4) % 16)
{
fprintf(stderr, "Total boot image size (%d) is not multiple of 16!\n",
opt->image_sz);
free(opt->image_buf);
goto header_error;
}
aes_crypt_cbc(&aes, AES_ENCRYPT, opt->image_sz - 20, IV,
opt->image_buf, opt->image_buf);
} /* AES-128 encryption */
/* Create RSA signature for the boot image file (checksum is not included) */
if (0 != create_rsa_signature(opt->image_buf, opt->image_sz - 4, secExtHdr->imgSign, "IMG SHA256: "))
{
fprintf(stderr, "Failed to create boot image RSA signature\n");
goto header_error;
}
#ifdef MV_MEMPOOL_STAT
fprintf(stdout, "Boot Image signature creation\n");
mpool_print_stat();
mpool_reset_stat();
#endif
if (0 != verify_rsa_signature(opt->image_buf, opt->image_sz - 4, secExtHdr->imgSign))
{
fprintf(stderr, "Failed to verify boot image RSA signature\n");
goto header_error;
}
#ifdef MV_MEMPOOL_STAT
fprintf(stdout, "Boot Image signature verification\n");
mpool_print_stat();
mpool_reset_stat();
#endif
/* the RSA signature is now can be created for the entire headers block */
if (0 != create_rsa_signature(tmpHeader, header_size, rsa_signature, 0))
{
fprintf(stderr, "Failed to create header RSA signature\n");
goto header_error;
}
#ifdef MV_MEMPOOL_STAT
fprintf(stdout, "Header signature creation\n");
mpool_print_stat();
mpool_reset_stat();
#endif
/* Header signature MUST be checked when it's placeholder in the heqader is zeroed */
if (0 != verify_rsa_signature(tmpHeader, header_size, rsa_signature))
{
fprintf(stderr, "Failed to verify header RSA signature\n");
goto header_error;
}
#ifdef MV_MEMPOOL_STAT
fprintf(stdout, "Header signature verification\n");
mpool_print_stat();
mpool_reset_stat();
#endif
memcpy(secExtHdr->hdrSign, rsa_signature, rsa.len);
} /* if (opt->flags & Z_OPTION_MASK)*/
/* Now the headers block checksum should be calculated and wrote in the header */
/* This checksum value should be valid for both secure and unsecure boot modes */
/* This value will be checked first before RSA key and signature verification */
hdr->checkSum = checksum8((MV_U32)hdr, MAIN_HDR_GET_LEN(hdr), 0);
/* Write to file(s) */
if (opt->header_mode == HDR_IMG_TWO_FILES)
{
/* copy header to output image */
size_written = write(f_header, tmpHeader, header_size);
if (size_written != header_size)
{
fprintf(stderr,"Error writing %s file \n",opt->fname.hdr_out);
goto header_error;
}
fprintf(stdout, "====>>>> %s was created\n", opt->fname_arr[HDR_FILE_INDX]);
} /* if (header_mode == HDR_IMG_TWO_FILES) */
else
{
/* copy header to output image */
size_written = write(f_out, tmpHeader, header_size);
if (size_written != header_size)
{
fprintf(stderr,"Error writing %s file \n",opt->fname.out);
goto header_error;
}
} /* if (header_mode != HDR_IMG_TWO_FILES) */
error = 0;
header_error:
if (tmpHeader)
free(tmpHeader);
return error;
} /* end of build_headers() */
/*******************************************************************************
* build_bootrom_img
*******************************************************************************/
int build_bootrom_img (USER_OPTIONS *opt, char *buf_in)
{
unsigned int CRC_32 = 0;
int tmpSize = BOOTROM_SIZE - sizeof(CRC_32);
char *tmpImg = NULL ;
int size_written = 0;
int error = 1;
tmpImg = malloc(tmpSize);
if (tmpImg == NULL)
return 1;
/* PAD image with Zeros until BOOTROM_SIZE*/
memcpy(tmpImg, buf_in, fs_stat.st_size);
memset(tmpImg + fs_stat.st_size, 0, tmpSize - fs_stat.st_size);
/* copy input image to output image */
size_written = write(f_out, tmpImg, tmpSize);
/* calculate checsum */
CRC_32 = crc32(0, (u32*)tmpImg, tmpSize/4);
tmpSize += sizeof(CRC_32) ;
printf("Image CRC32 (size = %d) = 0x%08x\n", tmpSize, CRC_32);
size_written += write(f_out, &CRC_32, sizeof(CRC_32));
if (size_written == tmpSize)
error = 0;
bootrom_img_error:
if (tmpImg)
free(tmpImg);
return error;
} /* end of build_bootrom_img() */
/*******************************************************************************
* build_hex_img
*******************************************************************************/
int build_hex_img (USER_OPTIONS *opt, char *buf_in)
{
FILE *f_desc[2] = {NULL};
char *tmpImg = NULL;
int hex_len;
int hex_unaligned_len = 0;
unsigned char *hex8 = NULL;
unsigned char tmp8;
unsigned short *hex16 = NULL;
unsigned short tmp16;
unsigned long *hex32 = NULL;
unsigned long tmp32;
unsigned long tmp32_low;
int size_written = 0;
int alignment = 0;
int files_num;
int i;
int error = 1;
/* Calculate aligned image size */
hex_len = fs_stat.st_size;
alignment = opt->hex_width >> 3;
hex_unaligned_len = fs_stat.st_size & (alignment - 1);
if (hex_unaligned_len)
{
hex_len -= hex_unaligned_len;
hex_len += alignment;
}
/* Copy the input image to memory buffer */
tmpImg = malloc(hex_len);
if (tmpImg == NULL)
goto hex_image_end;
memset(tmpImg, 0, hex_len);
memcpy(tmpImg, buf_in, fs_stat.st_size);
if (opt->fname.hdr_out)
{
files_num = 2;
}
else
{
files_num = 1;
}
for (i = 0; i < files_num; i++)
{
f_desc[i] = fopen(opt->fname_arr[i + 1], "w");
if (f_desc[i] == NULL)
goto hex_image_end;
}
switch (opt->hex_width)
{
case 8:
hex8 = (unsigned char*)tmpImg;
for (i = 0; hex_len > 0; hex_len--)
{
fprintf(f_desc[i],"%02X\n",*hex8++);
size_written += 1;
i ^= files_num - 1;
}
break;
case 16:
hex16 = (unsigned short*)tmpImg;
for (; hex_len > 0; hex_len -= 2)
{
fprintf(f_desc[0],"%04X\n",*hex16++);
size_written += 2;
}
break;
case 32:
hex32 = (long*)tmpImg;
for (; hex_len > 0; hex_len -= 4)
{
fprintf(f_desc[0],"%08lX\n",*hex32++);
size_written += 4;
}
break;
case 64:
hex32 = (long*)tmpImg;
for (; hex_len > 0; hex_len -= 8)
{
fprintf(f_desc[0],"%08lX%08lX\n",*hex32++, *hex32++);
size_written += 8;
}
break;
} /* switch (opt->hex_width)*/
error = 0;
hex_image_end:
if (tmpImg)
free(tmpImg);
for (i = 0; i < files_num; i++)
{
if (f_desc[i] != NULL)
fclose(f_desc[i]);
}
return error;
} /* end of build_hex_img() */
/*******************************************************************************
* build_bin_img
*******************************************************************************/
int build_bin_img (USER_OPTIONS *opt, char *buf_in)
{
FILE *f_ds = NULL;
FILE *f_desc[4] = {NULL};
char *tmpImg = NULL;
int hex_len = 0;
int one_file_len = 0;
int size_written = 0;
int alignment = 0;
int hex_unaligned_len = 0;
unsigned char *hex8 = NULL;
unsigned char tmp8;
unsigned short *hex16 = NULL;
unsigned short tmp16;
unsigned long *hex32 = NULL;
unsigned long tmp32;
unsigned long tmp32low;
int i;
int fidx;
int files_num = 1;
int error = 1;
/* Calculate aligned image size */
hex_len = fs_stat.st_size;
alignment = opt->hex_width >> 3;
hex_unaligned_len = fs_stat.st_size & (alignment - 1);
if (hex_unaligned_len)
{
hex_len -= hex_unaligned_len;
hex_len += alignment;
}
/* prepare output files */
if (opt->fname.romd) /*16KB*/
{
files_num = 4;
}
else if (opt->fname.romc) /*12KB*/
{
files_num = 3;
}
else if (opt->fname.hdr_out)
{
files_num = 2;
}
one_file_len = hex_len / files_num;
for (i = 0; i < files_num; i++)
{
f_desc[i] = fopen(opt->fname_arr[i + 1], "w");
if (f_desc[i] == NULL)
goto bin_image_end;
}
/* Copy the input image to memory buffer */
tmpImg = malloc(hex_len);
if (tmpImg == NULL)
goto bin_image_end;
memset(tmpImg, 0, (hex_len));
memcpy(tmpImg, buf_in, fs_stat.st_size);
/* Split output image buffer according to width and number of files */
switch (opt->hex_width)
{
case 8:
hex8 = (unsigned char*)tmpImg;
if (files_num != 2)
{
fprintf(stderr, "Must supply two output file names for this width!\n");
goto bin_image_end;
}
for (fidx = 1; (fidx >= 0) && (hex_len > 0); fidx--)
{
f_ds = f_desc[1 - fidx];
for (; hex_len > (fidx * one_file_len); hex_len--)
{
tmp8 = *hex8;
for (i = 0; i < opt->hex_width ; i++)
{
fprintf(f_ds, "%d", ((tmp8 & 0x80) >> 7));
tmp8 <<= 1;
}
fprintf(f_ds,"\n");
hex8++;
size_written += 1;
}
}
break;
case 16:
hex16 = (unsigned short*)tmpImg;
for (; hex_len > 0; hex_len -= 2)
{
tmp16 = *hex16;
for (i = 0; i < opt->hex_width ; i++)
{
fprintf(f_desc[0], "%d", ((tmp16 & 0x8000) >> 15));
tmp16 <<= 1;
}
fprintf(f_desc[0],"\n");
hex16++;
size_written += 2;
}
break;
case 32:
hex32 = (long*)tmpImg;
for (fidx = files_num - 1; (fidx >= 0) && (hex_len > 0); fidx--)
{
f_ds = f_desc[files_num - 1 - fidx];
for (; hex_len > (fidx * one_file_len); hex_len -= 4)
{
tmp32 = *hex32;
for (i = 0; i < opt->hex_width ; i++)
{
fprintf(f_ds, "%ld", ((tmp32 & 0x80000000) >> 31));
tmp32 <<= 1;
}
fprintf(f_ds,"\n");
hex32++;
size_written += 4;
}
}
break;
case 64:
hex32 = (long*)tmpImg;
for (; hex_len > 0; hex_len -= 8)
{
tmp32low = *hex32++;
tmp32 = *hex32++;
for (i = 0; i < 32 ; i++)
{
fprintf(f_desc[0], "%ld", ((tmp32 & 0x80000000) >> 31));
tmp32 <<= 1;
}
for (i = 0; i < 32 ; i++)
{
fprintf(f_desc[0], "%ld", ((tmp32low & 0x80000000) >> 31));
tmp32low <<= 1;
}
fprintf(f_desc[0],"\n");
size_written += 8;
}
break;
} /* switch (opt->hex_width) */
error = 0;
bin_image_end:
if (tmpImg)
free(tmpImg);
for (i = 0; i < files_num; i++)
{
if (f_desc[i] != NULL)
fclose(f_desc[i]);
}
return error;
} /* end of build_bin_img() */
/*******************************************************************************
* build_regular_img
*******************************************************************************/
int build_regular_img (USER_OPTIONS *opt, char *buf_in)
{
int size_written = 0;
int new_file_size = 0;
MV_U32 chsum32 = 0;
new_file_size = opt->image_sz;
if (0 != opt->img_gap) /* cache line/NAND page alignment */
{
MV_U8 gap_buf[4096] = {0}; /* Up to 4K page size */
size_written += write(f_out, gap_buf, opt->img_gap);
new_file_size += opt->img_gap ;
}
/* Calculate checksum and copy it to the image tail */
chsum32 = checksum32((void *)opt->image_buf, opt->image_sz - 4, 0);
memcpy(opt->image_buf + opt->image_sz - 4, &chsum32, 4);
/* copy input image to output image */
size_written += write(f_out, opt->image_buf, opt->image_sz);
free(opt->image_buf);
if (new_file_size != size_written)
{
fprintf(stderr, "Size mismatch between calculated and written amount!\n");
return 1;
}
return 0;
} /* end of build_other_img() */
/*******************************************************************************
* process_image
*******************************************************************************/
int process_image (USER_OPTIONS *opt)
{
int i;
int override[2];
char *buf_in = NULL;
int err = 1;
/* check if the output image exist */
printf(" ");
for(i = IMG_FILE_INDX; i <= HDR_FILE_INDX; i++)
{
if (opt->fname_arr[i])
{
override[i] = 0;
if (0 == stat(opt->fname_arr[i], &fs_stat))
{
char c;
fprintf(stderr,"File '%s' already exist! override (y/n)?",
opt->fname_arr[i]);
c = getc(stdin);
if ((c == 'N')||(c == 'n'))
{
printf("exit.. nothing done. \n");
exit(0);
}
/* for the Enter */
c = getc(stdin);
//fflush(stdin);
override[i] = 1;
}
}
}
/* open input image file and check if it's size is OK */
if (opt->header_mode != HDR_ONLY)
{
f_in = open(opt->fname.in, O_RDONLY|O_BINARY);
if (f_in == -1)
{
fprintf(stderr,"File '%s' not found \n", opt->fname.in);
goto end;
}
/* get the size of the input image */
if (0 != fstat(f_in, &fs_stat))
{
fprintf(stderr,"fstat failed for file: '%s' err=%d\n", opt->fname.in, err);
goto end;
}
/*Check the source image size for limited output storage */
if (opt->image_type == IMG_BOOTROM)
{
int max_img_size = BOOTROM_SIZE - sizeof(u32);
if (opt->flags & Z_OPTION_MASK)
{
fprintf(stderr,"RSA signature is not supported for this image type\n");
goto end;
}
if (fs_stat.st_size > max_img_size)
{
fprintf(stderr, "ERROR : source image is bigger "
"than %d bytes \n", max_img_size);
goto end;
}
}
/* map the input image */
buf_in = mmap(0, fs_stat.st_size, PROT_READ, MAP_SHARED, f_in, 0);
if (!buf_in)
{
fprintf(stderr,"Error mapping %s file \n", opt->fname.in);
goto end;
}
}
/* open the output image file */
if (override[IMG_FILE_INDX] == 0)
{
f_out = open(opt->fname.out, O_RDWR|O_TRUNC|O_CREAT|O_BINARY,0666);
}
else
{
f_out = open(opt->fname.out, O_RDWR|O_BINARY);
}
if (f_out == -1)
{
fprintf(stderr,"Error opening %s file \n", opt->fname.out);
goto end;
}
/* open the output header file */
if (opt->header_mode == HDR_IMG_TWO_FILES)
{
if (override[HDR_FILE_INDX] == 0)
{
f_header = open(opt->fname.hdr_out, O_RDWR|O_TRUNC|O_CREAT|O_BINARY, 0666);
}
else
{
f_header = open(opt->fname.hdr_out, O_RDWR|O_BINARY);
}
if (f_header == -1)
{
fprintf(stderr,"Error opening %s file \n",opt->fname.hdr_out);
goto end;
}
}
/* secure boot support - read RSA private key */
if (opt->flags & Z_OPTION_MASK)
{
FILE *f_prkey;
int ret;
if (opt->flags & U_OPTION_MASK)
{
fprintf(stderr, "Secure boot is not supported on restricted platform!\n");
goto end;
}
if ((f_prkey = fopen(opt->fname_prkey, "rb")) == NULL)
{
fprintf(stderr, "Error opening RSA private key file %s\n",
opt->fname_prkey);
goto end;
}
rsa_init(&rsa, RSA_PKCS_V15, 0, NULL, NULL);
if( (ret = mpi_read_file(&rsa.N , 16, f_prkey ) ) != 0 ||
(ret = mpi_read_file(&rsa.E , 16, f_prkey ) ) != 0 ||
(ret = mpi_read_file(&rsa.D , 16, f_prkey ) ) != 0 ||
(ret = mpi_read_file(&rsa.P , 16, f_prkey ) ) != 0 ||
(ret = mpi_read_file(&rsa.Q , 16, f_prkey ) ) != 0 ||
(ret = mpi_read_file(&rsa.DP, 16, f_prkey ) ) != 0 ||
(ret = mpi_read_file(&rsa.DQ, 16, f_prkey ) ) != 0 ||
(ret = mpi_read_file(&rsa.QP, 16, f_prkey ) ) != 0 )
{
fprintf(stderr, "Cannot read RSA private key file\n\n", ret);
fclose(f_prkey);
goto end;
}
rsa.len = (mpi_msb(&rsa.N) + 7) >> 3; /* key lenght in bytes */
fclose(f_prkey);
if (RSA_MAX_KEY_LEN_BYTES < rsa.len)
{
fprintf(stderr, "Wrong RSA key length - %d bytes!"
" Supported RSA keys up to %d bytes\n",
rsa.len, RSA_MAX_KEY_LEN_BYTES);
goto end;
}
else
{
fprintf(stdout, "Given RSA private key is %d bit long\n", rsa.len * 8);
}
/* Use AES-128 encryption */
if (opt->flags & A_OPTION_MASK)
{
FILE *f_aeskey;
struct timeval tv;
char *pTmp = (char *)&tv;
unsigned char aes_key[16];
unsigned char digest[32];
int k;
if ((f_aeskey = fopen(opt->fname_aeskey, "rb")) == NULL)
{
fprintf(stderr, "Error opening AES-128 key file %s\n",
opt->fname_aeskey);
goto end;
}
if (fread (aes_key, 1, 16, f_aeskey) != 16)
{
fprintf(stderr, "Error reading AES-128 key from file %s\n",
opt->fname_aeskey);
fclose(f_aeskey);
goto end;
}
fclose(f_aeskey);
/* Generate initialization vector and init the AES engine */
/* Use file name XOR current time and finaly SHA-256 [0...15] */
memcpy(IV, opt->fname.in, 16);
gettimeofday(&tv);
for (i = 0, k = 0; i < 16; i++, k = (k+1) % sizeof(struct timeval))
{
IV[i] ^= pTmp[k];
}
/* compute SHA-256 digest and use it as the init vector */
sha2(IV, 16, digest, 0);
memcpy(IV, digest, 16);
aes_setkey_enc(&aes, aes_key, 128);
}
}
/* Image Header */
if (opt->header_mode != IMG_ONLY)
{
if (0 != build_headers(opt, buf_in))
goto end;
}
/* Output Image */
if (opt->header_mode != HDR_ONLY)
{
if (opt->image_type == IMG_BOOTROM)
{
err = build_bootrom_img(opt, buf_in);
}
else if (opt->image_type == IMG_HEX)
{
err = build_hex_img(opt, buf_in);
}
else if (opt->image_type == IMG_BIN)
{
err = build_bin_img(opt, buf_in);
}
else
{
err = build_regular_img(opt, buf_in);
}
if (err != 0)
{
fprintf(stderr, "Error writing %s file \n", opt->fname.out);
goto end;
}
fprintf(stdout, "====>>>> %s was created\n", opt->fname_arr[IMG_FILE_INDX]);
} /* if (opt->header_mode != HDR_ONLY) */
end:
/* close handles */
if (f_out != -1)
close(f_out);
if (f_header != -1)
close(f_header);
if (buf_in)
munmap((void*)buf_in, fs_stat.st_size);
if (f_in != -1)
close(f_in);
return err;
} /* end of process_image() */
/*******************************************************************************
* print_usage
*******************************************************************************/
void print_usage(void)
{
printf("Marvell doimage Tool version %s\n", VERSION_NUMBER);
printf("Supported SoC devices: \n\t%s\n", PRODUCT_SUPPORT);
printf("\n");
printf("Usage: \n");
printf("doimage <mandatory_opt> [other_options] image_in image_out [header_out]\n\n");
printf("<mandatory_opt> - can be one or more of the following:\n\n");
printf("-T image_type: sata\\uart\\flash\\bootrom\\nand\\hex\\pex\n");
printf(" if image_type is sata, the image_out will\n");
printf(" include header only.\n");
printf("-D image_dest: image destination in dram (in hex)\n");
printf("-E image_exec: execution address in dram (in hex)\n");
printf(" if image_type is 'flash' and image_dest is 0xffffffff\n");
printf(" then execution address on the flash\n");
printf("-S image_source: if image_type is sata then the starting sector of\n");
printf(" the source image on the disk - mandatory for sata\n");
printf(" if image_type is flash\\nand then the starting offset of\n");
printf(" the source image at the flash - optional for flash\\nand\n");
printf("-W hex_width : HEX file width, can be 8,16,32,64 \n");
printf("-M twsi_file: ascii file name that contains the I2C init regs set by h/w.\n");
printf(" this is used in i2c boot only\n");
printf("\nThe following options are mandatory for NAND image type:\n\n");
printf("-L nand_blk_size:NAND block size in KBytes (decimal int in range 64-16320)\n");
printf(" This parameter is ignored for flashes with 512B pages\n");
printf(" Such small page flashes always use 16K block sizes\n");
printf("-N nand_cell_typ:NAND cell technology type (char: M for MLC, S for SLC)\n");
printf("-P nand_pg_size: NAND page size: (decimal 512, 2048, 4096 or 8192)\n");
printf("\nSecure boot mode options - all options are mandatory once secure mode is selected:\n");
printf("-Z prv_key_file: Create image with RSA signature for secure boot mode\n");
printf("-A aes_key_file: Encrypt boot image using AES-128-CBC algorythm\n");
printf("-J jtag_delay: Enable JTAG and delay boot execution by \"N\" ms\n");
printf("-B hex_box_id: Box ID (hex) - from 0 to 0xffffffff\n");
printf("-F hex_flash_id: Flash ID (hex) - from 0 to 0xffff \n\n");
printf("\n<other_options> - optional and can be one or more of the following:\n\n");
printf("-G exec_file: ascii file name that contains binary routine (ARM 5TE THUMB)\n");
printf(" to run before the bootloader image execution.\n");
printf(" The routine must contain an appropriate code for saving \n");
printf(" all registers at the routine start and restore them \n");
printf(" before return from the routine \n");
// printf("-K args_num: Number or arguments to be bassed to the binary routine.\n");
// printf(" First <args_num> 4-byte words in the binary file passed\n");
// printf(" using \"G\" parameter will be interpereted as routine input arguments\n");
// printf(" Maxumum number of argumets is 255, the default value is 0\n");
printf("-R dram_file: ascii file name that contains the list of dram regs\n");
printf("-C nand_ecc_mod: NAND ECC: Option is IGNORED in this release (1=Hamming, 2=RS, 3=None)\n");
printf("-X pre_padding_size (hex)\n");
printf("-Y post_padding_size (hex)\n");
printf("-U Restricted SoC variant, no L2 cache. The header size is limited to 8KB\n");
printf("-H header_mode: Header mode, can be:\n");
printf(" -H 1 :will create one file (image_out) for header and image\n");
printf(" -H 2 :will create two files, (image_out) for image , (header_out) for header\n");
printf(" -H 3 :will create one file (image_out) for header only \n");
printf(" -H 4 :will create one file (image_out) for image only \n");
printf("\nCommand examples: \n\n");
printf("doimage -T hex -W width image_in image_out\n");
printf("doimage -T bootrom image_in image_out\n");
printf("doimage -T resume image_in image_out\n");
printf("doimage -T sata -S sector -D image_dest -E image_exec\n");
printf(" [other_options] image_in image_out header_out\n\n");
printf("doimage -T flash -D image_dest -E image_exec [-S address]\n");
printf(" [other_options] image_in image_out\n\n");
printf("doimage -T pex -D image_dest -E image_exec \n");
printf(" [other_options] image_in image_out\n\n");
printf("doimage -T nand -D image_dest -E image_exec [-S address] -P page_size\n");
printf(" -L 2 -N S [other_options] image_in image_out\n\n");
printf("doimage -T uart -D image_dest -E image_exec\n");
printf(" [other_options] image_in image_out\n\n");
printf("doimage -T pex -D image_dest -E image_exec \n");
printf(" [other_options] image_in image_out\n\n");
printf("\n\n\n");
} /* end of print_usage() */
/*******************************************************************************
* checksum8
*******************************************************************************/
MV_U8 checksum8(MV_U32 start, MV_U32 len, MV_U8 csum)
{
register MV_U8 sum = csum;
volatile MV_U8* startp = (volatile MV_U8*)start;
do
{
sum += *startp;
startp++;
} while(--len);
return (sum);
} /* end of checksum8 */
/*******************************************************************************
* checksum32
*******************************************************************************/
MV_U32 checksum32(void *start, MV_U32 len, MV_U32 csum)
{
register MV_U32 sum = csum;
volatile MV_U32* startp = (volatile MV_U32*)start;
do
{
sum += *(MV_U32*)startp;
startp++;
len -= 4;
} while(len);
return (sum);
} /* *end of checksum32() */
/*******************************************************************************
* make_crc_table
*******************************************************************************/
void make_crc_table(MV_U32 *crc_table)
{
MV_U32 c;
MV_32 n, k;
MV_U32 poly;
/* terms of polynomial defining this crc (except x^32): */
static const MV_U8 p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
/* make exclusive-or pattern from polynomial (0xedb88320L) */
poly = 0L;
for (n = 0; n < sizeof(p)/sizeof(MV_U8); n++)
poly |= 1L << (31 - p[n]);
for (n = 0; n < 256; n++)
{
c = (MV_U32)n;
for (k = 0; k < 8; k++)
c = c & 1 ? poly ^ (c >> 1) : c >> 1;
crc_table[n] = c;
}
} /* end of make_crc_table */
#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
#define DO2(buf) DO1(buf); DO1(buf);
#define DO4(buf) DO2(buf); DO2(buf);
#define DO8(buf) DO4(buf); DO4(buf);
/*******************************************************************************
* crc32
*******************************************************************************/
MV_U32 crc32(MV_U32 crc, volatile MV_U32 *buf, MV_U32 len)
{
MV_U32 crc_table[256];
/* Create the CRC table */
make_crc_table(crc_table);
crc = crc ^ 0xffffffffL;
while (len >= 8)
{
DO8(buf);
len -= 8;
}
if (len) do
{
DO1(buf);
} while (--len);
return crc ^ 0xffffffffL;
} /* end of crc32() */
/*******************************************************************************
* select_image
*******************************************************************************/
int select_image (char *img_name, USER_OPTIONS *opt)
{
int i;
static IMG_MAP img_map[] = {
{ IMG_SATA, "sata", D_OPTION_MASK|T_OPTION_MASK|E_OPTION_MASK|S_OPTION_MASK },
{ IMG_UART, "uart", D_OPTION_MASK|T_OPTION_MASK|E_OPTION_MASK },
{ IMG_FLASH, "flash", D_OPTION_MASK|T_OPTION_MASK|E_OPTION_MASK },
{ IMG_BOOTROM, "bootrom", T_OPTION_MASK },
{ IMG_NAND, "nand", D_OPTION_MASK|T_OPTION_MASK|E_OPTION_MASK|
L_OPTION_MASK|N_OPTION_MASK|P_OPTION_MASK },
{ IMG_HEX, "hex", T_OPTION_MASK|W_OPTION_MASK},
{ IMG_BIN, "bin", T_OPTION_MASK|W_OPTION_MASK},
{ IMG_PEX, "pex", D_OPTION_MASK|T_OPTION_MASK|E_OPTION_MASK },
{ IMG_I2C, "i2c", D_OPTION_MASK|T_OPTION_MASK|E_OPTION_MASK|M_OPTION_MASK },
};
for (i = 0; i < sizeof(img_map)/sizeof(img_map[0]); i++)
{
if (strcmp(img_name, img_map[i].img_name) == 0)
{
opt->image_type = img_map[i].img_type;
opt->req_flags = img_map[i].img_opt;
return 0;
}
}
return 1;
} /* *end of select_image() */
/*******************************************************************************
* main
*******************************************************************************/
int main (int argc, char** argv)
{
USER_OPTIONS options;
int optch; /* command-line option char */
static char optstring[] = "T:D:E:X:Y:S:P:W:H:R:M:Z:J:B:F:A:G:L:N:C:U";
int i, k;
if (argc < 2) goto parse_error;
memset(&options, 0, sizeof(USER_OPTIONS));
options.header_mode = HDR_IMG_ONE_FILE;
fprintf(stdout, "\n");
while ((optch = getopt(argc, argv, optstring)) != -1)
{
char *endptr = NULL;
switch (optch)
{
case 'T': /* image type */
if ((select_image(optarg, &options) != 0) ||
(options.flags & T_OPTION_MASK)) goto parse_error;
options.flags |= T_OPTION_MASK;
break;
case 'D': /* image destination */
options.image_dest = strtoul(optarg, &endptr, 16);
if (*endptr || (options.flags & D_OPTION_MASK)) goto parse_error;
options.flags |= D_OPTION_MASK;
break;
case 'E': /* image execution */
options.image_exec = strtoul(optarg, &endptr, 16);
if (*endptr || (options.flags & E_OPTION_MASK)) goto parse_error;
options.flags |= E_OPTION_MASK;
break;
case 'X': /* Pre - Padding */
options.prepadding_size = strtoul(optarg, &endptr, 16);
if (*endptr || (options.flags & X_OPTION_MASK)) goto parse_error;
options.pre_padding = 1;
options.flags |= X_OPTION_MASK;
break;
case 'Y': /* Post - Padding */
options.postpadding_size = strtoul(optarg, &endptr, 16);
if (*endptr || (options.flags & Y_OPTION_MASK)) goto parse_error;
options.post_padding = 1;
options.flags |= Y_OPTION_MASK;
break;
case 'S': /* starting sector */
options.image_source = strtoul(optarg, &endptr, 16);
if (*endptr || (options.flags & S_OPTION_MASK)) goto parse_error;
options.flags |= S_OPTION_MASK;
break;
case 'P': /* NAND Page Size */
options.nandPageSize = strtoul (optarg, &endptr, 10);
if (*endptr || (options.flags & P_OPTION_MASK)) goto parse_error;
options.flags |= P_OPTION_MASK;
break;
case 'C': /* nand ecc mode */
// options.nandEccMode = strtoul (*++argv, &endptr, 10);
// if (*endptr || (options.flags & C_OPTION_MASK)) goto parse_error;
// options.flags |= C_OPTION_MASK;*/
break;
case 'W': /* HEX file width */
options.hex_width = strtoul(optarg, &endptr, 10);
if (*endptr || (options.flags & W_OPTION_MASK)) goto parse_error;
options.flags |= W_OPTION_MASK;
break;
case 'H': /* Header file mode */
options.header_mode = strtoul(optarg, &endptr, 10);
if (*endptr || (options.flags & H_OPTION_MASK)) goto parse_error;
options.flags |= H_OPTION_MASK;
break;
case 'R': /* dram file */
options.fname_dram = optarg;
if (options.flags & R_OPTION_MASK) goto parse_error;
options.flags |= R_OPTION_MASK;
break;
case 'M': /* TWSI file */
options.fname_twsi = optarg;
if (options.flags & M_OPTION_MASK) goto parse_error;
options.flags |= M_OPTION_MASK;
break;
case 'G': /* binary file */
options.fname_bin = optarg;
if (options.flags & G_OPTION_MASK) goto parse_error;
options.flags |= G_OPTION_MASK;
break;
case 'Z': /* secure boot - private key */
options.fname_prkey = optarg;
if (options.flags & Z_OPTION_MASK) goto parse_error;
options.flags |= Z_OPTION_MASK;
break;
case 'J': /* JTAG Enabled */
options.jtagDelay = strtoul(optarg, &endptr, 10);
if (*endptr || (options.flags & J_OPTION_MASK)) goto parse_error;
options.flags |= J_OPTION_MASK;
break;
case 'B': /* Box ID */
options.boxId = strtoul(optarg, &endptr, 16);
if (*endptr || (options.flags & B_OPTION_MASK)) goto parse_error;
options.flags |= B_OPTION_MASK;
break;
case 'F': /* Flash ID */
options.flashId = strtoul(optarg, &endptr, 16);
if (*endptr || (options.flags & F_OPTION_MASK)) goto parse_error;
options.flags |= F_OPTION_MASK;
break;
case 'A': /* secure boot - encrypt with AES-128 key */
options.fname_aeskey = optarg;
if (options.flags & A_OPTION_MASK) goto parse_error;
options.flags |= A_OPTION_MASK;
break;
case 'L': /* NAND block size */
options.nandBlkSize = strtoul(optarg, &endptr, 10) / 64;
if (*endptr || (options.flags & L_OPTION_MASK)) goto parse_error;
options.flags |= L_OPTION_MASK;
break;
case 'N': /* NAND cell technology */
options.nandCellTech = optarg[0];
if (options.flags & N_OPTION_MASK) goto parse_error;
options.flags |= N_OPTION_MASK;
break;
case 'U': /* Restricted SOC */
if (options.flags & U_OPTION_MASK) goto parse_error;
options.flags |= U_OPTION_MASK;
break;
default:
goto parse_error;
}
} /* parse command-line options */
/* assign file names */
for (i = 0; optind < argc; ++optind, i++)
{
options.fname_arr[i] = argv[optind];
/* verify that all file names are different */
for (k = 0; k < i; k++)
{
if (0 == strcmp(options.fname_arr[i], options.fname_arr[k]))
{
fprintf(stderr,"\nError: Input and output images can't be the same\n");
exit(1);
}
}
}
if (!(options.flags & T_OPTION_MASK))
{
goto parse_error;
}
/* 2 sperate images is used with SATA only */
if (!(options.flags & H_OPTION_MASK) &&
(options.image_type == IMG_SATA))
{
options.header_mode = HDR_IMG_TWO_FILES;
}
if (!(options.flags & S_OPTION_MASK) &&
(options.header_mode == HDR_IMG_TWO_FILES))
{
fprintf(stderr,"Error: -S option is missing\n\n\n\n\n");
goto parse_error;
}
/* verify HEX file width selection to be valid */
if ((options.flags & W_OPTION_MASK) &&
(options.hex_width != 8) && (options.hex_width != 16) &&
(options.hex_width != 32) && (options.hex_width != 64))
{
goto parse_error;
}
if ((options.image_type == IMG_BOOTROM) ||
(options.image_type == IMG_HEX) ||
(options.image_type == IMG_BIN))
{
options.header_mode = IMG_ONLY;
}
if (options.header_mode == IMG_ONLY)
{
/* remove unneeded options */
options.req_flags &= ~(D_OPTION_MASK|E_OPTION_MASK|S_OPTION_MASK|
R_OPTION_MASK|P_OPTION_MASK|L_OPTION_MASK|N_OPTION_MASK);
}
if (options.req_flags != (options.flags & options.req_flags))
{
goto parse_error;
}
if ((options.flags & F_OPTION_MASK) &&
(options.flashId > 0xFFFF))
{
fprintf(stderr,"Error: Flash ID is too long!\n\n\n\n\n");
goto parse_error;
}
if ((options.flags & L_OPTION_MASK) &&
((options.nandBlkSize > 255) ||
((options.nandBlkSize == 0) && (options.nandPageSize != 512))))
{
fprintf(stderr,"Error: wrong NAND block size %d!\n\n\n\n\n", 64*options.nandBlkSize);
goto parse_error;
}
if ((options.flags & N_OPTION_MASK) &&
(options.nandCellTech != 'S') && (options.nandCellTech != 'M') &&
(options.nandCellTech != 's') && (options.nandCellTech != 'm'))
{
fprintf(stderr,"Error: Wrong NAND cell technology type!\n\n\n\n\n");
goto parse_error;
}
return process_image(&options);
parse_error:
print_usage();
exit(1);
} /* end of main() */