mirror of https://github.com/acidanthera/audk.git
299 lines
7.1 KiB
C
299 lines
7.1 KiB
C
/** @file
|
|
Copyright (c) 2022, Mikhail Krichanov. All rights reserved.
|
|
SPDX-License-Identifier: BSD-3-Clause
|
|
**/
|
|
|
|
#include <assert.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <stdbool.h>
|
|
|
|
#include <UserFile.h>
|
|
|
|
#define DEFAULT_MC_ALIGNMENT 16
|
|
#define DEFAULT_MC_PAD_BYTE_VALUE 0xFF
|
|
|
|
typedef struct {
|
|
UINT32 HeaderVersion;
|
|
UINT32 PatchId;
|
|
UINT32 Date;
|
|
UINT32 CpuId;
|
|
UINT32 Checksum;
|
|
UINT32 LoaderVersion;
|
|
UINT32 PlatformId;
|
|
UINT32 DataSize; // if 0, then TotalSize = 2048, and TotalSize field is invalid
|
|
UINT32 TotalSize; // number of bytes
|
|
UINT32 Reserved[3];
|
|
} MICROCODE_HEADER;
|
|
|
|
static
|
|
RETURN_STATUS
|
|
TxtToBin (
|
|
IN const char *TxtName,
|
|
IN const char *BinName
|
|
)
|
|
{
|
|
char *Txt;
|
|
char *TxtStart;
|
|
uint32_t TxtSize;
|
|
UINT32 *Buffer;
|
|
UINT32 *BufferStart;
|
|
UINT32 FileLength;
|
|
UINT32 Index;
|
|
MICROCODE_HEADER *Micro;
|
|
UINT32 CheckSum;
|
|
|
|
assert (TxtName != NULL);
|
|
assert (BinName != NULL);
|
|
|
|
Txt = (char *)UserReadFile (TxtName, &TxtSize);
|
|
if (Txt == NULL) {
|
|
fprintf (stderr, "MicroTool: Could not open %s: %s\n", TxtName, strerror (errno));
|
|
return RETURN_ABORTED;
|
|
}
|
|
|
|
Buffer = calloc (1, TxtSize);
|
|
if (Buffer == NULL) {
|
|
fprintf (stderr, "MicroTool: Could not allocate memory for Buffer\n");
|
|
free (Txt);
|
|
return RETURN_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
BufferStart = Buffer;
|
|
TxtStart = Txt;
|
|
FileLength = 0;
|
|
for (Index = 0; Index < TxtSize; ++Index, ++Txt) {
|
|
//
|
|
// Skip Blank Lines and Comment Lines
|
|
//
|
|
if (isspace ((int)*Txt)) {
|
|
continue;
|
|
}
|
|
|
|
if (*Txt == ';') {
|
|
while ((Index < TxtSize) && (*Txt != '\n')) {
|
|
++Index;
|
|
++Txt;
|
|
}
|
|
|
|
if (Index == TxtSize) {
|
|
break;
|
|
}
|
|
|
|
++Index;
|
|
++Txt;
|
|
}
|
|
//
|
|
// Look for
|
|
// dd 000000001h ; comment
|
|
// dd XXXXXXXX
|
|
// DD XXXXXXXXX
|
|
// DD XXXXXXXXX
|
|
//
|
|
if (((Index + 2) < TxtSize) && (tolower ((int)Txt[0]) == 'd') && (tolower ((int)Txt[1]) == 'd') && isspace ((int)Txt[2])) {
|
|
//
|
|
// Skip blanks and look for a hex digit
|
|
//
|
|
Txt += 3;
|
|
Index += 3;
|
|
while ((Index < TxtSize) && isspace ((int)*Txt)) {
|
|
++Index;
|
|
++Txt;
|
|
}
|
|
|
|
if (Index == TxtSize) {
|
|
break;
|
|
}
|
|
|
|
if (isxdigit ((int)*Txt)) {
|
|
if (sscanf (Txt, "%X", Buffer) != 1) {
|
|
fprintf (stderr, "MicroTool: Could not write into Buffer\n");
|
|
free (TxtStart);
|
|
free (BufferStart);
|
|
return RETURN_ABORTED;
|
|
}
|
|
|
|
while ((Index < TxtSize) && (*Txt != '\n')) {
|
|
++Index;
|
|
++Txt;
|
|
}
|
|
}
|
|
|
|
++Buffer;
|
|
FileLength += sizeof (*Buffer);
|
|
continue;
|
|
}
|
|
|
|
fprintf (stderr, "MicroTool: Corrupted input file\n");
|
|
break;
|
|
}
|
|
|
|
free (TxtStart);
|
|
|
|
if (FileLength == 0) {
|
|
fprintf (stderr, "MicroTool: No parseable data found in file %s\n", TxtName);
|
|
free (BufferStart);
|
|
return RETURN_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (FileLength < sizeof (MICROCODE_HEADER)) {
|
|
fprintf (stderr, "MicroTool: Amount of parsable data in %s is insufficient to contain a microcode header\n", TxtName);
|
|
free (BufferStart);
|
|
return RETURN_VOLUME_CORRUPTED;
|
|
}
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
Micro = (MICROCODE_HEADER *)BufferStart;
|
|
if (Micro->DataSize == 0) {
|
|
Index = 2048;
|
|
} else {
|
|
Index = Micro->TotalSize;
|
|
}
|
|
|
|
if (Index != FileLength) {
|
|
fprintf (stderr, "MicroTool: File length of %s (0x%x) does not equal expected TotalSize: 0x%04X\n", TxtName, FileLength, Index);
|
|
free (BufferStart);
|
|
return RETURN_VOLUME_CORRUPTED;
|
|
}
|
|
|
|
//
|
|
// Checksum the contents
|
|
//
|
|
Buffer = BufferStart;
|
|
CheckSum = 0;
|
|
Index = 0;
|
|
while (Index < FileLength) {
|
|
CheckSum += *Buffer;
|
|
|
|
++Buffer;
|
|
Index += sizeof (*Buffer);
|
|
}
|
|
|
|
if (CheckSum != 0) {
|
|
fprintf (stderr, "MicroTool: Checksum (0x%x) failed on file %s\n", CheckSum, TxtName);
|
|
free (BufferStart);
|
|
return RETURN_VOLUME_CORRUPTED;
|
|
}
|
|
|
|
UserWriteFile (BinName, BufferStart, FileLength);
|
|
|
|
free (BufferStart);
|
|
|
|
return RETURN_SUCCESS;
|
|
}
|
|
|
|
static
|
|
RETURN_STATUS
|
|
Merge (
|
|
IN const char *Output,
|
|
IN const char *FileNames[],
|
|
IN UINT32 NumOfFiles
|
|
)
|
|
{
|
|
void *File;
|
|
uint32_t FileSize;
|
|
UINT32 Index;
|
|
UINT32 Total;
|
|
char *Buffer;
|
|
char *BufferStart;
|
|
UINT32 Addend;
|
|
|
|
assert (Output != NULL);
|
|
assert (FileNames != NULL);
|
|
|
|
Total = 0;
|
|
|
|
for (Index = 0; Index < NumOfFiles; ++Index) {
|
|
File = UserReadFile (FileNames[Index], &FileSize);
|
|
if (File == NULL) {
|
|
fprintf (stderr, "MicroTool: Could not open %s: %s\n", FileNames[Index], strerror (errno));
|
|
return RETURN_ABORTED;
|
|
}
|
|
|
|
Total += ALIGN_VALUE (FileSize, DEFAULT_MC_ALIGNMENT);
|
|
|
|
free (File);
|
|
}
|
|
|
|
Buffer = calloc (1, Total);
|
|
if (Buffer == NULL) {
|
|
fprintf (stderr, "MicroTool: Could not allocate memory for Buffer\n");
|
|
return RETURN_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
BufferStart = Buffer;
|
|
|
|
for (Index = 0; Index < NumOfFiles; ++Index) {
|
|
File = UserReadFile (FileNames[Index], &FileSize);
|
|
if (File == NULL) {
|
|
fprintf (stderr, "MicroTool: Could not reopen %s: %s\n", FileNames[Index], strerror (errno));
|
|
free (BufferStart);
|
|
return RETURN_ABORTED;
|
|
}
|
|
|
|
memcpy (Buffer, File, FileSize);
|
|
Buffer += FileSize;
|
|
|
|
Addend = ALIGN_VALUE_ADDEND (FileSize, DEFAULT_MC_ALIGNMENT);
|
|
memset (Buffer, DEFAULT_MC_PAD_BYTE_VALUE, Addend);
|
|
Buffer += Addend;
|
|
|
|
free (File);
|
|
}
|
|
|
|
UserWriteFile (Output, BufferStart, Total);
|
|
|
|
free (BufferStart);
|
|
|
|
return RETURN_SUCCESS;
|
|
}
|
|
|
|
int main (int argc, const char *argv[])
|
|
{
|
|
RETURN_STATUS Status;
|
|
UINT32 NumOfFiles;
|
|
|
|
if (argc < 2) {
|
|
fprintf (stderr, "MicroTool: No command is specified\n");
|
|
assert (false);
|
|
return -1;
|
|
}
|
|
|
|
if (strcmp (argv[1], "TxtToBin") == 0) {
|
|
if (argc < 4) {
|
|
fprintf (stderr, "MicroTool: Command arguments are missing\n");
|
|
fprintf (stderr, " Usage: MicroTool TxtToBin InputFile OutputFile\n");
|
|
assert (false);
|
|
return -1;
|
|
}
|
|
|
|
Status = TxtToBin (argv[2], argv [3]);
|
|
if (RETURN_ERROR (Status)) {
|
|
assert (false);
|
|
return -1;
|
|
}
|
|
} else if (strcmp (argv[1], "Merge") == 0) {
|
|
if (argc < 4) {
|
|
fprintf (stderr, "MicroTool: Command arguments are missing\n");
|
|
fprintf (stderr, " Usage: MicroTool Merge OutputFile InputFile1 InputFile2 ...\n");
|
|
assert (false);
|
|
return -1;
|
|
}
|
|
|
|
NumOfFiles = (UINT32)argc - 3U;
|
|
|
|
Status = Merge (argv[2], &argv[3], NumOfFiles);
|
|
if (RETURN_ERROR (Status)) {
|
|
assert (false);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|