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 This program and the accompanying materials
16 are licensed and made available under the terms and conditions of the BSD License
17 which accompanies this distribution. The full text of the license may be found at
18 http://opensource.org/licenses/bsd-license.php
20 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
21 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
27 #include <AcpiCpuData.h>
29 #include <Library/BaseLib.h>
30 #include <Library/BaseMemoryLib.h>
31 #include <Library/UefiBootServicesTableLib.h>
32 #include <Library/DebugLib.h>
33 #include <Library/MtrrLib.h>
34 #include <Library/MemoryAllocationLib.h>
36 #include <Protocol/MpService.h>
37 #include <Guid/EventGroup.h>
40 // Data structure used to allocate ACPI_CPU_DATA and its supporting structures
43 ACPI_CPU_DATA AcpiCpuData
;
44 MTRR_SETTINGS MtrrTable
;
45 IA32_DESCRIPTOR GdtrProfile
;
46 IA32_DESCRIPTOR IdtrProfile
;
50 Allocate EfiACPIMemoryNVS memory.
52 @param[in] Size Size of memory to allocate.
54 @return Allocated address for output.
58 AllocateAcpiNvsMemory (
62 EFI_PHYSICAL_ADDRESS Address
;
66 Status
= gBS
->AllocatePages (
69 EFI_SIZE_TO_PAGES (Size
),
72 if (EFI_ERROR (Status
)) {
76 Buffer
= (VOID
*)(UINTN
)Address
;
77 ZeroMem (Buffer
, Size
);
83 Allocate memory and clean it with zero.
85 @param[in] Size Size of memory to allocate.
87 @return Allocated address for output.
97 Buffer
= AllocatePages (EFI_SIZE_TO_PAGES (Size
));
99 ZeroMem (Buffer
, Size
);
105 Callback function executed when the EndOfDxe event group is signaled.
107 We delay allocating StartupVector and saving the MTRR settings until BDS signals EndOfDxe.
109 @param[in] Event Event whose notification function is being invoked.
110 @param[out] Context Pointer to the MTRR_SETTINGS buffer to fill in.
114 CpuS3DataOnEndOfDxe (
120 ACPI_CPU_DATA_EX
*AcpiCpuDataEx
;
122 AcpiCpuDataEx
= (ACPI_CPU_DATA_EX
*) Context
;
124 // Allocate a 4KB reserved page below 1MB
126 AcpiCpuDataEx
->AcpiCpuData
.StartupVector
= BASE_1MB
- 1;
127 Status
= gBS
->AllocatePages (
129 EfiReservedMemoryType
,
131 &AcpiCpuDataEx
->AcpiCpuData
.StartupVector
133 ASSERT_EFI_ERROR (Status
);
135 DEBUG ((EFI_D_VERBOSE
, "%a\n", __FUNCTION__
));
136 MtrrGetAllMtrrs (&AcpiCpuDataEx
->MtrrTable
);
139 // Close event, so it will not be invoked again.
141 gBS
->CloseEvent (Event
);
145 The entry function of the CpuS3Data driver.
147 Allocate and initialize all fields of the ACPI_CPU_DATA structure except the
148 MTRR settings. Register an event notification on gEfiEndOfDxeEventGroupGuid
149 to capture the ACPI_CPU_DATA MTRR settings. The PcdCpuS3DataAddress is set
150 to the address that ACPI_CPU_DATA is allocated at.
152 @param[in] ImageHandle The firmware allocated handle for the EFI image.
153 @param[in] SystemTable A pointer to the EFI System Table.
155 @retval EFI_SUCCESS The entry point is executed successfully.
156 @retval EFI_UNSUPPORTED Do not support ACPI S3.
157 @retval other Some error occurs when executing this entry point.
162 CpuS3DataInitialize (
163 IN EFI_HANDLE ImageHandle
,
164 IN EFI_SYSTEM_TABLE
*SystemTable
168 ACPI_CPU_DATA_EX
*AcpiCpuDataEx
;
169 ACPI_CPU_DATA
*AcpiCpuData
;
170 EFI_MP_SERVICES_PROTOCOL
*MpServices
;
172 UINTN NumberOfEnabledProcessors
;
175 CPU_REGISTER_TABLE
*RegisterTable
;
177 EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer
;
183 ACPI_CPU_DATA
*OldAcpiCpuData
;
185 if (!PcdGetBool (PcdAcpiS3Enable
)) {
186 return EFI_UNSUPPORTED
;
190 // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure
192 OldAcpiCpuData
= (ACPI_CPU_DATA
*) (UINTN
) PcdGet64 (PcdCpuS3DataAddress
);
194 AcpiCpuDataEx
= AllocateZeroPages (sizeof (ACPI_CPU_DATA_EX
));
195 ASSERT (AcpiCpuDataEx
!= NULL
);
196 AcpiCpuData
= &AcpiCpuDataEx
->AcpiCpuData
;
199 // Get MP Services Protocol
201 Status
= gBS
->LocateProtocol (
202 &gEfiMpServiceProtocolGuid
,
206 ASSERT_EFI_ERROR (Status
);
209 // Get the number of CPUs
211 Status
= MpServices
->GetNumberOfProcessors (
214 &NumberOfEnabledProcessors
216 ASSERT_EFI_ERROR (Status
);
217 AcpiCpuData
->NumberOfCpus
= (UINT32
)NumberOfCpus
;
220 // Initialize ACPI_CPU_DATA fields
222 AcpiCpuData
->StackSize
= PcdGet32 (PcdCpuApStackSize
);
223 AcpiCpuData
->ApMachineCheckHandlerBase
= 0;
224 AcpiCpuData
->ApMachineCheckHandlerSize
= 0;
225 AcpiCpuData
->GdtrProfile
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)&AcpiCpuDataEx
->GdtrProfile
;
226 AcpiCpuData
->IdtrProfile
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)&AcpiCpuDataEx
->IdtrProfile
;
227 AcpiCpuData
->MtrrTable
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)&AcpiCpuDataEx
->MtrrTable
;
230 // Allocate stack space for all CPUs.
231 // Use ACPI NVS memory type because this data will be directly used by APs
232 // in S3 resume phase in long mode. Also during S3 resume, the stack buffer
233 // will only be used as scratch space. i.e. we won't read anything from it
234 // before we write to it, in PiSmmCpuDxeSmm.
236 Stack
= AllocateAcpiNvsMemory (NumberOfCpus
* AcpiCpuData
->StackSize
);
237 ASSERT (Stack
!= NULL
);
238 AcpiCpuData
->StackAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)Stack
;
241 // Get the boot processor's GDT and IDT
243 AsmReadGdtr (&AcpiCpuDataEx
->GdtrProfile
);
244 AsmReadIdtr (&AcpiCpuDataEx
->IdtrProfile
);
247 // Allocate GDT and IDT and copy current GDT and IDT contents
249 GdtSize
= AcpiCpuDataEx
->GdtrProfile
.Limit
+ 1;
250 IdtSize
= AcpiCpuDataEx
->IdtrProfile
.Limit
+ 1;
251 Gdt
= AllocateZeroPages (GdtSize
+ IdtSize
);
252 ASSERT (Gdt
!= NULL
);
253 Idt
= (VOID
*)((UINTN
)Gdt
+ GdtSize
);
254 CopyMem (Gdt
, (VOID
*)AcpiCpuDataEx
->GdtrProfile
.Base
, GdtSize
);
255 CopyMem (Idt
, (VOID
*)AcpiCpuDataEx
->IdtrProfile
.Base
, IdtSize
);
256 AcpiCpuDataEx
->GdtrProfile
.Base
= (UINTN
)Gdt
;
257 AcpiCpuDataEx
->IdtrProfile
.Base
= (UINTN
)Idt
;
259 if (OldAcpiCpuData
!= NULL
) {
260 AcpiCpuData
->RegisterTable
= OldAcpiCpuData
->RegisterTable
;
261 AcpiCpuData
->PreSmmInitRegisterTable
= OldAcpiCpuData
->PreSmmInitRegisterTable
;
262 AcpiCpuData
->ApLocation
= OldAcpiCpuData
->ApLocation
;
263 CopyMem (&AcpiCpuData
->CpuStatus
, &OldAcpiCpuData
->CpuStatus
, sizeof (CPU_STATUS_INFORMATION
));
266 // Allocate buffer for empty RegisterTable and PreSmmInitRegisterTable for all CPUs
268 TableSize
= 2 * NumberOfCpus
* sizeof (CPU_REGISTER_TABLE
);
269 RegisterTable
= (CPU_REGISTER_TABLE
*)AllocateZeroPages (TableSize
);
270 ASSERT (RegisterTable
!= NULL
);
272 for (Index
= 0; Index
< NumberOfCpus
; Index
++) {
273 Status
= MpServices
->GetProcessorInfo (
278 ASSERT_EFI_ERROR (Status
);
280 RegisterTable
[Index
].InitialApicId
= (UINT32
)ProcessorInfoBuffer
.ProcessorId
;
281 RegisterTable
[Index
].TableLength
= 0;
282 RegisterTable
[Index
].AllocatedSize
= 0;
283 RegisterTable
[Index
].RegisterTableEntry
= 0;
285 RegisterTable
[NumberOfCpus
+ Index
].InitialApicId
= (UINT32
)ProcessorInfoBuffer
.ProcessorId
;
286 RegisterTable
[NumberOfCpus
+ Index
].TableLength
= 0;
287 RegisterTable
[NumberOfCpus
+ Index
].AllocatedSize
= 0;
288 RegisterTable
[NumberOfCpus
+ Index
].RegisterTableEntry
= 0;
290 AcpiCpuData
->RegisterTable
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)RegisterTable
;
291 AcpiCpuData
->PreSmmInitRegisterTable
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)(RegisterTable
+ NumberOfCpus
);
295 // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure
297 Status
= PcdSet64S (PcdCpuS3DataAddress
, (UINT64
)(UINTN
)AcpiCpuData
);
298 ASSERT_EFI_ERROR (Status
);
301 // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.
302 // The notification function allocates StartupVector and saves MTRRs for ACPI_CPU_DATA
304 Status
= gBS
->CreateEventEx (
309 &gEfiEndOfDxeEventGroupGuid
,
312 ASSERT_EFI_ERROR (Status
);