edk2/UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.c
Mingjie Shen f77646dccf UefiCpuPkg: Replace manual alignment checks with helper macros
Replace manual alignment checks with IS_ALIGNED() and
ADDRESS_IS_ALIGNED().

Convert the following bitmask and modulo forms:

- ((E & ((PowOf2Expr) - ONE)) == ZERO)
- ((E & ((PowOf2Expr) - ONE)) != ZERO)
- ((E % (PowOf2Expr)) == ZERO)
- ((E % (PowOf2Expr)) != ZERO)

to the corresponding helper macro forms:

+ IS_ALIGNED (E, PowOf2Expr)
+ !IS_ALIGNED (E, PowOf2Expr)

PowOf2Expr is limited to known power-of-two expressions, including
SIZE_* and BASE_* macros, EFI_PAGE_SIZE, CPU_STACK_ALIGNMENT,
RUNTIME_PAGE_ALLOCATION_GRANULARITY, sizeof() of UEFI integer types
(e.g. BOOLEAN, CHAR16, UINT32, UINTN) and pointer types, and 1 << E1
expressions.

Address checks that cast the checked value to UINTN are written with
ADDRESS_IS_ALIGNED().

The change was generated with the Coccinelle semantic patch below.

```smpl
@power_of_2_expr@
expression PowOf2Expr;
expression E1;
typedef BOOLEAN, CHAR8, CHAR16, INT8, UINT8, INT16, UINT16, INT32, UINT32, INT64, UINT64, INTN, UINTN;
type ScalarType = { BOOLEAN, CHAR8, CHAR16, INT8, UINT8, INT16, UINT16, INT32, UINT32, INT64, UINT64, INTN, UINTN };
type AnyType;
type PointerType = AnyType *;
idexpression ScalarType ScalarValue;
idexpression PointerType PointerValue;
constant SizeBase =~ "^(SIZE|BASE)_(1|2|4|8|16|32|64|128|256|512)[KMGTPE]B$";
constant NamedPowerOf2 =~ "^(EFI_PAGE_SIZE|CPU_STACK_ALIGNMENT|RUNTIME_PAGE_ALLOCATION_GRANULARITY)$";
constant ONE = {1, 1U, 1u};
@@
(
(
  SizeBase
|
  NamedPowerOf2
|
  ONE << E1
|
  sizeof (ScalarType)
|
  sizeof (PointerType)
|
  sizeof (ScalarValue)
|
  sizeof (PointerValue)
)
&
PowOf2Expr
)

@aligned depends on power_of_2_expr disable is_zero,isnt_zero@
expression E;
expression power_of_2_expr.PowOf2Expr;
constant ONE = {1, 1U, 1u};
constant ZERO = {0, 0U, 0u};
@@
(
  ((E & (E - ONE)) == ZERO)
|
- ((E & ((PowOf2Expr) - ONE)) == ZERO)
+ IS_ALIGNED (E, PowOf2Expr)
|
  ((E & (E - ONE)) != ZERO)
|
- ((E & ((PowOf2Expr) - ONE)) != ZERO)
+ !IS_ALIGNED (E, PowOf2Expr)
|
- ((E % (PowOf2Expr)) == ZERO)
+ IS_ALIGNED (E, PowOf2Expr)
|
- ((E % (PowOf2Expr)) != ZERO)
+ !IS_ALIGNED (E, PowOf2Expr)
)

@address_is_aligned@
typedef UINTN;
expression *Address;
expression Alignment;
@@
- IS_ALIGNED ((UINTN) Address, Alignment)
+ ADDRESS_IS_ALIGNED (Address, Alignment)

@normalize_aligned disable paren expression@
expression E, SZ;
@@
(
- (IS_ALIGNED (E, SZ))
+ IS_ALIGNED (E, SZ)
|
- (!IS_ALIGNED (E, SZ))
+ !IS_ALIGNED (E, SZ)
)

@normalize_macro_args disable paren expression@
expression E, SZ;
@@
(
- IS_ALIGNED ((E), SZ)
+ IS_ALIGNED (E, SZ)
|
- IS_ALIGNED (E, (SZ))
+ IS_ALIGNED (E, SZ)
)
```

Signed-off-by: Mingjie Shen <shen497@purdue.edu>
2026-06-09 07:20:10 +00:00

331 lines
11 KiB
C

/** @file
Implementation of MicrocodeLib.
Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Uefi/UefiBaseType.h>
#include <Register/Intel/Cpuid.h>
#include <Register/Intel/ArchitecturalMsr.h>
#include <Register/Intel/Microcode.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Ppi/ShadowMicrocode.h>
/**
Get microcode update signature of currently loaded microcode update.
@return Microcode signature.
**/
UINT32
EFIAPI
GetProcessorMicrocodeSignature (
VOID
)
{
MSR_IA32_BIOS_SIGN_ID_REGISTER BiosSignIdMsr;
AsmWriteMsr64 (MSR_IA32_BIOS_SIGN_ID, 0);
AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);
BiosSignIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_BIOS_SIGN_ID);
return BiosSignIdMsr.Bits.MicrocodeUpdateSignature;
}
/**
Get the processor signature and platform ID for current processor.
@param MicrocodeCpuId Return the processor signature and platform ID.
**/
VOID
EFIAPI
GetProcessorMicrocodeCpuId (
EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId
)
{
MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr;
ASSERT (MicrocodeCpuId != NULL);
PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID);
MicrocodeCpuId->PlatformId = (UINT8)PlatformIdMsr.Bits.PlatformId;
AsmCpuid (CPUID_VERSION_INFO, &MicrocodeCpuId->ProcessorSignature, NULL, NULL, NULL);
}
/**
Return the total size of the microcode entry.
Logic follows pseudo code in SDM as below:
N = 512
If (Update.DataSize != 00000000H)
N = Update.TotalSize / 4
If Microcode is NULL, then ASSERT.
@param Microcode Pointer to the microcode entry.
@return The microcode total size.
**/
UINT32
EFIAPI
GetMicrocodeLength (
IN CPU_MICROCODE_HEADER *Microcode
)
{
UINT32 TotalSize;
ASSERT (Microcode != NULL);
TotalSize = 2048;
if (Microcode->DataSize != 0) {
TotalSize = Microcode->TotalSize;
}
return TotalSize;
}
/**
Load the microcode to the processor.
If Microcode is NULL, then ASSERT.
@param Microcode Pointer to the microcode entry.
**/
VOID
EFIAPI
LoadMicrocode (
IN CPU_MICROCODE_HEADER *Microcode
)
{
ASSERT (Microcode != NULL);
AsmWriteMsr64 (MSR_IA32_BIOS_UPDT_TRIG, (UINT64)(UINTN)(Microcode + 1));
}
/**
Determine if a microcode patch matchs the specific processor signature and flag.
@param[in] ProcessorSignature The processor signature field value in a
microcode patch.
@param[in] ProcessorFlags The processor flags field value in a
microcode patch.
@param[in] MicrocodeCpuId A pointer to an array of EDKII_PEI_MICROCODE_CPU_ID
structures.
@param[in] MicrocodeCpuIdCount Number of elements in MicrocodeCpuId array.
@retval TRUE The specified microcode patch matches to one of the MicrocodeCpuId.
@retval FALSE The specified microcode patch doesn't match to any of the MicrocodeCpuId.
**/
BOOLEAN
IsProcessorMatchedMicrocode (
IN UINT32 ProcessorSignature,
IN UINT32 ProcessorFlags,
IN EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId,
IN UINTN MicrocodeCpuIdCount
)
{
UINTN Index;
if (MicrocodeCpuIdCount == 0) {
return TRUE;
}
for (Index = 0; Index < MicrocodeCpuIdCount; Index++) {
if ((ProcessorSignature == MicrocodeCpuId[Index].ProcessorSignature) &&
((ProcessorFlags & (1 << MicrocodeCpuId[Index].PlatformId)) != 0))
{
return TRUE;
}
}
return FALSE;
}
/**
Detect whether specified processor can find matching microcode patch and load it.
Microcode format is as below:
+----------------------------------------+-------------------------------------------------+
| CPU_MICROCODE_HEADER | |
+----------------------------------------+ V
| Update Data | CPU_MICROCODE_HEADER.Checksum
+----------------------------------------+-------+ ^
| CPU_MICROCODE_EXTENDED_TABLE_HEADER | | |
+----------------------------------------+ V |
| CPU_MICROCODE_EXTENDED_TABLE[0] | CPU_MICROCODE_EXTENDED_TABLE_HEADER.Checksum |
| CPU_MICROCODE_EXTENDED_TABLE[1] | ^ |
| ... | | |
+----------------------------------------+-------+-----------------------------------------+
There may by multiple CPU_MICROCODE_EXTENDED_TABLE in this format.
The count of CPU_MICROCODE_EXTENDED_TABLE is indicated by ExtendedSignatureCount
of CPU_MICROCODE_EXTENDED_TABLE_HEADER structure.
If Microcode is NULL, then ASSERT.
@param Microcode Pointer to a microcode entry.
@param MicrocodeLength The total length of the microcode entry.
@param MinimumRevision The microcode whose revision <= MinimumRevision is treated as invalid.
Caller can supply value get from GetProcessorMicrocodeSignature() to check
whether the microcode is newer than loaded one.
Caller can supply 0 to treat any revision (except 0) microcode as valid.
@param MicrocodeCpuIds Pointer to an array of processor signature and platform ID that represents
a set of processors.
Caller can supply zero-element array to skip the processor signature and
platform ID check.
@param MicrocodeCpuIdCount The number of elements in MicrocodeCpuIds.
@param VerifyChecksum FALSE to skip all the checksum verifications.
@retval TRUE The microcode is valid.
@retval FALSE The microcode is invalid.
**/
BOOLEAN
EFIAPI
IsValidMicrocode (
IN CPU_MICROCODE_HEADER *Microcode,
IN UINTN MicrocodeLength,
IN UINT32 MinimumRevision,
IN EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuIds,
IN UINTN MicrocodeCpuIdCount,
IN BOOLEAN VerifyChecksum
)
{
UINTN Index;
UINT32 DataSize;
UINT32 TotalSize;
CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;
CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;
UINT32 ExtendedTableLength;
UINT32 Sum32;
BOOLEAN Match;
ASSERT (Microcode != NULL);
//
// It's invalid when:
// the input microcode buffer is so small that even cannot contain the header.
// the input microcode buffer is so large that exceeds MAX_ADDRESS.
//
if ((MicrocodeLength < sizeof (CPU_MICROCODE_HEADER)) || (MicrocodeLength > (MAX_ADDRESS - (UINTN)Microcode))) {
return FALSE;
}
//
// Per SDM, HeaderVersion and LoaderRevision should both be 1.
//
if ((Microcode->HeaderVersion != 1) || (Microcode->LoaderRevision != 1)) {
return FALSE;
}
//
// The microcode revision should be larger than the minimum revision.
//
if (Microcode->UpdateRevision <= MinimumRevision) {
return FALSE;
}
DataSize = Microcode->DataSize;
if (DataSize == 0) {
DataSize = 2000;
}
//
// Per SDM, DataSize should be multiple of DWORDs.
//
if ((DataSize % 4) != 0) {
return FALSE;
}
TotalSize = GetMicrocodeLength (Microcode);
//
// Check whether the whole microcode is within the buffer.
// TotalSize should be multiple of 1024.
//
if (!IS_ALIGNED (TotalSize, SIZE_1KB) || (TotalSize > MicrocodeLength)) {
return FALSE;
}
//
// The summation of all DWORDs in microcode should be zero.
//
if (VerifyChecksum && (CalculateSum32 ((UINT32 *)Microcode, TotalSize) != 0)) {
return FALSE;
}
Sum32 = Microcode->ProcessorSignature.Uint32 + Microcode->ProcessorFlags + Microcode->Checksum;
//
// Check the processor signature and platform ID in the primary header.
//
Match = IsProcessorMatchedMicrocode (
Microcode->ProcessorSignature.Uint32,
Microcode->ProcessorFlags,
MicrocodeCpuIds,
MicrocodeCpuIdCount
);
if (Match) {
return TRUE;
}
ExtendedTableLength = TotalSize - (DataSize + sizeof (CPU_MICROCODE_HEADER));
if ((ExtendedTableLength < sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER)) || ((ExtendedTableLength % 4) != 0)) {
return FALSE;
}
//
// Extended Table exist, check if the CPU in support list
//
ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINTN)(Microcode + 1) + DataSize);
if (ExtendedTableHeader->ExtendedSignatureCount > MAX_UINT32 / sizeof (CPU_MICROCODE_EXTENDED_TABLE)) {
return FALSE;
}
if (ExtendedTableHeader->ExtendedSignatureCount * sizeof (CPU_MICROCODE_EXTENDED_TABLE)
> ExtendedTableLength - sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER))
{
return FALSE;
}
//
// Check the extended table checksum
//
if (VerifyChecksum && (CalculateSum32 ((UINT32 *)ExtendedTableHeader, ExtendedTableLength) != 0)) {
return FALSE;
}
ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);
for (Index = 0; Index < ExtendedTableHeader->ExtendedSignatureCount; Index++) {
if (VerifyChecksum &&
(ExtendedTable[Index].ProcessorSignature.Uint32 + ExtendedTable[Index].ProcessorFlag
+ ExtendedTable[Index].Checksum != Sum32))
{
//
// The extended table entry is valid when the summation of Processor Signature, Processor Flags
// and Checksum equal to the coresponding summation from primary header. Because:
// CalculateSum32 (Header + Update Binary) == 0
// CalculateSum32 (Header + Update Binary)
// - (Header.ProcessorSignature + Header.ProcessorFlag + Header.Checksum)
// + (Extended.ProcessorSignature + Extended.ProcessorFlag + Extended.Checksum) == 0
// So,
// (Header.ProcessorSignature + Header.ProcessorFlag + Header.Checksum)
// == (Extended.ProcessorSignature + Extended.ProcessorFlag + Extended.Checksum)
//
continue;
}
Match = IsProcessorMatchedMicrocode (
ExtendedTable[Index].ProcessorSignature.Uint32,
ExtendedTable[Index].ProcessorFlag,
MicrocodeCpuIds,
MicrocodeCpuIdCount
);
if (Match) {
return TRUE;
}
}
return FALSE;
}