| /*++ | |
| 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 | |
| // | |
| // 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; | |
| 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; | |
| } | |
| // | |
| // 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; | |
| } | |
| 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; | |
| 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); | |
| } | |
| } 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; | |
| do { | |
| Status = MicrocodeReadData (InFptr, &Data); | |
| if (Status == STATUS_SUCCESS) { | |
| *(unsigned int *) Ptr = Data; | |
| Ptr += sizeof (Data); | |
| } | |
| } 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; | |
| } |