Modified to strip leading white-space characters and ignore blank or comment only...
[people/mcb30/edk2.git] / edk2 / Tools / CCode / Source / FlashMap / Microcode.c
1 /*++\r
2 \r
3 Copyright (c)  2004-2006 Intel Corporation. All rights reserved\r
4 This program and the accompanying materials are licensed and made available \r
5 under the terms and conditions of the BSD License which accompanies this \r
6 distribution.  The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php\r
8 \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11 \r
12 Module Name:\r
13 \r
14   Microcode.c\r
15 \r
16 Abstract:\r
17 \r
18   Utility for working with microcode patch files in the Intel \r
19   Platform Innovation Framework for EFI build environment.\r
20 \r
21 --*/\r
22 \r
23 #include <stdio.h>\r
24 #include <string.h> // for memset()\r
25 #include <ctype.h>\r
26 #include <stdlib.h> // for malloc()\r
27 \r
28 #include "EfiUtilityMsgs.h"\r
29 #include "Microcode.h"\r
30 \r
31 #define MAX_LINE_LEN  256\r
32 \r
33 #define STATUS_IGNORE 0xA\r
34 \r
35 //\r
36 // Structure definition for a microcode header\r
37 //\r
38 typedef struct {\r
39   unsigned int  HeaderVersion;\r
40   unsigned int  PatchId;\r
41   unsigned int  Date;\r
42   unsigned int  CpuId;\r
43   unsigned int  Checksum;\r
44   unsigned int  LoaderVersion;\r
45   unsigned int  PlatformId;\r
46   unsigned int  DataSize;   // if 0, then TotalSize = 2048, and TotalSize field is invalid\r
47   unsigned int  TotalSize;  // number of bytes\r
48   unsigned int  Reserved[3];\r
49 } MICROCODE_IMAGE_HEADER;\r
50 \r
51 static\r
52 STATUS\r
53 MicrocodeReadData (\r
54   FILE          *InFptr,\r
55   unsigned int  *Data\r
56   );\r
57 \r
58 void\r
59 MicrocodeConstructor (\r
60   void\r
61   )\r
62 /*++\r
63 \r
64 Routine Description:\r
65 \r
66   Constructor of module Microcode\r
67 \r
68 Arguments:\r
69 \r
70   None\r
71 \r
72 Returns:\r
73 \r
74   None\r
75 \r
76 --*/\r
77 {\r
78 }\r
79 \r
80 void\r
81 MicrocodeDestructor (\r
82   void\r
83   )\r
84 /*++\r
85 \r
86 Routine Description:\r
87 \r
88   Destructor of module Microcode\r
89 \r
90 Arguments:\r
91 \r
92   None\r
93 \r
94 Returns:\r
95 \r
96   None\r
97 \r
98 --*/\r
99 {\r
100 }\r
101 \r
102 static\r
103 STATUS\r
104 MicrocodeReadData (\r
105   FILE          *InFptr,\r
106   unsigned int  *Data\r
107   )\r
108 /*++\r
109 \r
110 Routine Description:\r
111   Read a 32-bit microcode data value from a text file and convert to raw binary form.\r
112 \r
113 Arguments:\r
114   InFptr    - file pointer to input text file\r
115   Data      - pointer to where to return the data parsed\r
116 \r
117 Returns:\r
118   STATUS_SUCCESS    - no errors or warnings, Data contains valid information\r
119   STATUS_ERROR      - errors were encountered\r
120 \r
121 --*/\r
122 {\r
123   char  Line[MAX_LINE_LEN];\r
124   char  *cptr;\r
125   unsigned int  ctr;\r
126 \r
127   Line[MAX_LINE_LEN - 1]  = 0;\r
128   *Data                   = 0;\r
129   if (fgets (Line, MAX_LINE_LEN, InFptr) == NULL) {\r
130     return STATUS_ERROR;\r
131   }\r
132   //\r
133   // If it was a binary file, then it may have overwritten our null terminator\r
134   //\r
135   if (Line[MAX_LINE_LEN - 1] != 0) {\r
136     return STATUS_ERROR;\r
137   }\r
138 \r
139   // Strip leading white-space characters (except carriage returns) from Line\r
140   //\r
141   if (isspace(Line[0]) && Line[0] != '\n') {\r
142     while (isspace(Line[0])) {\r
143        for (ctr = 0; ctr < strlen(Line); ctr++)\r
144          if (Line[ctr] != '\n')\r
145            Line[ctr] = Line[ctr + 1];\r
146     }\r
147   }\r
148 \r
149   //\r
150   // Look for\r
151   // dd 000000001h ; comment\r
152   // dd XXXXXXXX\r
153   // DD  XXXXXXXXX\r
154   //  DD XXXXXXXXX\r
155   //\r
156   for (cptr = Line; *cptr && isspace(*cptr); cptr++) {\r
157   }\r
158   if ((tolower(cptr[0]) == 'd') && (tolower(cptr[1]) == 'd') && isspace (cptr[2])) {\r
159     //\r
160     // Skip blanks and look for a hex digit\r
161     //\r
162     cptr += 3;\r
163     for (; *cptr && isspace(*cptr); cptr++) {\r
164     }\r
165     if (isxdigit (*cptr)) {\r
166       if (sscanf (cptr, "%X", Data) != 1) {\r
167         return STATUS_ERROR;\r
168       }\r
169     }\r
170     return STATUS_SUCCESS;\r
171   }\r
172   if (strlen(Line) == 1) {\r
173     return STATUS_IGNORE;\r
174   }\r
175   if (tolower(cptr[0]) == ';') {\r
176     return STATUS_IGNORE;\r
177   }\r
178   return STATUS_ERROR;\r
179 }\r
180 \r
181 STATUS\r
182 MicrocodeParseFile (\r
183   char  *InFileName,\r
184   char  *OutFileName\r
185   )\r
186 /*++\r
187 \r
188 Routine Description:\r
189   Parse a microcode text file, and write the binary results to an output file.\r
190 \r
191 Arguments:\r
192   InFileName  - input text file to parse\r
193   OutFileName - output file to write raw binary data from parsed input file\r
194 \r
195 Returns:\r
196   STATUS_SUCCESS    - no errors or warnings\r
197   STATUS_ERROR      - errors were encountered\r
198 \r
199 --*/\r
200 {\r
201   FILE                    *InFptr;\r
202   FILE                    *OutFptr;\r
203   STATUS                  Status;\r
204   MICROCODE_IMAGE_HEADER  *Header;\r
205   unsigned int            Size;\r
206   unsigned int            Size2;\r
207   unsigned int            Data;\r
208   unsigned int            Checksum;\r
209   char                    *Buffer;\r
210   char                    *Ptr;\r
211   char                    *OrigPtr;\r
212   unsigned int            TotalSize;\r
213 \r
214   Status  = STATUS_ERROR;\r
215   InFptr  = NULL;\r
216   OutFptr = NULL;\r
217   Buffer  = NULL;\r
218   //\r
219   // Open the input text file\r
220   //\r
221   if ((InFptr = fopen (InFileName, "r")) == NULL) {\r
222     Error (NULL, 0, 0, InFileName, "failed to open input microcode file for reading");\r
223     return STATUS_ERROR;\r
224   }\r
225   //\r
226   // Make two passes on the input file. The first pass is to determine how\r
227   // much data is in the file so we can allocate a working buffer. Then\r
228   // we'll allocate a buffer and re-read the file into the buffer for processing.\r
229   //\r
230   Size = 0;\r
231   do {\r
232     Status = MicrocodeReadData (InFptr, &Data);\r
233     if (Status == STATUS_SUCCESS) {\r
234       Size += sizeof (Data);\r
235     }\r
236     if (Status == STATUS_IGNORE) {\r
237       Status = STATUS_SUCCESS;\r
238     }\r
239   } while (Status == STATUS_SUCCESS);\r
240   //\r
241   // Error if no data.\r
242   //\r
243   if (Size == 0) {\r
244     Error (NULL, 0, 0, InFileName, "no parse-able data found in file");\r
245     goto Done;\r
246   }\r
247   if (Size < sizeof (MICROCODE_IMAGE_HEADER)) {\r
248     Error (NULL, 0, 0, InFileName, "amount of parse-able data is insufficient to contain a microcode header");\r
249     goto Done;\r
250   }\r
251   //\r
252   // Allocate a buffer for the data\r
253   //\r
254   Buffer = (char *) _malloc (Size);\r
255   if (Buffer == NULL) {\r
256     Error (NULL, 0, 0, "memory allocation failure", NULL);\r
257     goto Done;\r
258   }\r
259   //\r
260   // Re-read the file, storing the data into our buffer\r
261   //\r
262   fseek (InFptr, 0, SEEK_SET);\r
263   Ptr = Buffer;\r
264   OrigPtr = Ptr;\r
265   do {\r
266     OrigPtr = Ptr;\r
267     Status = MicrocodeReadData (InFptr, &Data);\r
268     if (Status == STATUS_SUCCESS) {\r
269       *(unsigned int *) Ptr = Data;\r
270       Ptr += sizeof (Data);\r
271     }\r
272     if (Status == STATUS_IGNORE) {\r
273       Ptr = OrigPtr;\r
274       Status = STATUS_SUCCESS;\r
275     }\r
276   } while (Status == STATUS_SUCCESS);\r
277   //\r
278   // Can't do much checking on the header because, per the spec, the\r
279   // DataSize field may be 0, which means DataSize = 2000 and TotalSize = 2K,\r
280   // and the TotalSize field is invalid (actually missing). Thus we can't\r
281   // even verify the Reserved fields are 0.\r
282   //\r
283   Header = (MICROCODE_IMAGE_HEADER *) Buffer;\r
284   if (Header->DataSize == 0) {\r
285     TotalSize = 2048;\r
286   } else {\r
287     TotalSize = Header->TotalSize;\r
288   }\r
289   if (TotalSize != Size) {\r
290     Error (NULL, 0, 0, InFileName, "file contents do not contain expected TotalSize 0x%04X", TotalSize);\r
291     goto Done;\r
292   }\r
293   //\r
294   // Checksum the contents\r
295   //\r
296   Ptr       = Buffer;\r
297   Checksum  = 0;\r
298   Size2     = 0;\r
299   while (Size2 < Size) {\r
300     Checksum += *(unsigned int *) Ptr;\r
301     Ptr += 4;\r
302     Size2 += 4;\r
303   }\r
304   if (Checksum != 0) {\r
305     Error (NULL, 0, 0, InFileName, "checksum failed on file contents");\r
306     goto Done;\r
307   }\r
308   //\r
309   // Open the output file and write the buffer contents\r
310   //\r
311   if ((OutFptr = fopen (OutFileName, "wb")) == NULL) {\r
312     Error (NULL, 0, 0, OutFileName, "failed to open output microcode file for writing");\r
313     goto Done;\r
314   }\r
315   if (fwrite (Buffer, Size, 1, OutFptr) != 1) {\r
316     Error (NULL, 0, 0, OutFileName, "failed to write microcode data to output file");\r
317     goto Done;\r
318   }\r
319   Status = STATUS_SUCCESS;\r
320 Done:\r
321   if (Buffer != NULL) {\r
322     free (Buffer);\r
323   }\r
324   if (InFptr != NULL) {\r
325     fclose (InFptr);\r
326   }\r
327   if (OutFptr != NULL) {\r
328     fclose (OutFptr);\r
329     if (Status == STATUS_ERROR) {\r
330       remove (OutFileName);\r
331     }\r
332   }\r
333   return Status;\r
334 }\r