| /******************************************************************************* |
| 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> |
| #include <limits.h> |
| |
| #define _HOST_COMPILER |
| #include "bootstrap_def.h" |
| |
| #include "polarssl/havege.h" |
| #include "polarssl/sha2.h" |
| #include "polarssl/rsa.h" |
| #include "polarssl/aes.h" |
| #include "doimage.h" |
| |
| #include "polarssl/mvMemPool.h" |
| |
| #undef DEBUG |
| |
| #ifdef DEBUG |
| #define DB(x...) fprintf(stdout, x); |
| #else |
| #define DB(x...) |
| #endif |
| |
| /* Global variables */ |
| |
| int f_in = -1; |
| int f_out = -1; |
| int f_header = -1; |
| struct stat fs_stat; |
| rsa_context rsa; |
| rsa_context rsaCsk; |
| unsigned char IV[16] = {0}; |
| |
| /******************************************************************************* |
| * create_rsa_signature (memory buffer content) |
| * create RSA-2048 signature for memory buffer |
| * INPUT: |
| * input memory buffer |
| * ilen buffer length |
| * print_val if not 0, print SHA-256 digest of the memory buffer (debug) |
| * kak selector between kak key or csk key |
| * OUTPUT: |
| * signature RSA-2048 signature |
| * RETURN: |
| * 0 on success |
| *******************************************************************************/ |
| int create_rsa_signature ( |
| unsigned char *input, |
| int ilen, |
| unsigned char *signature, |
| char *print_val, |
| unsigned int kak) |
| { |
| unsigned char sha_256[32]; |
| int i; |
| rsa_context *rsaCont = &rsaCsk; |
| |
| memset(sha_256, 0, 32 * sizeof(unsigned char)); |
| |
| if (kak != 0) |
| rsaCont = &rsa; |
| |
| /* 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(rsaCont, RSA_PRIVATE, RSA_SHA256, 32, sha_256, signature); |
| |
| } /* end of create_rsa_signature() */ |
| |
| /******************************************************************************* |
| * verify_rsa_signature (memory buffer content) |
| * verify RSA-2048 signature for memory buffer |
| * INPUT: |
| * input memory buffer |
| * ilen buffer length |
| * signature RSA-2048 signature |
| * kak selector between kak key or csk key |
| * OUTPUT: |
| * none |
| * RETURN: |
| * 0 on success |
| *******************************************************************************/ |
| int verify_rsa_signature ( |
| unsigned char *input, |
| int ilen, |
| unsigned char *signature, |
| unsigned int kak) |
| { |
| unsigned char sha_256[32]; |
| rsa_context *rsaCont = &rsaCsk; |
| |
| memset(sha_256, 0, 32 * sizeof(unsigned char)); |
| |
| if (kak != 0) |
| rsaCont = &rsa; |
| |
| /* compute SHA-256 digest */ |
| sha2(input, ilen, sha_256, 0); |
| |
| return rsa_pkcs1_verify(rsaCont, RSA_PUBLIC, RSA_SHA256, 32, sha_256, signature); |
| |
| } /* end of create_rsa_signature() */ |
| |
| /******************************************************************************* |
| * pre_load_image |
| * pre-load the binary image into memory buffer taking into account paddings |
| * INPUT: |
| * opt user options |
| * buf_in mmapped input file |
| * OUTPUT: |
| * none |
| * RETURN: |
| * 0 on success |
| *******************************************************************************/ |
| 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; |
| } /* end of pre_load_image() */ |
| |
| /******************************************************************************* |
| * build_twsi_header |
| * create TWSI header and write it into output stream |
| * INPUT: |
| * opt user options |
| * OUTPUT: |
| * none |
| * RETURN: |
| * 0 on success |
| *******************************************************************************/ |
| int build_twsi_header (USER_OPTIONS *opt) |
| { |
| FILE *f_twsi; |
| MV_U8 *tmpTwsi = NULL; |
| MV_U32 *twsi_reg; |
| int i; |
| MV_U32 twsi_size = 0; |
| |
| tmpTwsi = malloc(MAX_TWSI_HDR_SIZE); |
| if (tmpTwsi == NULL) { |
| fprintf(stderr,"TWSI space allocation error!\n"); |
| return -1; |
| } |
| 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,"Failed to open file '%s'\n", opt->fname_twsi); |
| perror("Error:"); |
| return -1; |
| } |
| |
| 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); |
| return -1; |
| } |
| |
| return 0; |
| } /* end of build_twsi_header() */ |
| |
| /******************************************************************************* |
| * build_reg_header |
| * create BIN header and write it into output stream |
| * INPUT: |
| * fname - source file name |
| * buffer - Start address of boot image buffer |
| * current_size - number of bytes already placed into the boot image buffer |
| * OUTPUT: |
| * none |
| * RETURN: |
| * size of a reg header or 0 on fail |
| *******************************************************************************/ |
| int build_reg_header (char *fname, MV_U8 *buffer, MV_U32 current_size) |
| { |
| FILE *f_dram; |
| BHR_t *mainHdr = (BHR_t *)buffer; |
| headExtBHR_t *headExtHdr = headExtHdr = (headExtBHR_t *)(buffer + current_size); |
| tailExtBHR_t *prevExtHdrTail = NULL; /* tail of the previous extention header */ |
| MV_U32 max_bytes_to_write; |
| MV_U32 *dram_reg = (MV_U32 *)(buffer + current_size + sizeof(headExtBHR_t)); |
| MV_U32 tmp_len; |
| int i; |
| |
| if (mainHdr->ext == 255) { |
| fprintf(stderr,"Maximum number of extentions reached!\n"); |
| return 0; |
| } |
| |
| /* Indicate next header in previous extention if any */ |
| if (mainHdr->ext != 0) { |
| prevExtHdrTail = (tailExtBHR_t*)(buffer + current_size - sizeof(tailExtBHR_t)); |
| prevExtHdrTail->nextHdr = 1; |
| } |
| |
| /* Count extension headers in the main header */ |
| mainHdr->ext++; |
| |
| headExtHdr->type = EXT_HDR_TYP_REGISTER; |
| max_bytes_to_write = MAX_HEADER_SIZE - current_size - EXT_HDR_BASE_SIZE; |
| |
| if ((f_dram = fopen(fname, "r")) == NULL) { |
| fprintf(stderr,"Failed to open file '%s'\n", fname); |
| perror("Error:"); |
| return 0; |
| } |
| |
| 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); |
| return 0; |
| } |
| |
| /* Include extended header head and tail sizes */ |
| tmp_len = EXT_HDR_BASE_SIZE + i * 4; |
| /* Write total length into the current header fields */ |
| EXT_HDR_SET_LEN(headExtHdr, tmp_len); |
| |
| return tmp_len; |
| } /* end of build_reg_header() */ |
| |
| /******************************************************************************* |
| * build_bin_header |
| * create BIN header and write it into putput stream |
| * INPUT: |
| * fname - source file name |
| * buffer - Start address of boot image buffer |
| * current_size - number of bytes already placed into the boot image buffer |
| * OUTPUT: |
| * none |
| * RETURN: |
| * size of reg header |
| *******************************************************************************/ |
| int build_bin_header (char *fname, MV_U8 *buffer, MV_U32 current_size) |
| { |
| FILE *f_bin; |
| BHR_t *mainHdr = (BHR_t *)buffer; |
| headExtBHR_t *headExtHdr = (headExtBHR_t *)(buffer + current_size); |
| tailExtBHR_t *prevExtHdrTail = NULL; /* tail of the previous extention header */ |
| MV_U32 max_bytes_to_write; |
| MV_U32 *bin_reg = (MV_U32 *)(buffer + current_size + sizeof(headExtBHR_t)); |
| MV_U32 tmp_len; |
| int i; |
| |
| if (mainHdr->ext == 255) { |
| fprintf(stderr,"Maximum number of extentions reached!\n"); |
| return 0; |
| } |
| |
| /* Indicate next header in previous extention if any */ |
| if (mainHdr->ext != 0) { |
| prevExtHdrTail = (tailExtBHR_t*)(buffer + current_size - sizeof(tailExtBHR_t)); |
| prevExtHdrTail->nextHdr = 1; |
| } |
| |
| /* Count extension headers in main header */ |
| mainHdr->ext++; |
| |
| headExtHdr->type = EXT_HDR_TYP_BINARY; |
| max_bytes_to_write = MAX_HEADER_SIZE - current_size - EXT_HDR_BASE_SIZE; |
| |
| f_bin = fopen(fname, "r"); |
| if (f_bin == NULL) { |
| fprintf(stderr,"Failed to open file '%s'\n", fname); |
| perror("Error:"); |
| return 0; |
| } |
| |
| 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); |
| return 0; |
| } |
| |
| /* Include extended header head and tail sizes */ |
| tmp_len = EXT_HDR_BASE_SIZE + i * 4; |
| /* Write total length into the current header fields */ |
| EXT_HDR_SET_LEN(headExtHdr, tmp_len); |
| |
| return tmp_len; |
| } /* end of build_exec_header() */ |
| |
| /******************************************************************************* |
| * build_headers |
| * build headers block based on user options and write it into output stream |
| * INPUT: |
| * opt user options |
| * buf_in mmapped input file |
| * OUTPUT: |
| * none |
| * RETURN: |
| * 0 on success |
| *******************************************************************************/ |
| 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; |
| int size_written = 0; |
| MV_U32 max_bytes_to_write; |
| int error = 1; |
| |
| tmpHeader = malloc(MAX_HEADER_SIZE); |
| if (tmpHeader == NULL) { |
| fprintf(stderr,"Header space allocation error!\n"); |
| goto header_error; |
| } |
| |
| memset(tmpHeader, 0 , MAX_HEADER_SIZE); |
| 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_MMC: |
| hdr->blockID = IBR_HDR_MMC_ID; |
| break; |
| |
| case IMG_NAND: |
| hdr->blockID = IBR_HDR_NAND_ID; |
| /*hdr->nandEccMode = (MV_U8)opt->nandEccMode; <<== reserved */ |
| /*hdr->nandPageSize = (MV_U16)opt->nandPageSize; <<== reserved */ |
| 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; |
| } |
| |
| /* Debug print options */ |
| if (opt->flags & p_OPTION_MASK) |
| hdr->flags &= ~BHR_FLAG_PRINT_EN; |
| else |
| hdr->flags |= BHR_FLAG_PRINT_EN; /* Enable printing by default */ |
| |
| if (opt->flags & b_OPTION_MASK) { |
| switch (opt->baudRate) { |
| case 2400: |
| hdr->options = BHR_OPT_BAUD_2400; |
| break; |
| |
| case 4800: |
| hdr->options = BHR_OPT_BAUD_4800; |
| break; |
| |
| case 9600: |
| hdr->options = BHR_OPT_BAUD_9600; |
| break; |
| |
| case 19200: |
| hdr->options = BHR_OPT_BAUD_19200; |
| break; |
| |
| case 38400: |
| hdr->options = BHR_OPT_BAUD_38400; |
| break; |
| |
| case 57600: |
| hdr->options = BHR_OPT_BAUD_57600; |
| break; |
| |
| case 115200: |
| hdr->options = BHR_OPT_BAUD_115200; |
| break; |
| |
| default: |
| fprintf(stderr, "Unsupported baud rate - %d!\n", opt->baudRate); |
| return 1; |
| } |
| } else |
| hdr->options = BHR_OPT_BAUD_DEFAULT; |
| |
| /* debug port number */ |
| if (opt->flags & u_OPTION_MASK) |
| hdr->options |= (opt->debugPortNum << BHR_OPT_UART_PORT_OFFS) & BHR_OPT_UART_PORT_MASK; |
| |
| /* debug port MPP setup index */ |
| if (opt->flags & m_OPTION_MASK) |
| hdr->options |= (opt->debugPortMpp << BHR_OPT_UART_MPPS_OFFS) & BHR_OPT_UART_MPPS_MASK; |
| |
| |
| 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 - always single and always first after the Main header */ |
| if (opt->flags & Z_OPTION_MASK) { |
| /* 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) { |
| if (build_twsi_header(opt) != 0) |
| goto header_error; |
| } /* opt->fname_twsi */ |
| } /* (opt->flags & M_OPTION_MASK) */ |
| |
| /************************** End of TWSI Header ****************************/ |
| |
| /********************** Single Register Header ***************************/ |
| |
| if (opt->flags & R_OPTION_MASK) { |
| if (opt->fname_dram) { |
| MV_U32 rhdr_len = build_reg_header(opt->fname_dram, tmpHeader, header_size); |
| if (rhdr_len <= 0) |
| goto header_error; |
| |
| header_size += rhdr_len; |
| tailExtHdr = (tailExtBHR_t *)(tmpHeader + header_size - sizeof(tailExtBHR_t)); |
| } /* if (fname_dram) */ |
| } /* if (opts & R_OPTION_MASK) */ |
| |
| /******************** End of Single Register Header ************************/ |
| |
| /************************* Single Binary Header ****************************/ |
| |
| if (opt->flags & G_OPTION_MASK) { |
| if (opt->fname_bin) { |
| MV_U32 bhdr_len = build_bin_header(opt->fname_bin, tmpHeader, header_size); |
| if (bhdr_len <= 0) |
| goto header_error; |
| |
| header_size += bhdr_len; |
| tailExtHdr = (tailExtBHR_t *)(tmpHeader + header_size - sizeof(tailExtBHR_t)); |
| } /* if (fname_bin) */ |
| } /* (opt->flags & G_OPTION_MASK) */ |
| |
| /******************* End of Single Binary Header ***************************/ |
| |
| /************************* BIN/REG Headers list ****************************/ |
| |
| if (opt->flags & C_OPTION_MASK) { |
| if (opt->fname_list) { |
| FILE *f_list; |
| char buffer[PATH_MAX + 5]; |
| char *fname; |
| MV_U32 hdr_len = 0, last; |
| int (*build_hdr_func)(char*, MV_U8*, MV_U32); |
| |
| f_list = fopen(opt->fname_list, "r"); |
| if (f_list == NULL) { |
| fprintf(stderr,"File '%s' not found \n", opt->fname_list); |
| goto header_error; |
| } |
| /* read the headers list row by row */ |
| while (fgets(buffer, PATH_MAX + 4, f_list) != NULL) { |
| /* Ignore strings that are not starting with BIN/REG */ |
| if (strncmp(buffer, "BIN", 3) == 0) { |
| build_hdr_func = build_bin_header; |
| } else if (strncmp(buffer, "REG", 3) == 0) { |
| build_hdr_func = build_reg_header; |
| } else |
| continue; |
| |
| fname = buffer + 3; |
| /* strip leading spaces/tabs if any */ |
| while ((strncmp(fname, " ", 1) == 0) || (strncmp(fname, "\t", 1) == 0)) |
| fname++; |
| |
| /* strip trailing LF/CR symbols */ |
| last = strlen(fname) - 1; |
| while ((strncmp(fname + last, "\n", 1) == 0) || |
| (strncmp(fname + last, "\r", 1) == 0)) { |
| fname[last] = 0; |
| last--; |
| } |
| /* Insert required header into the output buffer */ |
| hdr_len = build_hdr_func(fname, tmpHeader, header_size); |
| if (hdr_len <= 0) |
| goto header_error; |
| |
| header_size += hdr_len; |
| tailExtHdr = (tailExtBHR_t *)(tmpHeader + header_size - sizeof(tailExtBHR_t)); |
| } |
| |
| fclose(f_list); |
| } /* if (fname_list) */ |
| }/* (opt->flags & C_OPTION_MASK) */ |
| |
| /********************** End of BIN/REG Headers list ************************/ |
| |
| /* 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) || (opt->image_type == IMG_MMC)) { |
| /* ... 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); |
| } |
| /* Setup the image source address */ |
| if (opt->image_type == IMG_SATA) { |
| if ((opt->image_source) && (opt->image_source > header_size)) |
| hdr->sourceAddr = opt->image_source; |
| else |
| hdr->sourceAddr = header_size >> 9; /* Already aligned to 512 */ |
| } else { |
| if ((opt->image_source) && (opt->image_source > header_size)) { |
| hdr->sourceAddr = opt->image_source; |
| opt->img_gap = opt->image_source - header_size; |
| } 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) || (opt->image_type == IMG_MMC)) |
| 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_MMC) || |
| (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]; |
| FILE *f_sha; |
| unsigned char rsa_digest[32]; |
| int k; |
| |
| 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 = opt->jtagDelay; |
| |
| /* Security header has a constant length */ |
| secExtHdr->head.lenLsb = sizeof(secExtBHR_t); |
| |
| /*CSK*/ |
| rsa_exp_len = (mpi_msb(&rsaCsk.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 = rsaCsk.len + rsa_exp_len + 8; |
| |
| /* First the CSK RSA public key should be inserted into security header */ |
| /* Use DER encoding and long length field form (3 bytes) */ |
| (((secExtHdr->cskArray)[opt->csk_index]).Key)[0] = 0x30; /*Type field for entire block */ |
| (((secExtHdr->cskArray)[opt->csk_index]).Key)[1] = 0x82; /*long form, 2 bytes length field */ |
| (((secExtHdr->cskArray)[opt->csk_index]).Key)[2] = (rsa_key_len & 0xFF00) >> 8; |
| (((secExtHdr->cskArray)[opt->csk_index]).Key)[3] = rsa_key_len & 0x00FF; |
| (((secExtHdr->cskArray)[opt->csk_index]).Key)[4] = 0x02; /*modulus type (integer) */ |
| (((secExtHdr->cskArray)[opt->csk_index]).Key)[5] = 0x82; /*long form, 2 bytes length field */ |
| (((secExtHdr->cskArray)[opt->csk_index]).Key)[6] = (rsaCsk.len & 0x0000FF00) >> 8; |
| (((secExtHdr->cskArray)[opt->csk_index]).Key)[7] = rsaCsk.len; /*we support up to 256 bytes key length */ |
| (((secExtHdr->cskArray)[opt->csk_index]).Key)[8 + rsaCsk.len] = 0x02; /* exponent type (integer) */ |
| (((secExtHdr->cskArray)[opt->csk_index]).Key)[9 + rsaCsk.len] = 0x82; /* long form, 2 bytes length field */ |
| (((secExtHdr->cskArray)[opt->csk_index]).Key)[10 + rsaCsk.len] = (rsa_exp_len & 0x0000FF00) >> 8; |
| (((secExtHdr->cskArray)[opt->csk_index]).Key)[11 + rsaCsk.len] = rsa_exp_len; |
| |
| if ((0 != mpi_write_binary(&rsaCsk.N, &(((secExtHdr->cskArray)[opt->csk_index]).Key)[8], rsa.len)) || |
| (0 != mpi_write_binary(&rsaCsk.E, &(((secExtHdr->cskArray)[opt->csk_index]).Key)[12 + rsa.len], |
| rsa_exp_len))) { |
| fprintf(stderr, "Failed to write RSA key to security header\n"); |
| goto header_error; |
| } |
| |
| sha2((unsigned char *)(((secExtHdr->cskArray)[opt->csk_index]).Key), rsa_key_len + 4, rsa_digest, 0); |
| if ((f_sha = fopen("./sha2_pub_csk.txt", "w")) == NULL) |
| fprintf(stderr, "Error opening SHA-256 digest file ./sha2_pub_csk.txt\n"); |
| |
| fprintf(f_sha, "SHA256 = "); |
| |
| for (k = 0; k < 32; k++) |
| fprintf(f_sha, "%02X", rsa_digest[k]); |
| |
| fprintf(f_sha, "\n"); |
| fclose(f_sha); |
| |
| DB(stdout, "Box ID = 0x%08X, Flash ID = 0x%04X, JTAG %s\n", |
| opt->boxId, opt->flashId, opt->jtagDelay == 0 ? "DISABLED" : "ENABLED"); |
| |
| /* the RSA signature is now can be created for the CSK Array using KAK */ |
| error = create_rsa_signature(tmpHeader + sizeof(BHR_t) + CSK_BLOCK_OFFSET, |
| CSK_BLOCK_SIZE, rsa_signature, "CSK ARRAY SHA256:", 1); |
| if (0 != error) { |
| fprintf(stderr, "Failed to create CSK array signature using KAK, error %d\n", error); |
| goto header_error; |
| } |
| |
| #if defined MV_MEMPOOL_STAT && defined NO_HEAP |
| fprintf(stdout, "CSK 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 + sizeof(BHR_t) + CSK_BLOCK_OFFSET, |
| CSK_BLOCK_SIZE, rsa_signature, 1 /* KAK*/)) { |
| fprintf(stderr, "Failed to verify header CSK RSA signature\n"); |
| goto header_error; |
| } |
| memcpy(secExtHdr->cskBlockSign, rsa_signature, rsa.len); |
| |
| /*KAK*/ |
| 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; |
| |
| /* Next the KAK RSA public key should be inserted into security header */ |
| /* Use DER encoding and long length field form (3 bytes) */ |
| ((secExtHdr->pubKey).Key)[0] = 0x30; /* Type field for entire block */ |
| ((secExtHdr->pubKey).Key)[1] = 0x82; /* long form, 2 bytes length field */ |
| ((secExtHdr->pubKey).Key)[2] = (rsa_key_len & 0xFF00) >> 8; |
| ((secExtHdr->pubKey).Key)[3] = rsa_key_len & 0x00FF; |
| ((secExtHdr->pubKey).Key)[4] = 0x02; /* modulus type (integer) */ |
| ((secExtHdr->pubKey).Key)[5] = 0x82; /* long form, 2 bytes length field */ |
| ((secExtHdr->pubKey).Key)[6] = (rsa.len & 0x0000FF00) >> 8; |
| ((secExtHdr->pubKey).Key)[7] = rsa.len; /*we support up to 256 bytes key length */ |
| ((secExtHdr->pubKey).Key)[8 + rsa.len] = 0x02; /* exponent type (integer) */ |
| ((secExtHdr->pubKey).Key)[9 + rsa.len] = 0x82; /* long form, 2 bytes length field */ |
| ((secExtHdr->pubKey).Key)[10 + rsa.len] = (rsa_exp_len & 0x0000FF00) >> 8; |
| ((secExtHdr->pubKey).Key)[11 + rsa.len] = rsa_exp_len; |
| |
| if ((0 != mpi_write_binary(&rsa.N, &((secExtHdr->pubKey).Key)[8], rsa.len)) || |
| (0 != mpi_write_binary(&rsa.E, &((secExtHdr->pubKey).Key)[12 + rsa.len], rsa_exp_len))) { |
| fprintf(stderr, "Failed to write RSA key to security header\n"); |
| goto header_error; |
| } |
| sha2((unsigned char *)((secExtHdr->pubKey).Key), rsa_key_len + 4, rsa_digest, 0); |
| if ((f_sha = fopen("./sha2_pub_kak.txt", "w")) == NULL) |
| fprintf(stderr, "Error opening SHA-256 digest file ./sha2_pub_kak.txt\n"); |
| |
| fprintf(f_sha, "SHA256 = "); |
| |
| for (k = 0; k < 32; k++) |
| fprintf(f_sha, "%02X", rsa_digest[k]); |
| |
| fprintf(f_sha, "\n"); |
| fclose(f_sha); |
| |
| /* Create RSA signature for the boot image file using CSK (checksum is not included) */ |
| error = create_rsa_signature(opt->image_buf, opt->image_sz - 4, secExtHdr->imgSign, "IMG SHA256:", 0 /*CSK*/); |
| if (0 != error) { |
| fprintf(stderr, "Failed to create boot image RSA signature, error %d\n", error); |
| goto header_error; |
| } |
| #if defined MV_MEMPOOL_STAT && defined NO_HEAP |
| |
| fprintf(stdout, "Boot Image signature creation\n"); |
| mpool_print_stat(); |
| mpool_reset_stat(); |
| #endif |
| error = verify_rsa_signature(opt->image_buf, opt->image_sz - 4, secExtHdr->imgSign, 0 /*CSK*/); |
| if (0 != error) { |
| fprintf(stderr, "Failed to verify boot image RSA signature, error %d\n", error); |
| goto header_error; |
| } |
| |
| #if defined MV_MEMPOOL_STAT && defined NO_HEAP |
| 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 using CSK */ |
| error = create_rsa_signature(tmpHeader, header_size, rsa_signature, "HDR SHA256:", 0 /*CSK*/); |
| if (0 != error) { |
| fprintf(stderr, "Failed to create header RSA signature, error %d\n", error); |
| goto header_error; |
| } |
| |
| #if defined MV_MEMPOOL_STAT && defined NO_HEAP |
| 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 */ |
| error = verify_rsa_signature(tmpHeader, header_size, rsa_signature, 0 /*CSK*/); |
| if (0 != error) { |
| fprintf(stderr, "Failed to verify header RSA signature, error %d\n", error); |
| goto header_error; |
| } |
| |
| #if defined MV_MEMPOOL_STAT && defined NO_HEAP |
| 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((void*)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 |
| * create image in bootrom format and write it into output stream |
| * INPUT: |
| * opt user options |
| * buf_in mmapped input file |
| * OUTPUT: |
| * none |
| * RETURN: |
| * 0 on success |
| *******************************************************************************/ |
| 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 |
| * create image in hex format and write it into output stream |
| * INPUT: |
| * opt user options |
| * buf_in mmapped input file |
| * OUTPUT: |
| * none |
| * RETURN: |
| * 0 on success |
| *******************************************************************************/ |
| 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 int *hex32 = NULL; |
| unsigned int tmp32; |
| unsigned int 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 = (unsigned int*)tmpImg; |
| |
| for (; hex_len > 0; hex_len -= 4) { |
| fprintf(f_desc[0],"%08X\n",*hex32++); |
| size_written += 4; |
| } |
| break; |
| |
| case 64: |
| hex32 = (unsigned int*)tmpImg; |
| |
| for (; hex_len > 0; hex_len -= 8) { |
| fprintf(f_desc[0],"%08X%08X\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 |
| * create image in binary format and write it into output stream |
| * INPUT: |
| * opt user options |
| * buf_in mmapped input file |
| * OUTPUT: |
| * none |
| * RETURN: |
| * 0 on success |
| *******************************************************************************/ |
| 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 |
| * create regular boot image and write it into output stream |
| * INPUT: |
| * opt user options |
| * buf_in mmapped input file |
| * OUTPUT: |
| * none |
| * RETURN: |
| * 0 on success |
| *******************************************************************************/ |
| 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/requested offset image alignment */ |
| MV_U8 *gap_buf; |
| |
| gap_buf = calloc(opt->img_gap, sizeof(MV_U8)); |
| if (gap_buf == NULL) { |
| fprintf(stderr, "Failed to allocate memory for header to image gap!\n"); |
| return 1; |
| } |
| size_written += write(f_out, gap_buf, opt->img_gap); |
| new_file_size += opt->img_gap ; |
| free(gap_buf); |
| } |
| |
| /* 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 %d " |
| "and written %d amount!\n", new_file_size, size_written); |
| return 1; |
| } |
| |
| return 0; |
| } /* end of build_other_img() */ |
| |
| /******************************************************************************* |
| * read_rsa_key |
| * read RSA private key from file |
| * INPUT: |
| * fname private key file name |
| * rsa RSA context |
| * kak Type of key to use (CSK or KAK) |
| * OUTPUT: |
| * rsa RSA context |
| * RETURN: |
| * 0 on success |
| *******************************************************************************/ |
| int read_rsa_key(char *fname, char kak) |
| { |
| FILE *f_prkey; |
| int ret; |
| rsa_context *rsaCont = &rsaCsk; |
| |
| if ((f_prkey = fopen(fname, "r")) == NULL) { |
| fprintf(stderr, "Error opening RSA private key file %s\n", fname); |
| return -1; |
| } |
| |
| if (kak != 0) |
| rsaCont = &rsa; |
| |
| rsa_init(rsaCont, RSA_PKCS_V15, 0, NULL, NULL); |
| |
| ret = mpi_read_file(&rsaCont->N , 16, f_prkey); |
| ret += mpi_read_file(&rsaCont->E , 16, f_prkey); |
| ret += mpi_read_file(&rsaCont->D , 16, f_prkey); |
| ret += mpi_read_file(&rsaCont->P , 16, f_prkey); |
| ret += mpi_read_file(&rsaCont->Q , 16, f_prkey); |
| ret += mpi_read_file(&rsaCont->DP, 16, f_prkey); |
| ret += mpi_read_file(&rsaCont->DQ, 16, f_prkey); |
| ret += mpi_read_file(&rsaCont->QP, 16, f_prkey); |
| |
| fclose(f_prkey); |
| |
| return ret; |
| } |
| |
| /******************************************************************************* |
| * generate_rsa_key |
| * generate RSA key pair and save new keys into text files |
| * INPUT: |
| * rsa RSA context |
| * kak Type of key to use (CSK or KAK) |
| * OUTPUT: |
| * rsa RSA context |
| * RETURN: |
| * 0 on success |
| *******************************************************************************/ |
| int generate_rsa_key(char kak) |
| { |
| int ret; |
| havege_state hs; |
| FILE *fpub = NULL; |
| FILE *fpriv = NULL; |
| rsa_context *rsaCont; |
| char fname[80]; |
| |
| havege_init(&hs); |
| |
| if (kak != 0) { |
| rsaCont = &rsa; |
| sprintf(fname, "rsa_pub_kak.txt"); |
| } else { |
| rsaCont = &rsaCsk; |
| sprintf(fname, "rsa_pub_csk.txt"); |
| } |
| |
| rsa_init(rsaCont, RSA_PKCS_V15, 0, havege_rand, &hs); |
| |
| if (rsa_gen_key(rsaCont, RSA_KEY_SIZE, RSA_EXPONENT) != 0) { |
| fprintf(stderr, "Failed to generate RSA key\n"); |
| return -1; |
| } |
| |
| fpub = fopen(fname, "w+"); |
| if (fpub == NULL) { |
| fprintf(stderr, "Could not open %s file for writing\n", fname); |
| return -1; |
| } |
| |
| ret = mpi_write_file("N = ", &rsaCont->N, 16, fpub); |
| ret += mpi_write_file("E = ", &rsaCont->E, 16, fpub); |
| fclose(fpub); |
| if (ret != 0) { |
| fprintf(stderr, "Failed to write into %s file!\n", fname); |
| return -1; |
| } |
| |
| if (kak != 0) |
| sprintf(fname, "rsa_priv_kak.txt"); |
| else |
| sprintf(fname, "rsa_priv_sck.txt"); |
| |
| fpriv = fopen(fname, "w+"); |
| if (fpriv == NULL) { |
| fprintf(stderr, "Could not open %s file for writing\n", fname); |
| return -1; |
| } |
| |
| ret = mpi_write_file("N = " , &rsaCont->N , 16, fpriv); |
| ret += mpi_write_file("E = " , &rsaCont->E , 16, fpriv); |
| ret += mpi_write_file("D = " , &rsaCont->D , 16, fpriv); |
| ret += mpi_write_file("P = " , &rsaCont->P , 16, fpriv); |
| ret += mpi_write_file("Q = " , &rsaCont->Q , 16, fpriv); |
| ret += mpi_write_file("DP = ", &rsaCont->DP, 16, fpriv); |
| ret += mpi_write_file("DQ = ", &rsaCont->DQ, 16, fpriv); |
| ret += mpi_write_file("QP = ", &rsaCont->QP, 16, fpriv); |
| if (ret != 0) |
| fprintf(stderr, "Failed to write into rsa_priv.txt file!\n"); |
| |
| return ret; |
| } |
| |
| /******************************************************************************* |
| * process_image |
| * handle input and output file options, read and verify RSA and AES keys. |
| * INPUT: |
| * opt user options |
| * OUTPUT: |
| * none |
| * RETURN: |
| * 0 on success |
| ******************************************************************************/ |
| int process_image(USER_OPTIONS *opt) |
| { |
| int i; |
| int override[2]; |
| char *buf_in = NULL; |
| int err = 0; |
| |
| /* 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; |
| /* ask for overwrite permissions */ |
| fprintf(stderr,"File '%s' already exist! Overwrite it (Y/n)?", |
| opt->fname_arr[i]); |
| c = getc(stdin); |
| if ((c == 'N')||(c == 'n')) { |
| printf("exit.. nothing done. \n"); |
| exit(0); |
| } else if ((c == 'Y')||(c == 'y')) { |
| /* additional read is needed for Enter key */ |
| c = getc(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 (bootrom) */ |
| 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 KAK RSA private key */ |
| if (opt->flags & Z_OPTION_MASK) { |
| /* KAK */ |
| if (strncmp(opt->fname_prkey, "@@", 2) != 0) { /* private key file supplied */ |
| if (read_rsa_key(opt->fname_prkey, 1) != 0) { |
| fprintf(stderr, "Cannot read KAK RSA private key file %s\n\n", opt->fname_prkey); |
| goto end; |
| } |
| } else { /* new key pair is required */ |
| DB("Generating new KAK RSA key pair..."); |
| if (generate_rsa_key(1) != 0) { |
| fprintf(stderr, "Cannot generate KAK RSA key pair\n\n"); |
| goto end; |
| } |
| DB("OK\n"); |
| } |
| |
| rsa.len = (mpi_msb(&rsa.N) + 7) >> 3; /* key lenght in bytes */ |
| |
| 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, "KAK RSA private key is %d bit long\n", rsa.len * 8); |
| |
| /*CSK*/ |
| /* secure boot support - read CSK RSA private key */ |
| if (strncmp(opt->fname_prkeyCsk, "@@", 2) != 0) { /* private key file supplied */ |
| if (read_rsa_key(opt->fname_prkeyCsk, 0) != 0) { |
| fprintf(stderr, "Cannot read CSK RSA private key file %s\n\n", opt->fname_prkey); |
| goto end; |
| } |
| } else { /* new key pair is required */ |
| DB("Generating new CSK RSA key pair..."); |
| if (generate_rsa_key(0) != 0) { |
| fprintf(stderr, "Cannot generate CSK RSA key pair\n\n"); |
| goto end; |
| } |
| DB("OK\n"); |
| } |
| |
| rsaCsk.len = (mpi_msb(&rsaCsk.N) + 7) >> 3; /* key lenght in bytes */ |
| |
| if (RSA_MAX_KEY_LEN_BYTES < rsaCsk.len) { |
| fprintf(stderr, "Wrong RSA key length - %d bytes!" |
| " Supported RSA keys up to %d bytes\n", |
| rsaCsk.len, RSA_MAX_KEY_LEN_BYTES); |
| goto end; |
| } else |
| fprintf(stdout, "CSK RSA private key is %d bit long\n", rsaCsk.len * 8); |
| } /* secure boot options */ |
| |
| /* Image Header(s) */ |
| 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; |
| } |
| } /* if (opt->header_mode != HDR_ONLY) */ |
| fprintf(stdout, "====>>>> %s was created\n", opt->fname_arr[IMG_FILE_INDX]); |
| |
| 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 |
| * print command switches and their description |
| * INPUT: |
| * none |
| * OUTPUT: |
| * none |
| * RETURN: |
| * none |
| *******************************************************************************/ |
| void print_usage(void) |
| { |
| printf("==============================================================================================\n\n"); |
| printf("Marvell doimage Tool version %s\n", VERSION_NUMBER); |
| printf("Supported SoC devices: \n\t%s\n", PRODUCT_SUPPORT); |
| printf("==============================================================================================\n\n"); |
| printf("Usage: \n"); |
| printf("doimage <mandatory_opt> [other_options] [bootrom_output] <image_in> <image_out> [header_out]\n\n"); |
| |
| printf("<mandatory_opt> - can be one or more of the following:\n"); |
| printf("==============================================================================================\n\n"); |
| |
| printf("-T image_type: sata\\uart\\flash\\bootrom\\nand\\hex\\bin\\pex\\mmc\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\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"); |
| printf("-----------------------------------------------------------------------------------------------\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 by Z switch:\n"); |
| printf("-----------------------------------------------------------------------------------------------\n\n"); |
| |
| printf("-Z [rsa_priv_kak_file]: Create image with RSA KAK block signature for secure boot mode\n"); |
| printf(" If the private key file name is \"@@\", a new key pair will be generated\n"); |
| printf(" and saved in files named rsa_priv_kak.key and rsa_pub_kak.key\n"); |
| printf(" A new file named sha2_pub_kak.txt will be generated for a public key\n"); |
| printf("-A [rsa_priv_csk_file]: Create image with RSA CSK signature for secure boot mode\n"); |
| printf(" If the private key file name is \"@@\", a new key pair will be generated\n"); |
| printf(" and saved in files named rsa_priv_csk.key and rsa_pub_sck.key\n"); |
| printf(" A new file named sha2_pub_csk.txt will be generated for a public key\n"); |
| printf("-K csk_index: CSK Array Index in range of 0 to 15\n"); |
| printf("-J jtag_delay: Enable JTAG and delay boot execution by \"jtag_delay\" 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 0xffffffff \n\n"); |
| |
| printf("\n[other_options] - optional and can be one or more of the following:\n"); |
| printf("==============================================================================================\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("-R dram_file: ascii file name that contains the list of dram regs\n"); |
| printf("-C hdrs_file: ascii file name that defines BIN/REG headers order and their sources\n"); |
| printf("-X pre_padding_size (hex)\n"); |
| printf("-Y post_padding_size (hex)\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("\n[bootrom_output] - optional and can be one or more of the following:\n"); |
| printf("==============================================================================================\n\n"); |
| |
| printf("-p Disable BootROM messages output to UART port (enabled by default)\n"); |
| printf("-b baudrate Set BootROM debug port UART baudrate \n"); |
| printf(" value = 2400,4800,9600,19200,38400,57600,115200 (use default baudrate is omitted)\n"); |
| printf("-u port_num Set BootROM debug port UART number value = 0-3 (use default port if omitted)\n"); |
| printf("-m mpp_config Select BootROM debug port MPPs configuration value = 0-7 (BootROM-specific)\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"); |
| |
| } /* end of print_usage() */ |
| |
| |
| /******************************************************************************* |
| * checksum8 |
| * calculate 8-bit checksum of memory buffer |
| * INPUT: |
| * start buffer start |
| * len buffer length |
| * csum initial checksum value |
| * OUTPUT: |
| * none |
| * RETURN: |
| * 8-bit buffer checksum |
| *******************************************************************************/ |
| MV_U8 checksum8(void* start, MV_U32 len, MV_U8 csum) |
| { |
| register MV_U8 sum = csum; |
| volatile MV_U8* startp = (volatile MV_U8*)start; |
| |
| do { |
| sum += *(MV_U8*)startp; |
| startp++; |
| |
| } while(--len); |
| |
| return (sum); |
| |
| } /* end of checksum8 */ |
| |
| /******************************************************************************* |
| * checksum32 |
| * calculate 32-bit checksum of memory buffer |
| * INPUT: |
| * start buffer start |
| * len buffer length |
| * csum initial checksum value |
| * OUTPUT: |
| * none |
| * RETURN: |
| * 32-bit buffer checksum |
| *******************************************************************************/ |
| 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 |
| * init CRC table |
| * INPUT: |
| * crc_table CRC table location |
| * OUTPUT: |
| * crc_table CRC table location |
| * RETURN: |
| * none |
| *******************************************************************************/ |
| 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 |
| * calculate CRC32 on memory buffer |
| * INPUT: |
| * crc initial CRC value |
| * buf memory buffer |
| * len buffer length |
| * OUTPUT: |
| * none |
| * RETURN: |
| * CRC32 of the memory buffer |
| *******************************************************************************/ |
| 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 |
| * select image options by the image name |
| * INPUT: |
| * img_name image name |
| * OUTPUT: |
| * opt image options |
| * RETURN: |
| * 0 on success, 1 if image name is invalid |
| *******************************************************************************/ |
| 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 }, |
| { 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_MMC, "mmc", 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 < ARRAY_SIZE(img_map); 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:K:J:B:F:A:G:L:N:C:b:u:m:p"; |
| int i, k; |
| unsigned long secureOptions; |
| |
| 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; |
| DB("Image destination address %#x\n", options.image_dest); |
| 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; |
| DB("Image execution address %#x\n", options.image_exec); |
| 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; |
| DB("Pre-pad image by %#x bytes\n", options.prepadding_size); |
| 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; |
| DB("Post-pad image by %#x bytes\n", options.postpadding_size); |
| 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; |
| DB("Image start sector (image source) %#x\n", options.image_source); |
| 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; |
| DB("NAND page size %d bytes\n", options.nandPageSize); |
| break; |
| |
| case 'C': /* headers definition filename */ |
| options.fname_list = optarg; |
| if (options.flags & C_OPTION_MASK) |
| goto parse_error; |
| options.flags |= C_OPTION_MASK; |
| DB("Headers definition file name %s\n", options.fname_list); |
| 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; |
| DB("HEX file width %d bytes\n", options.hex_width); |
| 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; |
| DB("Header file mode is %d\n", options.header_mode); |
| break; |
| |
| case 'R': /* dram file */ |
| options.fname_dram = optarg; |
| if (options.flags & R_OPTION_MASK) |
| goto parse_error; |
| options.flags |= R_OPTION_MASK; |
| DB("Registers header file name %s\n", options.fname_dram); |
| break; |
| |
| case 'M': /* TWSI file */ |
| options.fname_twsi = optarg; |
| if (options.flags & M_OPTION_MASK) |
| goto parse_error; |
| options.flags |= M_OPTION_MASK; |
| DB("TWSI header file name %s\n", options.fname_twsi); |
| break; |
| |
| case 'G': /* binary file */ |
| options.fname_bin = optarg; |
| if (options.flags & G_OPTION_MASK) |
| goto parse_error; |
| options.flags |= G_OPTION_MASK; |
| DB("Binary header file name %s\n", options.fname_bin); |
| 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; |
| DB("KAK RSA private Key file name %s\n", options.fname_prkey); |
| 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; |
| DB("JTAG delay %d ms\n", options.jtagDelay); |
| 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; |
| DB("Box ID %#x\n", options.boxId); |
| 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; |
| DB("Flash ID %#x\n", options.flashId); |
| break; |
| |
| case 'A': /* secure boot - CSK key */ |
| options.fname_prkeyCsk = optarg; |
| options.flags |= A_OPTION_MASK; |
| DB("CSK RSA private Key file name %s\n", options.fname_prkeyCsk); |
| break; |
| |
| case 'K': /* secure boot - CSK Array Index*/ |
| options.csk_index = strtoul(optarg, &endptr, 10); |
| options.flags |= K_OPTION_MASK; |
| DB("CSK Array Index %d\n", options.csk_index); |
| 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; |
| DB("NAND block size %d\n", options.nandBlkSize); |
| break; |
| |
| case 'N': /* NAND cell technology */ |
| options.nandCellTech = optarg[0]; |
| if (options.flags & N_OPTION_MASK) |
| goto parse_error; |
| options.flags |= N_OPTION_MASK; |
| DB("NAND cell technology %c\n", options.nandCellTech); |
| break; |
| |
| case 'p': /* BootROM debug output */ |
| if (options.flags & p_OPTION_MASK) |
| goto parse_error; |
| options.flags |= p_OPTION_MASK; |
| DB("BootROM debug output disabled\n"); |
| break; |
| |
| case 'b': /* BootROM debug port baudrate */ |
| options.baudRate = strtoul(optarg, &endptr, 10); |
| if (*endptr || (options.flags & b_OPTION_MASK)) |
| goto parse_error; |
| options.flags |= b_OPTION_MASK; |
| DB("BootROM debug port baudrate %d\n", options.baudRate); |
| break; |
| |
| case 'u': /* BootROM debug port number */ |
| options.debugPortNum = strtoul(optarg, &endptr, 10); |
| if (*endptr || (options.flags & u_OPTION_MASK)) |
| goto parse_error; |
| options.flags |= u_OPTION_MASK; |
| DB("BootROM debug port number %d\n", options.debugPortNum); |
| break; |
| |
| case 'm': /* BootROM debug port MPP settings */ |
| options.debugPortMpp = strtoul(optarg, &endptr, 10); |
| if (*endptr || (options.flags & m_OPTION_MASK)) |
| goto parse_error; |
| options.flags |= m_OPTION_MASK; |
| DB("BootROM debug port MPP setup # %d\n", options.debugPortMpp); |
| break; |
| |
| default: |
| goto parse_error; |
| } |
| } /* parse command-line options */ |
| |
| /* assign file names */ |
| for (i = 0; (optind < argc) && (i < ARRAY_SIZE(options.fname_arr)); ++optind, i++) { |
| options.fname_arr[i] = argv[optind]; |
| DB("File @ array index %d is %s (option index is %d)\n", i, argv[optind], 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; |
| |
| /* verify HEX/BIN 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; |
| /* BootROM test images, no header is needed */ |
| 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 & 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; |
| } |
| |
| secureOptions = A_OPTION_MASK | Z_OPTION_MASK | K_OPTION_MASK | |
| B_OPTION_MASK | F_OPTION_MASK; |
| if (options.flags & secureOptions) { |
| if ((options.flags & secureOptions) != secureOptions) { |
| fprintf(stderr,"Error: All secure options are mandatory!\n\n\n\n\n"); |
| goto parse_error; |
| } |
| if((options.csk_index < 0) || (options.csk_index > 16)) { |
| fprintf(stderr,"Error: Bad CSK Array Index - %d!\n\n\n\n\n", options.csk_index); |
| goto parse_error; |
| } |
| } |
| |
| return process_image(&options); |
| |
| parse_error: |
| |
| print_usage(); |
| exit(1); |
| |
| } /* end of main() */ |
| |