]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - UefiCpuPkg/CpuS3DataDxe/CpuS3Data.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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 - 2021, 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/**\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
114 EFI_STATUS Status;\r
115 ACPI_CPU_DATA_EX *AcpiCpuDataEx;\r
116\r
117 AcpiCpuDataEx = (ACPI_CPU_DATA_EX *)Context;\r
118 //\r
119 // Allocate a 4KB reserved page below 1MB\r
120 //\r
121 AcpiCpuDataEx->AcpiCpuData.StartupVector = BASE_1MB - 1;\r
122 Status = gBS->AllocatePages (\r
123 AllocateMaxAddress,\r
124 EfiReservedMemoryType,\r
125 1,\r
126 &AcpiCpuDataEx->AcpiCpuData.StartupVector\r
127 );\r
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
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 UINTN NumberOfEnabledProcessors;\r
168 VOID *Stack;\r
169 UINTN GdtSize;\r
170 UINTN IdtSize;\r
171 VOID *Gdt;\r
172 VOID *Idt;\r
173 EFI_EVENT Event;\r
174 ACPI_CPU_DATA *OldAcpiCpuData;\r
175\r
176 if (!PcdGetBool (PcdAcpiS3Enable)) {\r
177 return EFI_UNSUPPORTED;\r
178 }\r
179\r
180 //\r
181 // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure\r
182 //\r
183 OldAcpiCpuData = (ACPI_CPU_DATA *)(UINTN)PcdGet64 (PcdCpuS3DataAddress);\r
184\r
185 AcpiCpuDataEx = AllocateZeroPages (sizeof (ACPI_CPU_DATA_EX));\r
186 ASSERT (AcpiCpuDataEx != NULL);\r
187 AcpiCpuData = &AcpiCpuDataEx->AcpiCpuData;\r
188\r
189 //\r
190 // Get MP Services Protocol\r
191 //\r
192 Status = gBS->LocateProtocol (\r
193 &gEfiMpServiceProtocolGuid,\r
194 NULL,\r
195 (VOID **)&MpServices\r
196 );\r
197 ASSERT_EFI_ERROR (Status);\r
198\r
199 //\r
200 // Get the number of CPUs\r
201 //\r
202 Status = MpServices->GetNumberOfProcessors (\r
203 MpServices,\r
204 &NumberOfCpus,\r
205 &NumberOfEnabledProcessors\r
206 );\r
207 ASSERT_EFI_ERROR (Status);\r
208 AcpiCpuData->NumberOfCpus = (UINT32)NumberOfCpus;\r
209\r
210 //\r
211 // Initialize ACPI_CPU_DATA fields\r
212 //\r
213 AcpiCpuData->StackSize = PcdGet32 (PcdCpuApStackSize);\r
214 AcpiCpuData->ApMachineCheckHandlerBase = 0;\r
215 AcpiCpuData->ApMachineCheckHandlerSize = 0;\r
216 AcpiCpuData->GdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->GdtrProfile;\r
217 AcpiCpuData->IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->IdtrProfile;\r
218 AcpiCpuData->MtrrTable = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->MtrrTable;\r
219\r
220 //\r
221 // Allocate stack space for all CPUs.\r
222 // Use ACPI NVS memory type because this data will be directly used by APs\r
223 // in S3 resume phase in long mode. Also during S3 resume, the stack buffer\r
224 // will only be used as scratch space. i.e. we won't read anything from it\r
225 // before we write to it, in PiSmmCpuDxeSmm.\r
226 //\r
227 Stack = AllocateAcpiNvsMemory (NumberOfCpus * AcpiCpuData->StackSize);\r
228 ASSERT (Stack != NULL);\r
229 AcpiCpuData->StackAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Stack;\r
230\r
231 //\r
232 // Get the boot processor's GDT and IDT\r
233 //\r
234 AsmReadGdtr (&AcpiCpuDataEx->GdtrProfile);\r
235 AsmReadIdtr (&AcpiCpuDataEx->IdtrProfile);\r
236\r
237 //\r
238 // Allocate GDT and IDT and copy current GDT and IDT contents\r
239 //\r
240 GdtSize = AcpiCpuDataEx->GdtrProfile.Limit + 1;\r
241 IdtSize = AcpiCpuDataEx->IdtrProfile.Limit + 1;\r
242 Gdt = AllocateZeroPages (GdtSize + IdtSize);\r
243 ASSERT (Gdt != NULL);\r
244 Idt = (VOID *)((UINTN)Gdt + GdtSize);\r
245 CopyMem (Gdt, (VOID *)AcpiCpuDataEx->GdtrProfile.Base, GdtSize);\r
246 CopyMem (Idt, (VOID *)AcpiCpuDataEx->IdtrProfile.Base, IdtSize);\r
247 AcpiCpuDataEx->GdtrProfile.Base = (UINTN)Gdt;\r
248 AcpiCpuDataEx->IdtrProfile.Base = (UINTN)Idt;\r
249\r
250 if (OldAcpiCpuData != NULL) {\r
251 CopyMem (&AcpiCpuData->CpuFeatureInitData, &OldAcpiCpuData->CpuFeatureInitData, sizeof (CPU_FEATURE_INIT_DATA));\r
252 }\r
253\r
254 //\r
255 // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure\r
256 //\r
257 Status = PcdSet64S (PcdCpuS3DataAddress, (UINT64)(UINTN)AcpiCpuData);\r
258 ASSERT_EFI_ERROR (Status);\r
259\r
260 //\r
261 // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.\r
262 // The notification function allocates StartupVector and saves MTRRs for ACPI_CPU_DATA\r
263 //\r
264 Status = gBS->CreateEventEx (\r
265 EVT_NOTIFY_SIGNAL,\r
266 TPL_CALLBACK,\r
267 CpuS3DataOnEndOfDxe,\r
268 AcpiCpuData,\r
269 &gEfiEndOfDxeEventGroupGuid,\r
270 &Event\r
271 );\r
272 ASSERT_EFI_ERROR (Status);\r
273\r
274 return EFI_SUCCESS;\r
275}\r