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 - 2017, 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
);
99 Callback function executed when the EndOfDxe event group is signaled.
101 We delay allocating StartupVector and saving the MTRR settings until BDS signals EndOfDxe.
103 @param[in] Event Event whose notification function is being invoked.
104 @param[out] Context Pointer to the MTRR_SETTINGS buffer to fill in.
108 CpuS3DataOnEndOfDxe (
114 ACPI_CPU_DATA_EX
*AcpiCpuDataEx
;
116 AcpiCpuDataEx
= (ACPI_CPU_DATA_EX
*) Context
;
118 // Allocate a 4KB reserved page below 1MB
120 AcpiCpuDataEx
->AcpiCpuData
.StartupVector
= BASE_1MB
- 1;
121 Status
= gBS
->AllocatePages (
123 EfiReservedMemoryType
,
125 &AcpiCpuDataEx
->AcpiCpuData
.StartupVector
127 ASSERT_EFI_ERROR (Status
);
129 DEBUG ((EFI_D_VERBOSE
, "%a\n", __FUNCTION__
));
130 MtrrGetAllMtrrs (&AcpiCpuDataEx
->MtrrTable
);
133 // Close event, so it will not be invoked again.
135 gBS
->CloseEvent (Event
);
139 The entry function of the CpuS3Data driver.
141 Allocate and initialize all fields of the ACPI_CPU_DATA structure except the
142 MTRR settings. Register an event notification on gEfiEndOfDxeEventGroupGuid
143 to capture the ACPI_CPU_DATA MTRR settings. The PcdCpuS3DataAddress is set
144 to the address that ACPI_CPU_DATA is allocated at.
146 @param[in] ImageHandle The firmware allocated handle for the EFI image.
147 @param[in] SystemTable A pointer to the EFI System Table.
149 @retval EFI_SUCCESS The entry point is executed successfully.
150 @retval EFI_UNSUPPORTED Do not support ACPI S3.
151 @retval other Some error occurs when executing this entry point.
156 CpuS3DataInitialize (
157 IN EFI_HANDLE ImageHandle
,
158 IN EFI_SYSTEM_TABLE
*SystemTable
162 ACPI_CPU_DATA_EX
*AcpiCpuDataEx
;
163 ACPI_CPU_DATA
*AcpiCpuData
;
164 EFI_MP_SERVICES_PROTOCOL
*MpServices
;
166 UINTN NumberOfEnabledProcessors
;
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
;
189 // Get MP Services Protocol
191 Status
= gBS
->LocateProtocol (
192 &gEfiMpServiceProtocolGuid
,
196 ASSERT_EFI_ERROR (Status
);
199 // Get the number of CPUs
201 Status
= MpServices
->GetNumberOfProcessors (
204 &NumberOfEnabledProcessors
206 ASSERT_EFI_ERROR (Status
);
207 AcpiCpuData
->NumberOfCpus
= (UINT32
)NumberOfCpus
;
210 // Initialize ACPI_CPU_DATA fields
212 AcpiCpuData
->StackSize
= PcdGet32 (PcdCpuApStackSize
);
213 AcpiCpuData
->ApMachineCheckHandlerBase
= 0;
214 AcpiCpuData
->ApMachineCheckHandlerSize
= 0;
215 AcpiCpuData
->GdtrProfile
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)&AcpiCpuDataEx
->GdtrProfile
;
216 AcpiCpuData
->IdtrProfile
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)&AcpiCpuDataEx
->IdtrProfile
;
217 AcpiCpuData
->MtrrTable
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)&AcpiCpuDataEx
->MtrrTable
;
220 // Allocate stack space for all CPUs.
221 // Use ACPI NVS memory type because this data will be directly used by APs
222 // in S3 resume phase in long mode. Also during S3 resume, the stack buffer
223 // will only be used as scratch space. i.e. we won't read anything from it
224 // before we write to it, in PiSmmCpuDxeSmm.
226 Stack
= AllocateAcpiNvsMemory (NumberOfCpus
* AcpiCpuData
->StackSize
);
227 ASSERT (Stack
!= NULL
);
228 AcpiCpuData
->StackAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)Stack
;
231 // Get the boot processor's GDT and IDT
233 AsmReadGdtr (&AcpiCpuDataEx
->GdtrProfile
);
234 AsmReadIdtr (&AcpiCpuDataEx
->IdtrProfile
);
237 // Allocate GDT and IDT and copy current GDT and IDT contents
239 GdtSize
= AcpiCpuDataEx
->GdtrProfile
.Limit
+ 1;
240 IdtSize
= AcpiCpuDataEx
->IdtrProfile
.Limit
+ 1;
241 Gdt
= AllocateZeroPages (GdtSize
+ IdtSize
);
242 ASSERT (Gdt
!= NULL
);
243 Idt
= (VOID
*)((UINTN
)Gdt
+ GdtSize
);
244 CopyMem (Gdt
, (VOID
*)AcpiCpuDataEx
->GdtrProfile
.Base
, GdtSize
);
245 CopyMem (Idt
, (VOID
*)AcpiCpuDataEx
->IdtrProfile
.Base
, IdtSize
);
246 AcpiCpuDataEx
->GdtrProfile
.Base
= (UINTN
)Gdt
;
247 AcpiCpuDataEx
->IdtrProfile
.Base
= (UINTN
)Idt
;
249 if (OldAcpiCpuData
!= NULL
) {
250 AcpiCpuData
->RegisterTable
= OldAcpiCpuData
->RegisterTable
;
251 AcpiCpuData
->PreSmmInitRegisterTable
= OldAcpiCpuData
->PreSmmInitRegisterTable
;
252 AcpiCpuData
->ApLocation
= OldAcpiCpuData
->ApLocation
;
253 CopyMem (&AcpiCpuData
->CpuStatus
, &OldAcpiCpuData
->CpuStatus
, sizeof (CPU_STATUS_INFORMATION
));
257 // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure
259 Status
= PcdSet64S (PcdCpuS3DataAddress
, (UINT64
)(UINTN
)AcpiCpuData
);
260 ASSERT_EFI_ERROR (Status
);
263 // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.
264 // The notification function allocates StartupVector and saves MTRRs for ACPI_CPU_DATA
266 Status
= gBS
->CreateEventEx (
271 &gEfiEndOfDxeEventGroupGuid
,
274 ASSERT_EFI_ERROR (Status
);