blob: f5bea095e0e7211b923a8923f34d40cefb24f6c1 [file] [log] [blame]
/*++
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;
}