Newer
Older
AMI-Aptio-BIOS-Reversed / CpuMpDxe / CpuMpDxe.md
@Ajax Dong Ajax Dong 2 days ago 11 KB Init

CpuMpDxe

Function Table

Address Name Description
CpuMpAssertInternal
GetPcdValue
IoRead8
IoWrite8
CpuMpMicroSecondDelay
CpuMpQueryTimer
BitFieldRead32
CpuMpDebugPrint
CpuMpAssert
DetectUartBaudRate
DetectCmosPage
WaitUartReady
InitializeDriverServices
ProcessorConfigInit
SelectCpuFeatures
InitDataCollection
CpuMpDxeInit
StartAllCpus
StartCpu
SaveS3BootScript
CpuMpDxeUnload
CpuMpDxeDriverEntry
ModuleEntryPoint
Global UEFI table pointers
EFI_HANDLE gImageHandle = NULL;
CpuConfigLib runtime context (allocated per-cpu config buffer)
VOID *mCpuConfigLibConfigContextBuffer = NULL;
MP System Data globals
UINT64 mMpNumberOfCpus = 0; ///< qword_28340
MACHINE_CHECK_ATTRIBUTE *mMachineCheckAttribute = NULL; ///< qword_282E8
Boot performance measurement
UINT64 mBootTimeTimer = 0; ///< qword_17F58
CPUID feature bitmasks (AND-reduced across all CPUs)
UINT32 mCpuFeatureEdx = 0xFFFFFFFF; ///< dword_18280
Driver binding handle and processor configuration
EFI_HANDLE mDriverBindingHandle = NULL; ///< qword_17DD0
MP System Data (the aggregate mMPSystemData structure)
MP_SYSTEM_DATA mMPSystemData;
Offset 32 = Get64
Offset 48 = Set64
The decompiled code shows 8254 PIT-based delay via IO port 0x43/0x40.
This is a simplified implementation.
UINT64 Start;
Timestamp counter
ASSERT from BaseLib: EndBit < 32, StartBit <= EndBit
if (EndBit >= 32) {
BaseMemoryLibRepStr CopyMemWrapper.c asserts:
if ((Length - 1) > ~(UINTN)Destination) {
Read CMOS debug level from offset 0x4B.
CMOS index 0x70 bit 7 preserves NMI; offset 0x4B = BIOS debug level.
CmosIndex = __inbyte (0x70);
Serial port debug output via DebugPort protocol.
VSPrint (Buffer, sizeof (Buffer), Format, Args);
Output via serial port (I/O 0x3F8).
for (CHAR8 Ch = Buffer; Ch != '\0'; Ch++) {
Read CMOS index 0x5C for the base baud rate selector, then index 0x6C
for the extended byte.
IoWrite8 (0x72, 0x5C);
unk_1C200 case 0xA6: BaudRate = 57600; break;
Compute the actual baud rate divisor.
Reference clock = 0x1C200 = 115200 (standard UART clock).
return 0x1C200 / BaudRate;
LSR port (COM1 + 5 = 0x3FD for standard, or dynamic)
Poll LSR until bits 5 and 6 are both set.
do {
Locate the DXE Services Table. This is the standard library constructor
that the DxeServicesTableLib performs at module startup.
Status = gDS->Dispatch ();
ASSERT on failure.
if (EFI_ERROR (Status)) {
Locate the MM PCI Base protocol (DxeMmPciBaseLib).
This provides the MmPciBase (mPciUsra) for memory-mapped PCI config access.
if (mPciUsra == NULL) {
GUID from CpRcPkg
Initialize per-CPU context blocks (zero-initialized from allocation).
The C code also initializes lists at unk_17C80 and unk_17D00.
for (Index = 0; Index < NumberOfCpus; Index++) {
Allocate a 4KB config buffer (one physical page) for processor config I/O.
This is used for communicating configuration data between BSP and APs.
ConfigPagesAddress = 0xFFFFFFFFFFFFFFFFULL;
1 page = 4KB
Initialize the config buffer header.
CpuListHeads = (UINT64 *)(UINTN)ConfigPagesAddress;
Buffer size (32K)
Mark CPUs in the config buffer.
The original code writes 1 to the marker dword.
for (BufferIndex = 0; BufferIndex < NumberOfCpus; BufferIndex++) {
Allocate per-CPU data array (1088 bytes each) - qword_28350
mMpCpuList = (UINT64 )CpuMpAllocatePool ((UINTN)(1088 NumberOfCpus));
Allocate linked list heads (16 bytes each) - qword_28358
Initialize each as an empty doubly-linked list.
LinkedListHeads = (UINT64 )CpuMpAllocatePool ((UINTN)(16 NumberOfCpus));
Allocate per-CPU flags array (32 bytes each) - qword_28368
mMpPerCpuData = (UINT64)CpuMpAllocatePool ((UINTN)(32 * NumberOfCpus));
Allocate per-CPU flags shadow array (32 bytes each) - qword_28360
CPU index array: initialize with sequential indices - qword_28370
mMpCpuIndexArray = (UINT64)CpuMpAllocatePool ((UINTN)(24 * NumberOfCpus));
Report CPU count to CpuConfigLib via PCD 151.
This connects the config context to the library's internal tracking.
Status = SetPcdValue (151, NumberOfCpus);
Allocate per-CPU feature arrays
mMachineCheckAttribute = 128 bytes per CPU (qword_282E8)
16 UINT64 per CPU
mThermalMgmtCapability = 1 byte per CPU (qword_282B8)
mMaxCStateValue = 8 bytes per CPU (qword_18260)
mMicrocodeInfo = 24 bytes per CPU (qword_28300)
mLtSupported = 1 byte per CPU (qword_282F0)
mMsrValue = 8 bytes per CPU (qword_282F8)
Connect the global config context buffer pointer for CpuConfigLib.
This pointer is stored in qword_17FC8 and is used by multiple library functions.
mCpuConfigLibConfigContextBuffer = (VOID *)mMpCpuList;
Read PCD 155 for platform type and store it.
Initialize feature masks to all-ones (all features assumed present
until a CPU clears a bit).
mCpuFeatureEdx = 0xFFFFFFFF;
Read CPUID leaf 0x1 from CpuConfigLib.
CpuidRegisters = (CPUID_REGISTERS *)CpuConfigLibGetCpuid (
Read CPUID leaf 0x80000001 for extended features.
mCpuFeatureExtEdx &= CpuidRegisters->Edx;
Read PCD 146 (CPU data collection enable flag) and set bit 1.
Check PCD 147 for a specific feature enable flag (bit 1).
Enable the feature in PCD 145.
PcdValue = GetPcdValue (145);
Step 1: Read platform type from CpuConfigLib (PCD 155).
This determines which feature set to enable.
PlatformType = GetPcdValue (155);
Step 2: Initialize data collection subsystem.
InitDataCollection ();
Step 3: Initialize per-CPU feature subsystems.
These correspond to the source files in the CpuMpDxe directory.
Step 4: Allocate processor configuration structure (104 bytes).
mProcessorConfig = (PROCESSOR_CONFIG_DATA *)CpuMpAllocatePool (sizeof (PROCESSOR_CONFIG_DATA));
Fill in processor configuration structure.
Get the config buffer from the pages allocated during ProcessorConfigInit.
The base is stored at qword_18268 + 8.
CpuListHeads = (UINT64 *)(UINTN)1; // Placeholder: real address set in ProcessorConfigInit
Report configuration to CpuConfigLib via PCD 156.
Status = SetPcdValue (156, (UINT64)mProcessorConfig);
Step 5: Install the MP Services protocol or other protocols.
The decompile shows InstallMultipleProtocolInterfaces with GUID at 0x186A0.
NewHandle = mDriverBindingHandle;
Replace with actual GUID at 0x186A0
Step 6: Register for callback on a specific protocol notification.
The original calls sub_F7A0 with unk_17790 as the protocol GUID and
sub_5104 as the notification function.
Detect CMOS page and baud rate (serial init).
Program UART divisor.
Lcr = IoRead8 ((UINT16)(CmosPage + 3));
Clear DLAB, set FIFO.
IoWrite8 ((UINT16)(CmosPage + 2), 0);
Check for the speedstep flag from sub_780().
Read and validate the RTC timer.
TSC //
Wait for the timeout window.
The original uses a 357-CPU-index-based timeout comparison.
Wait loop with timeout check
Perform speedstep-specific delay compensation.
Set divisor to 1
Start each AP.
for (CpuIndex = 0; CpuIndex < (UINTN)mMpNumberOfCpus; CpuIndex++) {
Skip BSP
Get the APIC ID for this processor.
ApicId = (UINT32)GetPcdValue (ProcessorNumber); // Placeholder: read from CPU map
Send INIT IPI.
__writemsr (0x8B, 0); // Clear ICR
INIT IPI (fixed, edge, assert)
Microsecond delay (10ms per spec).
CpuMpMicroSecondDelay (10000);
Send first SIPI.
StartupAddress = 0x10000 >> 12; // Reset vector page
Microsecond delay (200us per spec).
CpuMpMicroSecondDelay (200);
Send second SIPI.
__writemsr **(0x8B, (ApicId << 32) 0x600 StartupAddress);**
Wait for AP to report in.
CpuMpMicroSecondDelay (100);
Locate the S3 boot script protocol.
Status = gBS->LocateProtocol (
Write IO write boot script entries for each MSR programmed during init.
return EFI_SUCCESS;
Save globals.
gImageHandle = ImageHandle;
Initialize DXE services and locate MM PCI base protocol.
Locate HII protocols.
Detect and configure the serial port baud rate and CMOS wait state.
Check if the UART is already configured for this baud rate.
If the divisor doesn't match, reprogram it.
if (CurrentDivisor != (UINT16)Divisor) {
Check for CPU 0 stepping/workaround via CMOS page.
Read PCD 1024068 (byte) and PCD 1024064 (base address) to check
for specific CPU stepping workaround.
If the byte at PCD 1024068 is >= 0 (signed), then perform a workaround
by setting bit 7 of the byte at PCD 1024064 + 1280.
INT8 Stepping;
Query CPU count from PCD 151.
NumberOfCpus = GetPcdValue (151);
Allocate and initialize MP system data structures.
Status = ProcessorConfigInit (NumberOfCpus);
Measure the boot TSC.
Check speedstep flag.
SpeedstepFlags = IoRead8 (0x780); // Simplified: actual call to sub_780()
Read TSC for timing
Perform timeout-adjusted delay loop using PCD 1288.
Wait with timeout using the CPU index-based check.
TimerCurrent = GetPcdValue (1288);
The original algorithm compares timer values with a wraparound
if (((TimerStart + 357 - NewTimer) & 0x800000) != 0) {
Set the final timer measurement.
Speedstep workaround: restore UART speed.
COM1 + 1 = IER
COM1 + 0 = DLL
Set DLAB + LCR
COM1 + 3 = LCR
Normal path: no speedstep compensation needed.
Invoke the main initialization dispatcher.
Status = CpuMpDxeInit ();

Generated by HR650X BIOS Decompilation Project