Windows-Server-2003/sdktools/mkupdate/mkupdate.c

830 lines
23 KiB
C

/*++
Copyright Microsoft Corporation, 1996-7, All Rights Reserved.
Module Name:
mkupdate.c
Abstract:
Application for creating the update database file from an
appropriately structured input update file and maintaining
the driver version in the resource file.
Author:
Shivnandan Kaushik
Environment:
User mode
Revision History:
--*/
#include <windows.h>
#include <stdio.h>
#include <winbase.h>
#include <winioctl.h>
#include <fcntl.h>
#include <stdlib.h>
#include <io.h>
#include <string.h>
#include "mkupdate.h"
//
// Globals
//
PUPDATE_ENTRY UpdateTable;
VOID
GenMSHeader(
FILE *file,
CHAR *Filename,
CHAR *Abstract
)
/*++
Routine Description:
Generates the Microsoft recommended header for code files.
Arguments:
File: Output file pointer
FileName: Output file name
Abstract: Description of file
Return Value:
None
--*/
{
fprintf(file,"/*++ \n\nCopyright (c) 1996-7 Microsoft Corporation, ");
fprintf(file,"All Rights Reserved.\n\n");
fprintf(file,"Copyright (c) 1995-2000 Intel Corporation. This update binary code\n");
fprintf(file,"is distributed for the sole purpose of being loaded into Intel\n");
fprintf(file,"Pentium(R) Pro Processor Family and Pentium(R) 4 Family microprocessors.\n");
fprintf(file,"All Rights on the binary code are reserved.\n\n");
fprintf(file,"Module Name:\n\n %s\n\n",Filename);
fprintf(file,"Abstract:\n\n %s\n\n",Abstract);
fprintf(file,"Author:\n\n !!!THIS IS A GENERATED FILE. DO NOT DIRECTLY EDIT!!!\n\n");
fprintf(file,"Revision History:\n\n--*/\n\n");
}
BOOL
GetVerifyPutUpdate(
FILE *OutputFile,
ULONG UpdateNum,
ULONG TotalUpdates
)
/*++
Routine Description:
Read in an update, verify it and write to data file.
Arguments:
OutputFile: output file pointer
UpdateNum: Update number in update list
TotalUpdates: Total number of updates in update list.
Return Value:
TRUE if writes succeeded else FALSE.
--*/
{
FILE *UpdateFile;
CHAR Line[MAX_LINE],UpdateString[MAX_LINE];
CHAR Filename[MAX_PATH];
BOOL BeginFound,EndFound;
ULONG CurrentDword,i,Checksum;
ULONG UpdateBuffer[sizeof(UPDATE)];
PUPDATE CurrentUpdate;
// create the string name of the file to open
strcpy(Filename,UpdateTable[UpdateNum].CpuSigStr);
strcat(Filename,"_");
strcat(Filename,UpdateTable[UpdateNum].UpdateRevStr);
strcat(Filename,".");
strcat(Filename,UpdateTable[UpdateNum].FlagsStr);
UpdateFile = fopen(Filename,"r");
if (UpdateFile == NULL) {
fprintf(stdout,"mkupdate:Unable to open update input file %s\n",Filename);
return(FALSE);
}
//
// Read in each update - scan till beginning of update
// marked by keyword BEGIN_UPDATE
//
BeginFound = FALSE;
while (fgets(Line,MAX_LINE,UpdateFile) != NULL) {
if (sscanf(Line,"%s",&UpdateString)) {
if (strcmp(UpdateString,"BEGIN_UPDATE") == 0) {
BeginFound = TRUE;
break;
}
}
}
if (!BeginFound) {
fprintf(stdout,"mkupdate:BEGIN_UPDATE not found in update file %s\n",Filename);
fclose(UpdateFile);
return(FALSE);
}
//
// scan "update size" forward.
//
EndFound = FALSE;
for (i = 0; i < sizeof(UPDATE)/sizeof(ULONG); i++) {
if (fgets(Line,MAX_LINE,UpdateFile) != NULL) {
if (sscanf(Line,"%lx",&CurrentDword))
UpdateBuffer[i] = CurrentDword;
} else {
EndFound = TRUE;
break;
}
}
if (EndFound) {
fprintf(stdout,"mkupdate:Abnormal termination of update file %s\n",Filename);
fclose(UpdateFile);
return(FALSE);
} else {
if (fgets(Line,MAX_LINE,UpdateFile) != NULL) {
if (sscanf(Line,"%s",&UpdateString)) {
if (strcmp(UpdateString,"END_UPDATE") != 0) {
fprintf(stdout,"mkupdate:Update data size in %s incorrect\n",Filename);
fclose(UpdateFile);
return(FALSE);
}
}
} else {
fprintf(stdout,"mkupdate:Abnormal termination of update file %s\n",Filename);
fclose(UpdateFile);
return(FALSE);
}
}
fclose (UpdateFile);
// Verify Update - Checksum Buffer
Checksum = 0;
for (i = 0; i < sizeof(UPDATE)/sizeof(ULONG); i++) {
Checksum += UpdateBuffer[i];
}
if (Checksum){
fprintf(stdout,"mkupdate:Incorrect update checksum in %s\n",Filename);
return(FALSE);
}
//
// Verify update - check if processor signature, update revision
// and processor flags match that specified in listing file and
// update data file name
//
CurrentUpdate = (PUPDATE) UpdateBuffer;
if ((CurrentUpdate->Processor.u.LongPart !=
UpdateTable[UpdateNum].CpuSignature)){
fprintf(stdout,"mkupdate:incorrect processor signature in %s: ",Filename);
fprintf(stdout,"expected 0x%lx got 0x%lx\n",
UpdateTable[UpdateNum].CpuSignature,
CurrentUpdate->Processor.u.LongPart);
return(FALSE);
}
if (CurrentUpdate->UpdateRevision !=
UpdateTable[UpdateNum].UpdateRevision){
fprintf(stdout,"mkupdate:incorrect update revision in %s: ",Filename);
fprintf(stdout,"expected 0x%lx got 0x%lx\n",
UpdateTable[UpdateNum].UpdateRevision,
CurrentUpdate->UpdateRevision);
return(FALSE);
}
if ((CurrentUpdate->ProcessorFlags.u.LongPart !=
UpdateTable[UpdateNum].ProcessorFlags)){
fprintf(stdout,"mkupdate:incorrect processor flags in %s: ",Filename);
fprintf(stdout,"expected 0x%lx got 0x%lx\n",
UpdateTable[UpdateNum].ProcessorFlags,
CurrentUpdate->ProcessorFlags.u.LongPart);
return(FALSE);
}
//
// Input update validated. Write out validated update
//
fprintf(OutputFile," {\n");
for (i = 0; i < sizeof(UPDATE)/sizeof(ULONG); i++) {
fprintf(OutputFile," 0x%.8x",UpdateBuffer[i]);
if (i == sizeof(UPDATE)/sizeof(ULONG) - 1) {
fprintf(OutputFile,"\n");
} else {
fprintf(OutputFile,",\n");
}
}
fprintf(OutputFile," }");
if (UpdateNum != TotalUpdates-1) {
fprintf(OutputFile,",\n");
}
return(TRUE);
}
VOID
BuildUpdateInfoTable(
FILE *OutputFile,
ULONG TotalUpdates
)
/*++
Routine Description:
Write the CPU Signature and Processor Flags into the
Build Table and adds NULL for the MDL Item.
Arguments:
OutputFile : output file pointer
TotalUpdates : Total number of updates in update list.
Return Value:
None:
--*/
{
ULONG CpuSignature, ProcessorFlags, i;
fprintf(OutputFile, "//\n// Update Info Table containing the CPU Signatures,\n");
fprintf(OutputFile, "// Processor Flags, and MDL Pointers. The MDL Pointers\n");
fprintf(OutputFile, "// are initialized to NULL. They get populated as pages\n");
fprintf(OutputFile, "// corresponding to specific updates are locked in memory.\n");
fprintf(OutputFile, "// This table contains the CPU Signatures and Processor Flags.\n");
fprintf(OutputFile, "// in the same order as in the update database. Therefore,\n");
fprintf(OutputFile, "// the Update Info Table self-indexes to the right update.\n//\n\n");
fprintf(OutputFile, "UPDATE_INFO UpdateInfo[] = {\n");
//
// Add each entry for the info
//
for (i = 0; i < TotalUpdates; i++) {
CpuSignature = strtoul(UpdateTable[i].CpuSigStr, NULL, 16);
ProcessorFlags = strtoul(UpdateTable[i].FlagsStr, NULL, 16);
if (i < (TotalUpdates - 1)) {
fprintf(OutputFile, " {0x%x, 0x%x, NULL},\n", CpuSignature, ProcessorFlags);
} else {
fprintf(OutputFile, " {0x%x, 0x%x, NULL}\n", CpuSignature, ProcessorFlags);
}
}
//
// generate closing code for the update info definition
//
fprintf(OutputFile, "};\n");
return;
}
ULONG
PopulateUpdateList(
CHAR *ListingFile
)
/*++
Routine Description:
Populates the update list with (processor signature, update revision)
pairs included in the update listing file and returns the number of
updates found.
Arguments:
ListingFile
Return Value:
Number of updates in the update list. 0 if no updates found or any
error encountered.
--*/
{
CHAR Line[MAX_LINE],UpdateString[MAX_LINE];
CHAR CpuSigStr[MAX_LINE],UpdateRevStr[MAX_LINE];
CHAR FlagsStr[MAX_LINE];
BOOL BeginFound,EndFound,Error;
FILE *TmpFilePtr;
ULONG NumUpdates,i;
ULONG CpuSignature,UpdateRevision,ProcessorFlags;
#ifdef DEBUG
fprintf(stderr,"listing file %s\n",ListingFile);
#endif
// Open the update listing file
TmpFilePtr = fopen(ListingFile,"r");
if (TmpFilePtr == NULL) {
fprintf(stdout,"mkupdate:Unable to open update listing file %s\n",ListingFile);
return(0);
};
//
// Scan for beginning of the update list marked by
// BEGIN_UPDATE_LIST keyword
//
BeginFound = FALSE;
while ((!BeginFound) && (fgets(Line,MAX_LINE,TmpFilePtr) != NULL)) {
if (sscanf(Line,"%s",&UpdateString)) {
if (strcmp(UpdateString,"BEGIN_UPDATE_LIST") == 0) {
BeginFound = TRUE;
}
}
}
if (!BeginFound) {
fprintf(stdout,"mkupdate:BEGIN_UPDATE_LIST not found in update listing file %s\n",ListingFile);
fclose(TmpFilePtr);
return(0);
};
//
// Scan for end of the update list marked by
// END_UPDATE_LIST keyword and count # updates.
//
NumUpdates = 0;
EndFound = FALSE;
while ((!EndFound) && (fgets(Line,MAX_LINE,TmpFilePtr) != NULL)) {
if (sscanf(Line,"%s",&UpdateString)) {
if (strcmp(UpdateString,"END_UPDATE_LIST") == 0) {
EndFound = TRUE;
} else {
NumUpdates++;
}
}
}
fclose(TmpFilePtr);
if (!EndFound) {
fprintf(stdout,"mkupdate:END_UPDATE_LIST not found in update listing file %s\n",ListingFile);
return(0);
}
//
// If legal file format and non-zero number of updates are found
// then read the processor signatures and update revisions into
// the update list.
//
if (NumUpdates) {
// allocate memory for storing cpu signatures
UpdateTable = (UPDATE_ENTRY *) malloc(NumUpdates*sizeof(UPDATE_ENTRY));
if (UpdateTable == NULL){
fprintf(stdout,"mkupdate:Error: Memory Allocation Error\n");
return(0);
}
TmpFilePtr = fopen(ListingFile,"r");
if (TmpFilePtr == NULL) {
fprintf(stdout,"mkupdate:Unable to open update listing file %s\n",ListingFile);
return(0);
};
while ((fgets(Line,MAX_LINE,TmpFilePtr) != NULL)) {
if (sscanf(Line,"%s",&UpdateString)) {
if (strcmp(UpdateString,"BEGIN_UPDATE_LIST") == 0) {
break;
}
}
}
// Scan the listing file and populate the update table
Error = FALSE;
for (i = 0; i < NumUpdates; i++) {
if (fgets(Line,MAX_LINE,TmpFilePtr) == NULL) {
fprintf(stdout,"mkupdate: Abnormal termination in update listing file %s\n",
ListingFile);
Error = TRUE;
break;
}
if (sscanf(Line,"%s %s %s",&CpuSigStr,&UpdateRevStr,&FlagsStr) != 3) {
fprintf(stdout,"mkupdate: Incorrect format of update listing file %s\n",
ListingFile);
Error = TRUE;
break;
}
#ifdef DEBUG
fprintf(stderr,"CpuSig %s Update Rev %s Processor Flags %s,\n",CpuSigStr,
UpdateRevStr,FlagsStr);
#endif
if (sscanf(CpuSigStr,"%lx",&CpuSignature) != 1) {
fprintf(stdout,"mkupdate: Incorrect Processor Signature in update listing file %s\n",
ListingFile);
Error = TRUE;
break;
}
if (sscanf(UpdateRevStr,"%lx",&UpdateRevision)!= 1) {
fprintf(stdout,"mkupdate: Incorrect Update Revision of update listing file %s\n",
ListingFile);
Error = TRUE;
break;
}
if (sscanf(FlagsStr,"%lx",&ProcessorFlags)!= 1) {
fprintf(stdout,"mkupdate: Incorrect Processor Flags in update listing file %s\n",
ListingFile);
Error = TRUE;
break;
}
#ifdef DEBUG
fprintf(stderr,"CpuSig 0x%lx Update Rev 0x%lx Flags 0x%lx,\n",
CpuSignature,UpdateRevision,ProcessorFlags);
#endif
strcpy(UpdateTable[i].CpuSigStr,CpuSigStr);
UpdateTable[i].CpuSignature = CpuSignature;
strcpy(UpdateTable[i].UpdateRevStr,UpdateRevStr);
UpdateTable[i].UpdateRevision = UpdateRevision;
strcpy(UpdateTable[i].FlagsStr,FlagsStr);
UpdateTable[i].ProcessorFlags = ProcessorFlags;
}
fclose(TmpFilePtr);
if (Error) {
NumUpdates = 0;
free(UpdateTable);
}
}
return(NumUpdates);
}
VOID
CleanupDataFile(
VOID
)
/*++
Routine Description:
If any operation during the creation of the new Data file fails,
then delete it so that the build for the driver will fail.
Arguments:
None
Return Value:
None
--*/
{
DeleteFile(UPDATE_DATA_FILE);
}
BOOL
SanitizeUpdateList(
ULONG NumUpdates
)
/*++
Routine Description:
Sanitizes the update list. Checking for duplicate processor
signatures.
Arguments:
NumUpdates: Number of updates in the update list.
Return Value:
TRUE is list clean else FALSE.
--*/
{
ULONG i,j;
PROCESSOR_FLAGS ProcessorFlags;
//
// Check for garbage values in the update table
//
for (i = 0; i < NumUpdates-1; i++) {
if (UpdateTable[i].CpuSignature == 0) {
fprintf(stdout,"mkupdate: Error: incorrect processor signature in update list.\n");
return(FALSE);
}
if (UpdateTable[i].UpdateRevision == 0) {
fprintf(stdout,"mkupdate: Error: incorrect update revision in update list.\n");
return(FALSE);
}
if (UpdateTable[i].ProcessorFlags != 0) {
// Only a single bit must be set
ProcessorFlags.u.LongPart = UpdateTable[i].ProcessorFlags;
if (((ProcessorFlags.u.hw.Slot1) &&
(ProcessorFlags.u.LongPart & MASK_SLOT1)) ||
((ProcessorFlags.u.hw.Mobile) &&
(ProcessorFlags.u.LongPart & MASK_MOBILE)) ||
((ProcessorFlags.u.hw.Slot2) &&
(ProcessorFlags.u.LongPart & MASK_SLOT2)) ||
((ProcessorFlags.u.hw.MobileModule) &&
(ProcessorFlags.u.LongPart & MASK_MODULE)) ||
((ProcessorFlags.u.hw.Reserved1) &&
(ProcessorFlags.u.LongPart & MASK_RESERVED1)) ||
((ProcessorFlags.u.hw.Reserved2) &&
(ProcessorFlags.u.LongPart & MASK_RESERVED2)) ||
((ProcessorFlags.u.hw.Reserved3) &&
(ProcessorFlags.u.LongPart & MASK_RESERVED3)) ||
((ProcessorFlags.u.hw.Reserved4) &&
(ProcessorFlags.u.LongPart & MASK_RESERVED4))) {
fprintf(stdout,"mkupdate: Error: incorrect processor flags in update list.\n");
return(FALSE);
}
}
}
for (i = 0; i < NumUpdates-1; i++) {
for (j = i+1; j < NumUpdates; j++) {
if ((UpdateTable[i].CpuSignature == UpdateTable[j].CpuSignature)
&& (UpdateTable[i].ProcessorFlags == UpdateTable[j].ProcessorFlags)){
fprintf(stdout,"mkupdate:Error: Duplicate processor entry 0x%lx:0x%lx in update list\n",
UpdateTable[i].CpuSignature,UpdateTable[i].ProcessorFlags);
return(FALSE);
}
}
}
return(TRUE);
}
int
__cdecl main(
int argc,
LPSTR argv[]
)
/*++
Routine Description:
Scans the processor update listing file, pick up the specified
processor updates, verify the updates and generate the update
data file to be used by the update driver. Generates the
version numbers and strings to be included in the
resource definition file.
Arguments:
listing file: list of the processor updates to be included in
the driver.
Return Value:
--*/
{
FILE *DataOut, *RCFile,*VerFile;
ULONG NumUpdates,i;
CHAR Line[MAX_LINE];
CHAR *CurrentDataVersionString;
BOOL VerFileFound;
CHAR VersionFile[MAX_LINE];
CHAR *VersionDirectory;
VersionFile[0] = 0;
if (argc < 2) {
fprintf(stdout,"%s: Usage: %s <patch listing file>\n",argv[0],argv[0]);
exit(0);
}
#ifdef DEBUG
fprintf(stderr,"listing file %s\n",argv[1]);
#endif
// Open generated file UPDATE_DATA_FILE. Delete previous file if any.
DataOut=fopen(UPDATE_DATA_FILE,"w");
if (DataOut == NULL) {
fprintf(stdout,"mkupdate:Unable to open update data file %s\n",UPDATE_DATA_FILE);
exit(0);
}
// Scan listing file and store all the CPU signatures in update table
NumUpdates = PopulateUpdateList(argv[1]);
if (NumUpdates == 0) {
fprintf(stdout,"mkupdate:Listing file %s: Incorrect format or no updates specified.\n",
argv[1]);
fclose(DataOut);
exit(0);
}
//
// Dynamically allocate the size for CurrentDataVersionString
//
CurrentDataVersionString = (CHAR*)malloc(NumUpdates * UPDATE_VER_SIZE);
if (CurrentDataVersionString == NULL) {
fprintf(stdout,"mkupdate:Listing file %s: Failed to allocate memory.\n",
argv[1]);
fclose(DataOut);
exit(0);
}
// Sanitize the update list
if (!SanitizeUpdateList(NumUpdates)) {
fclose(DataOut);
DeleteFile(UPDATE_DATA_FILE);
free(CurrentDataVersionString);
exit(0);
}
// Generate the data file. First generate all headers
GenMSHeader(DataOut,UPDATE_DATA_FILE,"Processor updates.");
// generate the data segment alloc pragmas
fprintf(DataOut,"\n#ifdef ALLOC_DATA_PRAGMA\n");
fprintf(DataOut,"#pragma data_seg(\"PAGELK\")\n");
fprintf(DataOut,"#endif\n\n");
// generate the update table definition
fprintf(DataOut,"//\n// Updates data\n//\n\n");
fprintf(DataOut,"UPDATE UpdateData[] = {\n");
// include each update
for (i=0; i < NumUpdates; i++) {
if (!GetVerifyPutUpdate(DataOut,i,NumUpdates)) {
fprintf(stdout,"mkupdate:Error: processing update data file %s_%s.%s\n",
UpdateTable[i].CpuSigStr,UpdateTable[i].UpdateRevStr,
UpdateTable[i].FlagsStr);
fclose(DataOut);
CleanupDataFile();
free(CurrentDataVersionString);
exit(0);
}
}
// generate closing code for the update table definition
fprintf(DataOut,"\n};\n");
// generate the closing data segment alloc pragmas
fprintf(DataOut,"\n#ifdef ALLOC_DATA_PRAGMA\n");
fprintf(DataOut,"#pragma data_seg()\n");
fprintf(DataOut,"#endif\n\n");
//
// Generate the Update Info Table containing the
// processor signatures, processor flags, and
// pointers to MDLs (initialized to NULL)
//
BuildUpdateInfoTable(DataOut, NumUpdates);
fclose(DataOut);
// Generate the version file. Delete previous file if any.
RCFile = fopen(UPDATE_VERSION_FILE,"w");
if (RCFile == NULL) {
fprintf(stdout,"%s: Unable to open version file %s\n",
argv[0],UPDATE_VERSION_FILE);
free(CurrentDataVersionString);
exit(0);
}
// Generate header
GenMSHeader(RCFile,UPDATE_VERSION_FILE,"Version information for update device driver.");
//
// Open common.ver. If found generate the dataversion string and
// copy everything to our RC file and insert our
// string definitions in the StringFileInfo resource section. We need
// to do this because inclusion of common.ver prevents the addition
// of new string defines in the stringfileinfo block. If common.ver
// is not found in the expected place we only include it expecting the
// appropriate settings in the build environment to locate the file.
//
//
// Generate the common.ver path name
//
//
// Obtain the Drive Name
//
VersionDirectory = getenv( "_NTDRIVE" );
if (VersionDirectory == NULL) {
fprintf(stdout,"%s: Unable to obtain _NTDRIVE ENV variable\n",argv[0]);
fclose(RCFile);
free(CurrentDataVersionString);
exit(0);
}
strcpy(VersionFile, VersionDirectory);
//
// Obtain the Base Directory
//
VersionDirectory = getenv( "_NTROOT" );
if (VersionDirectory == NULL) {
fprintf(stdout,"%s: Unable to obtain _NTROOT ENV variable\n",argv[0]);
fclose(RCFile);
free(CurrentDataVersionString);
exit(0);
}
strcat(VersionFile, VersionDirectory);
strcat(VersionFile, "\\public\\sdk\\inc\\common.ver");
VerFile = fopen(VersionFile,"r");
if (VerFile == NULL) {
fprintf(stdout,"%s: Unable to open version file common.ver\n",argv[0]);
VerFileFound = FALSE;
} else {
VerFileFound = TRUE;
}
if (VerFileFound) {
// Construct data version string from update listing table
strcpy(CurrentDataVersionString,"\"");
for (i=0; i < NumUpdates; i++) {
strcat(CurrentDataVersionString,UpdateTable[i].CpuSigStr);
strcat(CurrentDataVersionString,"-");
strcat(CurrentDataVersionString,UpdateTable[i].FlagsStr);
strcat(CurrentDataVersionString,",");
strcat(CurrentDataVersionString,UpdateTable[i].UpdateRevStr);
if (i != NumUpdates-1)
strcat(CurrentDataVersionString,",");
}
strcat(CurrentDataVersionString,"\"");
#ifdef DEBUG
fprintf(stderr,"DataVersionString %s\n",CurrentDataVersionString);
#endif
fprintf(RCFile,"#define VER_DATAVERSION_STR %s\n",
CurrentDataVersionString);
// Scan till string info block into version file, add our
// definition and scan till end
while (fgets(Line,MAX_LINE,VerFile) != NULL) {
fputs(Line,RCFile);
if (strstr(Line,"VALUE") && strstr(Line,"ProductVersion")
&& strstr(Line,"VER_PRODUCTVERSION_STR")){
fprintf(RCFile," VALUE \"DataVersion\", VER_DATAVERSION_STR\n");
}
}
} else {
// version file not found. Cannot define the dataversion
// and codeversion strings. Only include common.ver
fprintf(RCFile,"\n\n#include \"common.ver\"\n");
}
fclose(RCFile);
fclose(VerFile);
free(CurrentDataVersionString);
return(0);
}