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, 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/UefiBootServicesTableLib.h>
26 #include <Library/DebugLib.h>
27 #include <Library/MtrrLib.h>
28 #include <Library/MemoryAllocationLib.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
;
167 UINTN NumberOfEnabledProcessors
;
174 ACPI_CPU_DATA
*OldAcpiCpuData
;
176 if (!PcdGetBool (PcdAcpiS3Enable
)) {
177 return EFI_UNSUPPORTED
;
181 // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure
183 OldAcpiCpuData
= (ACPI_CPU_DATA
*)(UINTN
)PcdGet64 (PcdCpuS3DataAddress
);
185 AcpiCpuDataEx
= AllocateZeroPages (sizeof (ACPI_CPU_DATA_EX
));
186 ASSERT (AcpiCpuDataEx
!= NULL
);
187 AcpiCpuData
= &AcpiCpuDataEx
->AcpiCpuData
;
190 // Get MP Services Protocol
192 Status
= gBS
->LocateProtocol (
193 &gEfiMpServiceProtocolGuid
,
197 ASSERT_EFI_ERROR (Status
);
200 // Get the number of CPUs
202 Status
= MpServices
->GetNumberOfProcessors (
205 &NumberOfEnabledProcessors
207 ASSERT_EFI_ERROR (Status
);
208 AcpiCpuData
->NumberOfCpus
= (UINT32
)NumberOfCpus
;
211 // Initialize ACPI_CPU_DATA fields
213 AcpiCpuData
->StackSize
= PcdGet32 (PcdCpuApStackSize
);
214 AcpiCpuData
->ApMachineCheckHandlerBase
= 0;
215 AcpiCpuData
->ApMachineCheckHandlerSize
= 0;
216 AcpiCpuData
->GdtrProfile
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)&AcpiCpuDataEx
->GdtrProfile
;
217 AcpiCpuData
->IdtrProfile
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)&AcpiCpuDataEx
->IdtrProfile
;
218 AcpiCpuData
->MtrrTable
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)&AcpiCpuDataEx
->MtrrTable
;
221 // Allocate stack space for all CPUs.
222 // Use ACPI NVS memory type because this data will be directly used by APs
223 // in S3 resume phase in long mode. Also during S3 resume, the stack buffer
224 // will only be used as scratch space. i.e. we won't read anything from it
225 // before we write to it, in PiSmmCpuDxeSmm.
227 Stack
= AllocateAcpiNvsMemory (NumberOfCpus
* AcpiCpuData
->StackSize
);
228 ASSERT (Stack
!= NULL
);
229 AcpiCpuData
->StackAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)Stack
;
232 // Get the boot processor's GDT and IDT
234 AsmReadGdtr (&AcpiCpuDataEx
->GdtrProfile
);
235 AsmReadIdtr (&AcpiCpuDataEx
->IdtrProfile
);
238 // Allocate GDT and IDT and copy current GDT and IDT contents
240 GdtSize
= AcpiCpuDataEx
->GdtrProfile
.Limit
+ 1;
241 IdtSize
= AcpiCpuDataEx
->IdtrProfile
.Limit
+ 1;
242 Gdt
= AllocateZeroPages (GdtSize
+ IdtSize
);
243 ASSERT (Gdt
!= NULL
);
244 Idt
= (VOID
*)((UINTN
)Gdt
+ GdtSize
);
245 CopyMem (Gdt
, (VOID
*)AcpiCpuDataEx
->GdtrProfile
.Base
, GdtSize
);
246 CopyMem (Idt
, (VOID
*)AcpiCpuDataEx
->IdtrProfile
.Base
, IdtSize
);
247 AcpiCpuDataEx
->GdtrProfile
.Base
= (UINTN
)Gdt
;
248 AcpiCpuDataEx
->IdtrProfile
.Base
= (UINTN
)Idt
;
250 if (OldAcpiCpuData
!= NULL
) {
251 CopyMem (&AcpiCpuData
->CpuFeatureInitData
, &OldAcpiCpuData
->CpuFeatureInitData
, sizeof (CPU_FEATURE_INIT_DATA
));
255 // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure
257 Status
= PcdSet64S (PcdCpuS3DataAddress
, (UINT64
)(UINTN
)AcpiCpuData
);
258 ASSERT_EFI_ERROR (Status
);
261 // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.
262 // The notification function allocates StartupVector and saves MTRRs for ACPI_CPU_DATA
264 Status
= gBS
->CreateEventEx (
269 &gEfiEndOfDxeEventGroupGuid
,
272 ASSERT_EFI_ERROR (Status
);