]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/CpuS3DataDxe/CpuS3Data.c
OvmfPkg/CpuS3DataDxe: do not allocate useless register tables
[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
12Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>\r
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
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 ((DEBUG_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
55942db1 166 VOID *Stack;\r
55942db1
LE
167 UINTN GdtSize;\r
168 UINTN IdtSize;\r
169 VOID *Gdt;\r
170 VOID *Idt;\r
171 EFI_EVENT Event;\r
172 ACPI_CPU_DATA *OldAcpiCpuData;\r
173\r
174 if (!PcdGetBool (PcdAcpiS3Enable)) {\r
175 return EFI_UNSUPPORTED;\r
176 }\r
177\r
178 //\r
179 // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure\r
180 //\r
181 OldAcpiCpuData = (ACPI_CPU_DATA *) (UINTN) PcdGet64 (PcdCpuS3DataAddress);\r
182\r
183 AcpiCpuDataEx = AllocateZeroPages (sizeof (ACPI_CPU_DATA_EX));\r
184 ASSERT (AcpiCpuDataEx != NULL);\r
185 AcpiCpuData = &AcpiCpuDataEx->AcpiCpuData;\r
186\r
339371ef 187 if (PcdGetBool (PcdQ35SmramAtDefaultSmbase)) {\r
1158fc8e
LE
188 NumberOfCpus = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);\r
189 } else {\r
190 UINTN NumberOfEnabledProcessors;\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 }\r
55942db1
LE
212 AcpiCpuData->NumberOfCpus = (UINT32)NumberOfCpus;\r
213\r
214 //\r
215 // Initialize ACPI_CPU_DATA fields\r
216 //\r
217 AcpiCpuData->StackSize = PcdGet32 (PcdCpuApStackSize);\r
218 AcpiCpuData->ApMachineCheckHandlerBase = 0;\r
219 AcpiCpuData->ApMachineCheckHandlerSize = 0;\r
220 AcpiCpuData->GdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->GdtrProfile;\r
221 AcpiCpuData->IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->IdtrProfile;\r
222 AcpiCpuData->MtrrTable = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->MtrrTable;\r
223\r
224 //\r
225 // Allocate stack space for all CPUs.\r
226 // Use ACPI NVS memory type because this data will be directly used by APs\r
227 // in S3 resume phase in long mode. Also during S3 resume, the stack buffer\r
228 // will only be used as scratch space. i.e. we won't read anything from it\r
229 // before we write to it, in PiSmmCpuDxeSmm.\r
230 //\r
231 Stack = AllocateAcpiNvsMemory (NumberOfCpus * AcpiCpuData->StackSize);\r
232 ASSERT (Stack != NULL);\r
233 AcpiCpuData->StackAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Stack;\r
234\r
235 //\r
236 // Get the boot processor's GDT and IDT\r
237 //\r
238 AsmReadGdtr (&AcpiCpuDataEx->GdtrProfile);\r
239 AsmReadIdtr (&AcpiCpuDataEx->IdtrProfile);\r
240\r
241 //\r
242 // Allocate GDT and IDT and copy current GDT and IDT contents\r
243 //\r
244 GdtSize = AcpiCpuDataEx->GdtrProfile.Limit + 1;\r
245 IdtSize = AcpiCpuDataEx->IdtrProfile.Limit + 1;\r
246 Gdt = AllocateZeroPages (GdtSize + IdtSize);\r
247 ASSERT (Gdt != NULL);\r
248 Idt = (VOID *)((UINTN)Gdt + GdtSize);\r
249 CopyMem (Gdt, (VOID *)AcpiCpuDataEx->GdtrProfile.Base, GdtSize);\r
250 CopyMem (Idt, (VOID *)AcpiCpuDataEx->IdtrProfile.Base, IdtSize);\r
251 AcpiCpuDataEx->GdtrProfile.Base = (UINTN)Gdt;\r
252 AcpiCpuDataEx->IdtrProfile.Base = (UINTN)Idt;\r
253\r
254 if (OldAcpiCpuData != NULL) {\r
255 AcpiCpuData->RegisterTable = OldAcpiCpuData->RegisterTable;\r
256 AcpiCpuData->PreSmmInitRegisterTable = OldAcpiCpuData->PreSmmInitRegisterTable;\r
257 AcpiCpuData->ApLocation = OldAcpiCpuData->ApLocation;\r
258 CopyMem (&AcpiCpuData->CpuStatus, &OldAcpiCpuData->CpuStatus, sizeof (CPU_STATUS_INFORMATION));\r
55942db1
LE
259 }\r
260\r
261 //\r
262 // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure\r
263 //\r
264 Status = PcdSet64S (PcdCpuS3DataAddress, (UINT64)(UINTN)AcpiCpuData);\r
265 ASSERT_EFI_ERROR (Status);\r
266\r
267 //\r
268 // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.\r
269 // The notification function allocates StartupVector and saves MTRRs for ACPI_CPU_DATA\r
270 //\r
271 Status = gBS->CreateEventEx (\r
272 EVT_NOTIFY_SIGNAL,\r
273 TPL_CALLBACK,\r
274 CpuS3DataOnEndOfDxe,\r
275 AcpiCpuData,\r
276 &gEfiEndOfDxeEventGroupGuid,\r
277 &Event\r
278 );\r
279 ASSERT_EFI_ERROR (Status);\r
280\r
281 return EFI_SUCCESS;\r
282}\r