| /****************************************************************************** |
| * Copyright (c) 2004, 2008 IBM Corporation |
| * All rights reserved. |
| * This program and the accompanying materials |
| * are made available under the terms of the BSD License |
| * which accompanies this distribution, and is available at |
| * http://www.opensource.org/licenses/bsd-license.php |
| * |
| * Contributors: |
| * IBM Corporation - initial implementation |
| *****************************************************************************/ |
| |
| #include <assert.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| #include <cfgparse.h> |
| #include <time.h> |
| #include <calculatecrc.h> |
| #include <product.h> |
| #include "createcrc.h" |
| #include "crclib.h" |
| |
| /* file length in bytes */ |
| static uint64_t ui64globalFileSize = 0; |
| /* space for the file stream >= 4MB + 4bytes */ |
| static unsigned char pucFileStream[4400000]; |
| /* header length in bytes */ |
| static uint64_t ui64globalHeaderSize = 0; |
| /* flag to filter detect the header in buildDataStream() */ |
| static int iglobalHeaderFlag = 1; |
| |
| static size_t min(size_t a, size_t b) |
| { |
| return a < b ? a : b; |
| } |
| |
| /** |
| * Build the file image and store it as Data Stream of bytes |
| * calculate a first CRC for the first file and |
| * catch the position of this CRC |
| */ |
| int |
| buildDataStream(unsigned char *pucbuf, int size) |
| { |
| if (ui64globalFileSize + size > sizeof(pucFileStream)) { |
| printf("Error: File size is too big!\n"); |
| return -1; |
| } |
| |
| /* copy the data into the destination buffer */ |
| memcpy(pucFileStream + ui64globalFileSize, pucbuf, size); |
| ui64globalFileSize += size; |
| |
| if (iglobalHeaderFlag == 1) { // catch header |
| |
| ui64globalHeaderSize = ui64globalFileSize; |
| iglobalHeaderFlag = 0; |
| } |
| |
| return 0; |
| } |
| |
| /** |
| * write Header.img |
| */ |
| int |
| createHeaderImage(int notime) |
| { |
| int iCounter; |
| uint64_t ui64RomAddr, ui64DataAddr; |
| time_t caltime; |
| struct tm *tm; |
| char *pcVersion; |
| char dastr[16] = { 0, }; |
| unsigned long long da = 0; |
| |
| struct stH stHeader = { |
| .magic = FLASHFS_MAGIC, |
| .platform_name = FLASHFS_PLATFORM_MAGIC, |
| .platform_revision = FLASHFS_PLATFORM_REVISION, |
| .ui64FileEnd = -1, |
| }; |
| |
| /* read driver info */ |
| pcVersion = getenv("DRIVER_NAME"); |
| if (!pcVersion) |
| pcVersion = getenv("USER"); |
| if (!pcVersion) |
| pcVersion = "unknown"; |
| memcpy(stHeader.version, pcVersion, |
| min(strlen(pcVersion), sizeof(stHeader.version))); |
| |
| if (!notime) { |
| /* read time and write it into data stream */ |
| if ((caltime = time(NULL)) == -1) { |
| printf("time error\n"); |
| } |
| if ((tm = localtime(&caltime)) == NULL) { |
| printf("local time error\n"); |
| } |
| // length must be 13 instead 12 because of terminating |
| // NUL. Therefore uH.stH.platform_revison must be |
| // written later to overwrite the terminating NUL |
| if (strftime(dastr, 15, "0x%Y%m%d%H%M", tm) == 0) { |
| printf("strftime error\n"); |
| } |
| da = cpu_to_be64(strtoll(dastr, NULL, 16)); |
| } |
| memcpy(stHeader.date, &da, 8); |
| |
| /* read address of next file and address of header date, both are 64 bit values */ |
| ui64RomAddr = 0; |
| ui64DataAddr = 0; |
| for (iCounter = 0; iCounter < 8; iCounter++) { |
| /* addr of next file */ |
| ui64RomAddr = (ui64RomAddr << 8) + pucFileStream[FLASHFS_ROMADDR + iCounter]; |
| /* addr of header data */ |
| ui64DataAddr = (ui64DataAddr << 8) + pucFileStream[FLASHFS_DATADDR + iCounter]; |
| } |
| |
| /* calculate final flash-header-size and flash-file-size */ |
| /* calculate end addr of header */ |
| ui64globalHeaderSize = (uint32_t) ui64DataAddr + sizeof(stHeader); |
| /* cut 64 bit to place CRC for File-End */ |
| ui64globalHeaderSize -= 8; |
| /* add 64 bit to place CRC behind File-End */ |
| ui64globalFileSize += 8; |
| |
| if (ui64globalHeaderSize >= ui64RomAddr) { |
| printf("%s\n", "--- Header File to long"); |
| return 1; |
| } |
| |
| /* fill free space in Header with zeros */ |
| memset(&pucFileStream[ui64DataAddr], 0, (ui64RomAddr - ui64DataAddr)); |
| /* place data to header */ |
| memcpy(&pucFileStream[ui64DataAddr], &stHeader, sizeof(stHeader)); |
| |
| /* insert header length into data stream */ |
| *(uint64_t *) (pucFileStream + FLASHFS_HEADER_SIZE_ADDR) = |
| cpu_to_be64(ui64globalHeaderSize); |
| |
| /* insert flash length into data stream */ |
| *(uint64_t *) (pucFileStream + ui64DataAddr + FLASHFS_FILE_SIZE_ADDR) = |
| cpu_to_be64(ui64globalFileSize); |
| |
| /* insert zeros as placeholder for CRC */ |
| *(uint64_t *) (pucFileStream + ui64globalHeaderSize - 8) = 0; |
| *(uint64_t *) (pucFileStream + ui64globalFileSize - 8) = 0; |
| |
| return 0; |
| } |
| |
| /** |
| * insert header and file CRC into data stream |
| * do CRC check on header and file |
| * write data stream to disk |
| */ |
| int |
| writeDataStream(int iofd, int notime) |
| { |
| uint64_t ui64FileCRC = 0, ui64HeaderCRC = 0, ui64RegisterMask; |
| unsigned int uiRegisterLength; |
| |
| if (0 != createHeaderImage(notime)) { |
| return 1; |
| } |
| |
| createCRCParameter(&ui64RegisterMask, &uiRegisterLength); |
| |
| /* calculate CRC */ |
| ui64HeaderCRC = checkCRC(pucFileStream, ui64globalHeaderSize, 0); |
| *(uint64_t *) (pucFileStream + ui64globalHeaderSize - 8) = |
| cpu_to_be64(ui64HeaderCRC); |
| |
| ui64FileCRC = checkCRC(pucFileStream, ui64globalFileSize, 0); |
| *(uint64_t *) (pucFileStream + ui64globalFileSize - 8) = |
| cpu_to_be64(ui64FileCRC); |
| |
| /* check CRC-implementation */ |
| ui64HeaderCRC = calCRCword(pucFileStream, ui64globalHeaderSize, 0); |
| ui64FileCRC = calCRCword(pucFileStream, ui64globalFileSize, 0); |
| |
| if ((ui64HeaderCRC != 0) || (ui64FileCRC != 0)) { |
| printf("\n\n %s \n %s \n\n", "CRCs not correct implemented.", |
| " ---> Data will not be written do disk."); |
| return -1; |
| } |
| |
| /* write file image to disk */ |
| if (0 < write(iofd, pucFileStream, ui64globalFileSize)) |
| return 0; |
| |
| printf("<< write failed >>\n"); |
| return -1; |
| } |