| 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