Step to UEFI (117)Shell 下的 CPUID 工具

以前编写过 DOS 下 CPUID的工具,这次偶然在github上看到了 UEFI版本的 CPUID工具【参考1】,于是尝试编写一个 Application。
代码很长,但大部分是根据 BIT 解析信息的部分。

/** @file
  UEFI Application to display CPUID leaf information.

  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
  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.

**/
#include <Uefi.h>
#include <Library/BaseLib.h>
#include <Library/UefiLib.h>
#include "Cpuid.h"
#include  <Library/ShellCEntryLib.h>

///
/// Macro used to display the value of a bit field in a register returned by CPUID.
///
#define PRINT_BIT_FIELD(Variable, FieldName) \
  Print (L"%5a%42a: %x\n", #Variable, #FieldName, Variable.Bits.FieldName);

///
/// Macro used to display the value of a register returned by CPUID.
///
#define PRINT_VALUE(Variable, Description) \
  Print (L"%5a%42a: %x\n", #Variable, #Description, Variable);

///
/// Structure for cache description lookup table
///
typedef struct {
  UINT8  CacheDescriptor;
  CHAR8  *Type;
  CHAR8  *Description;
} CPUID_CACHE_INFO_DESCRIPTION;

///
/// Cache description lookup table
///
CPUID_CACHE_INFO_DESCRIPTION  mCpuidCacheInfoDescription[] = {
  { 0x00 , "General"  , "Null descriptor, this byte contains no information" },
  { 0x01 , "TLB"      , "Instruction TLB: 4 KByte pages, 4-way set associative, 32 entries" },
  { 0x02 , "TLB"      , "Instruction TLB: 4 MByte pages, fully associative, 2 entries" },
  { 0x03 , "TLB"      , "Data TLB: 4 KByte pages, 4-way set associative, 64 entries" },
  { 0x04 , "TLB"      , "Data TLB: 4 MByte pages, 4-way set associative, 8 entries" },
  { 0x05 , "TLB"      , "Data TLB1: 4 MByte pages, 4-way set associative, 32 entries" },
  { 0x06 , "Cache"    , "1st-level instruction cache: 8 KBytes, 4-way set associative, 32 byte line size" },
  { 0x08 , "Cache"    , "1st-level instruction cache: 16 KBytes, 4-way set associative, 32 byte line size" },
  { 0x09 , "Cache"    , "1st-level instruction cache: 32KBytes, 4-way set associative, 64 byte line size" },
  { 0x0A , "Cache"    , "1st-level data cache: 8 KBytes, 2-way set associative, 32 byte line size" },
  { 0x0B , "TLB"      , "Instruction TLB: 4 MByte pages, 4-way set associative, 4 entries" },
  { 0x0C , "Cache"    , "1st-level data cache: 16 KBytes, 4-way set associative, 32 byte line size" },
  { 0x0D , "Cache"    , "1st-level data cache: 16 KBytes, 4-way set associative, 64 byte line size" },
  { 0x0E , "Cache"    , "1st-level data cache: 24 KBytes, 6-way set associative, 64 byte line size" },
  { 0x1D , "Cache"    , "2nd-level cache: 128 KBytes, 2-way set associative, 64 byte line size" },
  { 0x21 , "Cache"    , "2nd-level cache: 256 KBytes, 8-way set associative, 64 byte line size" },
  { 0x22 , "Cache"    , "3rd-level cache: 512 KBytes, 4-way set associative, 64 byte line size, 2 lines per sector" },
  { 0x23 , "Cache"    , "3rd-level cache: 1 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector" },
  { 0x24 , "Cache"    , "2nd-level cache: 1 MBytes, 16-way set associative, 64 byte line size" },
  { 0x25 , "Cache"    , "3rd-level cache: 2 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector" },
  { 0x29 , "Cache"    , "3rd-level cache: 4 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector" },
  { 0x2C , "Cache"    , "1st-level data cache: 32 KBytes, 8-way set associative, 64 byte line size" },
  { 0x30 , "Cache"    , "1st-level instruction cache: 32 KBytes, 8-way set associative, 64 byte line size" },
  { 0x40 , "Cache"    , "No 2nd-level cache or, if processor contains a valid 2nd-level cache, no 3rd-level cache" },
  { 0x41 , "Cache"    , "2nd-level cache: 128 KBytes, 4-way set associative, 32 byte line size" },
  { 0x42 , "Cache"    , "2nd-level cache: 256 KBytes, 4-way set associative, 32 byte line size" },
  { 0x43 , "Cache"    , "2nd-level cache: 512 KBytes, 4-way set associative, 32 byte line size" },
  { 0x44 , "Cache"    , "2nd-level cache: 1 MByte, 4-way set associative, 32 byte line size" },
  { 0x45 , "Cache"    , "2nd-level cache: 2 MByte, 4-way set associative, 32 byte line size" },
  { 0x46 , "Cache"    , "3rd-level cache: 4 MByte, 4-way set associative, 64 byte line size" },
  { 0x47 , "Cache"    , "3rd-level cache: 8 MByte, 8-way set associative, 64 byte line size" },
  { 0x48 , "Cache"    , "2nd-level cache: 3MByte, 12-way set associative, 64 byte line size" },
  { 0x49 , "Cache"    , "3rd-level cache: 4MB, 16-way set associative, 64-byte line size (Intel Xeon processor MP, Family 0FH, Model 06H). 2nd-level cache: 4 MByte, 16-way set associative, 64 byte line size" },
  { 0x4A , "Cache"    , "3rd-level cache: 6MByte, 12-way set associative, 64 byte line size" },
  { 0x4B , "Cache"    , "3rd-level cache: 8MByte, 16-way set associative, 64 byte line size" },
  { 0x4C , "Cache"    , "3rd-level cache: 12MByte, 12-way set associative, 64 byte line size" },
  { 0x4D , "Cache"    , "3rd-level cache: 16MByte, 16-way set associative, 64 byte line size" },
  { 0x4E , "Cache"    , "2nd-level cache: 6MByte, 24-way set associative, 64 byte line size" },
  { 0x4F , "TLB"      , "Instruction TLB: 4 KByte pages, 32 entries" },
  { 0x50 , "TLB"      , "Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 64 entries" },
  { 0x51 , "TLB"      , "Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 128 entries" },
  { 0x52 , "TLB"      , "Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 256 entries" },
  { 0x55 , "TLB"      , "Instruction TLB: 2-MByte or 4-MByte pages, fully associative, 7 entries" },
  { 0x56 , "TLB"      , "Data TLB0: 4 MByte pages, 4-way set associative, 16 entries" },
  { 0x57 , "TLB"      , "Data TLB0: 4 KByte pages, 4-way associative, 16 entries" },
  { 0x59 , "TLB"      , "Data TLB0: 4 KByte pages, fully associative, 16 entries" },
  { 0x5A , "TLB"      , "Data TLB0: 2 MByte or 4 MByte pages, 4-way set associative, 32 entries" },
  { 0x5B , "TLB"      , "Data TLB: 4 KByte and 4 MByte pages, 64 entries" },
  { 0x5C , "TLB"      , "Data TLB: 4 KByte and 4 MByte pages,128 entries" },
  { 0x5D , "TLB"      , "Data TLB: 4 KByte and 4 MByte pages,256 entries" },
  { 0x60 , "Cache"    , "1st-level data cache: 16 KByte, 8-way set associative, 64 byte line size" },
  { 0x61 , "TLB"      , "Instruction TLB: 4 KByte pages, fully associative, 48 entries" },
  { 0x63 , "TLB"      , "Data TLB: 2 MByte or 4 MByte pages, 4-way set associative, 32 entries and a separate array with 1 GByte pages, 4-way set associative, 4 entries" },
  { 0x64 , "TLB"      , "Data TLB: 4 KByte pages, 4-way set associative, 512 entries" },
  { 0x66 , "Cache"    , "1st-level data cache: 8 KByte, 4-way set associative, 64 byte line size" },
  { 0x67 , "Cache"    , "1st-level data cache: 16 KByte, 4-way set associative, 64 byte line size" },
  { 0x68 , "Cache"    , "1st-level data cache: 32 KByte, 4-way set associative, 64 byte line size" },
  { 0x6A , "Cache"    , "uTLB: 4 KByte pages, 8-way set associative, 64 entries" },
  { 0x6B , "Cache"    , "DTLB: 4 KByte pages, 8-way set associative, 256 entries" },
  { 0x6C , "Cache"    , "DTLB: 2M/4M pages, 8-way set associative, 128 entries" },
  { 0x6D , "Cache"    , "DTLB: 1 GByte pages, fully associative, 16 entries" },
  { 0x70 , "Cache"    , "Trace cache: 12 K-uop, 8-way set associative" },
  { 0x71 , "Cache"    , "Trace cache: 16 K-uop, 8-way set associative" },
  { 0x72 , "Cache"    , "Trace cache: 32 K-uop, 8-way set associative" },
  { 0x76 , "TLB"      , "Instruction TLB: 2M/4M pages, fully associative, 8 entries" },
  { 0x78 , "Cache"    , "2nd-level cache: 1 MByte, 4-way set associative, 64byte line size" },
  { 0x79 , "Cache"    , "2nd-level cache: 128 KByte, 8-way set associative, 64 byte line size, 2 lines per sector" },
  { 0x7A , "Cache"    , "2nd-level cache: 256 KByte, 8-way set associative, 64 byte line size, 2 lines per sector" },
  { 0x7B , "Cache"    , "2nd-level cache: 512 KByte, 8-way set associative, 64 byte line size, 2 lines per sector" },
  { 0x7C , "Cache"    , "2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size, 2 lines per sector" },
  { 0x7D , "Cache"    , "2nd-level cache: 2 MByte, 8-way set associative, 64byte line size" },
  { 0x7F , "Cache"    , "2nd-level cache: 512 KByte, 2-way set associative, 64-byte line size" },
  { 0x80 , "Cache"    , "2nd-level cache: 512 KByte, 8-way set associative, 64-byte line size" },
  { 0x82 , "Cache"    , "2nd-level cache: 256 KByte, 8-way set associative, 32 byte line size" },
  { 0x83 , "Cache"    , "2nd-level cache: 512 KByte, 8-way set associative, 32 byte line size" },
  { 0x84 , "Cache"    , "2nd-level cache: 1 MByte, 8-way set associative, 32 byte line size" },
  { 0x85 , "Cache"    , "2nd-level cache: 2 MByte, 8-way set associative, 32 byte line size" },
  { 0x86 , "Cache"    , "2nd-level cache: 512 KByte, 4-way set associative, 64 byte line size" },
  { 0x87 , "Cache"    , "2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size" },
  { 0xA0 , "DTLB"     , "DTLB: 4k pages, fully associative, 32 entries" },
  { 0xB0 , "TLB"      , "Instruction TLB: 4 KByte pages, 4-way set associative, 128 entries" },
  { 0xB1 , "TLB"      , "Instruction TLB: 2M pages, 4-way, 8 entries or 4M pages, 4-way, 4 entries" },
  { 0xB2 , "TLB"      , "Instruction TLB: 4KByte pages, 4-way set associative, 64 entries" },
  { 0xB3 , "TLB"      , "Data TLB: 4 KByte pages, 4-way set associative, 128 entries" },
  { 0xB4 , "TLB"      , "Data TLB1: 4 KByte pages, 4-way associative, 256 entries" },
  { 0xB5 , "TLB"      , "Instruction TLB: 4KByte pages, 8-way set associative, 64 entries" },
  { 0xB6 , "TLB"      , "Instruction TLB: 4KByte pages, 8-way set associative, 128 entries" },
  { 0xBA , "TLB"      , "Data TLB1: 4 KByte pages, 4-way associative, 64 entries" },
  { 0xC0 , "TLB"      , "Data TLB: 4 KByte and 4 MByte pages, 4-way associative, 8 entries" },
  { 0xC1 , "STLB"     , "Shared 2nd-Level TLB: 4 KByte/2MByte pages, 8-way associative, 1024 entries" },
  { 0xC2 , "DTLB"     , "DTLB: 4 KByte/2 MByte pages, 4-way associative, 16 entries" },
  { 0xC3 , "STLB"     , "Shared 2nd-Level TLB: 4 KByte /2 MByte pages, 6-way associative, 1536 entries. Also 1GBbyte pages, 4-way, 16 entries." },
  { 0xC4 , "DTLB"     , "DTLB: 2M/4M Byte pages, 4-way associative, 32 entries" },
  { 0xCA , "STLB"     , "Shared 2nd-Level TLB: 4 KByte pages, 4-way associative, 512 entries" },
  { 0xD0 , "Cache"    , "3rd-level cache: 512 KByte, 4-way set associative, 64 byte line size" },
  { 0xD1 , "Cache"    , "3rd-level cache: 1 MByte, 4-way set associative, 64 byte line size" },
  { 0xD2 , "Cache"    , "3rd-level cache: 2 MByte, 4-way set associative, 64 byte line size" },
  { 0xD6 , "Cache"    , "3rd-level cache: 1 MByte, 8-way set associative, 64 byte line size" },
  { 0xD7 , "Cache"    , "3rd-level cache: 2 MByte, 8-way set associative, 64 byte line size" },
  { 0xD8 , "Cache"    , "3rd-level cache: 4 MByte, 8-way set associative, 64 byte line size" },
  { 0xDC , "Cache"    , "3rd-level cache: 1.5 MByte, 12-way set associative, 64 byte line size" },
  { 0xDD , "Cache"    , "3rd-level cache: 3 MByte, 12-way set associative, 64 byte line size" },
  { 0xDE , "Cache"    , "3rd-level cache: 6 MByte, 12-way set associative, 64 byte line size" },
  { 0xE2 , "Cache"    , "3rd-level cache: 2 MByte, 16-way set associative, 64 byte line size" },
  { 0xE3 , "Cache"    , "3rd-level cache: 4 MByte, 16-way set associative, 64 byte line size" },
  { 0xE4 , "Cache"    , "3rd-level cache: 8 MByte, 16-way set associative, 64 byte line size" },
  { 0xEA , "Cache"    , "3rd-level cache: 12MByte, 24-way set associative, 64 byte line size" },
  { 0xEB , "Cache"    , "3rd-level cache: 18MByte, 24-way set associative, 64 byte line size" },
  { 0xEC , "Cache"    , "3rd-level cache: 24MByte, 24-way set associative, 64 byte line size" },
  { 0xF0 , "Prefetch" , "64-Byte prefetching" },
  { 0xF1 , "Prefetch" , "128-Byte prefetching" },
  { 0xFF , "General"  , "CPUID leaf 2 does not report cache descriptor information, use CPUID leaf 4 to query cache parameters" }
};

///
/// The maximum supported CPUID leaf index starting from leaf 0x00000000.
///
UINT32  gMaximumBasicFunction    = CPUID_SIGNATURE;

///
/// The maximum supported CPUID leaf index starting from leaf 0x80000000.
///
UINT32  gMaximumExtendedFunction = CPUID_EXTENDED_FUNCTION;

/**
  Display CPUID_SIGNATURE leaf.

**/
VOID
CpuidSignature (
  VOID
  )
{
  UINT32 Eax;
  UINT32 Ebx;
  UINT32 Ecx;
  UINT32 Edx;
  CHAR8  Signature[13];

  AsmCpuid (CPUID_SIGNATURE, &Eax, &Ebx, &Ecx, &Edx);

  Print (L"CPUID_SIGNATURE (Leaf %08x)\n", CPUID_SIGNATURE);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax, Ebx, Ecx, Edx);
  PRINT_VALUE (Eax, MaximumLeaf);
  *(UINT32 *)(Signature + 0) = Ebx;
  *(UINT32 *)(Signature + 4) = Edx;
  *(UINT32 *)(Signature + 8) = Ecx;
  Signature [12] = 0;
  Print (L"  Signature = %a\n", Signature);

  gMaximumBasicFunction = Eax;
}

/**
  Display CPUID_VERSION_INFO leaf.

**/
VOID
CpuidVersionInfo (
  VOID
  )
{
  CPUID_VERSION_INFO_EAX  Eax;
  CPUID_VERSION_INFO_EBX  Ebx;
  CPUID_VERSION_INFO_ECX  Ecx;
  CPUID_VERSION_INFO_EDX  Edx;
  UINT32                  DisplayFamily;
  UINT32                  DisplayModel;

  if (CPUID_VERSION_INFO > gMaximumBasicFunction) {
    return;
  }

  AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, &Ebx.Uint32, &Ecx.Uint32, &Edx.Uint32);

  Print (L"CPUID_VERSION_INFO (Leaf %08x)\n", CPUID_VERSION_INFO);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax.Uint32, Ebx.Uint32, Ecx.Uint32, Edx.Uint32);

  DisplayFamily = Eax.Bits.FamilyId;
  if (Eax.Bits.FamilyId == 0x0F) {
    DisplayFamily |= (Eax.Bits.ExtendedFamilyId << 4);
  }

  DisplayModel = Eax.Bits.Model;
  if (Eax.Bits.FamilyId == 0x06 || Eax.Bits.FamilyId == 0x0f) {
    DisplayModel |= (Eax.Bits.ExtendedModelId << 4);
  }

  Print (L"  Family = %x  Model = %x  Stepping = %x\n", DisplayFamily, DisplayModel, Eax.Bits.SteppingId);

  PRINT_BIT_FIELD (Eax, SteppingId);
  PRINT_BIT_FIELD (Eax, Model);
  PRINT_BIT_FIELD (Eax, FamilyId);
  PRINT_BIT_FIELD (Eax, ProcessorType);
  PRINT_BIT_FIELD (Eax, ExtendedModelId);
  PRINT_BIT_FIELD (Eax, ExtendedFamilyId);
  PRINT_BIT_FIELD (Ebx, BrandIndex);
  PRINT_BIT_FIELD (Ebx, CacheLineSize);
  PRINT_BIT_FIELD (Ebx, MaximumAddressableIdsForLogicalProcessors);
  PRINT_BIT_FIELD (Ebx, InitialLocalApicId);
  PRINT_BIT_FIELD (Ecx, SSE3);
  PRINT_BIT_FIELD (Ecx, PCLMULQDQ);
  PRINT_BIT_FIELD (Ecx, DTES64);
  PRINT_BIT_FIELD (Ecx, MONITOR);
  PRINT_BIT_FIELD (Ecx, DS_CPL);
  PRINT_BIT_FIELD (Ecx, VMX);
  PRINT_BIT_FIELD (Ecx, SMX);
  PRINT_BIT_FIELD (Ecx, TM2);
  PRINT_BIT_FIELD (Ecx, SSSE3);
  PRINT_BIT_FIELD (Ecx, CNXT_ID);
  PRINT_BIT_FIELD (Ecx, SDBG);
  PRINT_BIT_FIELD (Ecx, FMA);
  PRINT_BIT_FIELD (Ecx, CMPXCHG16B);
  PRINT_BIT_FIELD (Ecx, xTPR_Update_Control);
  PRINT_BIT_FIELD (Ecx, PDCM);
  PRINT_BIT_FIELD (Ecx, PCID);
  PRINT_BIT_FIELD (Ecx, DCA);
  PRINT_BIT_FIELD (Ecx, SSE4_1);
  PRINT_BIT_FIELD (Ecx, SSE4_2);
  PRINT_BIT_FIELD (Ecx, x2APIC);
  PRINT_BIT_FIELD (Ecx, MOVBE);
  PRINT_BIT_FIELD (Ecx, POPCNT);
  PRINT_BIT_FIELD (Ecx, TSC_Deadline);
  PRINT_BIT_FIELD (Ecx, AESNI);
  PRINT_BIT_FIELD (Ecx, XSAVE);
  PRINT_BIT_FIELD (Ecx, OSXSAVE);
  PRINT_BIT_FIELD (Ecx, AVX);
  PRINT_BIT_FIELD (Ecx, F16C);
  PRINT_BIT_FIELD (Ecx, RDRAND);
  PRINT_BIT_FIELD (Edx, FPU);
  PRINT_BIT_FIELD (Edx, VME);
  PRINT_BIT_FIELD (Edx, DE);
  PRINT_BIT_FIELD (Edx, PSE);
  PRINT_BIT_FIELD (Edx, TSC);
  PRINT_BIT_FIELD (Edx, MSR);
  PRINT_BIT_FIELD (Edx, PAE);
  PRINT_BIT_FIELD (Edx, MCE);
  PRINT_BIT_FIELD (Edx, CX8);
  PRINT_BIT_FIELD (Edx, APIC);
  PRINT_BIT_FIELD (Edx, SEP);
  PRINT_BIT_FIELD (Edx, MTRR);
  PRINT_BIT_FIELD (Edx, PGE);
  PRINT_BIT_FIELD (Edx, MCA);
  PRINT_BIT_FIELD (Edx, CMOV);
  PRINT_BIT_FIELD (Edx, PAT);
  PRINT_BIT_FIELD (Edx, PSE_36);
  PRINT_BIT_FIELD (Edx, PSN);
  PRINT_BIT_FIELD (Edx, CLFSH);
  PRINT_BIT_FIELD (Edx, DS);
  PRINT_BIT_FIELD (Edx, ACPI);
  PRINT_BIT_FIELD (Edx, MMX);
  PRINT_BIT_FIELD (Edx, FXSR);
  PRINT_BIT_FIELD (Edx, SSE);
  PRINT_BIT_FIELD (Edx, SSE2);
  PRINT_BIT_FIELD (Edx, SS);
  PRINT_BIT_FIELD (Edx, HTT);
  PRINT_BIT_FIELD (Edx, TM);
  PRINT_BIT_FIELD (Edx, PBE);
}

/**
  Lookup a cache description string from the mCpuidCacheInfoDescription table.

  @param[in] CacheDescriptor  Cache descriptor value from CPUID_CACHE_INFO.

**/
CPUID_CACHE_INFO_DESCRIPTION *
LookupCacheDescription (
  UINT8  CacheDescriptor
  )
{
  UINTN  NumDescriptors;
  UINTN  Descriptor;

  if (CacheDescriptor == 0x00) {
    return NULL;
  }
  NumDescriptors = sizeof (mCpuidCacheInfoDescription)/sizeof (mCpuidCacheInfoDescription[0]);
  for (Descriptor = 0; Descriptor < NumDescriptors; Descriptor++) {
    if (CacheDescriptor == mCpuidCacheInfoDescription[Descriptor].CacheDescriptor) {
      return &mCpuidCacheInfoDescription[Descriptor];
    }
  }
  return NULL;
}

/**
  Display CPUID_CACHE_INFO leaf for each supported cache descriptor.

**/
VOID
CpuidCacheInfo (
  VOID
  )
{
  CPUID_CACHE_INFO_CACHE_TLB    Eax;
  CPUID_CACHE_INFO_CACHE_TLB    Ebx;
  CPUID_CACHE_INFO_CACHE_TLB    Ecx;
  CPUID_CACHE_INFO_CACHE_TLB    Edx;
  UINTN                         Index;
  CPUID_CACHE_INFO_DESCRIPTION  *CacheDescription;

  if (CPUID_CACHE_INFO > gMaximumBasicFunction) {
    return;
  }

  AsmCpuid (CPUID_CACHE_INFO, &Eax.Uint32, &Ebx.Uint32, &Ecx.Uint32, &Edx.Uint32);

  Print (L"CPUID_CACHE_INFO (Leaf %08x)\n", CPUID_CACHE_INFO);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax.Uint32, Ebx.Uint32, Ecx.Uint32, Edx.Uint32);
  if (Eax.Bits.NotValid == 0) {
    //
    // Process Eax.CacheDescriptor[1..3].  Ignore Eax.CacheDescriptor[0]
    //
    for (Index = 1; Index < 4; Index++) {
      CacheDescription = LookupCacheDescription (Eax.CacheDescriptor[Index]);
      if (CacheDescription != NULL) {
        Print (L"  %-8a %a\n",
          CacheDescription->Type,
          CacheDescription->Description
          );
      }
    }
  }
  if (Ebx.Bits.NotValid == 0) {
    //
    // Process Ebx.CacheDescriptor[0..3]
    //
    for (Index = 0; Index < 4; Index++) {
      CacheDescription = LookupCacheDescription (Ebx.CacheDescriptor[Index]);
      if (CacheDescription != NULL) {
        Print (L"  %-8a %a\n",
          CacheDescription->Type,
          CacheDescription->Description
          );
      }
    }
  }
  if (Ecx.Bits.NotValid == 0) {
    //
    // Process Ecx.CacheDescriptor[0..3]
    //
    for (Index = 0; Index < 4; Index++) {
      CacheDescription = LookupCacheDescription (Ecx.CacheDescriptor[Index]);
      if (CacheDescription != NULL) {
        Print (L"  %-8a %a\n",
          CacheDescription->Type,
          CacheDescription->Description
          );
      }
    }
  }
  if (Edx.Bits.NotValid == 0) {
    //
    // Process Edx.CacheDescriptor[0..3]
    //
    for (Index = 0; Index < 4; Index++) {
      CacheDescription = LookupCacheDescription (Edx.CacheDescriptor[Index]);
      if (CacheDescription != NULL) {
        Print (L"  %-8a %a\n",
          CacheDescription->Type,
          CacheDescription->Description
          );
      }
    }
  }
}

/**
  Display CPUID_SERIAL_NUMBER leaf if it is supported.

**/
VOID
CpuidSerialNumber (
  VOID
  )
{
  CPUID_VERSION_INFO_EDX  VersionInfoEdx;
  UINT32                  Ecx;
  UINT32                  Edx;

  Print (L"CPUID_SERIAL_NUMBER (Leaf %08x)\n", CPUID_SERIAL_NUMBER);

  if (CPUID_SERIAL_NUMBER > gMaximumBasicFunction) {
    return;
  }

  AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
  if (VersionInfoEdx.Bits.PSN == 0) {
    Print (L"  Not Supported\n");
    return;
  }

  AsmCpuid (CPUID_SERIAL_NUMBER, NULL, NULL, &Ecx, &Edx);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", 0, 0, Ecx, Edx);
  Print (L"  Processor Serial Number = %08x%08x%08x\n", 0, Edx, Ecx);
}

/**
  Display CPUID_CACHE_PARAMS for all supported sub-leafs.

**/
VOID
CpuidCacheParams (
  VOID
  )
{
  UINT32                  CacheLevel;
  CPUID_CACHE_PARAMS_EAX  Eax;
  CPUID_CACHE_PARAMS_EBX  Ebx;
  UINT32                  Ecx;
  CPUID_CACHE_PARAMS_EDX  Edx;

  if (CPUID_CACHE_PARAMS > gMaximumBasicFunction) {
    return;
  }

  CacheLevel = 0;
  do {
    AsmCpuidEx (
      CPUID_CACHE_PARAMS, CacheLevel,
      &Eax.Uint32, &Ebx.Uint32, &Ecx, &Edx.Uint32
      );
    if (Eax.Bits.CacheType != CPUID_CACHE_PARAMS_CACHE_TYPE_NULL) {
      Print (L"CPUID_CACHE_PARAMS (Leaf %08x, Sub-Leaf %08x)\n", CPUID_CACHE_PARAMS, CacheLevel);
      Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax.Uint32, Ebx.Uint32, Ecx, Edx.Uint32);
      PRINT_BIT_FIELD (Eax, CacheType);
      PRINT_BIT_FIELD (Eax, CacheLevel);
      PRINT_BIT_FIELD (Eax, SelfInitializingCache);
      PRINT_BIT_FIELD (Eax, FullyAssociativeCache);
      PRINT_BIT_FIELD (Eax, MaximumAddressableIdsForLogicalProcessors);
      PRINT_BIT_FIELD (Eax, MaximumAddressableIdsForProcessorCores);
      PRINT_BIT_FIELD (Ebx, LineSize);
      PRINT_BIT_FIELD (Ebx, LinePartitions);
      PRINT_BIT_FIELD (Ebx, Ways);
      PRINT_VALUE     (Ecx, NumberOfSets);
      PRINT_BIT_FIELD (Edx, Invalidate);
      PRINT_BIT_FIELD (Edx, CacheInclusiveness);
      PRINT_BIT_FIELD (Edx, ComplexCacheIndexing);
    }
    CacheLevel++;
  } while (Eax.Bits.CacheType != CPUID_CACHE_PARAMS_CACHE_TYPE_NULL);
}

/**
  Display CPUID_MONITOR_MWAIT leaf.

**/
VOID
CpuidMonitorMwait (
  VOID
  )
{
  CPUID_MONITOR_MWAIT_EAX  Eax;
  CPUID_MONITOR_MWAIT_EBX  Ebx;
  CPUID_MONITOR_MWAIT_ECX  Ecx;
  CPUID_MONITOR_MWAIT_EDX  Edx;

  if (CPUID_MONITOR_MWAIT > gMaximumBasicFunction) {
    return;
  }

  AsmCpuid (CPUID_MONITOR_MWAIT, &Eax.Uint32, &Ebx.Uint32, &Ecx.Uint32, &Edx.Uint32);

  Print (L"CPUID_MONITOR_MWAIT (Leaf %08x)\n", CPUID_MONITOR_MWAIT);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax.Uint32, Ebx.Uint32, Ecx.Uint32, Edx.Uint32);

  PRINT_BIT_FIELD (Eax, SmallestMonitorLineSize);
  PRINT_BIT_FIELD (Ebx, LargestMonitorLineSize);
  PRINT_BIT_FIELD (Ecx, ExtensionsSupported);
  PRINT_BIT_FIELD (Ecx, InterruptAsBreak);
  PRINT_BIT_FIELD (Edx, C0States);
  PRINT_BIT_FIELD (Edx, C1States);
  PRINT_BIT_FIELD (Edx, C2States);
  PRINT_BIT_FIELD (Edx, C3States);
  PRINT_BIT_FIELD (Edx, C4States);
  PRINT_BIT_FIELD (Edx, C5States);
  PRINT_BIT_FIELD (Edx, C6States);
  PRINT_BIT_FIELD (Edx, C7States);
}

/**
  Display CPUID_THERMAL_POWER_MANAGEMENT leaf.

**/
VOID
CpuidThermalPowerManagement (
  VOID
  )
{
  CPUID_THERMAL_POWER_MANAGEMENT_EAX  Eax;
  CPUID_THERMAL_POWER_MANAGEMENT_EBX  Ebx;
  CPUID_THERMAL_POWER_MANAGEMENT_ECX  Ecx;

  if (CPUID_THERMAL_POWER_MANAGEMENT > gMaximumBasicFunction) {
    return;
  }

  AsmCpuid (CPUID_THERMAL_POWER_MANAGEMENT, &Eax.Uint32, &Ebx.Uint32, &Ecx.Uint32, NULL);

  Print (L"CPUID_THERMAL_POWER_MANAGEMENT (Leaf %08x)\n", CPUID_THERMAL_POWER_MANAGEMENT);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax.Uint32, Ebx.Uint32, Ecx.Uint32, 0);

  PRINT_BIT_FIELD (Eax, DigitalTemperatureSensor);
  PRINT_BIT_FIELD (Eax, TurboBoostTechnology);
  PRINT_BIT_FIELD (Eax, ARAT);
  PRINT_BIT_FIELD (Eax, PLN);
  PRINT_BIT_FIELD (Eax, ECMD);
  PRINT_BIT_FIELD (Eax, PTM);
  PRINT_BIT_FIELD (Eax, HWP);
  PRINT_BIT_FIELD (Eax, HWP_Notification);
  PRINT_BIT_FIELD (Eax, HWP_Activity_Window);
  PRINT_BIT_FIELD (Eax, HWP_Energy_Performance_Preference);
  PRINT_BIT_FIELD (Eax, HWP_Package_Level_Request);
  PRINT_BIT_FIELD (Eax, HDC);
  PRINT_BIT_FIELD (Ebx, InterruptThresholds);
  PRINT_BIT_FIELD (Ecx, HardwareCoordinationFeedback);
  PRINT_BIT_FIELD (Ecx, PerformanceEnergyBias);
}

/**
  Display CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS for all supported sub-leafs.

**/
VOID
CpuidStructuredExtendedFeatureFlags (
  VOID
  )
{
  UINT32                                       Eax;
  CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_EBX  Ebx;
  CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_ECX  Ecx;
  UINT32                                       SubLeaf;

  if (CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS > gMaximumBasicFunction) {
    return;
  }

  AsmCpuidEx (
    CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS,
    CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_SUB_LEAF_INFO,
    &Eax, NULL, NULL, NULL
    );
  for (SubLeaf = 0; SubLeaf <= Eax; SubLeaf++) {
    AsmCpuidEx (
      CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS,
      SubLeaf,
      NULL, &Ebx.Uint32, &Ecx.Uint32, NULL
      );
    if (Ebx.Uint32 != 0 || Ecx.Uint32 != 0) {
      Print (L"CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS (Leaf %08x, Sub-Leaf %08x)\n", CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS, SubLeaf);
      Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax, Ebx.Uint32, Ecx.Uint32, 0);
      PRINT_BIT_FIELD (Ebx, FSGSBASE);
      PRINT_BIT_FIELD (Ebx, IA32_TSC_ADJUST);
      PRINT_BIT_FIELD (Ebx, SGX);
      PRINT_BIT_FIELD (Ebx, BMI1);
      PRINT_BIT_FIELD (Ebx, HLE);
      PRINT_BIT_FIELD (Ebx, AVX2);
      PRINT_BIT_FIELD (Ebx, FDP_EXCPTN_ONLY);
      PRINT_BIT_FIELD (Ebx, SMEP);
      PRINT_BIT_FIELD (Ebx, BMI2);
      PRINT_BIT_FIELD (Ebx, EnhancedRepMovsbStosb);
      PRINT_BIT_FIELD (Ebx, INVPCID);
      PRINT_BIT_FIELD (Ebx, RTM);
      PRINT_BIT_FIELD (Ebx, RDT_M);
      PRINT_BIT_FIELD (Ebx, DeprecateFpuCsDs);
      PRINT_BIT_FIELD (Ebx, MPX);
      PRINT_BIT_FIELD (Ebx, RDT_A);
      PRINT_BIT_FIELD (Ebx, RDSEED);
      PRINT_BIT_FIELD (Ebx, ADX);
      PRINT_BIT_FIELD (Ebx, SMAP);
      PRINT_BIT_FIELD (Ebx, CLFLUSHOPT);
      PRINT_BIT_FIELD (Ebx, CLWB);
      PRINT_BIT_FIELD (Ebx, IntelProcessorTrace);
      PRINT_BIT_FIELD (Ebx, SHA);
      PRINT_BIT_FIELD (Ecx, PREFETCHWT1);
      PRINT_BIT_FIELD (Ecx, UMIP);
      PRINT_BIT_FIELD (Ecx, PKU);
      PRINT_BIT_FIELD (Ecx, OSPKE);
      PRINT_BIT_FIELD (Ecx, MAWAU);
      PRINT_BIT_FIELD (Ecx, RDPID);
      PRINT_BIT_FIELD (Ecx, SGX_LC);
    }
  }
}

/**
  Display CPUID_DIRECT_CACHE_ACCESS_INFO leaf.

**/
VOID
CpuidDirectCacheAccessInfo (
  VOID
  )
{
  UINT32  Eax;

  if (CPUID_DIRECT_CACHE_ACCESS_INFO > gMaximumBasicFunction) {
    return;
  }

  AsmCpuid (CPUID_DIRECT_CACHE_ACCESS_INFO, &Eax, NULL, NULL, NULL);
  Print (L"CPUID_DIRECT_CACHE_ACCESS_INFO (Leaf %08x)\n", CPUID_DIRECT_CACHE_ACCESS_INFO);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax, 0, 0, 0);
}

/**
  Display CPUID_ARCHITECTURAL_PERFORMANCE_MONITORING leaf.

**/
VOID
CpuidArchitecturalPerformanceMonitoring (
  VOID
  )
{
  CPUID_ARCHITECTURAL_PERFORMANCE_MONITORING_EAX  Eax;
  CPUID_ARCHITECTURAL_PERFORMANCE_MONITORING_EBX  Ebx;
  CPUID_ARCHITECTURAL_PERFORMANCE_MONITORING_EDX  Edx;

  if (CPUID_ARCHITECTURAL_PERFORMANCE_MONITORING > gMaximumBasicFunction) {
    return;
  }

  AsmCpuid (CPUID_ARCHITECTURAL_PERFORMANCE_MONITORING, &Eax.Uint32, &Ebx.Uint32, NULL, &Edx.Uint32);
  Print (L"CPUID_ARCHITECTURAL_PERFORMANCE_MONITORING (Leaf %08x)\n", CPUID_ARCHITECTURAL_PERFORMANCE_MONITORING);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax.Uint32, Ebx.Uint32, 0, Edx.Uint32);
  PRINT_BIT_FIELD (Eax, ArchPerfMonVerID);
  PRINT_BIT_FIELD (Eax, PerformanceMonitorCounters);
  PRINT_BIT_FIELD (Eax, PerformanceMonitorCounterWidth);
  PRINT_BIT_FIELD (Eax, EbxBitVectorLength);
  PRINT_BIT_FIELD (Ebx, UnhaltedCoreCycles);
  PRINT_BIT_FIELD (Ebx, InstructionsRetired);
  PRINT_BIT_FIELD (Ebx, UnhaltedReferenceCycles);
  PRINT_BIT_FIELD (Ebx, LastLevelCacheReferences);
  PRINT_BIT_FIELD (Ebx, LastLevelCacheMisses);
  PRINT_BIT_FIELD (Ebx, BranchInstructionsRetired);
  PRINT_BIT_FIELD (Ebx, AllBranchMispredictRetired);
  PRINT_BIT_FIELD (Edx, FixedFunctionPerformanceCounters);
  PRINT_BIT_FIELD (Edx, FixedFunctionPerformanceCounterWidth);
}

/**
  Display CPUID_EXTENDED_TOPOLOGY leafs for all supported levels.

**/
VOID
CpuidExtendedTopology (
  VOID
  )
{
  CPUID_EXTENDED_TOPOLOGY_EAX  Eax;
  CPUID_EXTENDED_TOPOLOGY_EBX  Ebx;
  CPUID_EXTENDED_TOPOLOGY_ECX  Ecx;
  UINT32                       Edx;
  UINT32                       LevelNumber;

  if (CPUID_EXTENDED_TOPOLOGY > gMaximumBasicFunction) {
    return;
  }

  LevelNumber = 0;
  do {
    AsmCpuidEx (
      CPUID_EXTENDED_TOPOLOGY, LevelNumber,
      &Eax.Uint32, &Ebx.Uint32, &Ecx.Uint32, &Edx
      );
    if (Eax.Bits.ApicIdShift != 0) {
      Print (L"CPUID_EXTENDED_TOPOLOGY (Leaf %08x, Sub-Leaf %08x)\n", CPUID_EXTENDED_TOPOLOGY, LevelNumber);
      Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax.Uint32, Ebx.Uint32, Ecx.Uint32, Edx);
      PRINT_BIT_FIELD (Eax, ApicIdShift);
      PRINT_BIT_FIELD (Ebx, LogicalProcessors);
      PRINT_BIT_FIELD (Ecx, LevelNumber);
      PRINT_BIT_FIELD (Ecx, LevelType);
      PRINT_VALUE     (Edx, x2APIC_ID);
    }
    LevelNumber++;
  } while (Eax.Bits.ApicIdShift != 0);
}

/**
  Display CPUID_EXTENDED_STATE sub-leaf.

**/
VOID
CpuidExtendedStateSubLeaf (
  VOID
  )
{
  CPUID_EXTENDED_STATE_SUB_LEAF_EAX  Eax;
  UINT32                             Ebx;
  CPUID_EXTENDED_STATE_SUB_LEAF_ECX  Ecx;
  UINT32                             Edx;

  AsmCpuidEx (
    CPUID_EXTENDED_STATE, CPUID_EXTENDED_STATE_SUB_LEAF,
    &Eax.Uint32, &Ebx, &Ecx.Uint32, &Edx
    );
  Print (L"CPUID_EXTENDED_STATE (Leaf %08x, Sub-Leaf %08x)\n", CPUID_EXTENDED_STATE, CPUID_EXTENDED_STATE_SUB_LEAF);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax.Uint32, Ebx, Ecx.Uint32, Edx);
  PRINT_BIT_FIELD (Eax, XSAVEOPT);
  PRINT_BIT_FIELD (Eax, XSAVEC);
  PRINT_BIT_FIELD (Eax, XGETBV);
  PRINT_BIT_FIELD (Eax, XSAVES);
  PRINT_VALUE     (Ebx, EnabledSaveStateSize_XCR0_IA32_XSS);
  PRINT_BIT_FIELD (Ecx, XCR0);
  PRINT_BIT_FIELD (Ecx, PT);
  PRINT_BIT_FIELD (Ecx, XCR0_1);
  PRINT_VALUE     (Edx, IA32_XSS_Supported_32_63);
}

/**
  Display CPUID_EXTENDED_STATE size and offset information sub-leaf.

**/
VOID
CpuidExtendedStateSizeOffset (
  VOID
  )
{
  UINT32                                Eax;
  UINT32                                Ebx;
  CPUID_EXTENDED_STATE_SIZE_OFFSET_ECX  Ecx;
  UINT32                                Edx;
  UINT32                                SubLeaf;

  for (SubLeaf = CPUID_EXTENDED_STATE_SIZE_OFFSET; SubLeaf < 32; SubLeaf++) {
    AsmCpuidEx (
      CPUID_EXTENDED_STATE, SubLeaf,
      &Eax, &Ebx, &Ecx.Uint32, &Edx
      );
    if (Edx != 0) {
      Print (L"CPUID_EXTENDED_STATE (Leaf %08x, Sub-Leaf %08x)\n", CPUID_EXTENDED_STATE, SubLeaf);
      Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax, Ebx, Ecx.Uint32, Edx);
      PRINT_VALUE     (Eax, FeatureSaveStateSize);
      PRINT_VALUE     (Ebx, FeatureSaveStateOffset);
      PRINT_BIT_FIELD (Ecx, XSS);
      PRINT_BIT_FIELD (Ecx, Compacted);
    }
  }
}

/**
  Display CPUID_EXTENDED_STATE main leaf and sub-leafs.

**/
VOID
CpuidExtendedStateMainLeaf (
  VOID
  )
{
  CPUID_EXTENDED_STATE_MAIN_LEAF_EAX  Eax;
  UINT32                              Ebx;
  UINT32                              Ecx;
  UINT32                              Edx;

  if (CPUID_EXTENDED_STATE > gMaximumBasicFunction) {
    return;
  }

  AsmCpuidEx (
    CPUID_EXTENDED_STATE, CPUID_EXTENDED_STATE_MAIN_LEAF,
    &Eax.Uint32, &Ebx, &Ecx, &Edx
    );
  Print (L"CPUID_EXTENDED_STATE (Leaf %08x, Sub-Leaf %08x)\n", CPUID_EXTENDED_STATE, CPUID_EXTENDED_STATE_MAIN_LEAF);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax.Uint32, Ebx, Ecx, Edx);
  PRINT_BIT_FIELD (Eax, x87);
  PRINT_BIT_FIELD (Eax, SSE);
  PRINT_BIT_FIELD (Eax, AVX);
  PRINT_BIT_FIELD (Eax, MPX);
  PRINT_BIT_FIELD (Eax, AVX_512);
  PRINT_BIT_FIELD (Eax, IA32_XSS);
  PRINT_BIT_FIELD (Eax, PKRU);
  PRINT_VALUE     (Ebx, EnabledSaveStateSize);
  PRINT_VALUE     (Ecx, SupportedSaveStateSize);
  PRINT_VALUE     (Edx, XCR0_Supported_32_63);

  CpuidExtendedStateSubLeaf ();
  CpuidExtendedStateSizeOffset ();
}

/**
  Display CPUID_INTEL_RDT_MONITORING enumeration sub-leaf.

**/
VOID
CpuidIntelRdtMonitoringEnumerationSubLeaf (
  VOID
  )
{
  UINT32                                                  Ebx;
  CPUID_INTEL_RDT_MONITORING_ENUMERATION_SUB_LEAF_EDX     Edx;

  if (CPUID_INTEL_RDT_MONITORING > gMaximumBasicFunction) {
    return;
  }

  AsmCpuidEx (
    CPUID_INTEL_RDT_MONITORING, CPUID_INTEL_RDT_MONITORING_ENUMERATION_SUB_LEAF,
    NULL, &Ebx, NULL, &Edx.Uint32
    );
  Print (L"CPUID_INTEL_RDT_MONITORING (Leaf %08x, Sub-Leaf %08x)\n", CPUID_INTEL_RDT_MONITORING, CPUID_INTEL_RDT_MONITORING_ENUMERATION_SUB_LEAF);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", 0, Ebx, 0, Edx.Uint32);
  PRINT_VALUE     (Ebx, Maximum_RMID_Range);
  PRINT_BIT_FIELD (Edx, L3CacheRDT_M);
}

/**
  Display CPUID_INTEL_RDT_MONITORING L3 cache capability sub-leaf.

**/
VOID
CpuidIntelRdtMonitoringL3CacheCapabilitySubLeaf (
  VOID
  )
{
  UINT32                                                 Ebx;
  UINT32                                                 Ecx;
  CPUID_INTEL_RDT_MONITORING_L3_CACHE_SUB_LEAF_EDX       Edx;

  if (CPUID_INTEL_RDT_MONITORING > gMaximumBasicFunction) {
    return;
  }

  AsmCpuidEx (
    CPUID_INTEL_RDT_MONITORING, CPUID_INTEL_RDT_MONITORING_L3_CACHE_SUB_LEAF,
    NULL, &Ebx, &Ecx, &Edx.Uint32
    );
  Print (L"CPUID_INTEL_RDT_MONITORING (Leaf %08x, Sub-Leaf %08x)\n", CPUID_INTEL_RDT_MONITORING, CPUID_INTEL_RDT_MONITORING_L3_CACHE_SUB_LEAF);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", 0, Ebx, Ecx, Edx.Uint32);
  PRINT_VALUE     (Ebx, OccupancyConversionFactor);
  PRINT_VALUE     (Ecx, Maximum_RMID_Range);
  PRINT_BIT_FIELD (Edx, L3CacheOccupancyMonitoring);
  PRINT_BIT_FIELD (Edx, L3CacheTotalBandwidthMonitoring);
  PRINT_BIT_FIELD (Edx, L3CacheLocalBandwidthMonitoring);
}

/**
  Display CPUID_INTEL_RDT_ALLOCATION L3 cache allocation technology enumeration
  sub-leaf.

**/
VOID
CpuidIntelRdtAllocationL3CacheSubLeaf (
  VOID
  )
{
  CPUID_INTEL_RDT_ALLOCATION_L3_CACHE_SUB_LEAF_EAX  Eax;
  UINT32                                            Ebx;
  CPUID_INTEL_RDT_ALLOCATION_L3_CACHE_SUB_LEAF_ECX  Ecx;
  CPUID_INTEL_RDT_ALLOCATION_L3_CACHE_SUB_LEAF_EDX  Edx;

  AsmCpuidEx (
    CPUID_INTEL_RDT_ALLOCATION, CPUID_INTEL_RDT_ALLOCATION_L3_CACHE_SUB_LEAF,
    &Eax.Uint32, &Ebx, &Ecx.Uint32, &Edx.Uint32
    );
  Print (L"CPUID_INTEL_RDT_ALLOCATION (Leaf %08x, Sub-Leaf %08x)\n", CPUID_INTEL_RDT_ALLOCATION, CPUID_INTEL_RDT_ALLOCATION_L3_CACHE_SUB_LEAF);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax.Uint32, Ebx, Ecx.Uint32, Edx.Uint32);
  PRINT_BIT_FIELD (Eax, CapacityLength);
  PRINT_VALUE     (Ebx, AllocationUnitBitMap);
  PRINT_BIT_FIELD (Ecx, CosUpdatesInfrequent);
  PRINT_BIT_FIELD (Ecx, CodeDataPrioritization);
  PRINT_BIT_FIELD (Edx, HighestCosNumber);
}

/**
  Display CPUID_INTEL_RDT_ALLOCATION L2 cache allocation technology enumeration
  sub-leaf.

**/
VOID
CpuidIntelRdtAllocationL2CacheSubLeaf (
  VOID
  )
{
  CPUID_INTEL_RDT_ALLOCATION_L2_CACHE_SUB_LEAF_EAX  Eax;
  UINT32                                            Ebx;
  CPUID_INTEL_RDT_ALLOCATION_L2_CACHE_SUB_LEAF_EDX  Edx;

  AsmCpuidEx (
    CPUID_INTEL_RDT_ALLOCATION, CPUID_INTEL_RDT_ALLOCATION_L2_CACHE_SUB_LEAF,
    &Eax.Uint32, &Ebx, NULL, &Edx.Uint32
    );
  Print (L"CPUID_INTEL_RDT_ALLOCATION (Leaf %08x, Sub-Leaf %08x)\n", CPUID_INTEL_RDT_ALLOCATION, CPUID_INTEL_RDT_ALLOCATION_L2_CACHE_SUB_LEAF);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax.Uint32, Ebx, 0, Edx.Uint32);
  PRINT_BIT_FIELD (Eax, CapacityLength);
  PRINT_VALUE     (Ebx, AllocationUnitBitMap);
  PRINT_BIT_FIELD (Edx, HighestCosNumber);
}

/**
  Display CPUID_INTEL_RDT_ALLOCATION main leaf and sub-leaves.

**/
VOID
CpuidIntelRdtAllocationMainLeaf (
  VOID
  )
{
  CPUID_INTEL_RDT_ALLOCATION_ENUMERATION_SUB_LEAF_EBX  Ebx;

  if (CPUID_INTEL_RDT_ALLOCATION > gMaximumBasicFunction) {
    return;
  }

  AsmCpuidEx (
    CPUID_INTEL_RDT_ALLOCATION, CPUID_INTEL_RDT_ALLOCATION_ENUMERATION_SUB_LEAF,
    NULL, &Ebx.Uint32, NULL, NULL
    );
  Print (L"CPUID_INTEL_RDT_ALLOCATION (Leaf %08x, Sub-Leaf %08x)\n", CPUID_INTEL_RDT_ALLOCATION, CPUID_INTEL_RDT_ALLOCATION_ENUMERATION_SUB_LEAF);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", 0, Ebx.Uint32, 0, 0);
  PRINT_BIT_FIELD (Ebx, L3CacheAllocation);
  PRINT_BIT_FIELD (Ebx, L2CacheAllocation);

  CpuidIntelRdtAllocationL3CacheSubLeaf ();
  CpuidIntelRdtAllocationL2CacheSubLeaf ();
}

/**
  Display Sub-Leaf 0 Enumeration of Intel SGX Capabilities.

**/
VOID
CpuidEnumerationOfIntelSgxCapabilities0SubLeaf (
  VOID
  )
{
  CPUID_INTEL_SGX_CAPABILITIES_0_SUB_LEAF_EAX  Eax;
  UINT32                                       Ebx;
  CPUID_INTEL_SGX_CAPABILITIES_0_SUB_LEAF_EDX  Edx;

  AsmCpuidEx (
    CPUID_INTEL_SGX, CPUID_INTEL_SGX_CAPABILITIES_0_SUB_LEAF,
    &Eax.Uint32, &Ebx, NULL, &Edx.Uint32
    );
  Print (L"CPUID_INTEL_SGX (Leaf %08x, Sub-Leaf %08x)\n", CPUID_INTEL_SGX, CPUID_INTEL_SGX_CAPABILITIES_0_SUB_LEAF);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax.Uint32, Ebx, 0, Edx.Uint32);
  PRINT_BIT_FIELD (Eax, SGX1);
  PRINT_BIT_FIELD (Eax, SGX2);
  PRINT_BIT_FIELD (Edx, MaxEnclaveSize_Not64);
  PRINT_BIT_FIELD (Edx, MaxEnclaveSize_64);
}

/**
  Display Sub-Leaf 1 Enumeration of Intel SGX Capabilities.

**/
VOID
CpuidEnumerationOfIntelSgxCapabilities1SubLeaf (
  VOID
  )
{
  UINT32                                       Eax;
  UINT32                                       Ebx;
  UINT32                                       Ecx;
  UINT32                                       Edx;

  AsmCpuidEx (
    CPUID_INTEL_SGX, CPUID_INTEL_SGX_CAPABILITIES_1_SUB_LEAF,
    &Eax, &Ebx, &Ecx, &Edx
    );
  Print (L"CPUID_INTEL_SGX (Leaf %08x, Sub-Leaf %08x)\n", CPUID_INTEL_SGX, CPUID_INTEL_SGX_CAPABILITIES_1_SUB_LEAF);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax, Ebx, Ecx, Edx);
}

/**
  Display Sub-Leaf Index 2 or Higher Enumeration of Intel SGX Resources.

**/
VOID
CpuidEnumerationOfIntelSgxResourcesSubLeaf (
  VOID
  )
{
  CPUID_INTEL_SGX_CAPABILITIES_RESOURCES_SUB_LEAF_EAX  Eax;
  CPUID_INTEL_SGX_CAPABILITIES_RESOURCES_SUB_LEAF_EBX  Ebx;
  CPUID_INTEL_SGX_CAPABILITIES_RESOURCES_SUB_LEAF_ECX  Ecx;
  CPUID_INTEL_SGX_CAPABILITIES_RESOURCES_SUB_LEAF_EDX  Edx;
  UINT32                                               SubLeaf;
 
  SubLeaf = CPUID_INTEL_SGX_CAPABILITIES_RESOURCES_SUB_LEAF;
  do {
    AsmCpuidEx (
      CPUID_INTEL_SGX, SubLeaf,
      &Eax.Uint32, &Ebx.Uint32, &Ecx.Uint32, &Edx.Uint32
      );
    if (Eax.Bits.SubLeafType == 0x1) {
      Print (L"CPUID_INTEL_SGX (Leaf %08x, Sub-Leaf %08x)\n", CPUID_INTEL_SGX, SubLeaf);
      Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax.Uint32, Ebx.Uint32, Ecx.Uint32, Edx.Uint32);
      PRINT_BIT_FIELD (Eax, SubLeafType);
      PRINT_BIT_FIELD (Eax, LowAddressOfEpcSection);
      PRINT_BIT_FIELD (Ebx, HighAddressOfEpcSection);
      PRINT_BIT_FIELD (Ecx, EpcSection);
      PRINT_BIT_FIELD (Ecx, LowSizeOfEpcSection);
      PRINT_BIT_FIELD (Edx, HighSizeOfEpcSection);
    }
    SubLeaf++;
  } while (Eax.Bits.SubLeafType == 0x1);
}

/**
  Display Intel SGX Resource Enumeration.

**/
VOID
CpuidEnumerationOfIntelSgx (
  VOID
  )
{
  CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_EBX  Ebx;

  if (CPUID_INTEL_SGX > gMaximumBasicFunction) {
    return;
  }

  AsmCpuidEx (
    CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS,
    CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_SUB_LEAF_INFO,
    NULL, &Ebx.Uint32, NULL, NULL
    );
  if (Ebx.Bits.SGX != 1) {
    //
    // Only if CPUID.(EAX=07H, ECX=0H):EBX.SGX = 1, the processor has support
    // for Intel SGX.
    //
    return;
  }
  
  CpuidEnumerationOfIntelSgxCapabilities0SubLeaf ();
  CpuidEnumerationOfIntelSgxCapabilities1SubLeaf ();
  CpuidEnumerationOfIntelSgxResourcesSubLeaf ();
}

/**
  Display CPUID_INTEL_PROCESSOR_TRACE sub-leafs.

  @param[in] MaximumSubLeaf  Maximum sub-leaf index for CPUID_INTEL_PROCESSOR_TRACE.

**/
VOID
CpuidIntelProcessorTraceSubLeaf (
  UINT32  MaximumSubLeaf
  )
{
  UINT32                                    SubLeaf;
  CPUID_INTEL_PROCESSOR_TRACE_SUB_LEAF_EAX  Eax;
  CPUID_INTEL_PROCESSOR_TRACE_SUB_LEAF_EBX  Ebx;

  for (SubLeaf = CPUID_INTEL_PROCESSOR_TRACE_SUB_LEAF; SubLeaf <= MaximumSubLeaf; SubLeaf++) {
    AsmCpuidEx (
      CPUID_INTEL_PROCESSOR_TRACE, SubLeaf,
      &Eax.Uint32, &Ebx.Uint32, NULL, NULL
      );
    Print (L"CPUID_INTEL_PROCESSOR_TRACE (Leaf %08x, Sub-Leaf %08x)\n", CPUID_INTEL_PROCESSOR_TRACE, SubLeaf);
    Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax.Uint32, Ebx.Uint32, 0, 0);
    PRINT_BIT_FIELD (Eax, ConfigurableAddressRanges);
    PRINT_BIT_FIELD (Eax, MtcPeriodEncodings);
    PRINT_BIT_FIELD (Ebx, CycleThresholdEncodings);
    PRINT_BIT_FIELD (Ebx, PsbFrequencyEncodings);
  }
}

/**
  Display CPUID_INTEL_PROCESSOR_TRACE main leaf and sub-leafs.

**/
VOID
CpuidIntelProcessorTraceMainLeaf (
  VOID
  )
{
  UINT32                                     Eax;
  CPUID_INTEL_PROCESSOR_TRACE_MAIN_LEAF_EBX  Ebx;
  CPUID_INTEL_PROCESSOR_TRACE_MAIN_LEAF_ECX  Ecx;

  if (CPUID_INTEL_PROCESSOR_TRACE > gMaximumBasicFunction) {
    return;
  }

  AsmCpuidEx (
    CPUID_INTEL_PROCESSOR_TRACE, CPUID_INTEL_PROCESSOR_TRACE_MAIN_LEAF,
    &Eax, &Ebx.Uint32, &Ecx.Uint32, NULL
    );
  Print (L"CPUID_INTEL_PROCESSOR_TRACE (Leaf %08x, Sub-Leaf %08x)\n", CPUID_INTEL_PROCESSOR_TRACE, CPUID_INTEL_PROCESSOR_TRACE_MAIN_LEAF);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax, Ebx.Uint32, Ecx.Uint32, 0);
  PRINT_VALUE     (Eax, MaximumSubLeaf);
  PRINT_BIT_FIELD (Ebx, Cr3Filter);
  PRINT_BIT_FIELD (Ebx, ConfigurablePsb);
  PRINT_BIT_FIELD (Ebx, IpTraceStopFiltering);
  PRINT_BIT_FIELD (Ebx, Mtc);
  PRINT_BIT_FIELD (Ebx, PTWrite);
  PRINT_BIT_FIELD (Ebx, PowerEventTrace);
  PRINT_BIT_FIELD (Ecx, RTIT);
  PRINT_BIT_FIELD (Ecx, ToPA);
  PRINT_BIT_FIELD (Ecx, SingleRangeOutput);
  PRINT_BIT_FIELD (Ecx, TraceTransportSubsystem);
  PRINT_BIT_FIELD (Ecx, LIP);

  CpuidIntelProcessorTraceSubLeaf (Eax);
}

/**
  Display CPUID_TIME_STAMP_COUNTER leaf.

**/
VOID
CpuidTimeStampCounter (
  VOID
  )
{
  UINT32  Eax;
  UINT32  Ebx;
  UINT32  Ecx;

  if (CPUID_TIME_STAMP_COUNTER > gMaximumBasicFunction) {
    return;
  }

  AsmCpuid (CPUID_TIME_STAMP_COUNTER, &Eax, &Ebx, &Ecx, NULL);
  Print (L"CPUID_TIME_STAMP_COUNTER (Leaf %08x)\n", CPUID_TIME_STAMP_COUNTER);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax, Ebx, Ecx, 0);
}

/**
  Display CPUID_PROCESSOR_FREQUENCY leaf.

**/
VOID
CpuidProcessorFrequency (
  VOID
  )
{
  CPUID_PROCESSOR_FREQUENCY_EAX  Eax;
  CPUID_PROCESSOR_FREQUENCY_EBX  Ebx;
  CPUID_PROCESSOR_FREQUENCY_ECX  Ecx;

  if (CPUID_PROCESSOR_FREQUENCY > gMaximumBasicFunction) {
    return;
  }

  AsmCpuid (CPUID_PROCESSOR_FREQUENCY, &Eax.Uint32, &Ebx.Uint32, &Ecx.Uint32, NULL);
  Print (L"CPUID_PROCESSOR_FREQUENCY (Leaf %08x)\n", CPUID_PROCESSOR_FREQUENCY);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax.Uint32, Ebx.Uint32, Ecx.Uint32, 0);
  PRINT_BIT_FIELD (Eax, ProcessorBaseFrequency);
  PRINT_BIT_FIELD (Ebx, MaximumFrequency);
  PRINT_BIT_FIELD (Ecx, BusFrequency);
}

/**
  Display CPUID_SOC_VENDOR sub-leafs that contain the SoC Vendor Brand String.
  Also display these sub-leafs as a single SoC Vendor Brand String.

**/
VOID
CpuidSocVendorBrandString (
  VOID
  )
{
  CPUID_SOC_VENDOR_BRAND_STRING_DATA  Eax;
  CPUID_SOC_VENDOR_BRAND_STRING_DATA  Ebx;
  CPUID_SOC_VENDOR_BRAND_STRING_DATA  Ecx;
  CPUID_SOC_VENDOR_BRAND_STRING_DATA  Edx;
  //
  // Array to store brand string from 3 brand string leafs with
  // 4 32-bit brand string values per leaf and an extra value to
  // null terminate the string.
  //
  UINT32                              BrandString[3 * 4 + 1];

  AsmCpuidEx (
    CPUID_SOC_VENDOR, CPUID_SOC_VENDOR_BRAND_STRING1,
    &Eax.Uint32, &Ebx.Uint32, &Ecx.Uint32, &Edx.Uint32
    );
  Print (L"CPUID_SOC_VENDOR (Leaf %08x, Sub-Leaf %08x)\n", CPUID_SOC_VENDOR, CPUID_SOC_VENDOR_BRAND_STRING1);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax.Uint32, Ebx.Uint32, Ecx.Uint32, Edx.Uint32);
  BrandString[0] = Eax.Uint32;
  BrandString[1] = Ebx.Uint32;
  BrandString[2] = Ecx.Uint32;
  BrandString[3] = Edx.Uint32;

  AsmCpuidEx (
    CPUID_SOC_VENDOR, CPUID_SOC_VENDOR_BRAND_STRING2,
    &Eax.Uint32, &Ebx.Uint32, &Ecx.Uint32, &Edx.Uint32
    );
  Print (L"CPUID_SOC_VENDOR (Leaf %08x, Sub-Leaf %08x)\n", CPUID_SOC_VENDOR, CPUID_SOC_VENDOR_BRAND_STRING2);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax.Uint32, Ebx.Uint32, Ecx.Uint32, Edx.Uint32);
  BrandString[4] = Eax.Uint32;
  BrandString[5] = Ebx.Uint32;
  BrandString[6] = Ecx.Uint32;
  BrandString[7] = Edx.Uint32;

  AsmCpuidEx (
    CPUID_SOC_VENDOR, CPUID_SOC_VENDOR_BRAND_STRING3,
    &Eax.Uint32, &Ebx.Uint32, &Ecx.Uint32, &Edx.Uint32
    );
  Print (L"CPUID_SOC_VENDOR (Leaf %08x, Sub-Leaf %08x)\n", CPUID_SOC_VENDOR, CPUID_SOC_VENDOR_BRAND_STRING3);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax.Uint32, Ebx.Uint32, Ecx.Uint32, Edx.Uint32);
  BrandString[8]  = Eax.Uint32;
  BrandString[9]  = Ebx.Uint32;
  BrandString[10] = Ecx.Uint32;
  BrandString[11] = Edx.Uint32;

  BrandString[12] = 0;

  Print (L"Vendor Brand String = %a\n", (CHAR8 *)BrandString);
}

/**
  Display CPUID_SOC_VENDOR main leaf and sub-leafs.

**/
VOID
CpuidSocVendor (
  VOID
  )
{
  UINT32                          Eax;
  CPUID_SOC_VENDOR_MAIN_LEAF_EBX  Ebx;
  UINT32                          Ecx;
  UINT32                          Edx;

  if (CPUID_SOC_VENDOR > gMaximumBasicFunction) {
    return;
  }

  AsmCpuidEx (
    CPUID_SOC_VENDOR, CPUID_SOC_VENDOR_MAIN_LEAF,
    &Eax, &Ebx.Uint32, &Ecx, &Edx
    );
  Print (L"CPUID_SOC_VENDOR (Leaf %08x, Sub-Leaf %08x)\n", CPUID_SOC_VENDOR, CPUID_SOC_VENDOR_MAIN_LEAF);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax, Ebx.Uint32, Ecx, Edx);
  if (Eax < 3) {
    Print (L"  Not Supported\n");
    return;
  }
  PRINT_VALUE     (Eax, MaxSOCID_Index);
  PRINT_BIT_FIELD (Ebx, SocVendorId);
  PRINT_BIT_FIELD (Ebx, IsVendorScheme);
  PRINT_VALUE     (Ecx, ProjectID);
  PRINT_VALUE     (Edx, SteppingID);
  CpuidSocVendorBrandString ();
}

/**
  Display CPUID_EXTENDED_FUNCTION leaf.

**/
VOID
CpuidExtendedFunction (
  VOID
  )
{
  UINT32  Eax;

  AsmCpuid (CPUID_EXTENDED_FUNCTION, &Eax, NULL, NULL, NULL);
  Print (L"CPUID_EXTENDED_FUNCTION (Leaf %08x)\n", CPUID_EXTENDED_FUNCTION);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax, 0, 0, 0);
  PRINT_VALUE     (Eax, MaximumExtendedFunction);

  gMaximumExtendedFunction = Eax;
}

/**
  Display CPUID_EXTENDED_CPU_SIG leaf.

**/
VOID
CpuidExtendedCpuSig (
  VOID
  )
{
  UINT32                      Eax;
  CPUID_EXTENDED_CPU_SIG_ECX  Ecx;
  CPUID_EXTENDED_CPU_SIG_EDX  Edx;

  if (CPUID_EXTENDED_CPU_SIG > gMaximumExtendedFunction) {
    return;
  }

  AsmCpuid (CPUID_EXTENDED_CPU_SIG, &Eax, NULL, &Ecx.Uint32, &Edx.Uint32);
  Print (L"CPUID_EXTENDED_CPU_SIG (Leaf %08x)\n", CPUID_EXTENDED_CPU_SIG);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax, 0, Ecx.Uint32, Edx.Uint32);
  PRINT_BIT_FIELD (Ecx, LAHF_SAHF);
  PRINT_BIT_FIELD (Ecx, LZCNT);
  PRINT_BIT_FIELD (Ecx, PREFETCHW);
  PRINT_BIT_FIELD (Edx, SYSCALL_SYSRET);
  PRINT_BIT_FIELD (Edx, NX);
  PRINT_BIT_FIELD (Edx, Page1GB);
  PRINT_BIT_FIELD (Edx, RDTSCP);
  PRINT_BIT_FIELD (Edx, LM);
}

/**
  Display CPUID_BRAND_STRING1, CPUID_BRAND_STRING2 and  CPUID_BRAND_STRING3
  leafs.  Also display these three leafs as a single brand string.

**/
VOID
CpuidProcessorBrandString (
  VOID
  )
{
  CPUID_BRAND_STRING_DATA  Eax;
  CPUID_BRAND_STRING_DATA  Ebx;
  CPUID_BRAND_STRING_DATA  Ecx;
  CPUID_BRAND_STRING_DATA  Edx;
  //
  // Array to store brand string from 3 brand string leafs with
  // 4 32-bit brand string values per leaf and an extra value to
  // null terminate the string.
  //
  UINT32                   BrandString[3 * 4 + 1];

  if (CPUID_BRAND_STRING1 <= gMaximumExtendedFunction) {
    AsmCpuid (CPUID_BRAND_STRING1, &Eax.Uint32, &Ebx.Uint32, &Ecx.Uint32, &Edx.Uint32);
    Print (L"CPUID_BRAND_STRING1 (Leaf %08x)\n", CPUID_BRAND_STRING1);
    Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax.Uint32, Ebx.Uint32, Ecx.Uint32, Edx.Uint32);
    BrandString[0] = Eax.Uint32;
    BrandString[1] = Ebx.Uint32;
    BrandString[2] = Ecx.Uint32;
    BrandString[3] = Edx.Uint32;
  }

  if (CPUID_BRAND_STRING2 <= gMaximumExtendedFunction) {
    AsmCpuid (CPUID_BRAND_STRING2, &Eax.Uint32, &Ebx.Uint32, &Ecx.Uint32, &Edx.Uint32);
    Print (L"CPUID_BRAND_STRING2 (Leaf %08x)\n", CPUID_BRAND_STRING2);
    Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax.Uint32, Ebx.Uint32, Ecx.Uint32, Edx.Uint32);
    BrandString[4] = Eax.Uint32;
    BrandString[5] = Ebx.Uint32;
    BrandString[6] = Ecx.Uint32;
    BrandString[7] = Edx.Uint32;
  }

  if (CPUID_BRAND_STRING3 <= gMaximumExtendedFunction) {
    AsmCpuid (CPUID_BRAND_STRING3, &Eax.Uint32, &Ebx.Uint32, &Ecx.Uint32, &Edx.Uint32);
    Print (L"CPUID_BRAND_STRING3 (Leaf %08x)\n", CPUID_BRAND_STRING3);
    Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax.Uint32, Ebx.Uint32, Ecx.Uint32, Edx.Uint32);
    BrandString[8]  = Eax.Uint32;
    BrandString[9]  = Ebx.Uint32;
    BrandString[10] = Ecx.Uint32;
    BrandString[11] = Edx.Uint32;
  }

  BrandString[12] = 0;

  Print (L"Brand String = %a\n", (CHAR8 *)BrandString);
}

/**
  Display CPUID_EXTENDED_CACHE_INFO leaf.

**/
VOID
CpuidExtendedCacheInfo (
  VOID
  )
{
  CPUID_EXTENDED_CACHE_INFO_ECX  Ecx;

  if (CPUID_EXTENDED_CACHE_INFO > gMaximumExtendedFunction) {
    return;
  }

  AsmCpuid (CPUID_EXTENDED_CACHE_INFO, NULL, NULL, &Ecx.Uint32, NULL);
  Print (L"CPUID_EXTENDED_CACHE_INFO (Leaf %08x)\n", CPUID_EXTENDED_CACHE_INFO);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", 0, 0, Ecx.Uint32, 0);
  PRINT_BIT_FIELD (Ecx, CacheLineSize);
  PRINT_BIT_FIELD (Ecx, L2Associativity);
  PRINT_BIT_FIELD (Ecx, CacheSize);
}

/**
  Display CPUID_EXTENDED_TIME_STAMP_COUNTER leaf.

**/
VOID
CpuidExtendedTimeStampCounter (
  VOID
  )
{
  CPUID_EXTENDED_TIME_STAMP_COUNTER_EDX  Edx;

  if (CPUID_EXTENDED_TIME_STAMP_COUNTER > gMaximumExtendedFunction) {
    return;
  }

  AsmCpuid (CPUID_EXTENDED_TIME_STAMP_COUNTER, NULL, NULL, NULL, &Edx.Uint32);
  Print (L"CPUID_EXTENDED_TIME_STAMP_COUNTER (Leaf %08x)\n", CPUID_EXTENDED_TIME_STAMP_COUNTER);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", 0, 0, 0, Edx.Uint32);
  PRINT_BIT_FIELD (Edx, InvariantTsc);
}

/**
  Display CPUID_VIR_PHY_ADDRESS_SIZE leaf.

**/
VOID
CpuidVirPhyAddressSize (
  VOID
  )
{
  CPUID_VIR_PHY_ADDRESS_SIZE_EAX  Eax;

  if (CPUID_VIR_PHY_ADDRESS_SIZE > gMaximumExtendedFunction) {
    return;
  }

  AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &Eax.Uint32, NULL, NULL, NULL);
  Print (L"CPUID_VIR_PHY_ADDRESS_SIZE (Leaf %08x)\n", CPUID_VIR_PHY_ADDRESS_SIZE);
  Print (L"  EAX:%08x  EBX:%08x  ECX:%08x  EDX:%08x\n", Eax.Uint32, 0, 0, 0);
  PRINT_BIT_FIELD (Eax, PhysicalAddressBits);
  PRINT_BIT_FIELD (Eax, LinearAddressBits);
}

/**
  The user Entry Point for Application. The user code starts with this function
  as the real entry point for the application.

  @param[in] ImageHandle    The firmware allocated handle for the EFI image.
  @param[in] SystemTable    A pointer to the EFI System Table.

  @retval EFI_SUCCESS       The entry point is executed successfully.
  @retval other             Some error occurs when executing this entry point.

**/
EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  Print (L"UEFI CPUID Version 0.5\n");

  CpuidSignature ();
  CpuidVersionInfo ();
  CpuidCacheInfo ();
  CpuidSerialNumber ();
  CpuidCacheParams();
  CpuidMonitorMwait ();
  CpuidThermalPowerManagement ();
  CpuidStructuredExtendedFeatureFlags ();
  CpuidDirectCacheAccessInfo();
  CpuidArchitecturalPerformanceMonitoring ();
  CpuidExtendedTopology ();
  CpuidExtendedStateMainLeaf ();
  CpuidIntelRdtMonitoringEnumerationSubLeaf ();
  CpuidIntelRdtMonitoringL3CacheCapabilitySubLeaf ();
  CpuidIntelRdtAllocationMainLeaf ();
  CpuidEnumerationOfIntelSgx ();
  CpuidIntelProcessorTraceMainLeaf ();
  CpuidTimeStampCounter ();
  CpuidProcessorFrequency ();
  CpuidSocVendor ();
  CpuidExtendedFunction ();
  CpuidExtendedCpuSig ();
  CpuidProcessorBrandString ();
  CpuidExtendedCacheInfo ();
  CpuidExtendedTimeStampCounter ();
  CpuidVirPhyAddressSize ();

  return EFI_SUCCESS;
}

 

下面是我在 HDK Kabylake-R 上运行得到的结果:
UEFI CPUID Version 0.5
CPUID_SIGNATURE (Leaf 00000000)
EAX:00000016 EBX:756E6547 ECX:6C65746E EDX:49656E69
Eax MaximumLeaf: 16
Signature = GenuineIntel
CPUID_VERSION_INFO (Leaf 00000001)
EAX:000806EA EBX:00100800 ECX:77FAFBFF EDX:BFEBFBFF
Family = 6 Model = 8E Stepping = A
Eax SteppingId: A
Eax Model: E
Eax FamilyId: 6
Eax ProcessorType: 0
Eax ExtendedModelId: 8
Eax ExtendedFamilyId: 0
Ebx BrandIndex: 0
Ebx CacheLineSize: 8
Ebx MaximumAddressableIdsForLogicalProcessors: 10
Ebx InitialLocalApicId: 0
Ecx SSE3: 1
Ecx PCLMULQDQ: 1
Ecx DTES64: 1
Ecx MONITOR: 1
Ecx DS_CPL: 1
Ecx VMX: 1
Ecx SMX: 1
Ecx TM2: 1
Ecx SSSE3: 1
Ecx CNXT_ID: 0
Ecx SDBG: 1
Ecx FMA: 1
Ecx CMPXCHG16B: 1
Ecx xTPR_Update_Control: 1
Ecx PDCM: 1
Ecx PCID: 1
Ecx DCA: 0
Ecx SSE4_1: 1
Ecx SSE4_2: 1
Ecx x2APIC: 1
Ecx MOVBE: 1
Ecx POPCNT: 1
Ecx TSC_Deadline: 1
Ecx AESNI: 1
Ecx XSAVE: 1
Ecx OSXSAVE: 0
Ecx AVX: 1
Ecx F16C: 1
Ecx RDRAND: 1
Edx FPU: 1
Edx VME: 1
Edx DE: 1
Edx PSE: 1
Edx TSC: 1
Edx MSR: 1
Edx PAE: 1
Edx MCE: 1
Edx CX8: 1
Edx APIC: 1
Edx SEP: 1
Edx MTRR: 1
Edx PGE: 1
Edx MCA: 1
Edx CMOV: 1
Edx PAT: 1
Edx PSE_36: 1
Edx PSN: 0
Edx CLFSH: 1
Edx DS: 1
Edx ACPI: 1
Edx MMX: 1
Edx FXSR: 1
Edx SSE: 1
Edx SSE2: 1
Edx SS: 1
Edx HTT: 1
Edx TM: 1
Edx PBE: 1
CPUID_CACHE_INFO (Leaf 00000002)
EAX:76036301 EBX:00F0B6FF ECX:00000000 EDX:00C30000
TLB Data TLB: 2 MByte or 4 MByte pages, 4-way set associative, 32 entries and a separate array with 1 GByte pages, 4-way set associative, 4 entries
TLB Data TLB: 4 KByte pages, 4-way set associative, 64 entries
TLB Instruction TLB: 2M/4M pages, fully associative, 8 entries
General CPUID leaf 2 does not report cache descriptor information, use CPUID leaf 4 to query cache parameters
TLB Instruction TLB: 4KByte pages, 8-way set associative, 128 entries
Prefetch 64-Byte prefetching
STLB Shared 2nd-Level TLB: 4 KByte /2 MByte pages, 6-way associative, 1536 entries. Also 1GBbyte pages, 4-way, 16 entries.
CPUID_SERIAL_NUMBER (Leaf 00000003)
Not Supported
CPUID_CACHE_PARAMS (Leaf 00000004, Sub-Leaf 00000000)
EAX:1C004121 EBX:01C0003F ECX:0000003F EDX:00000000
Eax CacheType: 1
Eax CacheLevel: 1
Eax SelfInitializingCache: 1
Eax FullyAssociativeCache: 0
Eax MaximumAddressableIdsForLogicalProcessors: 1
Eax MaximumAddressableIdsForProcessorCores: 7
Ebx LineSize: 3F
Ebx LinePartitions: 0
Ebx Ways: 7
Ecx NumberOfSets: 3F
Edx Invalidate: 0
Edx CacheInclusiveness: 0
Edx ComplexCacheIndexing: 0
CPUID_CACHE_PARAMS (Leaf 00000004, Sub-Leaf 00000001)
EAX:1C004122 EBX:01C0003F ECX:0000003F EDX:00000000
Eax CacheType: 2
Eax CacheLevel: 1
Eax SelfInitializingCache: 1
Eax FullyAssociativeCache: 0
Eax MaximumAddressableIdsForLogicalProcessors: 1
Eax MaximumAddressableIdsForProcessorCores: 7
Ebx LineSize: 3F
Ebx LinePartitions: 0
Ebx Ways: 7
Ecx NumberOfSets: 3F
Edx Invalidate: 0
Edx CacheInclusiveness: 0
Edx ComplexCacheIndexing: 0
CPUID_CACHE_PARAMS (Leaf 00000004, Sub-Leaf 00000002)
EAX:1C004143 EBX:00C0003F ECX:000003FF EDX:00000000
Eax CacheType: 3
Eax CacheLevel: 2
Eax SelfInitializingCache: 1
Eax FullyAssociativeCache: 0
Eax MaximumAddressableIdsForLogicalProcessors: 1
Eax MaximumAddressableIdsForProcessorCores: 7
Ebx LineSize: 3F
Ebx LinePartitions: 0
Ebx Ways: 3
Ecx NumberOfSets: 3FF
Edx Invalidate: 0
Edx CacheInclusiveness: 0
Edx ComplexCacheIndexing: 0
CPUID_CACHE_PARAMS (Leaf 00000004, Sub-Leaf 00000003)
EAX:1C03C163 EBX:02C0003F ECX:00001FFF EDX:00000006
Eax CacheType: 3
Eax CacheLevel: 3
Eax SelfInitializingCache: 1
Eax FullyAssociativeCache: 0
Eax MaximumAddressableIdsForLogicalProcessors: F
Eax MaximumAddressableIdsForProcessorCores: 7
Ebx LineSize: 3F
Ebx LinePartitions: 0
Ebx Ways: B
Ecx NumberOfSets: 1FFF
Edx Invalidate: 0
Edx CacheInclusiveness: 1
Edx ComplexCacheIndexing: 1
CPUID_MONITOR_MWAIT (Leaf 00000005)
EAX:00000040 EBX:00000040 ECX:00000003 EDX:11142120
Eax SmallestMonitorLineSize: 40
Ebx LargestMonitorLineSize: 40
Ecx ExtensionsSupported: 1
Ecx InterruptAsBreak: 1
Edx C0States: 0
Edx C1States: 2
Edx C2States: 1
Edx C3States: 2
Edx C4States: 4
Edx C5States: 1
Edx C6States: 1
Edx C7States: 1
CPUID_THERMAL_POWER_MANAGEMENT (Leaf 00000006)
EAX:000027F7 EBX:00000002 ECX:00000009 EDX:00000000
Eax DigitalTemperatureSensor: 1
Eax TurboBoostTechnology: 1
Eax ARAT: 1
Eax PLN: 1
Eax ECMD: 1
Eax PTM: 1
Eax HWP: 1
Eax HWP_Notification: 1
Eax HWP_Activity_Window: 1
Eax HWP_Energy_Performance_Preference: 1
Eax HWP_Package_Level_Request: 0
Eax HDC: 1
Ebx InterruptThresholds: 2
Ecx HardwareCoordinationFeedback: 1
Ecx PerformanceEnergyBias: 1
CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS (Leaf 00000007, Sub-Leaf 00000000)
EAX:00000000 EBX:029C6FBF ECX:00000000 EDX:00000000
Ebx FSGSBASE: 1
Ebx IA32_TSC_ADJUST: 1
Ebx SGX: 1
Ebx BMI1: 1
Ebx HLE: 1
Ebx AVX2: 1
Ebx FDP_EXCPTN_ONLY: 0
Ebx SMEP: 1
Ebx BMI2: 1
Ebx EnhancedRepMovsbStosb: 1
Ebx INVPCID: 1
Ebx RTM: 1
Ebx RDT_M: 0
Ebx DeprecateFpuCsDs: 1
Ebx MPX: 1
Ebx RDT_A: 0
Ebx RDSEED: 1
Ebx ADX: 1
Ebx SMAP: 1
Ebx CLFLUSHOPT: 1
Ebx CLWB: 0
Ebx IntelProcessorTrace: 1
Ebx SHA: 0
Ecx PREFETCHWT1: 0
Ecx UMIP: 0
Ecx PKU: 0
Ecx OSPKE: 0
Ecx MAWAU: 0
Ecx RDPID: 0
Ecx SGX_LC: 0
CPUID_DIRECT_CACHE_ACCESS_INFO (Leaf 00000009)
EAX:00000000 EBX:00000000 ECX:00000000 EDX:00000000
CPUID_ARCHITECTURAL_PERFORMANCE_MONITORING (Leaf 0000000A)
EAX:07300804 EBX:00000000 ECX:00000000 EDX:00000603
Eax ArchPerfMonVerID: 4
Eax PerformanceMonitorCounters: 8
Eax PerformanceMonitorCounterWidth: 30
Eax EbxBitVectorLength: 7
Ebx UnhaltedCoreCycles: 0
Ebx InstructionsRetired: 0
Ebx UnhaltedReferenceCycles: 0
Ebx LastLevelCacheReferences: 0
Ebx LastLevelCacheMisses: 0
Ebx BranchInstructionsRetired: 0
Ebx AllBranchMispredictRetired: 0
Edx FixedFunctionPerformanceCounters: 3
Edx FixedFunctionPerformanceCounterWidth: 30
CPUID_EXTENDED_TOPOLOGY (Leaf 0000000B, Sub-Leaf 00000000)
EAX:00000001 EBX:00000001 ECX:00000100 EDX:00000000
Eax ApicIdShift: 1
Ebx LogicalProcessors: 1
Ecx LevelNumber: 0
Ecx LevelType: 1
Edx x2APIC_ID: 0
CPUID_EXTENDED_TOPOLOGY (Leaf 0000000B, Sub-Leaf 00000001)
EAX:00000004 EBX:00000004 ECX:00000201 EDX:00000000
Eax ApicIdShift: 4
Ebx LogicalProcessors: 4
Ecx LevelNumber: 1
Ecx LevelType: 2
Edx x2APIC_ID: 0
CPUID_EXTENDED_STATE (Leaf 0000000D, Sub-Leaf 00000000)
EAX:0000001F EBX:00000240 ECX:00000440 EDX:00000000
Eax x87: 1
Eax SSE: 1
Eax AVX: 1
Eax MPX: 3
Eax AVX_512: 0
Eax IA32_XSS: 0
Eax PKRU: 0
Ebx EnabledSaveStateSize: 240
Ecx SupportedSaveStateSize: 440
Edx XCR0_Supported_32_63: 0
CPUID_EXTENDED_STATE (Leaf 0000000D, Sub-Leaf 00000001)
EAX:0000000F EBX:00000240 ECX:00000100 EDX:00000000
Eax XSAVEOPT: 1
Eax XSAVEC: 1
Eax XGETBV: 1
Eax XSAVES: 1
Ebx EnabledSaveStateSize_XCR0_IA32_XSS: 240
Ecx XCR0: 0
Ecx PT: 0
Ecx XCR0_1: 0
Edx IA32_XSS_Supported_32_63: 0
CPUID_INTEL_RDT_MONITORING (Leaf 0000000F, Sub-Leaf 00000000)
EAX:00000000 EBX:00000000 ECX:00000000 EDX:00000000
Ebx Maximum_RMID_Range: 0
Edx L3CacheRDT_M: 0
CPUID_INTEL_RDT_MONITORING (Leaf 0000000F, Sub-Leaf 00000001)
EAX:00000000 EBX:00000000 ECX:00000000 EDX:00000000
Ebx OccupancyConversionFactor: 0
Ecx Maximum_RMID_Range: 0
Edx L3CacheOccupancyMonitoring: 0
Edx L3CacheTotalBandwidthMonitoring: 0
Edx L3CacheLocalBandwidthMonitoring: 0
CPUID_INTEL_RDT_ALLOCATION (Leaf 00000010, Sub-Leaf 00000000)
EAX:00000000 EBX:00000000 ECX:00000000 EDX:00000000
Ebx L3CacheAllocation: 0
Ebx L2CacheAllocation: 0
CPUID_INTEL_RDT_ALLOCATION (Leaf 00000010, Sub-Leaf 00000001)
EAX:00000000 EBX:00000000 ECX:00000000 EDX:00000000
Eax CapacityLength: 0
Ebx AllocationUnitBitMap: 0
Ecx CosUpdatesInfrequent: 0
Ecx CodeDataPrioritization: 0
Edx HighestCosNumber: 0
CPUID_INTEL_RDT_ALLOCATION (Leaf 00000010, Sub-Leaf 00000002)
EAX:00000000 EBX:00000000 ECX:00000000 EDX:00000000
Eax CapacityLength: 0
Ebx AllocationUnitBitMap: 0
Edx HighestCosNumber: 0
CPUID_INTEL_SGX (Leaf 00000012, Sub-Leaf 00000000)
EAX:00000000 EBX:00000000 ECX:00000000 EDX:00000000
Eax SGX1: 0
Eax SGX2: 0
Edx MaxEnclaveSize_Not64: 0
Edx MaxEnclaveSize_64: 0
CPUID_INTEL_SGX (Leaf 00000012, Sub-Leaf 00000001)
EAX:00000000 EBX:00000000 ECX:00000000 EDX:00000000
CPUID_INTEL_PROCESSOR_TRACE (Leaf 00000014, Sub-Leaf 00000000)
EAX:00000001 EBX:0000000F ECX:00000007 EDX:00000000
Eax MaximumSubLeaf: 1
Ebx Cr3Filter: 1
Ebx ConfigurablePsb: 1
Ebx IpTraceStopFiltering: 1
Ebx Mtc: 1
Ebx PTWrite: 0
Ebx PowerEventTrace: 0
Ecx RTIT: 1
Ecx ToPA: 1
Ecx SingleRangeOutput: 1
Ecx TraceTransportSubsystem: 0
Ecx LIP: 0
CPUID_INTEL_PROCESSOR_TRACE (Leaf 00000014, Sub-Leaf 00000001)
EAX:02490002 EBX:003F3FFF ECX:00000000 EDX:00000000
Eax ConfigurableAddressRanges: 2
Eax MtcPeriodEncodings: 249
Ebx CycleThresholdEncodings: 3FFF
Ebx PsbFrequencyEncodings: 3F
CPUID_TIME_STAMP_COUNTER (Leaf 00000015)
EAX:00000002 EBX:00000096 ECX:00000000 EDX:00000000
CPUID_PROCESSOR_FREQUENCY (Leaf 00000016)
EAX:00000708 EBX:00000D48 ECX:00000064 EDX:00000000
Eax ProcessorBaseFrequency: 708
Ebx MaximumFrequency: D48
Ecx BusFrequency: 64
CPUID_EXTENDED_FUNCTION (Leaf 80000000)
EAX:80000008 EBX:00000000 ECX:00000000 EDX:00000000
Eax MaximumExtendedFunction: 80000008
CPUID_EXTENDED_CPU_SIG (Leaf 80000001)
EAX:00000000 EBX:00000000 ECX:00000121 EDX:2C100800
Ecx LAHF_SAHF: 1
Ecx LZCNT: 1
Ecx PREFETCHW: 1
Edx SYSCALL_SYSRET: 1
Edx NX: 1
Edx Page1GB: 1
Edx RDTSCP: 1
Edx LM: 1
CPUID_BRAND_STRING1 (Leaf 80000002)
EAX:756E6547 EBX:20656E69 ECX:65746E49 EDX:2952286C
CPUID_BRAND_STRING2 (Leaf 80000003)
EAX:55504320 EBX:30303020 ECX:20402030 EDX:30342E31
CPUID_BRAND_STRING3 (Leaf 80000004)
EAX:007A4847 EBX:00000000 ECX:00000000 EDX:00000000
Brand String = Genuine Intel(R) CPU 0000 @ 1.40GHz
CPUID_EXTENDED_CACHE_INFO (Leaf 80000006)
EAX:00000000 EBX:00000000 ECX:01006040 EDX:00000000
Ecx CacheLineSize: 40
Ecx L2Associativity: 6
Ecx CacheSize: 100
CPUID_EXTENDED_TIME_STAMP_COUNTER (Leaf 80000007)
EAX:00000000 EBX:00000000 ECX:00000000 EDX:00000100
Edx InvariantTsc: 1
CPUID_VIR_PHY_ADDRESS_SIZE (Leaf 80000008)
EAX:00003027 EBX:00000000 ECX:00000000 EDX:00000000
Eax PhysicalAddressBits: 27
Eax LinearAddressBits: 30

编译后 IA32和 X64的Application

cpuidapp

完整的源代码
cpuid

参考:
1.https://raw.githubusercontent.com/tianocore/edk2/master/UefiCpuPkg/Application/Cpuid/Cpuid.c

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注