1 /******************************************************************************
2 * Copyright (c) 2004, 2008 IBM Corporation
4 * This program and the accompanying materials
5 * are made available under the terms of the BSD License
6 * which accompanies this distribution, and is available at
7 * http://www.opensource.org/licenses/bsd-license.php
10 * IBM Corporation - initial implementation
11 *****************************************************************************/
17 #include <sys/types.h>
19 #include <netinet/in.h>
25 #include <calculatecrc.h>
27 #include "createcrc.h"
29 int createHeaderImage(int);
30 unsigned int calCRCEthernet32(unsigned char *TextPtr,
31 unsigned long int TextLength,
32 unsigned int AccumCRC);
33 int createCRCParameter(uint64_t * ui64RegisterMask,
34 unsigned int *iRegisterLength);
35 uint64_t calCRCbyte(unsigned char *TextPtr, uint32_t Residual,
37 uint64_t calCRCword(unsigned char *TextPtr, uint32_t Residual,
39 uint64_t checkCRC(unsigned char *TextPtr, uint32_t Residual, uint64_t AccumCRC);
41 /* file length in bytes */
42 static uint64_t ui64globalFileSize = 0;
43 /* space for the file stream >= 4MB + 4bytes */
44 static unsigned char pucFileStream[4400000];
45 /* header length in bytes */
46 static uint64_t ui64globalHeaderSize = 0;
47 /* flag to filter detect the header in buildDataStream() */
48 static int iglobalHeaderFlag = 1;
49 static uint64_t ui64Generator1;
52 * Build the file image and store it as Data Stream of bytes
53 * calculate a first CRC for the first file and
54 * catch the position of this CRC
57 buildDataStream(unsigned char *pucbuf, int size)
59 if (ui64globalFileSize + size > sizeof(pucFileStream)) {
60 printf("Error: File size is too big!\n");
64 /* copy the data into the destination buffer */
65 memcpy(pucFileStream + ui64globalFileSize, pucbuf, size);
66 ui64globalFileSize += size;
68 if (iglobalHeaderFlag == 1) { // catch header
70 ui64globalHeaderSize = ui64globalFileSize;
71 iglobalHeaderFlag = 0;
81 createHeaderImage(int notime)
84 uint64_t ui64RomAddr, ui64DataAddr;
88 char dastr[16] = { 0, };
89 unsigned long long da = 0;
92 unsigned char pcArray[FLASHFS_HEADER_DATA_SIZE];
96 /* initialize Header */
97 memset(uHeader.pcArray, 0x00, FLASHFS_HEADER_DATA_SIZE);
99 /* read driver info */
100 if (NULL != (pcVersion = getenv("DRIVER_NAME"))) {
101 strncpy(uHeader.stHeader.version, pcVersion, 16);
102 } else if (NULL != (pcVersion = getenv("USER"))) {
103 strncpy(uHeader.stHeader.version, pcVersion, 16);
104 } else if (pcVersion == NULL) {
105 strncpy(uHeader.stHeader.version, "No known user!", 16);
109 /* read time and write it into data stream */
110 if ((caltime = time(NULL)) == -1) {
111 printf("time error\n");
113 if ((tm = localtime(&caltime)) == NULL) {
114 printf("local time error\n");
116 // length must be 13 instead 12 because of terminating
117 // NUL. Therefore uH.stH.platform_revison must be
118 // written later to overwrite the terminating NUL
119 if (strftime(dastr, 15, "0x%Y%m%d%H%M", tm) == 0) {
120 printf("strftime error\n");
122 da = cpu_to_be64(strtoll(dastr, NULL, 16));
124 memcpy(uHeader.stHeader.date, &da, 8);
126 /* write Magic value into data stream */
127 strncpy(uHeader.stHeader.magic, FLASHFS_MAGIC, 8);
128 /* write platform name into data stream */
129 strcpy(uHeader.stHeader.platform_name, FLASHFS_PLATFORM_MAGIC);
130 /* write platform revision into data stream */
131 strcpy(uHeader.stHeader.platform_revision, FLASHFS_PLATFORM_REVISION);
134 /* fill end of file info (8 bytes of FF) into data stream */
135 uHeader.stHeader.ui64FileEnd = -1;
137 /* read address of next file and address of header date, both are 64 bit values */
140 for (iCounter = 0; iCounter < 8; iCounter++) {
141 /* addr of next file */
142 ui64RomAddr = (ui64RomAddr << 8) + pucFileStream[FLASHFS_ROMADDR + iCounter];
143 /* addr of header data */
144 ui64DataAddr = (ui64DataAddr << 8) + pucFileStream[FLASHFS_DATADDR + iCounter];
147 /* calculate final flash-header-size and flash-file-size */
148 /* calculate end addr of header */
149 ui64globalHeaderSize = (uint32_t) ui64DataAddr + (uint32_t) FLASHFS_HEADER_DATA_SIZE;
150 /* cut 64 bit to place CRC for File-End */
151 ui64globalHeaderSize -= 8;
152 /* add 64 bit to place CRC behind File-End */
153 ui64globalFileSize += 8;
155 if (ui64globalHeaderSize >= ui64RomAddr) {
156 printf("%s\n", "--- Header File to long");
160 /* fill free space in Header with zeros */
161 memset(&pucFileStream[ui64DataAddr], 0, (ui64RomAddr - ui64DataAddr));
162 /* place data to header */
163 memcpy(&pucFileStream[ui64DataAddr], uHeader.pcArray,
164 FLASHFS_HEADER_DATA_SIZE);
166 /* insert header length into data stream */
167 *(uint64_t *) (pucFileStream + FLASHFS_HEADER_SIZE_ADDR) =
168 cpu_to_be64(ui64globalHeaderSize);
170 /* insert flash length into data stream */
171 *(uint64_t *) (pucFileStream + ui64DataAddr + FLASHFS_FILE_SIZE_ADDR) =
172 cpu_to_be64(ui64globalFileSize);
174 /* insert zeros as placeholder for CRC */
175 *(uint64_t *) (pucFileStream + ui64globalHeaderSize - 8) = 0;
176 *(uint64_t *) (pucFileStream + ui64globalFileSize - 8) = 0;
182 * calculate standart ethernet 32 bit CRC
183 * generator polynome is 0x104C11DB7
184 * this algorithm can be used for encoding and decoding
187 calCRCEthernet32(unsigned char *TextPtr, unsigned long int TextLength,
188 unsigned int AccumCRC)
190 const unsigned int CrcTableHigh[16] = {
191 0x00000000, 0x4C11DB70, 0x9823B6E0, 0xD4326D90,
192 0x34867077, 0x7897AB07, 0xACA5C697, 0xE0B41DE7,
193 0x690CE0EE, 0x251D3B9E, 0xF12F560E, 0xBD3E8D7E,
194 0x5D8A9099, 0x119B4BE9, 0xC5A92679, 0x89B8FD09
196 const unsigned CrcTableLow[16] = {
197 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,
198 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
199 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
200 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD
203 unsigned char *Buffer = TextPtr;
204 unsigned long int Residual = TextLength;
207 while (Residual > 0) {
208 unsigned int Temp = ((AccumCRC >> 24) ^ *Buffer) & 0x000000ff;
210 AccumCRC ^= CrcTableHigh[Temp / 16];
211 AccumCRC ^= CrcTableLow[Temp % 16];
219 * create CRC Parameter: CRC Polynome, Shiftregister Mask and length
221 * ui64Generator[0] = 0;
222 * ui64Generator[1] = 0x42F0E1EB;
223 * ui64Generator[1] = (ui64Generator[1] << 32) + 0xA9EA3693;
224 * iRegisterLength = 63;
225 * ui64RegisterMask = 0xffffffff;
226 * ui64RegisterMask = ((ui64RegisterMask) << 32) + 0xffffffff;
228 * ucl=0x00000000ffffffff = Mask for 32 bit LSFR to cut down number of bits
229 * in the variable to get the same length as LFSR
231 * il = length of LSFR = degree of generator polynom reduce il by one to calculate the degree
232 * of the highest register in LSFR
235 * CRC-16 for Tap: x16 + x15 + x2 + 1
236 * generator = 0x8005, il = 16, ucl = 0x000000000000FFFF
238 * CRC-16 for Floppy: x16 + x12 + x5 +1
239 * generator = 0x1021, il = 16, ucl = 0x000000000000FFFF
241 * CRC-32 for Ethernet: x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1
242 * generator = 0x04C11DB7, il = 32, ucl = 0x00000000FFFFFFFF
244 * CRC-64 SP-TrEMBL x64 + x4 + x3 + x + 1 (maximal-length LFSR)
245 * generator = 0x1B, il = 64, ucl = 0xFFFFFFFFFFFFFFFF
248 * x64 + x63 + x61 + x59 + x58 + x56 + x55 + x52 + x49 + x48 + x47 + x46+ x44 +
249 * x41 + x37 + x36 + x34 + x32 + x31 + x28 + x26 + x23 + x22 + x19 + x16 + x13 +
250 * x12 + x10 + x9 + x6 + x4 + x3 + 1
251 * (see http://www.cs.ud.ac.uk/staff/D.Jones/crcbote.pdf)
252 * generator = 0xAD93D23594C9362D, il = 64, ucl = 0xFFFFFFFFFFFFFFFF
255 * x64 + x62 + x57 + x55 + x54 + x53 + x52 + x47 + x46 + x45 + x40 + x39 + x38 + x37 +
256 * x35 + x33 + x32 + x31 + x29 + x27 + x24 + x23 + x22 + x21 + x19 + x17 + x13 + x12 +
257 * x10 + x9 + x7 + x4 + x + 1
258 * (see http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-182.pdf -> page63)
259 * generator = 0x42F0E1EBA9EA3693
261 * CRC-64 from internet G(x)= 1006003C000F0D50B
264 createCRCParameter(uint64_t * ui64RegisterMask, unsigned int *uiRegisterLength)
266 enum Generators { Tape_16, Floppy_16, Ethernet_32, SPTrEMBL_64,
267 SPTrEMBL_improved_64, DLT1_64
269 enum Generators Generator;
271 Generator = CRC_METHODE;
274 *ui64RegisterMask = 0x0000ffff;
275 ui64Generator1 = 0x00008005;
276 *uiRegisterLength = 16;
280 *ui64RegisterMask = 0x0000ffff;
281 ui64Generator1 = 0x00001021;
282 *uiRegisterLength = 16;
286 *ui64RegisterMask = 0xffffffff;
287 ui64Generator1 = 0x04C11DB7;
288 *uiRegisterLength = 32;
292 *ui64RegisterMask = 0xffffffff;
294 ((*ui64RegisterMask) << 32) + 0xffffffff;
295 ui64Generator1 = 0x0000001B;
296 *uiRegisterLength = 64;
299 case SPTrEMBL_improved_64:{
300 *ui64RegisterMask = 0xffffffff;
302 ((*ui64RegisterMask) << 32) + 0xffffffff;
303 ui64Generator1 = 0xAD93D235;
304 ui64Generator1 = (ui64Generator1 << 32) + 0x94C9362D;
305 *uiRegisterLength = 64;
309 *ui64RegisterMask = 0xffffffff;
311 ((*ui64RegisterMask) << 32) + 0xffffffff;
312 ui64Generator1 = 0x42F0E1EB;
313 ui64Generator1 = (ui64Generator1 << 32) + 0xA9EA3693;
314 *uiRegisterLength = 64;
318 (*uiRegisterLength)--;
324 * Check CRC by using Linear Feadback Shift Register (LFSR)
327 calCRCbyte(unsigned char *cPtr, uint32_t ui32NoWords, uint64_t AccumCRC)
330 uint64_t ui64Mask, ui64Generator0;
332 unsigned int uiRegisterLength;
335 createCRCParameter(&ui64Mask, &uiRegisterLength);
338 while (ui32NoWords > 0) {
339 for (iShift = 7; iShift >= 0; iShift--) {
341 ui64Generator0 = (AccumCRC >> uiRegisterLength);
343 ui64Generator0 &= 0x01;
344 ui64Generator0 = (0 - ui64Generator0);
345 AccumCRC ^= (ui64Generator1 & ui64Generator0);
347 AccumCRC ^= ui8Buffer;
348 AccumCRC &= ui64Mask;
357 * Check CRC by using Linear Feadback Shift Register (LFSR)
360 calCRCword(unsigned char *cPtr, uint32_t ui32NoWords, uint64_t AccumCRC)
363 uint64_t ui64Mask, ui64Generator0;
365 unsigned int uiRegisterLength;
368 createCRCParameter(&ui64Mask, &uiRegisterLength);
370 if ((ui32NoWords % 2) != 0) {
371 /* if Data string does not end at word boundery add one byte */
373 cPtr[ui32NoWords] = 0;
375 ui16Buffer = ((*(cPtr + 0)) * 256) + (*(cPtr + 1));
376 while (ui32NoWords > 0) {
377 for (iShift = 15; iShift >= 0; iShift--) {
378 ui64Generator0 = (AccumCRC >> uiRegisterLength);
380 ui64Generator0 &= 0x01;
381 ui64Generator0 = (0 - ui64Generator0);
382 AccumCRC ^= (ui64Generator1 & ui64Generator0);
384 AccumCRC ^= ui16Buffer;
385 AccumCRC &= ui64Mask;
388 ui16Buffer = ((*(cPtr + 0)) * 256) + (*(cPtr + 1));
394 checkCRC(unsigned char *cPtr, uint32_t ui32NoWords, uint64_t AccumCRC)
397 enum Generators { Ethernet_32 };
398 enum Generators Generator;
399 uint64_t ui64Buffer = AccumCRC;
401 Generator = CRC_METHODE;
405 /* (ui32NoWords - 4),no need of 4 bytes 0x as
406 * with shift-register method */
408 calCRCEthernet32(cPtr, (ui32NoWords - 4), AccumCRC);
412 AccumCRC = calCRCword(cPtr, ui32NoWords, AccumCRC);
417 if (calCRCbyte(cPtr, ui32NoWords, ui64Buffer) != AccumCRC) {
418 printf("\n --- big Endian - small Endian problem --- \n");
426 * insert header and file CRC into data stream
427 * do CRC check on header and file
428 * write data stream to disk
431 writeDataStream(int iofd, int notime)
433 uint64_t ui64FileCRC = 0, ui64HeaderCRC = 0, ui64RegisterMask;
434 unsigned int uiRegisterLength;
436 if (0 != createHeaderImage(notime)) {
440 createCRCParameter(&ui64RegisterMask, &uiRegisterLength);
443 ui64HeaderCRC = checkCRC(pucFileStream, ui64globalHeaderSize, 0);
444 *(uint64_t *) (pucFileStream + ui64globalHeaderSize - 8) =
445 cpu_to_be64(ui64HeaderCRC);
447 ui64FileCRC = checkCRC(pucFileStream, ui64globalFileSize, 0);
448 *(uint64_t *) (pucFileStream + ui64globalFileSize - 8) =
449 cpu_to_be64(ui64FileCRC);
451 /* check CRC-implementation */
452 ui64HeaderCRC = calCRCword(pucFileStream, ui64globalHeaderSize, 0);
453 ui64FileCRC = calCRCword(pucFileStream, ui64globalFileSize, 0);
455 if ((ui64HeaderCRC != 0) || (ui64FileCRC != 0)) {
456 printf("\n\n %s \n %s \n\n", "CRCs not correct implemented.",
457 " ---> Data will not be written do disk.");
461 /* write file image to disk */
462 if (0 < write(iofd, pucFileStream, ui64globalFileSize))
465 printf("<< write failed >>\n");