]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/CpuS3DataDxe/CpuS3Data.c
UefiCpuPkg: Apply uncrustify changes
[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
010753b7 12Copyright (c) 2013 - 2021, 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
053e878b
MK
37 ACPI_CPU_DATA AcpiCpuData;\r
38 MTRR_SETTINGS MtrrTable;\r
39 IA32_DESCRIPTOR GdtrProfile;\r
40 IA32_DESCRIPTOR IdtrProfile;\r
bfec5efa
MK
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
053e878b
MK
60 Status = gBS->AllocatePages (\r
61 AllocateAnyPages,\r
62 EfiACPIMemoryNVS,\r
63 EFI_SIZE_TO_PAGES (Size),\r
64 &Address\r
65 );\r
bfec5efa
MK
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
053e878b 89 VOID *Buffer;\r
b5817210
ED
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
053e878b 98\r
bfec5efa
MK
99/**\r
100 Callback function executed when the EndOfDxe event group is signaled.\r
101\r
65b24ada 102 We delay allocating StartupVector and saving the MTRR settings until BDS signals EndOfDxe.\r
bfec5efa
MK
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
65b24ada 109CpuS3DataOnEndOfDxe (\r
bfec5efa
MK
110 IN EFI_EVENT Event,\r
111 OUT VOID *Context\r
112 )\r
113{\r
053e878b
MK
114 EFI_STATUS Status;\r
115 ACPI_CPU_DATA_EX *AcpiCpuDataEx;\r
65b24ada 116\r
053e878b 117 AcpiCpuDataEx = (ACPI_CPU_DATA_EX *)Context;\r
65b24ada
JF
118 //\r
119 // Allocate a 4KB reserved page below 1MB\r
120 //\r
121 AcpiCpuDataEx->AcpiCpuData.StartupVector = BASE_1MB - 1;\r
053e878b
MK
122 Status = gBS->AllocatePages (\r
123 AllocateMaxAddress,\r
124 EfiReservedMemoryType,\r
125 1,\r
126 &AcpiCpuDataEx->AcpiCpuData.StartupVector\r
127 );\r
65b24ada
JF
128 ASSERT_EFI_ERROR (Status);\r
129\r
96e1cba5 130 DEBUG ((DEBUG_VERBOSE, "%a\n", __FUNCTION__));\r
65b24ada 131 MtrrGetAllMtrrs (&AcpiCpuDataEx->MtrrTable);\r
bfec5efa
MK
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
ca98f603 151 @retval EFI_UNSUPPORTED Do not support ACPI S3.\r
bfec5efa
MK
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
053e878b
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 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
bfec5efa 175\r
ca98f603
SZ
176 if (!PcdGetBool (PcdAcpiS3Enable)) {\r
177 return EFI_UNSUPPORTED;\r
178 }\r
179\r
8b371e93
JF
180 //\r
181 // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure\r
182 //\r
053e878b 183 OldAcpiCpuData = (ACPI_CPU_DATA *)(UINTN)PcdGet64 (PcdCpuS3DataAddress);\r
8b371e93 184\r
b5817210 185 AcpiCpuDataEx = AllocateZeroPages (sizeof (ACPI_CPU_DATA_EX));\r
bfec5efa
MK
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
bfec5efa
MK
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
053e878b
MK
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
bfec5efa
MK
219\r
220 //\r
6eab8b43
ED
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
bfec5efa 226 //\r
6eab8b43 227 Stack = AllocateAcpiNvsMemory (NumberOfCpus * AcpiCpuData->StackSize);\r
bfec5efa
MK
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
b5817210 238 // Allocate GDT and IDT and copy current GDT and IDT contents\r
bfec5efa
MK
239 //\r
240 GdtSize = AcpiCpuDataEx->GdtrProfile.Limit + 1;\r
241 IdtSize = AcpiCpuDataEx->IdtrProfile.Limit + 1;\r
053e878b 242 Gdt = AllocateZeroPages (GdtSize + IdtSize);\r
bfec5efa
MK
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
8b371e93 250 if (OldAcpiCpuData != NULL) {\r
010753b7 251 CopyMem (&AcpiCpuData->CpuFeatureInitData, &OldAcpiCpuData->CpuFeatureInitData, sizeof (CPU_FEATURE_INIT_DATA));\r
bfec5efa 252 }\r
bfec5efa
MK
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
65b24ada 262 // The notification function allocates StartupVector and saves MTRRs for ACPI_CPU_DATA\r
bfec5efa
MK
263 //\r
264 Status = gBS->CreateEventEx (\r
265 EVT_NOTIFY_SIGNAL,\r
266 TPL_CALLBACK,\r
65b24ada
JF
267 CpuS3DataOnEndOfDxe,\r
268 AcpiCpuData,\r
bfec5efa
MK
269 &gEfiEndOfDxeEventGroupGuid,\r
270 &Event\r
271 );\r
272 ASSERT_EFI_ERROR (Status);\r
273\r
274 return EFI_SUCCESS;\r
275}\r