/** This function will update any runtime platform specific information. This currently includes: Setting OEM table values, ID, table ID, creator ID and creator revision. Enabling the proper processor entries in the APIC tables. @param[in] Table The table to update. @retval EFI_SUCCESS The function completed successfully. **/ EFI_STATUS PlatformUpdateTables ( IN OUT EFI_ACPI_COMMON_HEADER *Table ) { EFI_ACPI_DESCRIPTION_HEADER *TableHeader; UINT8 *CurrPtr; UINT8 *EndPtr; ACPI_APIC_STRUCTURE_PTR *ApicPtr; UINT8 CurrProcessor; EFI_STATUS Status; EFI_MP_SERVICES_PROTOCOL *MpService; UINTN MaximumNumberOfCPUs; UINTN NumberOfEnabledCPUs; UINTN BufferSize; ACPI_APIC_STRUCTURE_PTR *ProcessorLocalApicEntry; UINTN BspIndex; EFI_ACPI_1_0_ASF_DESCRIPTION_TABLE *AsfEntry; EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER *HpetTbl; UINT64 OemIdValue; UINT8 Index; EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *Facp; EFI_ACPI_OSFR_TABLE *OsfrTable; EFI_ACPI_OSFR_OCUR_OBJECT *pOcurObject; EFI_ACPI_OSFR_OCUR_OBJECT OcurObject = {{0xB46F133D, 0x235F, 0x4634, 0x9F, 0x03, 0xB1, 0xC0, 0x1C, 0x54, 0x78, 0x5B}, 0, 0, 0, 0, 0}; CHAR16 *OcurMfgStringBuffer = NULL; CHAR16 *OcurModelStringBuffer = NULL; UINT8 *OcurRefDataBlockBuffer = NULL; UINTN OcurMfgStringBufferSize; UINTN OcurModelStringBufferSize; UINTN OcurRefDataBlockBufferSize; #if defined (IDCC2_SUPPORTED) && IDCC2_SUPPORTED EFI_ACPI_ASPT_TABLE *pSpttTable; #endif UINT16 NumberOfHpets; UINT16 HpetCapIdValue; UINT32 HpetBlockID; UINTN LocalApicCounter; EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer; UINT8 TempVal; EFI_ACPI_3_0_IO_APIC_STRUCTURE *IOApicType; EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *APICTableHeader; CurrPtr = NULL; EndPtr = NULL; ApicPtr = NULL; LocalApicCounter = 0; CurrProcessor = 0; ProcessorLocalApicEntry = NULL; if (Table->Signature != EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) { TableHeader = (EFI_ACPI_DESCRIPTION_HEADER *) Table; // // Update the OEMID. // OemIdValue = mPlatformInfo->AcpiOemId; *(UINT32 *)(TableHeader->OemId) = (UINT32)OemIdValue; *(UINT16 *)(TableHeader->OemId + 4) = *(UINT16*)(((UINT8 *)&OemIdValue) + 4); if ((Table->Signature != EFI_ACPI_2_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE)) { // // Update the OEM Table ID. // TableHeader->OemTableId = mPlatformInfo->AcpiOemTableId; } // // Update the OEM Table ID. // TableHeader->OemRevision = EFI_ACPI_OEM_REVISION; // // Update the creator ID. // TableHeader->CreatorId = EFI_ACPI_CREATOR_ID; // // Update the creator revision. // TableHeader->CreatorRevision = EFI_ACPI_CREATOR_REVISION; } // // Complete this function. // // // Locate the MP services protocol. // // // Find the MP Protocol. This is an MP platform, so MP protocol must be // there. // Status = gBS->LocateProtocol ( &gEfiMpServiceProtocolGuid, NULL, (VOID **) &MpService ); if (EFI_ERROR (Status)) { return Status; } // // Determine the number of processors. // MpService->GetNumberOfProcessors ( MpService, &MaximumNumberOfCPUs, &NumberOfEnabledCPUs ); ASSERT (MaximumNumberOfCPUs <= MAX_CPU_NUM && NumberOfEnabledCPUs >= 1); // // Assign a invalid intial value for update. // // // Update the processors in the APIC table. // switch (Table->Signature) { case EFI_ACPI_1_0_ASF_DESCRIPTION_TABLE_SIGNATURE: // // Update the table if ASF is enabled. Otherwise, return error so caller will not install. // if (mSystemConfig.Asf == 1) { return EFI_UNSUPPORTED; } AsfEntry = (EFI_ACPI_1_0_ASF_DESCRIPTION_TABLE *) Table; TempVal = (mNumberSmbusAddress < ASF_ADDR_DEVICE_ARRAY_LENGTH)? mNumberSmbusAddress : ASF_ADDR_DEVICE_ARRAY_LENGTH; for (Index = 0; Index < TempVal; Index++) { AsfEntry->AsfAddr.FixedSmbusAddresses[Index] = mSmbusRsvdAddresses[Index]; } break; case EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE: Status = MpService->WhoAmI ( MpService, &BspIndex ); // // PCAT_COMPAT Set to 1 indicate 8259 vectors should be disabled. // APICTableHeader = (EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *)Table; APICTableHeader->Flags |= EFI_ACPI_3_0_PCAT_COMPAT; CurrPtr = (UINT8 *) &((EFI_ACPI_DESCRIPTION_HEADER *) Table)[1]; CurrPtr = CurrPtr + 8; // // Size of Local APIC Address & Flag. // EndPtr = (UINT8 *) Table; EndPtr = EndPtr + Table->Length; while (CurrPtr < EndPtr) { ApicPtr = (ACPI_APIC_STRUCTURE_PTR *) CurrPtr; switch (ApicPtr->AcpiApicCommon.Type) { case EFI_ACPI_3_0_PROCESSOR_LOCAL_APIC: // // ESS override // Fix for Ordering of MADT to be maintained as it is in MADT table. // // Update processor enabled or disabled and keep the local APIC // order in MADT intact. // // Sanity check to make sure proc-id is not arbitrary. // DEBUG ((EFI_D_ERROR, "ApicPtr->AcpiLocalApic.AcpiProcessorId = %x, MaximumNumberOfCPUs = %x\n", \ ApicPtr->AcpiLocalApic.AcpiProcessorId, MaximumNumberOfCPUs)); if(ApicPtr->AcpiLocalApic.AcpiProcessorId > MaximumNumberOfCPUs) { ApicPtr->AcpiLocalApic.AcpiProcessorId = (UINT8)MaximumNumberOfCPUs; } BufferSize = 0; ApicPtr->AcpiLocalApic.Flags = 0; for (CurrProcessor = 0; CurrProcessor < MaximumNumberOfCPUs; CurrProcessor++) { Status = MpService->GetProcessorInfo ( MpService, CurrProcessor, &ProcessorInfoBuffer ); if (Status == EFI_SUCCESS && ProcessorInfoBuffer.ProcessorId == ApicPtr->AcpiLocalApic.ApicId) { // // Check to see whether or not a processor (or thread) is enabled. // if ((BspIndex == CurrProcessor) || ((ProcessorInfoBuffer.StatusFlag & PROCESSOR_ENABLED_BIT) != 0)) { // // Go on and check if Hyper Threading is enabled. If HT not enabled // hide this thread from OS by not setting the flag to 1. This is the // software way to disable Hyper Threading. Basically we just hide it // from the OS. // ApicPtr->AcpiLocalApic.Flags = EFI_ACPI_1_0_LOCAL_APIC_ENABLED; if(ProcessorInfoBuffer.Location.Thread != 0) { ApicPtr->AcpiLocalApic.Flags = 0; } AppendCpuMapTableEntry (&(ApicPtr->AcpiLocalApic)); } break; } } // // If no APIC-ID match, the cpu may not be populated. // break; case EFI_ACPI_3_0_IO_APIC: IOApicType = (EFI_ACPI_3_0_IO_APIC_STRUCTURE *)CurrPtr; IOApicType->IoApicId = 0x02; // // IO APIC entries can be patched here. // break; } CurrPtr = CurrPtr + ApicPtr->AcpiApicCommon.Length; } break; case EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE: Facp = (EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *) Table; Facp->Flags &= (UINT32)(~(3<<2)); break; case EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE: // // Patch the memory resource. // PatchDsdtTable ((EFI_ACPI_DESCRIPTION_HEADER *) Table); break; case EFI_ACPI_3_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE: // // Gv3 support // // TBD: Need re-design based on the ValleyTrail platform. // break; case EFI_ACPI_3_0_HIGH_PRECISION_EVENT_TIMER_TABLE_SIGNATURE: // // Adjust HPET Table to correct the Base Address. // // Enable HPET always as Hpet.asi always indicates that Hpet is enabled. // MmioOr8 (R_PCH_PCH_HPET + R_PCH_PCH_HPET_GCFG, B_PCH_PCH_HPET_GCFG_EN); HpetTbl = (EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER *) Table; HpetTbl->BaseAddressLower32Bit.Address = HPET_BASE_ADDRESS; HpetTbl->EventTimerBlockId = *((UINT32*)(UINTN)HPET_BASE_ADDRESS); HpetCapIdValue = *(UINT16 *)(UINTN)(HPET_BASE_ADDRESS); NumberOfHpets = HpetCapIdValue & B_PCH_PCH_HPET_GCID_NT; // Bits [8:12] contains the number of Hpets HpetBlockID = EFI_ACPI_EVENT_TIMER_BLOCK_ID; if((NumberOfHpets) && (NumberOfHpets & B_PCH_PCH_HPET_GCID_NT)) { HpetBlockID |= (NumberOfHpets); } HpetTbl->EventTimerBlockId = HpetBlockID; break; case EFI_ACPI_3_0_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE: // // Update MCFG base and end bus number. // ((EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE *) Table)->Segment[0].BaseAddress = mPlatformInfo->PciData.PciExpressBase; ((EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE *) Table)->Segment[0].EndBusNumber = (UINT8)RShiftU64 (mPlatformInfo->PciData.PciExpressSize, 20) - 1; break; case EFI_ACPI_OSFR_TABLE_SIGNATURE: // // Get size of OSFR variable. // OcurMfgStringBufferSize = 0; Status = gRT->GetVariable ( gACPIOSFRMfgStringVariableName, &gACPIOSFRMfgStringVariableGuid, NULL, &OcurMfgStringBufferSize, NULL ); if (Status != EFI_BUFFER_TOO_SMALL) { // // Variable must not be present on the system. // return EFI_UNSUPPORTED; } // // Allocate memory for variable data. // OcurMfgStringBuffer = AllocatePool (OcurMfgStringBufferSize); Status = gRT->GetVariable ( gACPIOSFRMfgStringVariableName, &gACPIOSFRMfgStringVariableGuid, NULL, &OcurMfgStringBufferSize, OcurMfgStringBuffer ); if (!EFI_ERROR (Status)) { OcurModelStringBufferSize = 0; Status = gRT->GetVariable ( gACPIOSFRModelStringVariableName, &gACPIOSFRModelStringVariableGuid, NULL, &OcurModelStringBufferSize, NULL ); if (Status != EFI_BUFFER_TOO_SMALL) { // // Variable must not be present on the system. // return EFI_UNSUPPORTED; } // // Allocate memory for variable data. // OcurModelStringBuffer = AllocatePool (OcurModelStringBufferSize); Status = gRT->GetVariable ( gACPIOSFRModelStringVariableName, &gACPIOSFRModelStringVariableGuid, NULL, &OcurModelStringBufferSize, OcurModelStringBuffer ); if (!EFI_ERROR (Status)) { OcurRefDataBlockBufferSize = 0; Status = gRT->GetVariable ( gACPIOSFRRefDataBlockVariableName, &gACPIOSFRRefDataBlockVariableGuid, NULL, &OcurRefDataBlockBufferSize, NULL ); if (Status == EFI_BUFFER_TOO_SMALL) { // // Allocate memory for variable data. // OcurRefDataBlockBuffer = AllocatePool (OcurRefDataBlockBufferSize); Status = gRT->GetVariable ( gACPIOSFRRefDataBlockVariableName, &gACPIOSFRRefDataBlockVariableGuid, NULL, &OcurRefDataBlockBufferSize, OcurRefDataBlockBuffer ); } OsfrTable = (EFI_ACPI_OSFR_TABLE *) Table; // // Currently only one object is defined: OCUR_OSFR_TABLE. // OsfrTable->ObjectCount = 1; // // Initialize table length to fixed portion of the ACPI OSFR table. // OsfrTable->Header.Length = sizeof (EFI_ACPI_OSFR_TABLE_FIXED_PORTION); *(UINT32 *)((UINTN) OsfrTable + sizeof (EFI_ACPI_OSFR_TABLE_FIXED_PORTION)) = \ (UINT32) (sizeof (EFI_ACPI_OSFR_TABLE_FIXED_PORTION) + sizeof (UINT32)); pOcurObject = (EFI_ACPI_OSFR_OCUR_OBJECT *)((UINTN) OsfrTable + sizeof (EFI_ACPI_OSFR_TABLE_FIXED_PORTION) + \ sizeof (UINT32)); CopyMem (pOcurObject, &OcurObject, sizeof (EFI_ACPI_OSFR_OCUR_OBJECT)); pOcurObject->ManufacturerNameStringOffset = (UINT32)((UINTN) pOcurObject - (UINTN) OsfrTable + \ sizeof (EFI_ACPI_OSFR_OCUR_OBJECT)); pOcurObject->ModelNameStringOffset = (UINT32)((UINTN) pOcurObject - (UINTN) OsfrTable + \ sizeof (EFI_ACPI_OSFR_OCUR_OBJECT) + OcurMfgStringBufferSize); if (OcurRefDataBlockBufferSize > 0) { pOcurObject->MicrosoftReferenceOffset = (UINT32)((UINTN) pOcurObject - (UINTN) OsfrTable + \ sizeof (EFI_ACPI_OSFR_OCUR_OBJECT) + OcurMfgStringBufferSize + OcurModelStringBufferSize); } CopyMem ((UINTN *)((UINTN) pOcurObject + sizeof (EFI_ACPI_OSFR_OCUR_OBJECT)), OcurMfgStringBuffer, \ OcurMfgStringBufferSize); CopyMem ((UINTN *)((UINTN) pOcurObject + sizeof (EFI_ACPI_OSFR_OCUR_OBJECT) + OcurMfgStringBufferSize), \ OcurModelStringBuffer, OcurModelStringBufferSize); if (OcurRefDataBlockBufferSize > 0) { CopyMem ((UINTN *)((UINTN) pOcurObject + sizeof (EFI_ACPI_OSFR_OCUR_OBJECT) + OcurMfgStringBufferSize + \ OcurModelStringBufferSize),OcurRefDataBlockBuffer, OcurRefDataBlockBufferSize); } OsfrTable->Header.Length += (UINT32)(OcurMfgStringBufferSize + OcurModelStringBufferSize + OcurRefDataBlockBufferSize); OsfrTable->Header.Length += sizeof (EFI_ACPI_OSFR_OCUR_OBJECT) + sizeof (UINT32); } } gBS->FreePool (OcurMfgStringBuffer); gBS->FreePool (OcurModelStringBuffer); gBS->FreePool (OcurRefDataBlockBuffer); break; default: break; } // // // Update the hardware signature in the FACS structure. // // // Locate the SPCR table and update based on current settings. // The user may change CR settings via setup or other methods. // The SPCR table must match. // return EFI_SUCCESS; }
VOID ApicTableUpdate ( IN OUT EFI_ACPI_DESCRIPTION_HEADER *TableHeader, IN OUT EFI_ACPI_TABLE_VERSION *Version ) /*++ Routine Description: Update the processors information in the APIC table Arguments: Table - The table to be set Version - Version to publish Returns: None --*/ { EFI_STATUS Status; EFI_MP_SERVICES_PROTOCOL *MpService; UINT8 *CurrPtr; UINT8 *EndPtr; UINT8 CurrIoApic; UINT8 CurrProcessor; UINTN NumberOfCPUs; UINTN NumberOfEnabledCPUs; UINTN BufferSize; EFI_PROCESSOR_INFORMATION MpContext; ACPI_APIC_STRUCTURE_PTR *ApicPtr; CurrIoApic = 0; CurrProcessor = 0; // // Find the MP Protocol. This is an MP platform, so MP protocol must be // there. // Status = gBS->LocateProtocol ( &gEfiMpServiceProtocolGuid, NULL, (VOID**)&MpService ); if (EFI_ERROR (Status)) { // // Failed to get MP information, doesn't publish the invalid table // *Version = EFI_ACPI_TABLE_VERSION_NONE; return; } // // Determine the number of processors // MpService->GetNumberOfProcessors ( MpService, &NumberOfCPUs, &NumberOfEnabledCPUs ); CurrPtr = (UINT8*) &(TableHeader[1]); CurrPtr = CurrPtr + 8; // Size of Local APIC Address & Flag EndPtr = (UINT8*) TableHeader; EndPtr = EndPtr + TableHeader->Length; while (CurrPtr < EndPtr) { ApicPtr = (ACPI_APIC_STRUCTURE_PTR*) CurrPtr; switch (ApicPtr->AcpiApicCommon.Type) { case EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC: BufferSize = sizeof (EFI_PROCESSOR_INFORMATION); ApicPtr->AcpiLocalApic.Flags = 0; ApicPtr->AcpiLocalApic.ApicId = 0; Status = MpService->GetProcessorInfo ( MpService, CurrProcessor, &MpContext ); if (!EFI_ERROR (Status)) { if (MpContext.StatusFlag & PROCESSOR_ENABLED_BIT) { ApicPtr->AcpiLocalApic.Flags = EFI_ACPI_3_0_LOCAL_APIC_ENABLED; } ApicPtr->AcpiLocalApic.ApicId = (UINT8)MpContext.ProcessorId; } CurrProcessor++; break; case EFI_ACPI_1_0_IO_APIC: // // IO APIC entries can be patched here // if (CurrIoApic == 0) { // // Update SOC internel IOAPIC base // ApicPtr->AcpiIoApic.IoApicId = PcdGet8 (PcdIoApicSettingIoApicId); ApicPtr->AcpiIoApic.IoApicAddress = (UINT32)FixedPcdGet64(PcdIoApicBaseAddress); ApicPtr->AcpiIoApic.GlobalSystemInterruptBase = 0; } else { // // Porting is required to update other IOAPIC entries if available // ASSERT (0); } CurrIoApic++; break; default: break; }; CurrPtr = CurrPtr + ApicPtr->AcpiApicCommon.Length; } }
/** Get All processors EFI_CPU_LOCATION in system. LocationBuf is allocated inside the function Caller is responsible to free LocationBuf. @param[out] LocationBuf Returns Processor Location Buffer. @param[out] Num Returns processor number. @retval EFI_SUCCESS Operation completed successfully. @retval EFI_UNSUPPORTED MpService protocol not found. **/ EFI_STATUS GetProcessorsCpuLocation ( OUT EFI_CPU_PHYSICAL_LOCATION **LocationBuf, OUT UINTN *Num ) { EFI_STATUS Status; EFI_MP_SERVICES_PROTOCOL *MpProtocol; UINTN ProcessorNum; UINTN EnabledProcessorNum; EFI_PROCESSOR_INFORMATION ProcessorInfo; EFI_CPU_PHYSICAL_LOCATION *ProcessorLocBuf; UINTN Index; Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **) &MpProtocol); if (EFI_ERROR (Status)) { // // MP protocol is not installed // return EFI_UNSUPPORTED; } Status = MpProtocol->GetNumberOfProcessors( MpProtocol, &ProcessorNum, &EnabledProcessorNum ); if (EFI_ERROR(Status)){ return Status; } Status = gBS->AllocatePool( EfiBootServicesData, sizeof(EFI_CPU_PHYSICAL_LOCATION) * ProcessorNum, (VOID **) &ProcessorLocBuf ); if (EFI_ERROR(Status)){ return Status; } // // Get each processor Location info // for (Index = 0; Index < ProcessorNum; Index++) { Status = MpProtocol->GetProcessorInfo( MpProtocol, Index, &ProcessorInfo ); if (EFI_ERROR(Status)){ FreePool(ProcessorLocBuf); return Status; } // // Get all Processor Location info & measure // CopyMem( &ProcessorLocBuf[Index], &ProcessorInfo.Location, sizeof(EFI_CPU_PHYSICAL_LOCATION) ); } *LocationBuf = ProcessorLocBuf; *Num = ProcessorNum; return Status; }
/** The entry function of the CpuS3Data driver. Allocate and initialize all fields of the ACPI_CPU_DATA structure except the MTRR settings. Register an event notification on gEfiEndOfDxeEventGroupGuid to capture the ACPI_CPU_DATA MTRR settings. The PcdCpuS3DataAddress is set to the address that ACPI_CPU_DATA is allocated at. @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 EFI_UNSUPPORTED Do not support ACPI S3. @retval other Some error occurs when executing this entry point. **/ EFI_STATUS EFIAPI CpuS3DataInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; ACPI_CPU_DATA_EX *AcpiCpuDataEx; ACPI_CPU_DATA *AcpiCpuData; EFI_MP_SERVICES_PROTOCOL *MpServices; UINTN NumberOfCpus; UINTN NumberOfEnabledProcessors; VOID *Stack; UINTN TableSize; CPU_REGISTER_TABLE *RegisterTable; UINTN Index; EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer; UINTN GdtSize; UINTN IdtSize; VOID *Gdt; VOID *Idt; EFI_EVENT Event; ACPI_CPU_DATA *OldAcpiCpuData; if (!PcdGetBool (PcdAcpiS3Enable)) { return EFI_UNSUPPORTED; } // // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure // OldAcpiCpuData = (ACPI_CPU_DATA *) (UINTN) PcdGet64 (PcdCpuS3DataAddress); AcpiCpuDataEx = AllocateZeroPages (sizeof (ACPI_CPU_DATA_EX)); ASSERT (AcpiCpuDataEx != NULL); AcpiCpuData = &AcpiCpuDataEx->AcpiCpuData; // // Get MP Services Protocol // Status = gBS->LocateProtocol ( &gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpServices ); ASSERT_EFI_ERROR (Status); // // Get the number of CPUs // Status = MpServices->GetNumberOfProcessors ( MpServices, &NumberOfCpus, &NumberOfEnabledProcessors ); ASSERT_EFI_ERROR (Status); AcpiCpuData->NumberOfCpus = (UINT32)NumberOfCpus; // // Initialize ACPI_CPU_DATA fields // AcpiCpuData->StackSize = PcdGet32 (PcdCpuApStackSize); AcpiCpuData->ApMachineCheckHandlerBase = 0; AcpiCpuData->ApMachineCheckHandlerSize = 0; AcpiCpuData->GdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->GdtrProfile; AcpiCpuData->IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->IdtrProfile; AcpiCpuData->MtrrTable = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->MtrrTable; // // Allocate stack space for all CPUs. // Use ACPI NVS memory type because this data will be directly used by APs // in S3 resume phase in long mode. Also during S3 resume, the stack buffer // will only be used as scratch space. i.e. we won't read anything from it // before we write to it, in PiSmmCpuDxeSmm. // Stack = AllocateAcpiNvsMemory (NumberOfCpus * AcpiCpuData->StackSize); ASSERT (Stack != NULL); AcpiCpuData->StackAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Stack; // // Get the boot processor's GDT and IDT // AsmReadGdtr (&AcpiCpuDataEx->GdtrProfile); AsmReadIdtr (&AcpiCpuDataEx->IdtrProfile); // // Allocate GDT and IDT and copy current GDT and IDT contents // GdtSize = AcpiCpuDataEx->GdtrProfile.Limit + 1; IdtSize = AcpiCpuDataEx->IdtrProfile.Limit + 1; Gdt = AllocateZeroPages (GdtSize + IdtSize); ASSERT (Gdt != NULL); Idt = (VOID *)((UINTN)Gdt + GdtSize); CopyMem (Gdt, (VOID *)AcpiCpuDataEx->GdtrProfile.Base, GdtSize); CopyMem (Idt, (VOID *)AcpiCpuDataEx->IdtrProfile.Base, IdtSize); AcpiCpuDataEx->GdtrProfile.Base = (UINTN)Gdt; AcpiCpuDataEx->IdtrProfile.Base = (UINTN)Idt; if (OldAcpiCpuData != NULL) { AcpiCpuData->RegisterTable = OldAcpiCpuData->RegisterTable; AcpiCpuData->PreSmmInitRegisterTable = OldAcpiCpuData->PreSmmInitRegisterTable; AcpiCpuData->ApLocation = OldAcpiCpuData->ApLocation; CopyMem (&AcpiCpuData->CpuStatus, &OldAcpiCpuData->CpuStatus, sizeof (CPU_STATUS_INFORMATION)); } else { // // Allocate buffer for empty RegisterTable and PreSmmInitRegisterTable for all CPUs // TableSize = 2 * NumberOfCpus * sizeof (CPU_REGISTER_TABLE); RegisterTable = (CPU_REGISTER_TABLE *)AllocateZeroPages (TableSize); ASSERT (RegisterTable != NULL); for (Index = 0; Index < NumberOfCpus; Index++) { Status = MpServices->GetProcessorInfo ( MpServices, Index, &ProcessorInfoBuffer ); ASSERT_EFI_ERROR (Status); RegisterTable[Index].InitialApicId = (UINT32)ProcessorInfoBuffer.ProcessorId; RegisterTable[Index].TableLength = 0; RegisterTable[Index].AllocatedSize = 0; RegisterTable[Index].RegisterTableEntry = 0; RegisterTable[NumberOfCpus + Index].InitialApicId = (UINT32)ProcessorInfoBuffer.ProcessorId; RegisterTable[NumberOfCpus + Index].TableLength = 0; RegisterTable[NumberOfCpus + Index].AllocatedSize = 0; RegisterTable[NumberOfCpus + Index].RegisterTableEntry = 0; } AcpiCpuData->RegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)RegisterTable; AcpiCpuData->PreSmmInitRegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)(RegisterTable + NumberOfCpus); } // // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure // Status = PcdSet64S (PcdCpuS3DataAddress, (UINT64)(UINTN)AcpiCpuData); ASSERT_EFI_ERROR (Status); // // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event. // The notification function allocates StartupVector and saves MTRRs for ACPI_CPU_DATA // Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_CALLBACK, CpuS3DataOnEndOfDxe, AcpiCpuData, &gEfiEndOfDxeEventGroupGuid, &Event ); ASSERT_EFI_ERROR (Status); return EFI_SUCCESS; }