]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - UefiCpuPkg/CpuS3DataDxe/CpuS3Data.c
ArmPkg: only attempt buildin MmCommunicationDxe for AArch64
[mirror_edk2.git] / UefiCpuPkg / CpuS3DataDxe / CpuS3Data.c
... / ...
CommitLineData
1/** @file\r
2ACPI CPU Data initialization module\r
3\r
4This module initializes the ACPI_CPU_DATA structure and registers the address\r
5of this structure in the PcdCpuS3DataAddress PCD. This is a generic/simple\r
6version of this module. It does not provide a machine check handler or CPU\r
7register initialization tables for ACPI S3 resume. It also only supports the\r
8number of CPUs reported by the MP Services Protocol, so this module does not\r
9support hot plug CPUs. This module can be copied into a CPU specific package\r
10and customized if these additional features are required.\r
11\r
12Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>\r
13Copyright (c) 2015, Red Hat, Inc.\r
14\r
15SPDX-License-Identifier: BSD-2-Clause-Patent\r
16\r
17**/\r
18\r
19#include <PiDxe.h>\r
20\r
21#include <AcpiCpuData.h>\r
22\r
23#include <Library/BaseLib.h>\r
24#include <Library/BaseMemoryLib.h>\r
25#include <Library/UefiBootServicesTableLib.h>\r
26#include <Library/DebugLib.h>\r
27#include <Library/MtrrLib.h>\r
28#include <Library/MemoryAllocationLib.h>\r
29\r
30#include <Protocol/MpService.h>\r
31#include <Guid/EventGroup.h>\r
32\r
33//\r
34// Data structure used to allocate ACPI_CPU_DATA and its supporting structures\r
35//\r
36typedef struct {\r
37 ACPI_CPU_DATA AcpiCpuData;\r
38 MTRR_SETTINGS MtrrTable;\r
39 IA32_DESCRIPTOR GdtrProfile;\r
40 IA32_DESCRIPTOR IdtrProfile;\r
41} ACPI_CPU_DATA_EX;\r
42\r
43/**\r
44 Allocate EfiACPIMemoryNVS memory.\r
45\r
46 @param[in] Size Size of memory to allocate.\r
47\r
48 @return Allocated address for output.\r
49\r
50**/\r
51VOID *\r
52AllocateAcpiNvsMemory (\r
53 IN UINTN Size\r
54 )\r
55{\r
56 EFI_PHYSICAL_ADDRESS Address;\r
57 EFI_STATUS Status;\r
58 VOID *Buffer;\r
59\r
60 Status = gBS->AllocatePages (\r
61 AllocateAnyPages,\r
62 EfiACPIMemoryNVS,\r
63 EFI_SIZE_TO_PAGES (Size),\r
64 &Address\r
65 );\r
66 if (EFI_ERROR (Status)) {\r
67 return NULL;\r
68 }\r
69\r
70 Buffer = (VOID *)(UINTN)Address;\r
71 ZeroMem (Buffer, Size);\r
72\r
73 return Buffer;\r
74}\r
75\r
76/**\r
77 Allocate memory and clean it with zero.\r
78\r
79 @param[in] Size Size of memory to allocate.\r
80\r
81 @return Allocated address for output.\r
82\r
83**/\r
84VOID *\r
85AllocateZeroPages (\r
86 IN UINTN Size\r
87 )\r
88{\r
89 VOID *Buffer;\r
90\r
91 Buffer = AllocatePages (EFI_SIZE_TO_PAGES (Size));\r
92 if (Buffer != NULL) {\r
93 ZeroMem (Buffer, Size);\r
94 }\r
95\r
96 return Buffer;\r
97}\r
98/**\r
99 Callback function executed when the EndOfDxe event group is signaled.\r
100\r
101 We delay allocating StartupVector and saving the MTRR settings until BDS signals EndOfDxe.\r
102\r
103 @param[in] Event Event whose notification function is being invoked.\r
104 @param[out] Context Pointer to the MTRR_SETTINGS buffer to fill in.\r
105**/\r
106VOID\r
107EFIAPI\r
108CpuS3DataOnEndOfDxe (\r
109 IN EFI_EVENT Event,\r
110 OUT VOID *Context\r
111 )\r
112{\r
113 EFI_STATUS Status;\r
114 ACPI_CPU_DATA_EX *AcpiCpuDataEx;\r
115\r
116 AcpiCpuDataEx = (ACPI_CPU_DATA_EX *) Context;\r
117 //\r
118 // Allocate a 4KB reserved page below 1MB\r
119 //\r
120 AcpiCpuDataEx->AcpiCpuData.StartupVector = BASE_1MB - 1;\r
121 Status = gBS->AllocatePages (\r
122 AllocateMaxAddress,\r
123 EfiReservedMemoryType,\r
124 1,\r
125 &AcpiCpuDataEx->AcpiCpuData.StartupVector\r
126 );\r
127 ASSERT_EFI_ERROR (Status);\r
128\r
129 DEBUG ((EFI_D_VERBOSE, "%a\n", __FUNCTION__));\r
130 MtrrGetAllMtrrs (&AcpiCpuDataEx->MtrrTable);\r
131\r
132 //\r
133 // Close event, so it will not be invoked again.\r
134 //\r
135 gBS->CloseEvent (Event);\r
136}\r
137\r
138/**\r
139 The entry function of the CpuS3Data driver.\r
140\r
141 Allocate and initialize all fields of the ACPI_CPU_DATA structure except the\r
142 MTRR settings. Register an event notification on gEfiEndOfDxeEventGroupGuid\r
143 to capture the ACPI_CPU_DATA MTRR settings. The PcdCpuS3DataAddress is set\r
144 to the address that ACPI_CPU_DATA is allocated at.\r
145\r
146 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
147 @param[in] SystemTable A pointer to the EFI System Table.\r
148\r
149 @retval EFI_SUCCESS The entry point is executed successfully.\r
150 @retval EFI_UNSUPPORTED Do not support ACPI S3.\r
151 @retval other Some error occurs when executing this entry point.\r
152\r
153**/\r
154EFI_STATUS\r
155EFIAPI\r
156CpuS3DataInitialize (\r
157 IN EFI_HANDLE ImageHandle,\r
158 IN EFI_SYSTEM_TABLE *SystemTable\r
159 )\r
160{\r
161 EFI_STATUS Status;\r
162 ACPI_CPU_DATA_EX *AcpiCpuDataEx;\r
163 ACPI_CPU_DATA *AcpiCpuData;\r
164 EFI_MP_SERVICES_PROTOCOL *MpServices;\r
165 UINTN NumberOfCpus;\r
166 UINTN NumberOfEnabledProcessors;\r
167 VOID *Stack;\r
168 UINTN TableSize;\r
169 CPU_REGISTER_TABLE *RegisterTable;\r
170 UINTN Index;\r
171 EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer;\r
172 UINTN GdtSize;\r
173 UINTN IdtSize;\r
174 VOID *Gdt;\r
175 VOID *Idt;\r
176 EFI_EVENT Event;\r
177 ACPI_CPU_DATA *OldAcpiCpuData;\r
178\r
179 if (!PcdGetBool (PcdAcpiS3Enable)) {\r
180 return EFI_UNSUPPORTED;\r
181 }\r
182\r
183 //\r
184 // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure\r
185 //\r
186 OldAcpiCpuData = (ACPI_CPU_DATA *) (UINTN) PcdGet64 (PcdCpuS3DataAddress);\r
187\r
188 AcpiCpuDataEx = AllocateZeroPages (sizeof (ACPI_CPU_DATA_EX));\r
189 ASSERT (AcpiCpuDataEx != NULL);\r
190 AcpiCpuData = &AcpiCpuDataEx->AcpiCpuData;\r
191\r
192 //\r
193 // Get MP Services Protocol\r
194 //\r
195 Status = gBS->LocateProtocol (\r
196 &gEfiMpServiceProtocolGuid,\r
197 NULL,\r
198 (VOID **)&MpServices\r
199 );\r
200 ASSERT_EFI_ERROR (Status);\r
201\r
202 //\r
203 // Get the number of CPUs\r
204 //\r
205 Status = MpServices->GetNumberOfProcessors (\r
206 MpServices,\r
207 &NumberOfCpus,\r
208 &NumberOfEnabledProcessors\r
209 );\r
210 ASSERT_EFI_ERROR (Status);\r
211 AcpiCpuData->NumberOfCpus = (UINT32)NumberOfCpus;\r
212\r
213 //\r
214 // Initialize ACPI_CPU_DATA fields\r
215 //\r
216 AcpiCpuData->StackSize = PcdGet32 (PcdCpuApStackSize);\r
217 AcpiCpuData->ApMachineCheckHandlerBase = 0;\r
218 AcpiCpuData->ApMachineCheckHandlerSize = 0;\r
219 AcpiCpuData->GdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->GdtrProfile;\r
220 AcpiCpuData->IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->IdtrProfile;\r
221 AcpiCpuData->MtrrTable = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->MtrrTable;\r
222\r
223 //\r
224 // Allocate stack space for all CPUs.\r
225 // Use ACPI NVS memory type because this data will be directly used by APs\r
226 // in S3 resume phase in long mode. Also during S3 resume, the stack buffer\r
227 // will only be used as scratch space. i.e. we won't read anything from it\r
228 // before we write to it, in PiSmmCpuDxeSmm.\r
229 //\r
230 Stack = AllocateAcpiNvsMemory (NumberOfCpus * AcpiCpuData->StackSize);\r
231 ASSERT (Stack != NULL);\r
232 AcpiCpuData->StackAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Stack;\r
233\r
234 //\r
235 // Get the boot processor's GDT and IDT\r
236 //\r
237 AsmReadGdtr (&AcpiCpuDataEx->GdtrProfile);\r
238 AsmReadIdtr (&AcpiCpuDataEx->IdtrProfile);\r
239\r
240 //\r
241 // Allocate GDT and IDT and copy current GDT and IDT contents\r
242 //\r
243 GdtSize = AcpiCpuDataEx->GdtrProfile.Limit + 1;\r
244 IdtSize = AcpiCpuDataEx->IdtrProfile.Limit + 1;\r
245 Gdt = AllocateZeroPages (GdtSize + IdtSize);\r
246 ASSERT (Gdt != NULL);\r
247 Idt = (VOID *)((UINTN)Gdt + GdtSize);\r
248 CopyMem (Gdt, (VOID *)AcpiCpuDataEx->GdtrProfile.Base, GdtSize);\r
249 CopyMem (Idt, (VOID *)AcpiCpuDataEx->IdtrProfile.Base, IdtSize);\r
250 AcpiCpuDataEx->GdtrProfile.Base = (UINTN)Gdt;\r
251 AcpiCpuDataEx->IdtrProfile.Base = (UINTN)Idt;\r
252\r
253 if (OldAcpiCpuData != NULL) {\r
254 AcpiCpuData->RegisterTable = OldAcpiCpuData->RegisterTable;\r
255 AcpiCpuData->PreSmmInitRegisterTable = OldAcpiCpuData->PreSmmInitRegisterTable;\r
256 AcpiCpuData->ApLocation = OldAcpiCpuData->ApLocation;\r
257 CopyMem (&AcpiCpuData->CpuStatus, &OldAcpiCpuData->CpuStatus, sizeof (CPU_STATUS_INFORMATION));\r
258 } else {\r
259 //\r
260 // Allocate buffer for empty RegisterTable and PreSmmInitRegisterTable for all CPUs\r
261 //\r
262 TableSize = 2 * NumberOfCpus * sizeof (CPU_REGISTER_TABLE);\r
263 RegisterTable = (CPU_REGISTER_TABLE *)AllocateZeroPages (TableSize);\r
264 ASSERT (RegisterTable != NULL);\r
265\r
266 for (Index = 0; Index < NumberOfCpus; Index++) {\r
267 Status = MpServices->GetProcessorInfo (\r
268 MpServices,\r
269 Index,\r
270 &ProcessorInfoBuffer\r
271 );\r
272 ASSERT_EFI_ERROR (Status);\r
273\r
274 RegisterTable[Index].InitialApicId = (UINT32)ProcessorInfoBuffer.ProcessorId;\r
275 RegisterTable[Index].TableLength = 0;\r
276 RegisterTable[Index].AllocatedSize = 0;\r
277 RegisterTable[Index].RegisterTableEntry = 0;\r
278\r
279 RegisterTable[NumberOfCpus + Index].InitialApicId = (UINT32)ProcessorInfoBuffer.ProcessorId;\r
280 RegisterTable[NumberOfCpus + Index].TableLength = 0;\r
281 RegisterTable[NumberOfCpus + Index].AllocatedSize = 0;\r
282 RegisterTable[NumberOfCpus + Index].RegisterTableEntry = 0;\r
283 }\r
284 AcpiCpuData->RegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)RegisterTable;\r
285 AcpiCpuData->PreSmmInitRegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)(RegisterTable + NumberOfCpus);\r
286 }\r
287\r
288 //\r
289 // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure\r
290 //\r
291 Status = PcdSet64S (PcdCpuS3DataAddress, (UINT64)(UINTN)AcpiCpuData);\r
292 ASSERT_EFI_ERROR (Status);\r
293\r
294 //\r
295 // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.\r
296 // The notification function allocates StartupVector and saves MTRRs for ACPI_CPU_DATA\r
297 //\r
298 Status = gBS->CreateEventEx (\r
299 EVT_NOTIFY_SIGNAL,\r
300 TPL_CALLBACK,\r
301 CpuS3DataOnEndOfDxe,\r
302 AcpiCpuData,\r
303 &gEfiEndOfDxeEventGroupGuid,\r
304 &Event\r
305 );\r
306 ASSERT_EFI_ERROR (Status);\r
307\r
308 return EFI_SUCCESS;\r
309}\r