Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / romfs / tools / create_crc.c
1 /******************************************************************************
2  * Copyright (c) 2004, 2008 IBM Corporation
3  * All rights reserved.
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
8  *
9  * Contributors:
10  *     IBM Corporation - initial implementation
11  *****************************************************************************/
12
13 #include <stdint.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <netinet/in.h>
20 #include <fcntl.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <cfgparse.h>
24 #include <time.h>
25 #include <calculatecrc.h>
26 #include <product.h>
27 #include "createcrc.h"
28
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,
36                     uint64_t AccumCRC);
37 uint64_t calCRCword(unsigned char *TextPtr, uint32_t Residual,
38                     uint64_t AccumCRC);
39 uint64_t checkCRC(unsigned char *TextPtr, uint32_t Residual, uint64_t AccumCRC);
40
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;
50
51 /**
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
55  */
56 int
57 buildDataStream(unsigned char *pucbuf, int size)
58 {
59         if (ui64globalFileSize + size > sizeof(pucFileStream)) {
60                 printf("Error: File size is too big!\n");
61                 return -1;
62         }
63
64         /* copy the data into the destination buffer */
65         memcpy(pucFileStream + ui64globalFileSize, pucbuf, size);
66         ui64globalFileSize += size;
67
68         if (iglobalHeaderFlag == 1) {   // catch header
69
70                 ui64globalHeaderSize = ui64globalFileSize;
71                 iglobalHeaderFlag = 0;
72         }
73
74         return 0;
75 }
76
77 /**
78  * write Header.img
79  */
80 int
81 createHeaderImage(int notime)
82 {
83         int iCounter;
84         uint64_t ui64RomAddr, ui64DataAddr;
85         time_t caltime;
86         struct tm *tm;
87         char *pcVersion;
88         char dastr[16] = { 0, };
89         unsigned long long da = 0;
90
91         union {
92                 unsigned char pcArray[FLASHFS_HEADER_DATA_SIZE];
93                 struct stH stHeader;
94         } uHeader;
95
96         /* initialize Header */
97         memset(uHeader.pcArray, 0x00, FLASHFS_HEADER_DATA_SIZE);
98
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);
106         }
107
108         if (!notime) {
109                 /* read time and write it into data stream */
110                 if ((caltime = time(NULL)) == -1) {
111                         printf("time error\n");
112                 }
113                 if ((tm = localtime(&caltime)) == NULL) {
114                         printf("local time error\n");
115                 }
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");
121                 }
122                 da = cpu_to_be64(strtoll(dastr, NULL, 16));
123         }
124         memcpy(uHeader.stHeader.date, &da, 8);
125
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);
132
133
134         /* fill end of file info (8 bytes of FF) into data stream */
135         uHeader.stHeader.ui64FileEnd = -1;
136
137         /* read address of next file and address of header date, both are 64 bit values */
138         ui64RomAddr = 0;
139         ui64DataAddr = 0;
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];
145         }
146
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;
154
155         if (ui64globalHeaderSize >= ui64RomAddr) {
156                 printf("%s\n", "--- Header File to long");
157                 return 1;
158         }
159
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);
165
166         /* insert header length into data stream */
167         *(uint64_t *) (pucFileStream + FLASHFS_HEADER_SIZE_ADDR) =
168             cpu_to_be64(ui64globalHeaderSize);
169
170         /* insert flash length into data stream */
171         *(uint64_t *) (pucFileStream + ui64DataAddr + FLASHFS_FILE_SIZE_ADDR) =
172             cpu_to_be64(ui64globalFileSize);
173
174         /* insert zeros as placeholder for CRC */
175         *(uint64_t *) (pucFileStream + ui64globalHeaderSize - 8) = 0;
176         *(uint64_t *) (pucFileStream + ui64globalFileSize - 8) = 0;
177
178         return 0;
179 }
180
181 /**
182  * calculate standart ethernet 32 bit CRC
183  * generator polynome is 0x104C11DB7
184  * this algorithm can be used for encoding and decoding
185  */
186 unsigned int
187 calCRCEthernet32(unsigned char *TextPtr, unsigned long int TextLength,
188                  unsigned int AccumCRC)
189 {
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
195         };
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
201         };
202
203         unsigned char *Buffer = TextPtr;
204         unsigned long int Residual = TextLength;
205
206
207         while (Residual > 0) {
208                 unsigned int Temp = ((AccumCRC >> 24) ^ *Buffer) & 0x000000ff;
209                 AccumCRC <<= 8;
210                 AccumCRC ^= CrcTableHigh[Temp / 16];
211                 AccumCRC ^= CrcTableLow[Temp % 16];
212                 ++Buffer;
213                 --Residual;
214         }
215         return AccumCRC;
216 }
217
218 /**
219  * create CRC Parameter:  CRC Polynome, Shiftregister Mask and length
220  *
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;
227  *
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
230  *
231  *    il = length of LSFR = degree of generator polynom reduce il by one to calculate the degree
232  *    of the highest register in LSFR
233  *
234  *    Examples:
235  *    CRC-16 for Tap:           x16 + x15 + x2 + 1
236  *     generator = 0x8005,      il = 16,        ucl = 0x000000000000FFFF
237  *
238  *    CRC-16 for Floppy:                x16 + x12 + x5 +1
239  *     generator = 0x1021,      il = 16,        ucl = 0x000000000000FFFF
240  *
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
243  *
244  *    CRC-64 SP-TrEMBL  x64 + x4 + x3 + x + 1 (maximal-length LFSR)
245  *     generator = 0x1B,        il = 64,        ucl = 0xFFFFFFFFFFFFFFFF
246  *
247  *    CRC-64 improved
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
253  *
254  *    CRC-64 DLT1 spec
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
260  *
261  *    CRC-64 from internet G(x)= 1006003C000F0D50B
262  */
263 int
264 createCRCParameter(uint64_t * ui64RegisterMask, unsigned int *uiRegisterLength)
265 {
266         enum Generators { Tape_16, Floppy_16, Ethernet_32, SPTrEMBL_64,
267                 SPTrEMBL_improved_64, DLT1_64
268         };
269         enum Generators Generator;
270
271         Generator = CRC_METHODE;
272         switch (Generator) {
273         case Tape_16:{
274                         *ui64RegisterMask = 0x0000ffff;
275                         ui64Generator1 = 0x00008005;
276                         *uiRegisterLength = 16;
277                         break;
278                 }
279         case Floppy_16:{
280                         *ui64RegisterMask = 0x0000ffff;
281                         ui64Generator1 = 0x00001021;
282                         *uiRegisterLength = 16;
283                         break;
284                 }
285         case Ethernet_32:{
286                         *ui64RegisterMask = 0xffffffff;
287                         ui64Generator1 = 0x04C11DB7;
288                         *uiRegisterLength = 32;
289                         break;
290                 }
291         case SPTrEMBL_64:{
292                         *ui64RegisterMask = 0xffffffff;
293                         *ui64RegisterMask =
294                             ((*ui64RegisterMask) << 32) + 0xffffffff;
295                         ui64Generator1 = 0x0000001B;
296                         *uiRegisterLength = 64;
297                         break;
298                 }
299         case SPTrEMBL_improved_64:{
300                         *ui64RegisterMask = 0xffffffff;
301                         *ui64RegisterMask =
302                             ((*ui64RegisterMask) << 32) + 0xffffffff;
303                         ui64Generator1 = 0xAD93D235;
304                         ui64Generator1 = (ui64Generator1 << 32) + 0x94C9362D;
305                         *uiRegisterLength = 64;
306                         break;
307                 }
308         case DLT1_64:{
309                         *ui64RegisterMask = 0xffffffff;
310                         *ui64RegisterMask =
311                             ((*ui64RegisterMask) << 32) + 0xffffffff;
312                         ui64Generator1 = 0x42F0E1EB;
313                         ui64Generator1 = (ui64Generator1 << 32) + 0xA9EA3693;
314                         *uiRegisterLength = 64;
315                         break;
316                 }
317         }
318         (*uiRegisterLength)--;
319
320         return 0;
321 }
322
323 /**
324  *  Check CRC by using Linear Feadback Shift Register (LFSR)
325  */
326 uint64_t
327 calCRCbyte(unsigned char *cPtr, uint32_t ui32NoWords, uint64_t AccumCRC)
328 {
329
330         uint64_t ui64Mask, ui64Generator0;
331         uint8_t ui8Buffer;
332         unsigned int uiRegisterLength;
333         int iShift;
334
335         createCRCParameter(&ui64Mask, &uiRegisterLength);
336
337         ui8Buffer = (*cPtr);
338         while (ui32NoWords > 0) {
339                 for (iShift = 7; iShift >= 0; iShift--) {
340
341                         ui64Generator0 = (AccumCRC >> uiRegisterLength);
342                         AccumCRC <<= 1;
343                         ui64Generator0 &= 0x01;
344                         ui64Generator0 = (0 - ui64Generator0);
345                         AccumCRC ^= (ui64Generator1 & ui64Generator0);
346                 }
347                 AccumCRC ^= ui8Buffer;
348                 AccumCRC &= ui64Mask;
349                 ui32NoWords -= 1;
350                 cPtr += 1;
351                 ui8Buffer = (*cPtr);
352         }
353         return AccumCRC;
354 }
355
356 /**
357  *  Check CRC by using Linear Feadback Shift Register (LFSR)
358  */
359 uint64_t
360 calCRCword(unsigned char *cPtr, uint32_t ui32NoWords, uint64_t AccumCRC)
361 {
362
363         uint64_t ui64Mask, ui64Generator0;
364         uint16_t ui16Buffer;
365         unsigned int uiRegisterLength;
366         int iShift;
367
368         createCRCParameter(&ui64Mask, &uiRegisterLength);
369
370         if ((ui32NoWords % 2) != 0) {
371                 /* if Data string does not end at word boundery add one byte */
372                 ui32NoWords++;
373                 cPtr[ui32NoWords] = 0;
374         }
375         ui16Buffer = ((*(cPtr + 0)) * 256) + (*(cPtr + 1));
376         while (ui32NoWords > 0) {
377                 for (iShift = 15; iShift >= 0; iShift--) {
378                         ui64Generator0 = (AccumCRC >> uiRegisterLength);
379                         AccumCRC <<= 1;
380                         ui64Generator0 &= 0x01;
381                         ui64Generator0 = (0 - ui64Generator0);
382                         AccumCRC ^= (ui64Generator1 & ui64Generator0);
383                 }
384                 AccumCRC ^= ui16Buffer;
385                 AccumCRC &= ui64Mask;
386                 ui32NoWords -= 2;
387                 cPtr += 2;
388                 ui16Buffer = ((*(cPtr + 0)) * 256) + (*(cPtr + 1));
389         }
390         return AccumCRC;
391 }
392
393 uint64_t
394 checkCRC(unsigned char *cPtr, uint32_t ui32NoWords, uint64_t AccumCRC)
395 {
396
397         enum Generators { Ethernet_32 };
398         enum Generators Generator;
399         uint64_t ui64Buffer = AccumCRC;
400
401         Generator = CRC_METHODE;
402
403         switch (Generator) {
404         case Ethernet_32:{
405                         /* (ui32NoWords - 4),no need of 4 bytes 0x as
406                          * with shift-register method */
407                         AccumCRC =
408                             calCRCEthernet32(cPtr, (ui32NoWords - 4), AccumCRC);
409                         break;
410                 }
411         default:{
412                         AccumCRC = calCRCword(cPtr, ui32NoWords, AccumCRC);
413                         break;
414                 }
415         }
416
417         if (calCRCbyte(cPtr, ui32NoWords, ui64Buffer) != AccumCRC) {
418                 printf("\n --- big Endian - small Endian problem --- \n");
419                 AccumCRC--;
420         }
421
422         return (AccumCRC);
423 }
424
425 /**
426  *  insert header and file CRC into data stream
427  *  do CRC check on header and file
428  *  write data stream to disk
429  */
430 int
431 writeDataStream(int iofd, int notime)
432 {
433         uint64_t ui64FileCRC = 0, ui64HeaderCRC = 0, ui64RegisterMask;
434         unsigned int uiRegisterLength;
435
436         if (0 != createHeaderImage(notime)) {
437                 return 1;
438         }
439
440         createCRCParameter(&ui64RegisterMask, &uiRegisterLength);
441
442         /* calculate CRC */
443         ui64HeaderCRC = checkCRC(pucFileStream, ui64globalHeaderSize, 0);
444         *(uint64_t *) (pucFileStream + ui64globalHeaderSize - 8) =
445             cpu_to_be64(ui64HeaderCRC);
446
447         ui64FileCRC = checkCRC(pucFileStream, ui64globalFileSize, 0);
448         *(uint64_t *) (pucFileStream + ui64globalFileSize - 8) =
449             cpu_to_be64(ui64FileCRC);
450
451         /* check CRC-implementation */
452         ui64HeaderCRC = calCRCword(pucFileStream, ui64globalHeaderSize, 0);
453         ui64FileCRC = calCRCword(pucFileStream, ui64globalFileSize, 0);
454
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.");
458                 return -1;
459         }
460
461         /* write file image to disk */
462         if (0 < write(iofd, pucFileStream, ui64globalFileSize))
463                 return 0;
464
465         printf("<< write failed >>\n");
466         return -1;
467 }