support hot plug CPUs. This module can be copied into a CPU specific package\r
and customized if these additional features are required.\r
\r
-Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>\r
Copyright (c) 2015, Red Hat, Inc.\r
\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
#include <Library/UefiBootServicesTableLib.h>\r
#include <Library/DebugLib.h>\r
#include <Library/MtrrLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
\r
#include <Protocol/MpService.h>\r
#include <Guid/EventGroup.h>\r
} ACPI_CPU_DATA_EX;\r
\r
/**\r
- Allocate EfiACPIMemoryNVS below 4G memory address.\r
-\r
- This function allocates EfiACPIMemoryNVS below 4G memory address.\r
+ Allocate EfiACPIMemoryNVS memory.\r
\r
@param[in] Size Size of memory to allocate.\r
\r
\r
**/\r
VOID *\r
-AllocateAcpiNvsMemoryBelow4G (\r
+AllocateAcpiNvsMemory (\r
IN UINTN Size\r
)\r
{\r
EFI_STATUS Status;\r
VOID *Buffer;\r
\r
- Address = BASE_4GB - 1;\r
Status = gBS->AllocatePages (\r
- AllocateMaxAddress,\r
+ AllocateAnyPages,\r
EfiACPIMemoryNVS,\r
EFI_SIZE_TO_PAGES (Size),\r
&Address\r
return Buffer;\r
}\r
\r
+/**\r
+ Allocate memory and clean it with zero.\r
+\r
+ @param[in] Size Size of memory to allocate.\r
+\r
+ @return Allocated address for output.\r
+\r
+**/\r
+VOID *\r
+AllocateZeroPages (\r
+ IN UINTN Size\r
+ )\r
+{\r
+ VOID *Buffer;\r
+\r
+ Buffer = AllocatePages (EFI_SIZE_TO_PAGES (Size));\r
+ if (Buffer != NULL) {\r
+ ZeroMem (Buffer, Size);\r
+ }\r
+\r
+ return Buffer;\r
+}\r
/**\r
Callback function executed when the EndOfDxe event group is signaled.\r
\r
- We delay saving the MTRR settings until BDS signals EndOfDxe.\r
+ We delay allocating StartupVector and saving the MTRR settings until BDS signals EndOfDxe.\r
\r
@param[in] Event Event whose notification function is being invoked.\r
@param[out] Context Pointer to the MTRR_SETTINGS buffer to fill in.\r
**/\r
VOID\r
EFIAPI\r
-SaveMtrrsOnEndOfDxe (\r
+CpuS3DataOnEndOfDxe (\r
IN EFI_EVENT Event,\r
OUT VOID *Context\r
)\r
{\r
+ EFI_STATUS Status;\r
+ ACPI_CPU_DATA_EX *AcpiCpuDataEx;\r
+\r
+ AcpiCpuDataEx = (ACPI_CPU_DATA_EX *) Context;\r
+ //\r
+ // Allocate a 4KB reserved page below 1MB\r
+ //\r
+ AcpiCpuDataEx->AcpiCpuData.StartupVector = BASE_1MB - 1;\r
+ Status = gBS->AllocatePages (\r
+ AllocateMaxAddress,\r
+ EfiReservedMemoryType,\r
+ 1,\r
+ &AcpiCpuDataEx->AcpiCpuData.StartupVector\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
DEBUG ((EFI_D_VERBOSE, "%a\n", __FUNCTION__));\r
- MtrrGetAllMtrrs (Context);\r
+ MtrrGetAllMtrrs (&AcpiCpuDataEx->MtrrTable);\r
\r
//\r
// Close event, so it will not be invoked again.\r
@param[in] SystemTable A pointer to the EFI System Table.\r
\r
@retval EFI_SUCCESS The entry point is executed successfully.\r
+ @retval EFI_UNSUPPORTED Do not support ACPI S3.\r
@retval other Some error occurs when executing this entry point.\r
\r
**/\r
VOID *Gdt;\r
VOID *Idt;\r
EFI_EVENT Event;\r
+ ACPI_CPU_DATA *OldAcpiCpuData;\r
+\r
+ if (!PcdGetBool (PcdAcpiS3Enable)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
\r
//\r
- // Allocate ACPI NVS memory below 4G memory for use on ACPI S3 resume.\r
+ // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure\r
//\r
- AcpiCpuDataEx = AllocateAcpiNvsMemoryBelow4G (sizeof (ACPI_CPU_DATA_EX));\r
+ OldAcpiCpuData = (ACPI_CPU_DATA *) (UINTN) PcdGet64 (PcdCpuS3DataAddress);\r
+\r
+ AcpiCpuDataEx = AllocateZeroPages (sizeof (ACPI_CPU_DATA_EX));\r
ASSERT (AcpiCpuDataEx != NULL);\r
AcpiCpuData = &AcpiCpuDataEx->AcpiCpuData;\r
\r
);\r
ASSERT_EFI_ERROR (Status);\r
\r
- //\r
- // Allocate a 4KB reserved page below 1MB\r
- //\r
- AcpiCpuData->StartupVector = BASE_1MB - 1;\r
- Status = gBS->AllocatePages (\r
- AllocateMaxAddress,\r
- EfiReservedMemoryType,\r
- 1,\r
- &AcpiCpuData->StartupVector\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
//\r
// Get the number of CPUs\r
//\r
AcpiCpuData->MtrrTable = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->MtrrTable;\r
\r
//\r
- // Allocate stack space for all CPUs\r
+ // Allocate stack space for all CPUs.\r
+ // Use ACPI NVS memory type because this data will be directly used by APs\r
+ // in S3 resume phase in long mode. Also during S3 resume, the stack buffer\r
+ // will only be used as scratch space. i.e. we won't read anything from it\r
+ // before we write to it, in PiSmmCpuDxeSmm.\r
//\r
- Stack = AllocateAcpiNvsMemoryBelow4G (NumberOfCpus * AcpiCpuData->StackSize);\r
+ Stack = AllocateAcpiNvsMemory (NumberOfCpus * AcpiCpuData->StackSize);\r
ASSERT (Stack != NULL);\r
AcpiCpuData->StackAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Stack;\r
\r
AsmReadIdtr (&AcpiCpuDataEx->IdtrProfile);\r
\r
//\r
- // Allocate GDT and IDT in ACPI NVS and copy current GDT and IDT contents\r
+ // Allocate GDT and IDT and copy current GDT and IDT contents\r
//\r
GdtSize = AcpiCpuDataEx->GdtrProfile.Limit + 1;\r
IdtSize = AcpiCpuDataEx->IdtrProfile.Limit + 1;\r
- Gdt = AllocateAcpiNvsMemoryBelow4G (GdtSize + IdtSize);\r
+ Gdt = AllocateZeroPages (GdtSize + IdtSize);\r
ASSERT (Gdt != NULL);\r
Idt = (VOID *)((UINTN)Gdt + GdtSize);\r
CopyMem (Gdt, (VOID *)AcpiCpuDataEx->GdtrProfile.Base, GdtSize);\r
AcpiCpuDataEx->GdtrProfile.Base = (UINTN)Gdt;\r
AcpiCpuDataEx->IdtrProfile.Base = (UINTN)Idt;\r
\r
- //\r
- // Allocate buffer for empty RegisterTable and PreSmmInitRegisterTable for all CPUs\r
- //\r
- TableSize = 2 * NumberOfCpus * sizeof (CPU_REGISTER_TABLE);\r
- RegisterTable = (CPU_REGISTER_TABLE *)AllocateAcpiNvsMemoryBelow4G (TableSize);\r
- ASSERT (RegisterTable != NULL);\r
- for (Index = 0; Index < NumberOfCpus; Index++) {\r
- Status = MpServices->GetProcessorInfo (\r
+ if (OldAcpiCpuData != NULL) {\r
+ AcpiCpuData->RegisterTable = OldAcpiCpuData->RegisterTable;\r
+ AcpiCpuData->PreSmmInitRegisterTable = OldAcpiCpuData->PreSmmInitRegisterTable;\r
+ AcpiCpuData->ApLocation = OldAcpiCpuData->ApLocation;\r
+ CopyMem (&AcpiCpuData->CpuStatus, &OldAcpiCpuData->CpuStatus, sizeof (CPU_STATUS_INFORMATION));\r
+ } else {\r
+ //\r
+ // Allocate buffer for empty RegisterTable and PreSmmInitRegisterTable for all CPUs\r
+ //\r
+ TableSize = 2 * NumberOfCpus * sizeof (CPU_REGISTER_TABLE);\r
+ RegisterTable = (CPU_REGISTER_TABLE *)AllocateZeroPages (TableSize);\r
+ ASSERT (RegisterTable != NULL);\r
+\r
+ for (Index = 0; Index < NumberOfCpus; Index++) {\r
+ Status = MpServices->GetProcessorInfo (\r
MpServices,\r
Index,\r
&ProcessorInfoBuffer\r
);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- RegisterTable[Index].InitialApicId = (UINT32)ProcessorInfoBuffer.ProcessorId;\r
- RegisterTable[Index].TableLength = 0;\r
- RegisterTable[Index].AllocatedSize = 0;\r
- RegisterTable[Index].RegisterTableEntry = NULL;\r
-\r
- RegisterTable[NumberOfCpus + Index].InitialApicId = (UINT32)ProcessorInfoBuffer.ProcessorId;\r
- RegisterTable[NumberOfCpus + Index].TableLength = 0;\r
- RegisterTable[NumberOfCpus + Index].AllocatedSize = 0;\r
- RegisterTable[NumberOfCpus + Index].RegisterTableEntry = NULL;\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ RegisterTable[Index].InitialApicId = (UINT32)ProcessorInfoBuffer.ProcessorId;\r
+ RegisterTable[Index].TableLength = 0;\r
+ RegisterTable[Index].AllocatedSize = 0;\r
+ RegisterTable[Index].RegisterTableEntry = 0;\r
+\r
+ RegisterTable[NumberOfCpus + Index].InitialApicId = (UINT32)ProcessorInfoBuffer.ProcessorId;\r
+ RegisterTable[NumberOfCpus + Index].TableLength = 0;\r
+ RegisterTable[NumberOfCpus + Index].AllocatedSize = 0;\r
+ RegisterTable[NumberOfCpus + Index].RegisterTableEntry = 0;\r
+ }\r
+ AcpiCpuData->RegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)RegisterTable;\r
+ AcpiCpuData->PreSmmInitRegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)(RegisterTable + NumberOfCpus);\r
}\r
- AcpiCpuData->RegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)RegisterTable;\r
- AcpiCpuData->PreSmmInitRegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)(RegisterTable + NumberOfCpus);\r
\r
//\r
// Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure\r
\r
//\r
// Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.\r
- // The notification function saves MTRRs for ACPI_CPU_DATA\r
+ // The notification function allocates StartupVector and saves MTRRs for ACPI_CPU_DATA\r
//\r
Status = gBS->CreateEventEx (\r
EVT_NOTIFY_SIGNAL,\r
TPL_CALLBACK,\r
- SaveMtrrsOnEndOfDxe,\r
- &AcpiCpuDataEx->MtrrTable,\r
+ CpuS3DataOnEndOfDxe,\r
+ AcpiCpuData,\r
&gEfiEndOfDxeEventGroupGuid,\r
&Event\r
);\r