/*++ | |
Copyright (c) 2004 Intel Corporation. All rights reserved | |
This software and associated documentation (if any) is furnished | |
under a license and may only be used or copied in accordance | |
with the terms of the license. Except as permitted by such | |
license, no part of this software or documentation may be | |
reproduced, stored in a retrieval system, or transmitted in any | |
form or by any means without the express written consent of | |
Intel Corporation. | |
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; | |
} |