mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-10-27 01:03:45 +01:00 
			
		
		
		
	git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@4080 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			335 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			335 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*++
 | |
| 
 | |
| 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;
 | |
| }
 |