2 ACPI CPU Data initialization module
4 This module initializes the ACPI_CPU_DATA structure and registers the address
5 of this structure in the PcdCpuS3DataAddress PCD. This is a generic/simple
6 version of this module. It does not provide a machine check handler or CPU
7 register initialization tables for ACPI S3 resume. It also only supports the
8 number of CPUs reported by the MP Services Protocol, so this module does not
9 support hot plug CPUs. This module can be copied into a CPU specific package
10 and customized if these additional features are required.
12 Copyright (c) 2013 - 2021, Intel Corporation. All rights reserved.<BR>
13 Copyright (c) 2015 - 2020, Red Hat, Inc.
15 SPDX-License-Identifier: BSD-2-Clause-Patent
21 #include <AcpiCpuData.h>
23 #include <Library/BaseLib.h>
24 #include <Library/BaseMemoryLib.h>
25 #include <Library/DebugLib.h>
26 #include <Library/MemoryAllocationLib.h>
27 #include <Library/MtrrLib.h>
28 #include <Library/UefiBootServicesTableLib.h>
30 #include <Protocol/MpService.h>
31 #include <Guid/EventGroup.h>
34 // Data structure used to allocate ACPI_CPU_DATA and its supporting structures
37 ACPI_CPU_DATA AcpiCpuData
;
38 MTRR_SETTINGS MtrrTable
;
39 IA32_DESCRIPTOR GdtrProfile
;
40 IA32_DESCRIPTOR IdtrProfile
;
44 Allocate EfiACPIMemoryNVS memory.
46 @param[in] Size Size of memory to allocate.
48 @return Allocated address for output.
52 AllocateAcpiNvsMemory (
56 EFI_PHYSICAL_ADDRESS Address
;
60 Status
= gBS
->AllocatePages (
63 EFI_SIZE_TO_PAGES (Size
),
66 if (EFI_ERROR (Status
)) {
70 Buffer
= (VOID
*)(UINTN
)Address
;
71 ZeroMem (Buffer
, Size
);
77 Allocate memory and clean it with zero.
79 @param[in] Size Size of memory to allocate.
81 @return Allocated address for output.
91 Buffer
= AllocatePages (EFI_SIZE_TO_PAGES (Size
));
93 ZeroMem (Buffer
, Size
);
100 Callback function executed when the EndOfDxe event group is signaled.
102 We delay allocating StartupVector and saving the MTRR settings until BDS signals EndOfDxe.
104 @param[in] Event Event whose notification function is being invoked.
105 @param[out] Context Pointer to the MTRR_SETTINGS buffer to fill in.
109 CpuS3DataOnEndOfDxe (
115 ACPI_CPU_DATA_EX
*AcpiCpuDataEx
;
117 AcpiCpuDataEx
= (ACPI_CPU_DATA_EX
*)Context
;
119 // Allocate a 4KB reserved page below 1MB
121 AcpiCpuDataEx
->AcpiCpuData
.StartupVector
= BASE_1MB
- 1;
122 Status
= gBS
->AllocatePages (
124 EfiReservedMemoryType
,
126 &AcpiCpuDataEx
->AcpiCpuData
.StartupVector
128 ASSERT_EFI_ERROR (Status
);
130 DEBUG ((DEBUG_VERBOSE
, "%a\n", __FUNCTION__
));
131 MtrrGetAllMtrrs (&AcpiCpuDataEx
->MtrrTable
);
134 // Close event, so it will not be invoked again.
136 gBS
->CloseEvent (Event
);
140 The entry function of the CpuS3Data driver.
142 Allocate and initialize all fields of the ACPI_CPU_DATA structure except the
143 MTRR settings. Register an event notification on gEfiEndOfDxeEventGroupGuid
144 to capture the ACPI_CPU_DATA MTRR settings. The PcdCpuS3DataAddress is set
145 to the address that ACPI_CPU_DATA is allocated at.
147 @param[in] ImageHandle The firmware allocated handle for the EFI image.
148 @param[in] SystemTable A pointer to the EFI System Table.
150 @retval EFI_SUCCESS The entry point is executed successfully.
151 @retval EFI_UNSUPPORTED Do not support ACPI S3.
152 @retval other Some error occurs when executing this entry point.
157 CpuS3DataInitialize (
158 IN EFI_HANDLE ImageHandle
,
159 IN EFI_SYSTEM_TABLE
*SystemTable
163 ACPI_CPU_DATA_EX
*AcpiCpuDataEx
;
164 ACPI_CPU_DATA
*AcpiCpuData
;
165 EFI_MP_SERVICES_PROTOCOL
*MpServices
;
173 ACPI_CPU_DATA
*OldAcpiCpuData
;
175 if (!PcdGetBool (PcdAcpiS3Enable
)) {
176 return EFI_UNSUPPORTED
;
180 // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure
182 OldAcpiCpuData
= (ACPI_CPU_DATA
*)(UINTN
)PcdGet64 (PcdCpuS3DataAddress
);
184 AcpiCpuDataEx
= AllocateZeroPages (sizeof (ACPI_CPU_DATA_EX
));
185 ASSERT (AcpiCpuDataEx
!= NULL
);
186 AcpiCpuData
= &AcpiCpuDataEx
->AcpiCpuData
;
188 if (PcdGetBool (PcdQ35SmramAtDefaultSmbase
)) {
189 NumberOfCpus
= PcdGet32 (PcdCpuMaxLogicalProcessorNumber
);
191 UINTN NumberOfEnabledProcessors
;
194 // Get MP Services Protocol
196 Status
= gBS
->LocateProtocol (
197 &gEfiMpServiceProtocolGuid
,
201 ASSERT_EFI_ERROR (Status
);
204 // Get the number of CPUs
206 Status
= MpServices
->GetNumberOfProcessors (
209 &NumberOfEnabledProcessors
211 ASSERT_EFI_ERROR (Status
);
214 AcpiCpuData
->NumberOfCpus
= (UINT32
)NumberOfCpus
;
217 // Initialize ACPI_CPU_DATA fields
219 AcpiCpuData
->StackSize
= PcdGet32 (PcdCpuApStackSize
);
220 AcpiCpuData
->ApMachineCheckHandlerBase
= 0;
221 AcpiCpuData
->ApMachineCheckHandlerSize
= 0;
222 AcpiCpuData
->GdtrProfile
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)&AcpiCpuDataEx
->GdtrProfile
;
223 AcpiCpuData
->IdtrProfile
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)&AcpiCpuDataEx
->IdtrProfile
;
224 AcpiCpuData
->MtrrTable
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)&AcpiCpuDataEx
->MtrrTable
;
227 // Allocate stack space for all CPUs.
228 // Use ACPI NVS memory type because this data will be directly used by APs
229 // in S3 resume phase in long mode. Also during S3 resume, the stack buffer
230 // will only be used as scratch space. i.e. we won't read anything from it
231 // before we write to it, in PiSmmCpuDxeSmm.
233 Stack
= AllocateAcpiNvsMemory (NumberOfCpus
* AcpiCpuData
->StackSize
);
234 ASSERT (Stack
!= NULL
);
235 AcpiCpuData
->StackAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)Stack
;
238 // Get the boot processor's GDT and IDT
240 AsmReadGdtr (&AcpiCpuDataEx
->GdtrProfile
);
241 AsmReadIdtr (&AcpiCpuDataEx
->IdtrProfile
);
244 // Allocate GDT and IDT and copy current GDT and IDT contents
246 GdtSize
= AcpiCpuDataEx
->GdtrProfile
.Limit
+ 1;
247 IdtSize
= AcpiCpuDataEx
->IdtrProfile
.Limit
+ 1;
248 Gdt
= AllocateZeroPages (GdtSize
+ IdtSize
);
249 ASSERT (Gdt
!= NULL
);
250 Idt
= (VOID
*)((UINTN
)Gdt
+ GdtSize
);
251 CopyMem (Gdt
, (VOID
*)AcpiCpuDataEx
->GdtrProfile
.Base
, GdtSize
);
252 CopyMem (Idt
, (VOID
*)AcpiCpuDataEx
->IdtrProfile
.Base
, IdtSize
);
253 AcpiCpuDataEx
->GdtrProfile
.Base
= (UINTN
)Gdt
;
254 AcpiCpuDataEx
->IdtrProfile
.Base
= (UINTN
)Idt
;
256 if (OldAcpiCpuData
!= NULL
) {
257 CopyMem (&AcpiCpuData
->CpuFeatureInitData
, &OldAcpiCpuData
->CpuFeatureInitData
, sizeof (CPU_FEATURE_INIT_DATA
));
261 // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure
263 Status
= PcdSet64S (PcdCpuS3DataAddress
, (UINT64
)(UINTN
)AcpiCpuData
);
264 ASSERT_EFI_ERROR (Status
);
267 // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.
268 // The notification function allocates StartupVector and saves MTRRs for ACPI_CPU_DATA
270 Status
= gBS
->CreateEventEx (
275 &gEfiEndOfDxeEventGroupGuid
,
278 ASSERT_EFI_ERROR (Status
);