ptgen: add Chromium OS kernel partition support
[project/firmware-utils.git] / src / srec2bin.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 #include <stdio.h>
3 #include <ctype.h>
4 #include <string.h>
5
6 //Rev 0.1 Original
7 // 8 Jan 2001 MJH Added code to write data to Binary file
8 // note: outputfile is name.bin, where name is first part
9 // of input file. ie tmp.rec -> tmp.bin
10 //
11 // srec2bin <input SREC file> <Output Binary File> <If Present, Big Endian>
12 //
13 // TAG
14 // bit32u TAG_BIG = 0xDEADBE42;
15 // bit32u TAG_LITTLE = 0xFEEDFA42;
16 //
17 // File Structure
18 //
19 // TAG : 32 Bits
20 // [DATA RECORDS]
21 //
22 // Data Records Structure
23 //
24 // LENGTH : 32 Bits <- Length of DATA, excludes ADDRESS and CHECKSUM
25 // ADDRESS : 32 Bits
26 // DATA : 8 Bits * LENGTH
27 // CHECKSUM: 32 Bits <- 0 - (Sum of Length --> End of Data)
28 //
29 // Note : If Length == 0, Address will be Program Start
30 //
31 //
32 //
33 //
34 //
35
36 #define MajRevNum 0
37 #define MinRevNum 2
38
39
40 #define EndianSwitch(x) ((x >> 24) | (x << 24) | ((x << 8) & (0x00FF0000)) | ((x >> 8) & (0x0000FF00)) )
41
42 typedef unsigned char bit8u;
43 typedef unsigned int bit32u;
44 typedef int bit32;
45
46 #define FALSE 0
47 #define TRUE (!FALSE)
48
49
50 bit32u CheckSum;
51 int RecStart;
52 int debug;
53 int verbose;
54
55 FILE *OpenOutputFile( char *Name );
56 FILE *fOut;
57 bit32u RecLength=0;
58
59 bit32u AddressCurrent;
60
61 bit32u gh(char *cp,int nibs);
62
63 int BigEndian;
64
65 int inputline;
66
67 // char buf[16*1024];
68
69 char buffer[2048];
70 char *cur_ptr;
71 int cur_line=0;
72 int cur_len=0;
73
74 int s1s2s3_total=0;
75
76 bit32u PBVal;
77 int PBValid;
78 bit32u PBAdr;
79
80
81 void dumpfTell(char *s, bit32u Value)
82 {
83 int Length;
84 Length = (int) RecLength;
85 if (debug)
86 printf("[%s ] ftell()[0x%08lX] Length[0x%4X] Length[%4d] Value[0x%08x]\n",
87 s, ftell(fOut), Length, Length, Value);
88 }
89
90 void DispHex(bit32u Hex)
91 {
92 // printf("%X", Hex);
93 }
94
95 void WaitDisplay(void)
96 {
97 static int Count=0;
98 static int Index=0;
99 char iline[]={"-\\|/"};
100
101 Count++;
102 if ((Count % 32)==0)
103 {
104 if (verbose)
105 printf("%c%c",iline[Index++],8);
106 Index &= 3;
107 }
108 }
109
110
111 void binOut32 ( bit32u Data )
112 {
113 // On UNIX machine all 32bit writes need ENDIAN switched
114 // Data = EndianSwitch(Data);
115 // fwrite( &Data, sizeof(bit32u), 1, fOut);
116
117 char sdat[4];
118 int i;
119
120 for(i=0;i<4;i++)
121 sdat[i]=(char)(Data>>(i*8));
122 fwrite( sdat, 1, 4, fOut);
123 dumpfTell("Out32" , Data);
124 }
125
126 // Only update RecLength on Byte Writes
127 // All 32 bit writes will be for Length etc
128
129 void binOut8 ( bit8u Data )
130 {
131 int n;
132 dumpfTell("B4Data" , (bit32u) (Data & 0xFF) );
133 n = fwrite( &Data, sizeof(bit8u), 1, fOut);
134 if (n != 1)
135 printf("Error in writing %X for Address 0x%8X\n", Data, AddressCurrent);
136 RecLength += 1;
137 }
138
139 // Currently ONLY used for outputting Program Start
140
141 void binRecStart(bit32u Address)
142 {
143 RecLength = 0;
144 CheckSum = Address;
145 RecStart = TRUE;
146
147 if (debug)
148 printf("[RecStart] CheckSum[0x%08X] Length[%4d] Address[0x%08X]\n",
149 CheckSum, RecLength, Address);
150
151
152 dumpfTell("RecLength", RecLength);
153 binOut32( RecLength );
154 dumpfTell("Address", Address);
155 binOut32( Address );
156 }
157
158 void binRecEnd(void)
159 {
160 long RecEnd;
161
162 if (!RecStart) // if no record started, do not end it
163 {
164 return;
165 }
166
167 RecStart = FALSE;
168
169
170 RecEnd = ftell(fOut); // Save Current position
171
172 if (debug)
173 printf("[RecEnd ] CheckSum[0x%08X] Length[%4d] Length[0x%X] RecEnd[0x%08lX]\n",
174 CheckSum, RecLength, RecLength, RecEnd);
175
176 fseek( fOut, -((long) RecLength), SEEK_CUR); // move back Start Of Data
177
178 dumpfTell("Data ", -1);
179
180 fseek( fOut, -4, SEEK_CUR); // move back Start Of Address
181
182 dumpfTell("Address ", -1);
183
184 fseek( fOut, -4, SEEK_CUR); // move back Start Of Length
185
186 dumpfTell("Length ", -1);
187
188 binOut32( RecLength );
189
190 fseek( fOut, RecEnd, SEEK_SET); // move to end of Record
191
192 CheckSum += RecLength;
193
194 CheckSum = ~CheckSum + 1; // Two's complement
195
196 binOut32( CheckSum );
197
198 if (verbose)
199 printf("[Created Record of %d Bytes with CheckSum [0x%8X]\n", RecLength, CheckSum);
200 }
201
202 void binRecOutProgramStart(bit32u Address)
203 {
204 if (Address != (AddressCurrent+1))
205 {
206 binRecEnd();
207 binRecStart(Address);
208 }
209 AddressCurrent = Address;
210 }
211 void binRecOutByte(bit32u Address, bit8u Data)
212 {
213 // If Address is one after Current Address, output Byte
214 // If not, close out last record, update Length, write checksum
215 // Then Start New Record, updating Current Address
216
217 if (Address != (AddressCurrent+1))
218 {
219 binRecEnd();
220 binRecStart(Address);
221 }
222 AddressCurrent = Address;
223 CheckSum += Data;
224 binOut8( Data );
225 }
226
227 //=============================================================================
228 // SUPPORT FUNCTIONS
229 //=============================================================================
230 int readline(FILE *fil,char *buf,int len)
231 {
232 int rlen;
233
234 rlen=0;
235 if (len==0) return(0);
236 while(1)
237 {
238 if (cur_len==0)
239 {
240 cur_len=fread(buffer, 1, sizeof(buffer), fil);
241 if (cur_len==0)
242 {
243 if (rlen)
244 {
245 *buf=0;
246 return(rlen);
247 }
248 return(-1);
249 }
250 cur_ptr=buffer;
251 }
252 if (cur_len)
253 {
254 if (*cur_ptr=='\n')
255 {
256 *buf=0;
257 cur_ptr++;
258 cur_len--;
259 return(rlen);
260 }
261 else
262 {
263 if ((len>1)&&(*cur_ptr!='\r'))
264 {
265 *buf++=*cur_ptr++;
266 len--;
267 }
268 else
269 cur_ptr++;
270
271 rlen++;
272 cur_len--;
273 }
274 }
275 else
276 {
277 *buf=0;
278 cur_ptr++;
279 cur_len--;
280 return(rlen);
281 }
282 }
283 }
284
285
286 int SRLerrorout(char *c1,char *c2)
287 {
288 printf("\nERROR: %s - '%s'.",c1,c2);
289 return(FALSE);
290 }
291
292
293 int checksum(char *cp,int count)
294 {
295 char *scp;
296 int cksum;
297 int dum;
298
299 scp=cp;
300 while(*scp)
301 {
302 if (!isxdigit(*scp++))
303 return(SRLerrorout("Invalid hex digits",cp));
304 }
305 scp=cp;
306
307 cksum=count;
308
309 while(count)
310 {
311 cksum += gh(scp,2);
312 if (count == 2)
313 dum = ~cksum;
314 scp += 2;
315 count--;
316 }
317 cksum&=0x0ff;
318 // printf("\nCk:%02x",cksum);
319 return(cksum==0x0ff);
320 }
321
322 bit32u gh(char *cp,int nibs)
323 {
324 int i;
325 bit32u j;
326
327 j=0;
328
329 for(i=0;i<nibs;i++)
330 {
331 j<<=4;
332 if ((*cp>='a')&&(*cp<='z')) *cp &= 0x5f;
333 if ((*cp>='0')&&(*cp<='9'))
334 j += (*cp-0x30);
335 else
336 if ((*cp>='A')&&(*cp<='F'))
337 j += (*cp-0x37);
338 else
339 SRLerrorout("Bad Hex char", cp);
340 cp++;
341 }
342 return(j);
343 }
344
345
346 //=============================================================================
347 // PROCESS SREC LINE
348 //=============================================================================
349
350 int srecLine(char *pSrecLine)
351 {
352 char *scp,ch;
353 int itmp,count,dat;
354 bit32u adr;
355 static bit32u RecordCounter=0;
356
357 cur_line++;
358 scp=pSrecLine;
359
360 if (*pSrecLine!='S')
361 return(SRLerrorout("Not an Srecord file",scp));
362 pSrecLine++;
363 if (strlen(pSrecLine)<4)
364 return(SRLerrorout("Srecord too short",scp));
365
366 ch=*pSrecLine++;
367
368 count=gh(pSrecLine,2);
369
370 pSrecLine += 2;
371
372 // if(debug)
373 // printf("count %d, strlen(pSrecLine) = %d, pSrecLine =[%s]\n", count, strlen(pSrecLine), pSrecLine);
374 RecordCounter++;
375 DispHex(RecordCounter);
376
377 if ((count*2) != strlen(pSrecLine)) return(SRLerrorout("Count field larger than record",scp));
378
379 if (!checksum(pSrecLine, count)) return(SRLerrorout("Bad Checksum",scp));
380
381 switch(ch)
382 {
383 case '0': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp));
384 itmp=gh(pSrecLine,4); pSrecLine+=4; count-=2;
385 if (itmp) return(SRLerrorout("Srecord 1 address not zero",scp));
386 break;
387 case '1': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp));
388 return(SRLerrorout("Srecord Not valid for MIPS",scp));
389 break;
390 case '2': if (count<4) return(SRLerrorout("Invalid Srecord count field",scp));
391 return(SRLerrorout("Srecord Not valid for MIPS",scp));
392 break;
393 case '3': if (count<5) return(SRLerrorout("Invalid Srecord count field",scp));
394 adr=gh(pSrecLine,8); pSrecLine+=8; count-=4;
395 count--;
396 while(count)
397 {
398 dat=gh(pSrecLine,2); pSrecLine+=2; count--;
399 binRecOutByte(adr, (char) (dat & 0xFF));
400 adr++;
401 }
402 s1s2s3_total++;
403 break;
404 case '4': return(SRLerrorout("Invalid Srecord type",scp));
405 break;
406 case '5': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp));
407 itmp=gh(pSrecLine,4); pSrecLine+=4; count-=2;
408 if (itmp|=s1s2s3_total) return(SRLerrorout("Incorrect number of S3 Record processed",scp));
409 break;
410 case '6': return(SRLerrorout("Invalid Srecord type",scp));
411 break;
412 case '7': // PROGRAM START
413 if (count<5) return(SRLerrorout("Invalid Srecord count field",scp));
414 adr=gh(pSrecLine,8); pSrecLine+=8; count-=4;
415 if (count!=1) return(SRLerrorout("Invalid Srecord count field",scp));
416 binRecOutProgramStart(adr);
417 break;
418 case '8': if (count<4) return(SRLerrorout("Invalid Srecord count field",scp));
419 return(SRLerrorout("Srecord Not valid for MIPS",scp));
420 break;
421 case '9': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp));
422 return(SRLerrorout("Srecord Not valid for MIPS",scp));
423 break;
424 default:
425 break;
426 }
427 return(TRUE);
428 }
429
430
431 //=============================================================================
432 // MAIN LOGIC, READS IN LINE AND OUTPUTS BINARY
433 //=============================================================================
434
435 int srec2bin(int argc,char *argv[],int verbose)
436 {
437 int rlen,sts;
438 FILE *fp;
439 char buff[256];
440 bit32u TAG_BIG = 0xDEADBE42;
441 bit32u TAG_LITTLE = 0xFEEDFA42;
442
443 bit32u Tag;
444
445
446 if(argc < 3)
447 {
448 printf("\nError: <srec2bin <srec input file> <bin output file>\n\n");
449 return(0);
450 }
451
452 if (argc > 3) BigEndian=TRUE; else BigEndian=FALSE;
453
454 if (BigEndian)
455 Tag = TAG_BIG;
456 else
457 Tag = TAG_LITTLE;
458
459 if (verbose)
460 printf("\nEndian: %s, Tag is 0x%8X\n",(BigEndian)?"BIG":"LITTLE", Tag);
461
462 fp = fopen(argv[1],"rt");
463
464 if (fp==NULL)
465 {
466 printf("\nError: Opening input file, %s.", argv[1]);
467 return(0);
468 }
469
470 fOut = fopen( argv[2], "wb");
471
472 if (fOut==NULL)
473 {
474 printf("\nError: Opening Output file, %s.", argv[2]);
475 if(fp) fclose(fp);
476 return(0);
477 }
478
479 RecStart = FALSE;
480
481 AddressCurrent = 0xFFFFFFFFL;
482
483 // Setup Tag
484
485 dumpfTell("Tag", Tag);
486
487 binOut32(Tag);
488
489
490 inputline=0;
491 sts=TRUE;
492
493 rlen = readline(fp,buff,sizeof buff);
494
495 while( (sts) && (rlen != -1))
496 {
497 if (strlen(buff))
498 {
499 sts &= srecLine(buff);
500 WaitDisplay();
501 }
502 rlen = readline(fp,buff,sizeof buff);
503 }
504
505
506 // printf("PC: 0x%08X, Length 0x%08X, Tag 0x%08X\n", ProgramStart, RecLength, TAG_LITTLE);
507
508 binRecEnd();
509
510 if(fp) fclose(fp);
511 if(fOut) fclose(fOut);
512
513 return(1);
514 }
515
516 int main(int argc, char *argv[])
517 {
518 debug = TRUE;
519 debug = FALSE;
520 verbose = FALSE;
521 srec2bin(argc,argv,verbose);
522 return 0;
523 }
524