summaryrefslogtreecommitdiff
path: root/Tools/CCode/Source/FlashMap/Microcode.c
blob: 84534e316ff11f9b6d9ac0c73f1194bffb04b28f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
/*++

Copyright (c)  2004-2006 Intel Corporation. All rights reserved
This program and the accompanying materials are licensed and made available 
under the terms and conditions of the BSD License which accompanies this 
distribution.  The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php

THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

Module Name:

  Microcode.c

Abstract:

  Utility for working with microcode patch files in the Intel 
  Platform Innovation Framework for EFI build environment.

--*/

#include <stdio.h>
#include <string.h> // for memset()
#include <ctype.h>
#include <stdlib.h> // for malloc()

#include "EfiUtilityMsgs.h"
#include "Microcode.h"

#define MAX_LINE_LEN  256

#define STATUS_IGNORE 0xA

//
// Structure definition for a microcode header
//
typedef struct {
  unsigned int  HeaderVersion;
  unsigned int  PatchId;
  unsigned int  Date;
  unsigned int  CpuId;
  unsigned int  Checksum;
  unsigned int  LoaderVersion;
  unsigned int  PlatformId;
  unsigned int  DataSize;   // if 0, then TotalSize = 2048, and TotalSize field is invalid
  unsigned int  TotalSize;  // number of bytes
  unsigned int  Reserved[3];
} MICROCODE_IMAGE_HEADER;

static
STATUS
MicrocodeReadData (
  FILE          *InFptr,
  unsigned int  *Data
  );

void
MicrocodeConstructor (
  void
  )
/*++

Routine Description:

  Constructor of module Microcode

Arguments:

  None

Returns:

  None

--*/
{
}

void
MicrocodeDestructor (
  void
  )
/*++

Routine Description:

  Destructor of module Microcode

Arguments:

  None

Returns:

  None

--*/
{
}

static
STATUS
MicrocodeReadData (
  FILE          *InFptr,
  unsigned int  *Data
  )
/*++

Routine Description:
  Read a 32-bit microcode data value from a text file and convert to raw binary form.

Arguments:
  InFptr    - file pointer to input text file
  Data      - pointer to where to return the data parsed

Returns:
  STATUS_SUCCESS    - no errors or warnings, Data contains valid information
  STATUS_ERROR      - errors were encountered

--*/
{
  char  Line[MAX_LINE_LEN];
  char  *cptr;
  unsigned int  ctr;

  Line[MAX_LINE_LEN - 1]  = 0;
  *Data                   = 0;
  if (fgets (Line, MAX_LINE_LEN, InFptr) == NULL) {
    return STATUS_ERROR;
  }
  //
  // If it was a binary file, then it may have overwritten our null terminator
  //
  if (Line[MAX_LINE_LEN - 1] != 0) {
    return STATUS_ERROR;
  }

  // Strip leading white-space characters (except carriage returns) from Line
  //
  if (isspace(Line[0]) && Line[0] != '\n') {
    while (isspace(Line[0])) {
       for (ctr = 0; ctr < strlen(Line); ctr++)
         if (Line[ctr] != '\n')
           Line[ctr] = Line[ctr + 1];
    }
  }

  //
  // Look for
  // dd 000000001h ; comment
  // dd XXXXXXXX
  // DD  XXXXXXXXX
  //  DD XXXXXXXXX
  //
  for (cptr = Line; *cptr && isspace(*cptr); cptr++) {
  }
  if ((tolower(cptr[0]) == 'd') && (tolower(cptr[1]) == 'd') && isspace (cptr[2])) {
    //
    // Skip blanks and look for a hex digit
    //
    cptr += 3;
    for (; *cptr && isspace(*cptr); cptr++) {
    }
    if (isxdigit (*cptr)) {
      if (sscanf (cptr, "%X", Data) != 1) {
        return STATUS_ERROR;
      }
    }
    return STATUS_SUCCESS;
  }
  if (strlen(Line) == 1) {
    return STATUS_IGNORE;
  }
  if (tolower(cptr[0]) == ';') {
    return STATUS_IGNORE;
  }
  return STATUS_ERROR;
}

STATUS
MicrocodeParseFile (
  char  *InFileName,
  char  *OutFileName
  )
/*++

Routine Description:
  Parse a microcode text file, and write the binary results to an output file.

Arguments:
  InFileName  - input text file to parse
  OutFileName - output file to write raw binary data from parsed input file

Returns:
  STATUS_SUCCESS    - no errors or warnings
  STATUS_ERROR      - errors were encountered

--*/
{
  FILE                    *InFptr;
  FILE                    *OutFptr;
  STATUS                  Status;
  MICROCODE_IMAGE_HEADER  *Header;
  unsigned int            Size;
  unsigned int            Size2;
  unsigned int            Data;
  unsigned int            Checksum;
  char                    *Buffer;
  char                    *Ptr;
  char                    *OrigPtr;
  unsigned int            TotalSize;

  Status  = STATUS_ERROR;
  InFptr  = NULL;
  OutFptr = NULL;
  Buffer  = NULL;
  //
  // Open the input text file
  //
  if ((InFptr = fopen (InFileName, "r")) == NULL) {
    Error (NULL, 0, 0, InFileName, "failed to open input microcode file for reading");
    return STATUS_ERROR;
  }
  //
  // Make two passes on the input file. The first pass is to determine how
  // much data is in the file so we can allocate a working buffer. Then
  // we'll allocate a buffer and re-read the file into the buffer for processing.
  //
  Size = 0;
  do {
    Status = MicrocodeReadData (InFptr, &Data);
    if (Status == STATUS_SUCCESS) {
      Size += sizeof (Data);
    }
    if (Status == STATUS_IGNORE) {
      Status = STATUS_SUCCESS;
    }
  } while (Status == STATUS_SUCCESS);
  //
  // Error if no data.
  //
  if (Size == 0) {
    Error (NULL, 0, 0, InFileName, "no parse-able data found in file");
    goto Done;
  }
  if (Size < sizeof (MICROCODE_IMAGE_HEADER)) {
    Error (NULL, 0, 0, InFileName, "amount of parse-able data is insufficient to contain a microcode header");
    goto Done;
  }
  //
  // Allocate a buffer for the data
  //
  Buffer = (char *) _malloc (Size);
  if (Buffer == NULL) {
    Error (NULL, 0, 0, "memory allocation failure", NULL);
    goto Done;
  }
  //
  // Re-read the file, storing the data into our buffer
  //
  fseek (InFptr, 0, SEEK_SET);
  Ptr = Buffer;
  OrigPtr = Ptr;
  do {
    OrigPtr = Ptr;
    Status = MicrocodeReadData (InFptr, &Data);
    if (Status == STATUS_SUCCESS) {
      *(unsigned int *) Ptr = Data;
      Ptr += sizeof (Data);
    }
    if (Status == STATUS_IGNORE) {
      Ptr = OrigPtr;
      Status = STATUS_SUCCESS;
    }
  } while (Status == STATUS_SUCCESS);
  //
  // Can't do much checking on the header because, per the spec, the
  // DataSize field may be 0, which means DataSize = 2000 and TotalSize = 2K,
  // and the TotalSize field is invalid (actually missing). Thus we can't
  // even verify the Reserved fields are 0.
  //
  Header = (MICROCODE_IMAGE_HEADER *) Buffer;
  if (Header->DataSize == 0) {
    TotalSize = 2048;
  } else {
    TotalSize = Header->TotalSize;
  }
  if (TotalSize != Size) {
    Error (NULL, 0, 0, InFileName, "file contents do not contain expected TotalSize 0x%04X", TotalSize);
    goto Done;
  }
  //
  // Checksum the contents
  //
  Ptr       = Buffer;
  Checksum  = 0;
  Size2     = 0;
  while (Size2 < Size) {
    Checksum += *(unsigned int *) Ptr;
    Ptr += 4;
    Size2 += 4;
  }
  if (Checksum != 0) {
    Error (NULL, 0, 0, InFileName, "checksum failed on file contents");
    goto Done;
  }
  //
  // Open the output file and write the buffer contents
  //
  if ((OutFptr = fopen (OutFileName, "wb")) == NULL) {
    Error (NULL, 0, 0, OutFileName, "failed to open output microcode file for writing");
    goto Done;
  }
  if (fwrite (Buffer, Size, 1, OutFptr) != 1) {
    Error (NULL, 0, 0, OutFileName, "failed to write microcode data to output file");
    goto Done;
  }
  Status = STATUS_SUCCESS;
Done:
  if (Buffer != NULL) {
    free (Buffer);
  }
  if (InFptr != NULL) {
    fclose (InFptr);
  }
  if (OutFptr != NULL) {
    fclose (OutFptr);
    if (Status == STATUS_ERROR) {
      remove (OutFileName);
    }
  }
  return Status;
}