git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@246 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			305 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			305 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*++
 | 
						|
 | 
						|
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;
 | 
						|
}
 |