]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/CpuS3DataDxe/CpuS3Data.c
OvmfPkg: Apply uncrustify changes
[mirror_edk2.git] / OvmfPkg / CpuS3DataDxe / CpuS3Data.c
CommitLineData
55942db1
LE
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
010753b7 12Copyright (c) 2013 - 2021, Intel Corporation. All rights reserved.<BR>\r
55942db1
LE
13Copyright (c) 2015 - 2020, 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
55942db1 25#include <Library/DebugLib.h>\r
55942db1 26#include <Library/MemoryAllocationLib.h>\r
8f3ed1bc
LE
27#include <Library/MtrrLib.h>\r
28#include <Library/UefiBootServicesTableLib.h>\r
55942db1
LE
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
ac0a286f
MK
37 ACPI_CPU_DATA AcpiCpuData;\r
38 MTRR_SETTINGS MtrrTable;\r
39 IA32_DESCRIPTOR GdtrProfile;\r
40 IA32_DESCRIPTOR IdtrProfile;\r
55942db1
LE
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
ac0a286f
MK
60 Status = gBS->AllocatePages (\r
61 AllocateAnyPages,\r
62 EfiACPIMemoryNVS,\r
63 EFI_SIZE_TO_PAGES (Size),\r
64 &Address\r
65 );\r
55942db1
LE
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
ac0a286f 89 VOID *Buffer;\r
55942db1
LE
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
ac0a286f 98\r
55942db1
LE
99/**\r
100 Callback function executed when the EndOfDxe event group is signaled.\r
101\r
102 We delay allocating StartupVector and saving the MTRR settings until BDS signals EndOfDxe.\r
103\r
104 @param[in] Event Event whose notification function is being invoked.\r
105 @param[out] Context Pointer to the MTRR_SETTINGS buffer to fill in.\r
106**/\r
107VOID\r
108EFIAPI\r
109CpuS3DataOnEndOfDxe (\r
110 IN EFI_EVENT Event,\r
111 OUT VOID *Context\r
112 )\r
113{\r
ac0a286f
MK
114 EFI_STATUS Status;\r
115 ACPI_CPU_DATA_EX *AcpiCpuDataEx;\r
55942db1 116\r
ac0a286f 117 AcpiCpuDataEx = (ACPI_CPU_DATA_EX *)Context;\r
55942db1
LE
118 //\r
119 // Allocate a 4KB reserved page below 1MB\r
120 //\r
121 AcpiCpuDataEx->AcpiCpuData.StartupVector = BASE_1MB - 1;\r
ac0a286f
MK
122 Status = gBS->AllocatePages (\r
123 AllocateMaxAddress,\r
124 EfiReservedMemoryType,\r
125 1,\r
126 &AcpiCpuDataEx->AcpiCpuData.StartupVector\r
127 );\r
55942db1
LE
128 ASSERT_EFI_ERROR (Status);\r
129\r
130 DEBUG ((DEBUG_VERBOSE, "%a\n", __FUNCTION__));\r
131 MtrrGetAllMtrrs (&AcpiCpuDataEx->MtrrTable);\r
132\r
133 //\r
134 // Close event, so it will not be invoked again.\r
135 //\r
136 gBS->CloseEvent (Event);\r
137}\r
138\r
139/**\r
140 The entry function of the CpuS3Data driver.\r
141\r
142 Allocate and initialize all fields of the ACPI_CPU_DATA structure except the\r
143 MTRR settings. Register an event notification on gEfiEndOfDxeEventGroupGuid\r
144 to capture the ACPI_CPU_DATA MTRR settings. The PcdCpuS3DataAddress is set\r
145 to the address that ACPI_CPU_DATA is allocated at.\r
146\r
147 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
148 @param[in] SystemTable A pointer to the EFI System Table.\r
149\r
150 @retval EFI_SUCCESS The entry point is executed successfully.\r
151 @retval EFI_UNSUPPORTED Do not support ACPI S3.\r
152 @retval other Some error occurs when executing this entry point.\r
153\r
154**/\r
155EFI_STATUS\r
156EFIAPI\r
157CpuS3DataInitialize (\r
158 IN EFI_HANDLE ImageHandle,\r
159 IN EFI_SYSTEM_TABLE *SystemTable\r
160 )\r
161{\r
ac0a286f
MK
162 EFI_STATUS Status;\r
163 ACPI_CPU_DATA_EX *AcpiCpuDataEx;\r
164 ACPI_CPU_DATA *AcpiCpuData;\r
165 EFI_MP_SERVICES_PROTOCOL *MpServices;\r
166 UINTN NumberOfCpus;\r
167 VOID *Stack;\r
168 UINTN GdtSize;\r
169 UINTN IdtSize;\r
170 VOID *Gdt;\r
171 VOID *Idt;\r
172 EFI_EVENT Event;\r
173 ACPI_CPU_DATA *OldAcpiCpuData;\r
55942db1
LE
174\r
175 if (!PcdGetBool (PcdAcpiS3Enable)) {\r
176 return EFI_UNSUPPORTED;\r
177 }\r
178\r
179 //\r
180 // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure\r
181 //\r
ac0a286f 182 OldAcpiCpuData = (ACPI_CPU_DATA *)(UINTN)PcdGet64 (PcdCpuS3DataAddress);\r
55942db1
LE
183\r
184 AcpiCpuDataEx = AllocateZeroPages (sizeof (ACPI_CPU_DATA_EX));\r
185 ASSERT (AcpiCpuDataEx != NULL);\r
186 AcpiCpuData = &AcpiCpuDataEx->AcpiCpuData;\r
187\r
339371ef 188 if (PcdGetBool (PcdQ35SmramAtDefaultSmbase)) {\r
1158fc8e
LE
189 NumberOfCpus = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);\r
190 } else {\r
ac0a286f 191 UINTN NumberOfEnabledProcessors;\r
1158fc8e
LE
192\r
193 //\r
194 // Get MP Services Protocol\r
195 //\r
196 Status = gBS->LocateProtocol (\r
197 &gEfiMpServiceProtocolGuid,\r
198 NULL,\r
199 (VOID **)&MpServices\r
200 );\r
201 ASSERT_EFI_ERROR (Status);\r
202\r
203 //\r
204 // Get the number of CPUs\r
205 //\r
206 Status = MpServices->GetNumberOfProcessors (\r
207 MpServices,\r
208 &NumberOfCpus,\r
209 &NumberOfEnabledProcessors\r
210 );\r
211 ASSERT_EFI_ERROR (Status);\r
212 }\r
ac0a286f 213\r
55942db1
LE
214 AcpiCpuData->NumberOfCpus = (UINT32)NumberOfCpus;\r
215\r
216 //\r
217 // Initialize ACPI_CPU_DATA fields\r
218 //\r
219 AcpiCpuData->StackSize = PcdGet32 (PcdCpuApStackSize);\r
220 AcpiCpuData->ApMachineCheckHandlerBase = 0;\r
221 AcpiCpuData->ApMachineCheckHandlerSize = 0;\r
ac0a286f
MK
222 AcpiCpuData->GdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->GdtrProfile;\r
223 AcpiCpuData->IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->IdtrProfile;\r
224 AcpiCpuData->MtrrTable = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->MtrrTable;\r
55942db1
LE
225\r
226 //\r
227 // Allocate stack space for all CPUs.\r
228 // Use ACPI NVS memory type because this data will be directly used by APs\r
229 // in S3 resume phase in long mode. Also during S3 resume, the stack buffer\r
230 // will only be used as scratch space. i.e. we won't read anything from it\r
231 // before we write to it, in PiSmmCpuDxeSmm.\r
232 //\r
233 Stack = AllocateAcpiNvsMemory (NumberOfCpus * AcpiCpuData->StackSize);\r
234 ASSERT (Stack != NULL);\r
235 AcpiCpuData->StackAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Stack;\r
236\r
237 //\r
238 // Get the boot processor's GDT and IDT\r
239 //\r
240 AsmReadGdtr (&AcpiCpuDataEx->GdtrProfile);\r
241 AsmReadIdtr (&AcpiCpuDataEx->IdtrProfile);\r
242\r
243 //\r
244 // Allocate GDT and IDT and copy current GDT and IDT contents\r
245 //\r
246 GdtSize = AcpiCpuDataEx->GdtrProfile.Limit + 1;\r
247 IdtSize = AcpiCpuDataEx->IdtrProfile.Limit + 1;\r
ac0a286f 248 Gdt = AllocateZeroPages (GdtSize + IdtSize);\r
55942db1
LE
249 ASSERT (Gdt != NULL);\r
250 Idt = (VOID *)((UINTN)Gdt + GdtSize);\r
251 CopyMem (Gdt, (VOID *)AcpiCpuDataEx->GdtrProfile.Base, GdtSize);\r
252 CopyMem (Idt, (VOID *)AcpiCpuDataEx->IdtrProfile.Base, IdtSize);\r
253 AcpiCpuDataEx->GdtrProfile.Base = (UINTN)Gdt;\r
254 AcpiCpuDataEx->IdtrProfile.Base = (UINTN)Idt;\r
255\r
256 if (OldAcpiCpuData != NULL) {\r
010753b7 257 CopyMem (&AcpiCpuData->CpuFeatureInitData, &OldAcpiCpuData->CpuFeatureInitData, sizeof (CPU_FEATURE_INIT_DATA));\r
55942db1
LE
258 }\r
259\r
260 //\r
261 // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure\r
262 //\r
263 Status = PcdSet64S (PcdCpuS3DataAddress, (UINT64)(UINTN)AcpiCpuData);\r
264 ASSERT_EFI_ERROR (Status);\r
265\r
266 //\r
267 // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.\r
268 // The notification function allocates StartupVector and saves MTRRs for ACPI_CPU_DATA\r
269 //\r
270 Status = gBS->CreateEventEx (\r
271 EVT_NOTIFY_SIGNAL,\r
272 TPL_CALLBACK,\r
273 CpuS3DataOnEndOfDxe,\r
274 AcpiCpuData,\r
275 &gEfiEndOfDxeEventGroupGuid,\r
276 &Event\r
277 );\r
278 ASSERT_EFI_ERROR (Status);\r
279\r
280 return EFI_SUCCESS;\r
281}\r