]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/CpuS3DataDxe/CpuS3Data.c
ArmPkg: only attempt buildin MmCommunicationDxe for AArch64
[mirror_edk2.git] / UefiCpuPkg / CpuS3DataDxe / CpuS3Data.c
CommitLineData
bfec5efa
MK
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
9cc45009 12Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>\r
bfec5efa
MK
13Copyright (c) 2015, Red Hat, Inc.\r
14\r
0acd8697 15SPDX-License-Identifier: BSD-2-Clause-Patent\r
bfec5efa
MK
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
b5817210 28#include <Library/MemoryAllocationLib.h>\r
bfec5efa
MK
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
6eab8b43 44 Allocate EfiACPIMemoryNVS memory.\r
bfec5efa
MK
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
6eab8b43 52AllocateAcpiNvsMemory (\r
bfec5efa
MK
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
bfec5efa 60 Status = gBS->AllocatePages (\r
6eab8b43 61 AllocateAnyPages,\r
bfec5efa
MK
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
b5817210
ED
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
bfec5efa
MK
98/**\r
99 Callback function executed when the EndOfDxe event group is signaled.\r
100\r
65b24ada 101 We delay allocating StartupVector and saving the MTRR settings until BDS signals EndOfDxe.\r
bfec5efa
MK
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
65b24ada 108CpuS3DataOnEndOfDxe (\r
bfec5efa
MK
109 IN EFI_EVENT Event,\r
110 OUT VOID *Context\r
111 )\r
112{\r
65b24ada
JF
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
bfec5efa 129 DEBUG ((EFI_D_VERBOSE, "%a\n", __FUNCTION__));\r
65b24ada 130 MtrrGetAllMtrrs (&AcpiCpuDataEx->MtrrTable);\r
bfec5efa
MK
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
ca98f603 150 @retval EFI_UNSUPPORTED Do not support ACPI S3.\r
bfec5efa
MK
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
8b371e93 177 ACPI_CPU_DATA *OldAcpiCpuData;\r
bfec5efa 178\r
ca98f603
SZ
179 if (!PcdGetBool (PcdAcpiS3Enable)) {\r
180 return EFI_UNSUPPORTED;\r
181 }\r
182\r
8b371e93
JF
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
b5817210 188 AcpiCpuDataEx = AllocateZeroPages (sizeof (ACPI_CPU_DATA_EX));\r
bfec5efa
MK
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
bfec5efa
MK
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
6eab8b43
ED
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
bfec5efa 229 //\r
6eab8b43 230 Stack = AllocateAcpiNvsMemory (NumberOfCpus * AcpiCpuData->StackSize);\r
bfec5efa
MK
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
b5817210 241 // Allocate GDT and IDT and copy current GDT and IDT contents\r
bfec5efa
MK
242 //\r
243 GdtSize = AcpiCpuDataEx->GdtrProfile.Limit + 1;\r
244 IdtSize = AcpiCpuDataEx->IdtrProfile.Limit + 1;\r
b5817210 245 Gdt = AllocateZeroPages (GdtSize + IdtSize);\r
bfec5efa
MK
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
8b371e93
JF
253 if (OldAcpiCpuData != NULL) {\r
254 AcpiCpuData->RegisterTable = OldAcpiCpuData->RegisterTable;\r
255 AcpiCpuData->PreSmmInitRegisterTable = OldAcpiCpuData->PreSmmInitRegisterTable;\r
38381e18
ED
256 AcpiCpuData->ApLocation = OldAcpiCpuData->ApLocation;\r
257 CopyMem (&AcpiCpuData->CpuStatus, &OldAcpiCpuData->CpuStatus, sizeof (CPU_STATUS_INFORMATION));\r
8b371e93
JF
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
b5817210 263 RegisterTable = (CPU_REGISTER_TABLE *)AllocateZeroPages (TableSize);\r
8b371e93
JF
264 ASSERT (RegisterTable != NULL);\r
265\r
266 for (Index = 0; Index < NumberOfCpus; Index++) {\r
267 Status = MpServices->GetProcessorInfo (\r
bfec5efa
MK
268 MpServices,\r
269 Index,\r
270 &ProcessorInfoBuffer\r
271 );\r
8b371e93
JF
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
bfec5efa 286 }\r
bfec5efa
MK
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
65b24ada 296 // The notification function allocates StartupVector and saves MTRRs for ACPI_CPU_DATA\r
bfec5efa
MK
297 //\r
298 Status = gBS->CreateEventEx (\r
299 EVT_NOTIFY_SIGNAL,\r
300 TPL_CALLBACK,\r
65b24ada
JF
301 CpuS3DataOnEndOfDxe,\r
302 AcpiCpuData,\r
bfec5efa
MK
303 &gEfiEndOfDxeEventGroupGuid,\r
304 &Event\r
305 );\r
306 ASSERT_EFI_ERROR (Status);\r
307\r
308 return EFI_SUCCESS;\r
309}\r